From 0f619c65bab2465ffa84eb64cc62fe56506121f8 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Sat, 1 Apr 2006 18:38:34 +0000 Subject: Move Sudoku plugin into its own subdirectory and add a random game generator. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9407 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/SOURCES | 4 - apps/plugins/SUBDIRS | 4 + apps/plugins/sudoku.c | 1166 ---------------- apps/plugins/sudoku/Makefile | 117 ++ apps/plugins/sudoku/SOURCES | 3 + apps/plugins/sudoku/generator.c | 1097 +++++++++++++++ apps/plugins/sudoku/generator.h | 1 + apps/plugins/sudoku/sudoku.c | 1124 +++++++++++++++ apps/plugins/sudoku/sudoku.h | 104 ++ apps/plugins/sudoku/templates.c | 2877 +++++++++++++++++++++++++++++++++++++++ apps/plugins/sudoku/templates.h | 8 + 11 files changed, 5335 insertions(+), 1170 deletions(-) delete mode 100644 apps/plugins/sudoku.c create mode 100644 apps/plugins/sudoku/Makefile create mode 100644 apps/plugins/sudoku/SOURCES create mode 100644 apps/plugins/sudoku/generator.c create mode 100644 apps/plugins/sudoku/generator.h create mode 100644 apps/plugins/sudoku/sudoku.c create mode 100644 apps/plugins/sudoku/sudoku.h create mode 100644 apps/plugins/sudoku/templates.c create mode 100644 apps/plugins/sudoku/templates.h (limited to 'apps') diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 27dfc757be..ba489d0d94 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -58,10 +58,6 @@ solitaire.c sokoban.c star.c starfield.c -#if (LCD_WIDTH != 176) && (LCD_WIDTH != 138) -/* These need adjusting for the iPod Nano and Mini */ -sudoku.c -#endif #if (LCD_WIDTH != 240) && (LCD_WIDTH != 138) && (LCD_WIDTH != 128) tetrox.c #endif diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index 01d9540531..922d562330 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS @@ -16,6 +16,10 @@ rockboy /* For all targets with a bitmap display */ #ifdef HAVE_LCD_BITMAP chessbox +#if (LCD_WIDTH != 176) && (LCD_WIDTH != 138) +/* This needs adjusting for the iPod Nano and Mini */ +sudoku +#endif #endif /* For all the colour targets and iriver H1x0 */ diff --git a/apps/plugins/sudoku.c b/apps/plugins/sudoku.c deleted file mode 100644 index ece0fbb564..0000000000 --- a/apps/plugins/sudoku.c +++ /dev/null @@ -1,1166 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -/*** -Sudoku by Dave Chapman - -User instructions ------------------ - -Use the arrow keys to move cursor, and press SELECT/ON/F2 to increment -the number under the cursor. - -At any time during the game, press On to bring up the game menu with -further options: - - Save - Reload - Clear - Solve - -Sudoku is implemented as a "viewer" for a ".ss" file, as generated by -Simple Sudoku and other applications - http://angusj.com/sudoku/ - -In-progress game positions are saved in the original .ss file, with -A-I used to indicate numbers entered by the user. - -Example ".ss" file, and one with a saved state: - -...|...|... ...|...|... -2..|8.4|9.1 2.C|8.4|9.1 -...|1.6|32. E..|1.6|32. ------------ ----------- -...|..5|.4. ...|..5|.4. -8..|423|..6 8..|423|..6 -.3.|9..|... .3D|9..|A.. ------------ ----------- -.63|7.9|... .63|7.9|... -4.9|5.2|..8 4.9|5.2|.C8 -...|...|... ...|...|... - -*/ - -#include "plugin.h" - -#ifdef HAVE_LCD_BITMAP - -PLUGIN_HEADER - -#define STATE_FILE PLUGIN_DIR "/sudoku.state" -#define GAMES_FILE PLUGIN_DIR "/sudoku.levels" - -/* variable button definitions */ -#if CONFIG_KEYPAD == RECORDER_PAD -#define SUDOKU_BUTTON_QUIT BUTTON_OFF -#define SUDOKU_BUTTON_UP BUTTON_UP -#define SUDOKU_BUTTON_DOWN BUTTON_DOWN -#define SUDOKU_BUTTON_TOGGLE BUTTON_PLAY -#define SUDOKU_BUTTON_MENU BUTTON_F1 -#define SUDOKU_BUTTON_POSSIBLE BUTTON_F2 - -#elif CONFIG_KEYPAD == ONDIO_PAD -#define SUDOKU_BUTTON_QUIT BUTTON_OFF -#define SUDOKU_BUTTON_UP BUTTON_UP -#define SUDOKU_BUTTON_DOWN BUTTON_DOWN -#define SUDOKU_BUTTON_ALTTOGGLE (BUTTON_MENU | BUTTON_DOWN) -#define SUDOKU_BUTTON_TOGGLE_PRE BUTTON_MENU -#define SUDOKU_BUTTON_TOGGLE (BUTTON_MENU | BUTTON_REL) -#define SUDOKU_BUTTON_MENU_PRE BUTTON_MENU -#define SUDOKU_BUTTON_MENU (BUTTON_MENU | BUTTON_REPEAT) -#define SUDOKU_BUTTON_POSSIBLE (BUTTON_MENU | BUTTON_LEFT) - -#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ - (CONFIG_KEYPAD == IRIVER_H300_PAD) -#define SUDOKU_BUTTON_QUIT BUTTON_OFF -#define SUDOKU_BUTTON_UP BUTTON_UP -#define SUDOKU_BUTTON_DOWN BUTTON_DOWN -#define SUDOKU_BUTTON_ALTTOGGLE BUTTON_ON -#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT -#define SUDOKU_BUTTON_MENU BUTTON_MODE -#define SUDOKU_BUTTON_POSSIBLE BUTTON_REC - -#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ - (CONFIG_KEYPAD == IPOD_3G_PAD) -#define SUDOKU_BUTTON_QUIT (BUTTON_SELECT | BUTTON_MENU) -#define SUDOKU_BUTTON_UP BUTTON_SCROLL_BACK -#define SUDOKU_BUTTON_DOWN BUTTON_SCROLL_FWD -#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT -#define SUDOKU_BUTTON_MENU BUTTON_MENU -#define SUDOKU_BUTTON_POSSIBLE (BUTTON_SELECT | BUTTON_LEFT) - -#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) -#define SUDOKU_BUTTON_QUIT BUTTON_POWER -#define SUDOKU_BUTTON_UP BUTTON_UP -#define SUDOKU_BUTTON_DOWN BUTTON_DOWN -#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT -#define SUDOKU_BUTTON_MENU BUTTON_PLAY -#define SUDOKU_BUTTON_POSSIBLE BUTTON_REC - -#elif (CONFIG_KEYPAD == GIGABEAT_PAD) -#define SUDOKU_BUTTON_QUIT BUTTON_A -#define SUDOKU_BUTTON_UP BUTTON_UP -#define SUDOKU_BUTTON_DOWN BUTTON_DOWN -#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT -#define SUDOKU_BUTTON_MENU BUTTON_MENU -#define SUDOKU_BUTTON_POSSIBLE BUTTON_POWER - -#elif - #error SUDOKU: Unsupported keypad -#endif - -/* The bitmaps */ -extern const fb_data sudoku_normal[]; -extern const fb_data sudoku_start[]; -extern const fb_data sudoku_inverse[]; - -#if (LCD_HEIGHT==128) && (LCD_WIDTH==160) -/* For iriver H1x0 - 160x128, 9 cells @ 12x12 with 14 border lines*/ - -/* Internal dimensions of a cell */ -#define CELL_WIDTH 12 -#define CELL_HEIGHT 12 - -#define BOARD_WIDTH (CELL_WIDTH*9+10+4) -#define BOARD_HEIGHT (CELL_HEIGHT*9+10+4) - -#define XOFS (((LCD_WIDTH-BOARD_WIDTH)/2)+10) -#define YOFS ((LCD_HEIGHT-BOARD_HEIGHT)/2) - -#define XOFSSCRATCHPAD 3 - -/* Locations of each cell */ -static unsigned char cellxpos[9]={ 2, 15, 28, 42, 55, 68, 82, 95, 108 }; -static unsigned char cellypos[9]={ 2, 15, 28, 42, 55, 68, 82, 95, 108 }; - -/* The height of one cell in the bitmap */ -#define BITMAP_HEIGHT 12 -#define BITMAP_STRIDE 12 - -#elif (LCD_HEIGHT==64) && (LCD_WIDTH==112) -/* For Archos Recorder, FM and Ondio (112x64): - 9 cells @ 8x6 with 10 border lines -*/ - -/* Internal dimensions of a cell */ -#define CELL_WIDTH 8 -#define CELL_HEIGHT 6 - -#define BOARD_WIDTH (CELL_WIDTH*9+10) -#define BOARD_HEIGHT (CELL_HEIGHT*9+10) - -#define XOFS (((LCD_WIDTH-BOARD_WIDTH)/2)+7) -#define YOFS ((LCD_HEIGHT-BOARD_HEIGHT)/2) - -#define XOFSSCRATCHPAD 2 - -/* Locations of each cell */ -static unsigned char cellxpos[9]={ 1, 10, 19, 28, 37, 46, 55, 64, 73 }; -static unsigned char cellypos[9]={ 1, 8, 15, 22, 29, 36, 43, 50, 57 }; - -/* The height of one cell in the bitmap */ -#define BITMAP_HEIGHT 8 -#define BITMAP_STRIDE 8 - -#elif (LCD_HEIGHT>=176) && (LCD_WIDTH>=220) -/* iriver h300 */ - -/* Internal dimensions of a cell */ -#define CELL_WIDTH 16 -#define CELL_HEIGHT 16 - -#define BOARD_WIDTH (CELL_WIDTH*9+10+4) -#define BOARD_HEIGHT (CELL_HEIGHT*9+10+4) - -#define XOFS (((LCD_WIDTH-BOARD_WIDTH)/2)+15) -#define YOFS ((LCD_HEIGHT-BOARD_HEIGHT)/2) - -#define XOFSSCRATCHPAD 10 - -/* Locations of each cell */ -static unsigned char cellxpos[9]={ 2, 19, 36, 54, 71, 88, 106, 123, 140 }; -static unsigned char cellypos[9]={ 2, 19, 36, 54, 71, 88, 106, 123, 140 }; - -/* The height of one cell in the bitmap */ -#define BITMAP_HEIGHT 16 -#define BITMAP_STRIDE 16 - -#else - #error SUDOKU: Unsupported LCD size -#endif - -/* here is a global api struct pointer. while not strictly necessary, - it's nice not to have to pass the api pointer in all function calls - in the plugin */ -static struct plugin_api* rb; - -struct sudoku_state_t { - char filename[MAX_PATH]; /* Filename */ - char startboard[9][9]; /* The initial state of the game */ - char currentboard[9][9]; /* The current state of the game */ - char savedboard[9][9]; /* Cached copy of saved state */ - int x,y; /* Cursor position */ - int editmode; /* We are editing the start board */ -#ifdef SUDOKU_BUTTON_POSSIBLE - short possiblevals[9][9]; /* possible values a cell could be, user sets them */ -#endif -}; - -/****** Solver routine by Tom Shackell - -Downloaded from: - -http://www-users.cs.york.ac.uk/~shackell/sudoku/Sudoku.html - -Released under GPLv2 - -*/ - -typedef unsigned int Bitset; - -#define BLOCK 3 -#define SIZE (BLOCK*BLOCK) - -#define true 1 -#define false 0 - -typedef struct _Sudoku { - Bitset table[SIZE][SIZE]; -}Sudoku; - -typedef struct _Stats { - int numTries; - int backTracks; - int numEmpty; - bool solutionFound; -}Stats; - -typedef struct _Options { - bool allSolutions; - bool uniquenessCheck; -}Options; - -void sudoku_init(Sudoku* sud); -void sudoku_set(Sudoku* sud, int x, int y, int num, bool original); -int sudoku_get(Sudoku* sud, int x, int y, bool* original); - -#define BIT(n) ((Bitset)(1<<(n))) -#define BIT_TEST(v,n) ((((Bitset)v) & BIT(n)) != 0) -#define BIT_CLEAR(v,n) (v) &= ~BIT(n) -#define MARK_BIT BIT(0) -#define ORIGINAL_BIT BIT(SIZE+1) - -#define ALL_BITS (BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9)) - -/* initialize a sudoku problem, should be called before using set or get */ -void sudoku_init(Sudoku* sud) -{ - int y, x; - for (y = 0; y < SIZE; y++){ - for (x = 0; x < SIZE; x++){ - sud->table[x][y] = ALL_BITS; - } - } -} - -/* set the number at a particular x and y column */ -void sudoku_set(Sudoku* sud, int x, int y, int num, bool original) -{ - int i, j; - int bx, by; - Bitset orig; - - /* clear the row and columns */ - for (i = 0; i < SIZE; i++){ - BIT_CLEAR(sud->table[i][y], num); - BIT_CLEAR(sud->table[x][i], num); - } - /* clear the block */ - bx = x - (x % BLOCK); - by = y - (y % BLOCK); - for (i = 0; i < BLOCK; i++){ - for (j = 0; j < BLOCK; j++){ - BIT_CLEAR(sud->table[bx+j][by+i], num); - } - } - /* mark the table */ - orig = original ? ORIGINAL_BIT : 0; - sud->table[x][y] = BIT(num) | MARK_BIT | orig; -} - -/* get the number at a particular x and y column, if this - is not unique return 0 */ -int sudoku_get(Sudoku* sud, int x, int y, bool* original) -{ - Bitset val = sud->table[x][y]; - int result = 0; - int i; - - if (original) { - *original = val & ORIGINAL_BIT; - } - for (i = 1; i <= SIZE; i++){ - if (BIT_TEST(val, i)){ - if (result != 0){ - return 0; - } - result = i; - } - } - return result; -} - -/* returns true if this is a valid problem, this is necessary because the input - problem might be degenerate which breaks the solver algorithm. */ -static bool is_valid(const Sudoku* sud) -{ - int x, y; - - for (y = 0; y < SIZE; y++){ - for (x = 0; x < SIZE; x++){ - if ((sud->table[x][y] & ALL_BITS) == 0){ - return false; - } - } - } - return true; -} - -/* scan the table for the most constrained item, giving all it's options, sets - the best x and y coordinates, the number of options and the options for - that coordinate and returns true if the puzzle is finished */ -static bool scan(const Sudoku* sud, int* rX, int* rY, int *num, int* options) -{ - int x, y, i, j; - int bestCount = SIZE+1; - Bitset val; - bool allMarked = true; - - for (y = 0; y < SIZE; y++){ - for (x = 0; x < SIZE; x++){ - Bitset val = sud->table[x][y]; - int i; - int count = 0; - - if (val & MARK_BIT) { - /* already set */ - continue; - } - allMarked = false; - for (i = 1; i <= SIZE; i++){ - if (BIT_TEST(val, i)){ - count++; - } - } - if (count < bestCount){ - bestCount = count; - *rX = x; - *rY = y; - if (count == 0){ - /* can't possibly be beaten */ - *num = 0; - return false; - } - } - } - } - /* now copy into options */ - *num = bestCount; - val = sud->table[*rX][*rY]; - for (i = 1, j = 0; i <= SIZE; i++){ - if (BIT_TEST(val, i)){ - options[j++] = i; - } - } - return allMarked; -} - -static bool solve(Sudoku* sud, Stats* stats, const Options* options); - -/* try a particular option and return true if that gives a solution or false - if it doesn't, restores board on backtracking */ -static bool spawn_option(Sudoku* sud, Stats* stats, const Options* options, - int x, int y, int num) -{ - Sudoku copy; - - rb->memcpy(©,sud,sizeof(Sudoku)); - sudoku_set(©, x, y, num, false); - stats->numTries += 1; - if (solve(©, stats, options)){ - if (!options->allSolutions && stats->solutionFound){ - rb->memcpy(sud,©,sizeof(Sudoku)); - } - return true; - }else{ - stats->backTracks++; - } - return false; -} - -/* solve a sudoku problem, returns true if there is a solution and false - otherwise. stats is used to track statisticss */ -static bool solve(Sudoku* sud, Stats* stats, const Options* options) -{ - while (true){ - int x, y, i, num; - int places[SIZE]; - - if (scan(sud, &x, &y, &num, places)){ - /* a solution was found! */ - if (options->uniquenessCheck && stats->solutionFound){ - /*printf("\n\t... But the solution is not unique!\n"); */ - return true; - } - stats->solutionFound = true; - if (options->allSolutions || options->uniquenessCheck){ - /*printf("\n\tSolution after %d iterations\n", stats->numTries); */ - /*sudoku_print(sud); */ - return false; - } - else{ - return true; - } - } - if (num == 0){ - /* can't be satisfied */ - return false; - } - /* try all the places (except the last one) */ - for (i = 0; i < num-1; i++){ - if (spawn_option(sud, stats, options, x, y, places[i])){ - /* solution found! */ - if (!options->allSolutions && stats->solutionFound){ - return true; - } - } - } - /* take the last place ourself */ - stats->numTries += 1; - sudoku_set(sud, x, y, places[num-1], false); - } -} - -/******** END OF IMPORTED CODE */ - - -/* A wrapper function between the Sudoku plugin and the above solver code */ -void sudoku_solve(struct sudoku_state_t* state) -{ - bool ret; - Stats stats; - Options options; - Sudoku sud; - bool original; - int r,c; - - /* Initialise the parameters */ - sudoku_init(&sud); - rb->memset(&stats,0,sizeof(stats)); - options.allSolutions=false; - options.uniquenessCheck=false; - - /* Convert Rockbox format into format for solver */ - for (r=0;r<9;r++) { - for (c=0;c<9;c++) { - if (state->startboard[r][c]!='0') { - sudoku_set(&sud, c, r, state->startboard[r][c]-'0', true); - } - } - } - - /* need to check for degenerate input problems ... */ - if (is_valid(&sud)){ - ret = solve(&sud, &stats, &options); - } else { - ret = false; - } - - if (ret) { - /* Populate the board with the solution. */ - for (r=0;r<9;r++) { - for (c=0;c<9;c++) { - state->currentboard[r][c]='0'+ - sudoku_get(&sud, c, r, &original); - } - } - } else { - rb->splash(HZ*2, true, "Solve failed"); - } - - return; -} - - -void clear_state(struct sudoku_state_t* state) -{ - int r,c; - - state->filename[0]=0; - for (r=0;r<9;r++) { - for (c=0;c<9;c++) { - state->startboard[r][c]='0'; - state->currentboard[r][c]='0'; -#ifdef SUDOKU_BUTTON_POSSIBLE - state->possiblevals[r][c]=0; -#endif - } - } - - state->x=0; - state->y=0; - state->editmode=0; -} - -/* Load game - only ".ss" is officially supported, but any sensible - text representation (one line per row) may load. -*/ -bool load_sudoku(struct sudoku_state_t* state, char* filename) -{ - int fd; - size_t n; - int r = 0, c = 0; - unsigned int i; - int valid=0; - char buf[300]; /* A buffer to read a sudoku board from */ - - fd=rb->open(filename, O_RDONLY); - if (fd < 0) { - rb->splash(HZ*2, true, "Can not open"); - LOGF("Invalid sudoku file: %s\n",filename); - return(false); - } - - rb->strncpy(state->filename,filename,MAX_PATH); - n=rb->read(fd,buf,300); - if (n <= 0) { - return(false); - } - rb->close(fd); - - r=0; - c=0; - i=0; - while ((i < n) && (r < 9)) { - switch (buf[i]){ - case ' ': case '\t': - if (c > 0) - valid=1; - break; - case '|': - case '*': - case '-': - case '\r': - break; - case '\n': - if (valid) { - r++; - valid=0; - } - c = 0; - break; - case '_': case '.': - valid=1; - if (c >= SIZE || r >= SIZE){ - LOGF("ERROR: sudoku problem is the wrong size (%d,%d)\n", - c, r); - return(false); - } - c++; - break; - default: - if (((buf[i]>='A') && (buf[i]<='I')) || - ((buf[i]>='0') && (buf[i]<='9'))) { - valid=1; - if (r >= SIZE || c >= SIZE){ - LOGF("ERROR: sudoku problem is the wrong size " - "(%d,%d)\n", c, r); - return(false); - } - if ((buf[i]>='0') && (buf[i]<='9')) { - state->startboard[r][c]=buf[i]; - state->currentboard[r][c]=buf[i]; - } else { - state->currentboard[r][c]='1'+(buf[i]-'A'); - } - c++; - } - /* Ignore any other characters */ - break; - } - i++; - } - - /* Save a copy of the saved state - so we can reload without using the - disk */ - rb->memcpy(state->savedboard,state->currentboard,81); - return(true); -} - -bool save_sudoku(struct sudoku_state_t* state) -{ - int fd; - int r,c; - int i; - char line[16]; - char sep[16]; - - rb->memcpy(line,"...|...|...\r\n",13); - rb->memcpy(sep,"-----------\r\n",13); - - if (state->filename[0]==0) { - return false; - } - - fd=rb->open(state->filename, O_WRONLY|O_CREAT); - if (fd >= 0) { - for (r=0;r<9;r++) { - i=0; - for (c=0;c<9;c++) { - if (state->startboard[r][c]!='0') { - line[i]=state->startboard[r][c]; - } else if (state->currentboard[r][c]!='0') { - line[i]='A'+(state->currentboard[r][c]-'1'); - } else { - line[i]='.'; - } - i++; - if ((c==2) || (c==5)) { - i++; - } - } - rb->write(fd,line,sizeof(line)-1); - if ((r==2) || (r==5)) { - rb->write(fd,sep,sizeof(sep)-1); - } - } - /* Add a blank line at end */ - rb->write(fd,"\r\n",2); - rb->close(fd); - /* Save a copy of the saved state - so we can reload without - using the disk */ - rb->memcpy(state->savedboard,state->currentboard,81); - return true; - } else { - return false; - } -} - -void restore_state(struct sudoku_state_t* state) -{ - rb->memcpy(state->currentboard,state->savedboard,81); -} - -void clear_board(struct sudoku_state_t* state) -{ - int r,c; - - for (r=0;r<9;r++) { - for (c=0;c<9;c++) { - state->currentboard[r][c]=state->startboard[r][c]; - } - } - state->x=0; - state->y=0; -} - -void update_cell(struct sudoku_state_t* state, int r, int c) -{ - /* We have four types of cell: - 1) User-entered number - 2) Starting number - 3) Cursor in cell - */ - - if ((r==state->y) && (c==state->x)) { - rb->lcd_bitmap_part(sudoku_inverse,0, - BITMAP_HEIGHT*(state->currentboard[r][c]-'0'), - BITMAP_STRIDE, - XOFS+cellxpos[c],YOFS+cellypos[r],CELL_WIDTH, - CELL_HEIGHT); - } else { - if (state->startboard[r][c]!='0') { - rb->lcd_bitmap_part(sudoku_start,0, - BITMAP_HEIGHT*(state->startboard[r][c]-'0'), - BITMAP_STRIDE, - XOFS+cellxpos[c],YOFS+cellypos[r], - CELL_WIDTH,CELL_HEIGHT); - } else { - rb->lcd_bitmap_part(sudoku_normal,0, - BITMAP_HEIGHT*(state->currentboard[r][c]-'0'), - BITMAP_STRIDE, - XOFS+cellxpos[c],YOFS+cellypos[r], - CELL_WIDTH,CELL_HEIGHT); - } - } - - rb->lcd_update_rect(cellxpos[c],cellypos[r],CELL_WIDTH,CELL_HEIGHT); -} - - -void display_board(struct sudoku_state_t* state) -{ - int r,c; - - /* Clear the display buffer */ - rb->lcd_clear_display(); - - /* Draw the gridlines - differently for different targets */ - -#if LCD_HEIGHT > 64 - /* Large targets - draw single/double lines */ - for (r=0;r<9;r++) { - rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-1); - rb->lcd_vline(XOFS+cellxpos[r]-1,YOFS,YOFS+BOARD_HEIGHT-1); - if ((r % 3)==0) { - rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-2); - rb->lcd_vline(XOFS+cellxpos[r]-2,YOFS,YOFS+BOARD_HEIGHT-1); - } - } - rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT); - rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT+1); - rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH,YOFS,YOFS+BOARD_HEIGHT-1); - rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH+1,YOFS,YOFS+BOARD_HEIGHT-1); -#elif (LCD_HEIGHT==64) - /* Small targets - draw dotted/single lines */ - for (r=0;r<9;r++) { - if ((r % 3)==0) { - /* Solid Line */ - rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-1); - rb->lcd_vline(XOFS+cellxpos[r]-1,YOFS,YOFS+BOARD_HEIGHT-1); - } else { - /* Dotted line */ - for (c=XOFS;clcd_drawpixel(c,YOFS+cellypos[r]-1); - } - for (c=YOFS;clcd_drawpixel(XOFS+cellxpos[r]-1,c); - } - } - } - rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT); - rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH,YOFS,YOFS+BOARD_HEIGHT-1); -#else -#error SUDOKU: Unsupported LCD height -#endif - -#ifdef SUDOKU_BUTTON_POSSIBLE - rb->lcd_vline(XOFSSCRATCHPAD,YOFS,YOFS+BOARD_HEIGHT-1); - rb->lcd_vline(XOFSSCRATCHPAD+CELL_WIDTH+1,YOFS,YOFS+BOARD_HEIGHT-1); - for (r=0;r<9;r++) { -#if LCD_HEIGHT > 64 - /* Large targets - draw single/double lines */ - rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, - YOFS+cellypos[r]-1); - if ((r % 3)==0) - rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, - YOFS+cellypos[r]-2); -#elif LCD_HEIGHT == 64 - /* Small targets - draw dotted/single lines */ - if ((r % 3)==0) { - /* Solid Line */ - rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, - YOFS+cellypos[r]-1); - } else { - /* Dotted line */ - for (c=XOFSSCRATCHPAD;clcd_drawpixel(c,YOFS+cellypos[r]-1); - } - } -#endif - if ((r>0) && state->possiblevals[state->y][state->x]&(1<<(r))) - rb->lcd_bitmap_part(sudoku_normal,0,BITMAP_HEIGHT*r,BITMAP_STRIDE, - XOFSSCRATCHPAD+1,YOFS+cellypos[r-1], - CELL_WIDTH,CELL_HEIGHT); - } - rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, - YOFS+cellypos[8]+CELL_HEIGHT); -#if LCD_HEIGHT > 64 - rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, - YOFS+cellypos[8]+CELL_HEIGHT+1); -#endif - if (state->possiblevals[state->y][state->x]&(1<<(r))) - rb->lcd_bitmap_part(sudoku_normal,0,BITMAP_HEIGHT*r,BITMAP_STRIDE, - XOFSSCRATCHPAD+1,YOFS+cellypos[8], - CELL_WIDTH,CELL_HEIGHT); -#endif - - /* Draw the numbers */ - for (r=0;r<9;r++) { - for (c=0;c<9;c++) { - /* We have four types of cell: - 1) User-entered number - 2) Starting number - 3) Cursor in cell - */ - - if ((r==state->y) && (c==state->x)) { - rb->lcd_bitmap_part(sudoku_inverse,0, - BITMAP_HEIGHT*(state->currentboard[r][c]- - '0'), - BITMAP_STRIDE, - XOFS+cellxpos[c],YOFS+cellypos[r], - CELL_WIDTH,CELL_HEIGHT); - } else { - if (state->startboard[r][c]!='0') { - rb->lcd_bitmap_part(sudoku_start,0, - BITMAP_HEIGHT*(state->startboard[r][c]- - '0'), - BITMAP_STRIDE, - XOFS+cellxpos[c],YOFS+cellypos[r], - CELL_WIDTH,CELL_HEIGHT); - } else { - rb->lcd_bitmap_part(sudoku_normal,0, - BITMAP_HEIGHT* - (state->currentboard[r][c]-'0'), - BITMAP_STRIDE, - XOFS+cellxpos[c],YOFS+cellypos[r], - CELL_WIDTH,CELL_HEIGHT); - } - } - } - } - - /* update the screen */ - rb->lcd_update(); -} - -/* Check the status of the board, assuming a change at the cursor location */ -bool check_status(struct sudoku_state_t* state) -{ - int check[9]; - int r,c; - int r1,c1; - int cell; - - /* First, check the column */ - for (cell=0;cell<9;cell++) { - check[cell]=0; - } - for (r=0;r<9;r++) { - cell=state->currentboard[r][state->x]; - if (cell!='0') { - if (check[cell-'1']==1) { - return true; - } - check[cell-'1']=1; - } - } - - /* Second, check the row */ - for (cell=0;cell<9;cell++) { - check[cell]=0; - } - for (c=0;c<9;c++) { - cell=state->currentboard[state->y][c]; - if (cell!='0') { - if (check[cell-'1']==1) { - return true; - } - check[cell-'1']=1; - } - } - - /* Finally, check the 3x3 sub-grid */ - for (cell=0;cell<9;cell++) { - check[cell]=0; - } - r1=(state->y/3)*3; - c1=(state->x/3)*3; - for (r=r1;rcurrentboard[r][c]; - if (cell!='0') { - if (check[cell-'1']==1) { - return true; - } - check[cell-'1']=1; - } - } - } - - /* We passed all the checks :) */ - - return false; -} - -int sudoku_menu_cb(int key, int m) -{ - (void)m; - switch(key) - { -#ifdef MENU_ENTER2 - case MENU_ENTER2: -#endif - case MENU_ENTER: - key = BUTTON_NONE; /* eat the downpress, next menu reacts on release */ - break; - -#ifdef MENU_ENTER2 - case MENU_ENTER2 | BUTTON_REL: -#endif - case MENU_ENTER | BUTTON_REL: - key = MENU_ENTER; /* fake downpress, next menu doesn't like release */ - break; - } - - return key; -} - -bool sudoku_menu(struct sudoku_state_t* state) -{ - int m; - int result; - - static const struct menu_item items[] = { - { "Save", NULL }, - { "Reload", NULL }, - { "Clear", NULL }, - { "Solve", NULL }, - { "New", NULL }, - }; - - m = rb->menu_init(items, sizeof(items) / sizeof(*items), - sudoku_menu_cb, NULL, NULL, NULL); - - result=rb->menu_show(m); - - switch (result) { - case 0: /* Save state */ - save_sudoku(state); - break; - - case 1: /* Restore state */ - restore_state(state); - break; - - case 2: /* Clear all */ - clear_board(state); - break; - - case 3: /* Solve */ - sudoku_solve(state); - break; - - case 4: /* Create a new game manually */ - clear_state(state); - state->editmode=1; - break; - - default: - break; - } - - rb->menu_exit(m); - - return (result==MENU_ATTACHED_USB); -} - -void move_cursor(struct sudoku_state_t* state, int newx, int newy) -{ - int oldx, oldy; - - /* Check that the character at the cursor position is legal */ - if (check_status(state)) { - rb->splash(HZ*2, true, "Illegal move!"); - /* Ignore any button presses during the splash */ - rb->button_clear_queue(); - return; - } - - /* Move Cursor */ - oldx=state->x; - oldy=state->y; - state->x=newx; - state->y=newy; - - /* Redraw current and old cells */ - update_cell(state,oldx,oldy); - update_cell(state,newx,newy); -} - -/* plugin entry point */ -enum plugin_status plugin_start(struct plugin_api* api, void* parameter) -{ - bool exit; - int button; - int lastbutton = BUTTON_NONE; - long ticks; - struct sudoku_state_t state; - - /* plugin init */ - rb = api; - /* end of plugin init */ - - clear_state(&state); - - if (parameter==NULL) { - state.editmode=1; - } else { - if (!load_sudoku(&state,(char*)parameter)) { - rb->splash(HZ*2, true, "Load error"); - return(PLUGIN_ERROR); - } - } - - display_board(&state); - - /* The main game loop */ - exit=false; - ticks=0; - while(!exit) { - button = rb->button_get(true); - - switch(button){ - /* Exit game */ - case SUDOKU_BUTTON_QUIT: - exit=1; - break; - - /* Increment digit */ -#ifdef SUDOKU_BUTTON_ALTTOGGLE - case SUDOKU_BUTTON_ALTTOGGLE | BUTTON_REPEAT: -#endif - case SUDOKU_BUTTON_TOGGLE | BUTTON_REPEAT: - /* Slow down the repeat speed to 1/3 second */ - if ((*rb->current_tick-ticks) < (HZ/3)) { - break; - } - -#ifdef SUDOKU_BUTTON_ALTTOGGLE - case SUDOKU_BUTTON_ALTTOGGLE: -#endif - case SUDOKU_BUTTON_TOGGLE: -#ifdef SUDOKU_BUTTON_TOGGLE_PRE - if ((button == SUDOKU_BUTTON_TOGGLE) - && (lastbutton != SUDOKU_BUTTON_TOGGLE_PRE)) - break; -#endif - /* Increment digit */ - ticks=*rb->current_tick; - if (state.editmode) { - if (state.startboard[state.y][state.x]=='9') { - state.startboard[state.y][state.x]='0'; - state.currentboard[state.y][state.x]='0'; - } else { - state.startboard[state.y][state.x]++; - state.currentboard[state.y][state.x]++; - } - } else { - if (state.startboard[state.y][state.x]=='0') { - if (state.currentboard[state.y][state.x]=='9') { - state.currentboard[state.y][state.x]='0'; - } else { - state.currentboard[state.y][state.x]++; - } - } - } - update_cell(&state,state.y,state.x); - break; - - /* move cursor left */ - case BUTTON_LEFT: - case (BUTTON_LEFT | BUTTON_REPEAT): - if (state.x==0) { - move_cursor(&state,8,state.y); - } else { - move_cursor(&state,state.x-1,state.y); - } - break; - - /* move cursor right */ - case BUTTON_RIGHT: - case (BUTTON_RIGHT | BUTTON_REPEAT): - if (state.x==8) { - move_cursor(&state,0,state.y); - } else { - move_cursor(&state,state.x+1,state.y); - } - break; - - /* move cursor up */ - case SUDOKU_BUTTON_UP: - case (SUDOKU_BUTTON_UP | BUTTON_REPEAT): - if (state.y==0) { - move_cursor(&state,state.x,8); - } else { - move_cursor(&state,state.x,state.y-1); - } - break; - - /* move cursor down */ - case SUDOKU_BUTTON_DOWN: - case (SUDOKU_BUTTON_DOWN | BUTTON_REPEAT): - if (state.y==8) { - move_cursor(&state,state.x,0); - } else { - move_cursor(&state,state.x,state.y+1); - } - break; - - case SUDOKU_BUTTON_MENU: -#ifdef SUDOKU_BUTTON_MENU_PRE - if (lastbutton != SUDOKU_BUTTON_MENU_PRE) - break; -#endif - /* Don't let the user leave a game in a bad state */ - if (check_status(&state)) { - rb->splash(HZ*2, true, "Illegal move!"); - /* Ignore any button presses during the splash */ - rb->button_clear_queue(); - } else { - if (state.editmode) { - rb->kbd_input(state.filename,MAX_PATH); - if (save_sudoku(&state)) { - state.editmode=0; - } else { - rb->splash(HZ*2, true, "Save failed"); - } - } else { - if (sudoku_menu(&state)) { - return PLUGIN_USB_CONNECTED; - } - } - } - break; -#ifdef SUDOKU_BUTTON_POSSIBLE - case SUDOKU_BUTTON_POSSIBLE: - /* Toggle current number in the possiblevals structure */ - if (state.currentboard[state.y][state.x]!='0') { - state.possiblevals[state.y][state.x]^= - (1 << (state.currentboard[state.y][state.x] - '0')); - } - break; -#endif - default: - if (rb->default_event_handler(button) == SYS_USB_CONNECTED) { - /* Quit if USB has been connected */ - return PLUGIN_USB_CONNECTED; - } - break; - } - if (button != BUTTON_NONE) - lastbutton = button; - - display_board(&state); - } - - return PLUGIN_OK; -} - -#endif diff --git a/apps/plugins/sudoku/Makefile b/apps/plugins/sudoku/Makefile new file mode 100644 index 0000000000..9b9c1c6b2e --- /dev/null +++ b/apps/plugins/sudoku/Makefile @@ -0,0 +1,117 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +INCLUDES = -I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ + -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR) +CFLAGS = $(GCCOPTS) $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \ + -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN + +ifdef APPEXTRA + INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) +endif + +LINKFILE := $(OBJDIR)/link.lds +DEPFILE = $(OBJDIR)/dep-sudoku + +# This sets up 'SRC' based on the files mentioned in SOURCES +include $(TOOLSDIR)/makesrc.inc + +SOURCES = $(SRC) +OBJS := $(SRC:%.c=$(OBJDIR)/%.o) +DIRS = . + +ifndef SIMVER + LDS := ../plugin.lds + OUTPUT = $(OUTDIR)/sudoku.rock +else ## simulators + OUTPUT = $(OUTDIR)/sudoku.rock +endif + +all: $(OUTPUT) + +ifndef SIMVER +$(OBJDIR)/sudoku.elf: $(OBJS) $(LINKFILE) $(BITMAPLIBS) + @echo "LD "`basename $@` + @$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \ + $(LINKBITMAPS) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/sudoku.map + +$(OUTPUT): $(OBJDIR)/sudoku.elf + @echo "OBJCOPY "`basename $@` + @$(OC) -O binary $< $@ +else + +ifeq ($(SIMVER), x11) +################################################### +# This is the X11 simulator version + +$(OUTPUT): $(OBJS) + @echo "LD $<" + @$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif + +else # end of x11-simulator +ifeq ($(SIMVER), sdl) +################################################### +# This is the SDL simulator version + +$(OUTPUT): $(OBJS) + @echo "LD $<" + @$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif + +else # end of sdl-simulator +################################################### +# This is the win32 simulator version +DLLTOOLFLAGS = --export-all +DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin + +$(OUTPUT): $(OBJS) + @echo "DLL "`basename $@` + @$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS) + @$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \ + $(BUILDDIR)/libplugin.a $(BITMAPLIBS) -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif +endif # end of win32-simulator +endif +endif # end of simulator section + + +include $(TOOLSDIR)/make.inc + +# MEMORYSIZE should be passed on to this makefile with the chosen memory size +# given in number of MB +$(LINKFILE): $(LDS) + @echo "build "`basename $@` + @cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \ + $(DEFINES) -E -P - >$@ + +clean: + @echo "cleaning sudoku" + @rm -rf $(OBJDIR)/sudoku + @rm -f $(OBJDIR)/sudoku.* $(DEPFILE) + +-include $(DEPFILE) diff --git a/apps/plugins/sudoku/SOURCES b/apps/plugins/sudoku/SOURCES new file mode 100644 index 0000000000..7cce555c93 --- /dev/null +++ b/apps/plugins/sudoku/SOURCES @@ -0,0 +1,3 @@ +sudoku.c +generator.c +templates.c diff --git a/apps/plugins/sudoku/generator.c b/apps/plugins/sudoku/generator.c new file mode 100644 index 0000000000..d43e970ab8 --- /dev/null +++ b/apps/plugins/sudoku/generator.c @@ -0,0 +1,1097 @@ +/* sudoku.c - sudoku game + * + * Writing a fun Su-Do-Ku game has turned out to be a difficult exercise. + * The biggest difficulty is keeping the game fun - and this means allowing + * the user to make mistakes. The game is not much fun if it prevents the + * user from making moves, or if it informs them of an incorrect move. + * With movement constraints, the 'game' is little more than an automated + * solver (and no fun at all). + * + * Another challenge is generating good puzzles that are entertaining to + * solve. It is certainly true that there is an art to creating good + * Su-Do-Ku puzzles, and that good hand generated puzzles are more + * entertaining than many computer generated puzzles - I just hope that + * the algorithm implemented here provides fun puzzles. It is an area + * that needs work. The puzzle classification is very simple, and could + * also do with work. Finally, understanding the automatically generated + * hints is sometimes more work than solving the puzzle - a better, and + * more human friendly, mechanism is needed. + * + * Comments, suggestions, and contributions are always welcome - send email + * to: mike 'at' laurasia.com.au. Note that this code assumes a single + * threaded process, makes extensive use of global variables, and has + * not been written to be reused in other applications. The code makes no + * use of dynamic memory allocation, and hence, requires no heap. It should + * also run with minimal stack space. + * + * This code and accompanying files have been placed into the public domain + * by Michael Kennett, July 2005. It is provided without any warranty + * whatsoever, and in no event shall Michael Kennett be liable for + * any damages of any kind, however caused, arising from this software. + */ + +#include "plugin.h" + +#include "sudoku.h" +#include "templates.h" + +extern struct plugin_api* rb; + +#define assert(x) + +/* Common state encoding in a 32-bit integer: + * bits 0-6 index + * 7-15 state [bit high signals digits not possible] + * 16-19 digit + * 20 fixed [set if digit initially fixed] + * 21 choice [set if solver chose this digit] + * 22 ignore [set if ignored by reapply()] + * 23 unused + * 24-26 hint + * 27-31 unused + */ +#define INDEX_MASK 0x0000007f +#define GET_INDEX(val) (INDEX_MASK&(val)) +#define SET_INDEX(val) (val) + +#define STATE_MASK 0x0000ff80 +#define STATE_SHIFT (7-1) /* digits 1..9 */ +#define DIGIT_STATE(digit) (1<<(STATE_SHIFT+(digit))) + +#define DIGIT_MASK 0x000f0000 +#define DIGIT_SHIFT 16 +#define GET_DIGIT(val) (((val)&DIGIT_MASK)>>(DIGIT_SHIFT)) +#define SET_DIGIT(val) ((val)<<(DIGIT_SHIFT)) + +#define FIXED 0x00100000 +#define CHOICE 0x00200000 +#define IGNORED 0x00400000 + +/* Hint codes (c.f. singles(), pairs(), findmoves()) */ +#define HINT_ROW 0x01000000 +#define HINT_COLUMN 0x02000000 +#define HINT_BLOCK 0x04000000 + +/* For a general board it may be necessary to do backtracking (i.e. to + * rewind the board to an earlier state), and make choices during the + * solution process. This can be implemented naturally using recursion, + * but it is more efficient to maintain a single board. + */ +static int board[ 81 ]; + +/* Addressing board elements: linear array 0..80 */ +#define ROW(idx) ((idx)/9) +#define COLUMN(idx) ((idx)%9) +#define BLOCK(idx) (3*(ROW(idx)/3)+(COLUMN(idx)/3)) +#define INDEX(row,col) (9*(row)+(col)) + +/* Blocks indexed 0..9 */ +#define IDX_BLOCK(row,col) (3*((row)/3)+((col)/3)) +#define TOP_LEFT(block) (INDEX(block/3,block%3)) + +/* Board state */ +#define STATE(idx) ((board[idx])&STATE_MASK) +#define DIGIT(idx) (GET_DIGIT(board[idx])) +#define HINT(idx) ((board[idx])&HINT_MASK) +#define IS_EMPTY(idx) (0 == DIGIT(idx)) +#define DISALLOWED(idx,digit) ((board[idx])&DIGIT_STATE(digit)) +#define IS_FIXED(idx) (board[idx]&FIXED) + +/* Record move history, and maintain a counter for the current + * move number. Concessions are made for the user interface, and + * allow digit 0 to indicate clearing a square. The move history + * is used to support 'undo's for the user interface, and hence + * is larger than required - there is sufficient space to solve + * the puzzle, undo every move, and then redo the puzzle - and + * if the user requires more space, then the full history will be + * lost. + */ +static int idx_history; +static int history[ 3 * 81 ]; + +/* Possible moves for a given board (c.f. fillmoves()). + * Also used by choice() when the deterministic solver has failed, + * and for calculating user hints. The number of hints is stored + * in num_hints, or -1 if no hints calculated. The number of hints + * requested by the user since their last move is stored in req_hints; + * if the user keeps requesting hints, start giving more information. + * Finally, record the last hint issued to the user; attempt to give + * different hints each time. + */ +static int idx_possible; +static int possible[ 81 ]; + +static int pass; /* count # passes of deterministic solver */ + +/* Support for template file */ +static int tmplt[ 81 ]; /* Template indices */ +static int len_tmplt; /* Number of template indices */ + +/* Reset global state */ +static +void +reset( void ) +{ + rb->memset( board, 0x00, sizeof( board ) ); + rb->memset( history, 0x00, sizeof( history ) ); + idx_history = 0; + pass = 0; +} + +/* Management of the move history - compression */ +static +void +compress( int limit ) +{ + int i, j; + for( i = j = 0 ; i < idx_history && j < limit ; ++i ) + if( !( history[ i ] & IGNORED ) ) + history[ j++ ] = history[ i ]; + for( ; i < idx_history ; ++i ) + history[ j++ ] = history[ i ]; + idx_history = j; +} + +/* Management of the move history - adding a move */ +static +void +add_move( int idx, int digit, int choice ) +{ + int i; + + if( sizeof( history ) / sizeof( int ) == idx_history ) + compress( 81 ); + + /* Never ignore the last move */ + history[ idx_history++ ] = SET_INDEX( idx ) | SET_DIGIT( digit ) | choice; + + /* Ignore all previous references to idx */ + for( i = idx_history - 2 ; 0 <= i ; --i ) + if( GET_INDEX( history[ i ] ) == idx ) + { + history[ i ] |= IGNORED; + break; + } +} + +/* Iteration over rows/columns/blocks handled by specialised code. + * Each function returns a block index - call must manage element/idx. + */ +static +int +idx_row( int el, int idx ) /* Index within a row */ +{ + return INDEX( el, idx ); +} + +static +int +idx_column( int el, int idx ) /* Index within a column */ +{ + return INDEX( idx, el ); +} + +static +int +idx_block( int el, int idx ) /* Index within a block */ +{ + return INDEX( 3 * ( el / 3 ) + idx / 3, 3 * ( el % 3 ) + idx % 3 ); +} + +/* Update board state after setting a digit (clearing not handled) + */ +static +void +update( int idx ) +{ + const int row = ROW( idx ); + const int col = COLUMN( idx ); + const int block = IDX_BLOCK( row, col ); + const int mask = DIGIT_STATE( DIGIT( idx ) ); + int i; + + board[ idx ] |= STATE_MASK; /* filled - no choice possible */ + + /* Digit cannot appear in row, column or block */ + for( i = 0 ; i < 9 ; ++i ) + { + board[ idx_row( row, i ) ] |= mask; + board[ idx_column( col, i ) ] |= mask; + board[ idx_block( block, i ) ] |= mask; + } +} + +/* Refresh board state, given move history. Note that this can yield + * an incorrect state if the user has made errors - return -1 if an + * incorrect state is generated; else return 0 for a correct state. + */ +static +int +reapply( void ) +{ + int digit, idx, j; + int allok = 0; + rb->memset( board, 0x00, sizeof( board ) ); + for( j = 0 ; j < idx_history ; ++j ) + if( !( history[ j ] & IGNORED ) && 0 != GET_DIGIT( history[ j ] ) ) + { + idx = GET_INDEX( history[ j ] ); + digit = GET_DIGIT( history[ j ] ); + if( !IS_EMPTY( idx ) || DISALLOWED( idx, digit ) ) + allok = -1; + board[ idx ] = SET_DIGIT( digit ); + if( history[ j ] & FIXED ) + board[ idx ] |= FIXED; + update( idx ); + } + return allok; +} + +/* Clear moves, leaving fixed squares + */ +static +void +clear_moves( void ) +{ + for( idx_history = 0 ; history[ idx_history ] & FIXED ; ++idx_history ) + ; + reapply( ); +} + +static int digits[ 9 ]; /* # digits expressed in element square */ +static int counts[ 9 ]; /* Count of digits (c.f. count_set_digits()) */ + +/* Count # set bits (within STATE_MASK) */ +static +int +numset( int mask ) +{ + int i, n = 0; + for( i = STATE_SHIFT + 1 ; i <= STATE_SHIFT + 9 ; ++i ) + if( mask & (1<memset( counts, 0x00, sizeof( counts ) ); + for( i = 0 ; i < 9 ; ++i ) + digits[ i ] = numset( board[ (*idx_fn)( el, i ) ] ); +} + +/* Fill square with given digit, and update state. + * Returns 0 on success, else -1 on error (i.e. invalid fill) + */ +static +int +fill( int idx, int digit ) +{ + assert( 0 != digit ); + + if( !IS_EMPTY( idx ) ) + return ( DIGIT( idx ) == digit ) ? 0 : -1; + + if( DISALLOWED( idx, digit ) ) + return -1; + + board[ idx ] = SET_DIGIT( digit ); + update( idx ); + add_move( idx, digit, 0 ); + + return 0; +} + +/* Find all squares with a single digit allowed -- do not mutate board */ +static +void +singles( int el, int (*idx_fn)( int, int ), int hintcode ) +{ + int i, j, idx; + + count_set_digits( el, idx_fn ); + + for( i = 0 ; i < 9 ; ++i ) + { + if( 1 == counts[ i ] ) + { + /* Digit 'i+1' appears just once in the element */ + for( j = 0 ; j < 9 ; ++j ) + { + idx = (*idx_fn)( el, j ); + if( !DISALLOWED( idx, i + 1 ) && idx_possible < 81 ) + possible[ idx_possible++ ] = SET_INDEX( idx ) + | SET_DIGIT( i + 1 ) + | hintcode; + } + } + if( 8 == digits[ i ] ) + { + /* 8 digits are masked at this position - just one remaining */ + idx = (*idx_fn)( el, i ); + for( j = 1 ; j <= 9 ; ++j ) + if( 0 == ( STATE( idx ) & DIGIT_STATE( j ) ) && idx_possible < 81 ) + possible[ idx_possible++ ] = SET_INDEX( idx ) + | SET_DIGIT( j ) + | hintcode; + } + } +} + +/* Given the board state, find all possible 'moves' (i.e. squares with just + * a single digit). + * + * Returns the number of (deterministic) moves (and fills the moves array), + * or 0 if no moves are possible. This function does not mutate the board + * state, and hence, can return the same move multiple times (with + * different hints). + */ +static +int +findmoves( void ) +{ + int i; + + idx_possible = 0; + for( i = 0 ; i < 9 ; ++i ) + { + singles( i, idx_row, HINT_ROW ); + singles( i, idx_column, HINT_COLUMN ); + singles( i, idx_block, HINT_BLOCK ); + } + return idx_possible; +} + +/* Strategies for refining the board state + * - 'pairs' if there are two unfilled squares in a given row/column/ + * block with the same state, and just two possibilities, + * then all other unfilled squares in the row/column/block + * CANNOT be either of these digits. + * - 'block' if the unknown squares in a block all appear in the same + * row or column, then all unknown squares outside the block + * and in the same row/column cannot be any of the unknown + * squares in the block. + * - 'common' if all possible locations for a digit in a block appear + * in a row or column, then that digit cannot appear outside + * the block in the same row or column. + * - 'position2' if the positions of 2 unknown digits in a block match + * identically in precisely 2 positions, then those 2 positions + * can only contain the 2 unknown digits. + * + * Recall that each state bit uses a 1 to prevent a digit from + * filling that square. + */ + +static +void +pairs( int el, int (*idx_fn)( int, int ) ) +{ + int i, j, k, mask, idx; + for( i = 0 ; i < 8 ; ++i ) + if( 7 == digits[ i ] ) /* 2 digits unknown */ + for( j = i + 1 ; j < 9 ; ++j ) + { + idx = (*idx_fn)( el, i ); + if( STATE( idx ) == STATE( (*idx_fn)( el, j ) ) ) + { + /* Found a row/column pair - mask other entries */ + mask = STATE_MASK ^ (STATE_MASK & board[ idx ] ); + for( k = 0 ; k < i ; ++k ) + board[ (*idx_fn)( el, k ) ] |= mask; + for( k = i + 1 ; k < j ; ++k ) + board[ (*idx_fn)( el, k ) ] |= mask; + for( k = j + 1 ; k < 9 ; ++k ) + board[ (*idx_fn)( el, k ) ] |= mask; + digits[ j ] = -1; /* now processed */ + } + } +} + +/* Worker: mask elements outside block */ +static +void +exmask( int mask, int block, int el, int (*idx_fn)( int, int ) ) +{ + int i, idx; + + for( i = 0 ; i < 9 ; ++i ) + { + idx = (*idx_fn)( el, i ); + if( block != BLOCK( idx ) && IS_EMPTY( idx ) ) + board[ idx ] |= mask; + } +} + +/* Worker for block() */ +static +void +exblock( int block, int el, int (*idx_fn)( int, int ) ) +{ + int i, idx, mask; + + /* By assumption, all unknown squares in the block appear in the + * same row/column, so to construct a mask for these squares, it + * is sufficient to invert the mask for the known squares in the + * block. + */ + mask = 0; + for( i = 0 ; i < 9 ; ++i ) + { + idx = idx_block( block, i ); + if( !IS_EMPTY( idx ) ) + mask |= DIGIT_STATE( DIGIT( idx ) ); + } + exmask( mask ^ STATE_MASK, block, el, idx_fn ); +} + +static +void +block( int el ) +{ + int i, idx = 0, row, col; + + /* Find first unknown square */ + for( i = 0 ; i < 9 && !IS_EMPTY( idx = idx_block( el, i ) ) ; ++i ) + ; + if( i < 9 ) + { + assert( IS_EMPTY( idx ) ); + row = ROW( idx ); + col = COLUMN( idx ); + for( ++i ; i < 9 ; ++i ) + { + idx = idx_block( el, i ); + if( IS_EMPTY( idx ) ) + { + if( ROW( idx ) != row ) + row = -1; + if( COLUMN( idx ) != col ) + col = -1; + } + } + if( 0 <= row ) + exblock( el, row, idx_row ); + if( 0 <= col ) + exblock( el, col, idx_column ); + } +} + +static +void +common( int el ) +{ + int i, idx, row, col, digit, mask; + + for( digit = 1 ; digit <= 9 ; ++digit ) + { + mask = DIGIT_STATE( digit ); + row = col = -1; /* Value '9' indicates invalid */ + for( i = 0 ; i < 9 ; ++i ) + { + /* Digit possible? */ + idx = idx_block( el, i ); + if( IS_EMPTY( idx ) && 0 == ( board[ idx ] & mask ) ) + { + if( row < 0 ) + row = ROW( idx ); + else + if( row != ROW( idx ) ) + row = 9; /* Digit appears in multiple rows */ + if( col < 0 ) + col = COLUMN( idx ); + else + if( col != COLUMN( idx ) ) + col = 9; /* Digit appears in multiple columns */ + } + } + if( -1 != row && row < 9 ) + exmask( mask, el, row, idx_row ); + if( -1 != col && col < 9 ) + exmask( mask, el, col, idx_column ); + } +} + +/* Encoding of positions of a digit (c.f. position2()) - abuse DIGIT_STATE */ +static int posn_digit[ 10 ]; + +static +void +position2( int el ) +{ + int digit, digit2, i, mask, mask2, posn, count, idx; + + /* Calculate positions of each digit within block */ + for( digit = 1 ; digit <= 9 ; ++digit ) + { + mask = DIGIT_STATE( digit ); + posn_digit[ digit ] = count = posn = 0; + for( i = 0 ; i < 9 ; ++i ) + if( 0 == ( mask & board[ idx_block( el, i ) ] ) ) + { + ++count; + posn |= DIGIT_STATE( i ); + } + if( 2 == count ) + posn_digit[ digit ] = posn; + } + /* Find pairs of matching positions, and mask */ + for( digit = 1 ; digit < 9 ; ++digit ) + if( 0 != posn_digit[ digit ] ) + for( digit2 = digit + 1 ; digit2 <= 9 ; ++digit2 ) + if( posn_digit[ digit ] == posn_digit[ digit2 ] ) + { + mask = STATE_MASK + ^ ( DIGIT_STATE( digit ) | DIGIT_STATE( digit2 ) ); + mask2 = DIGIT_STATE( digit ); + for( i = 0 ; i < 9 ; ++i ) + { + idx = idx_block( el, i ); + if( 0 == ( mask2 & board[ idx ] ) ) + { + assert( 0 == (DIGIT_STATE(digit2) & board[idx]) ); + board[ idx ] |= mask; + } + } + posn_digit[ digit ] = posn_digit[ digit2 ] = 0; + break; + } +} + +/* Find some moves for the board; starts with a simple approach (finding + * singles), and if no moves found, starts using more involved strategies + * until a move is found. The more advanced strategies can mask states + * in the board, making this an efficient mechanism, but difficult for + * a human to understand. + */ +static +int +allmoves( void ) +{ + int i, n; + + n = findmoves( ); + if( 0 < n ) + return n; + + for( i = 0 ; i < 9 ; ++i ) + { + count_set_digits( i, idx_row ); + pairs( i, idx_row ); + + count_set_digits( i, idx_column ); + pairs( i, idx_column ); + + count_set_digits( i, idx_block ); + pairs( i, idx_block ); + } + n = findmoves( ); + if( 0 < n ) + return n; + + for( i = 0 ; i < 9 ; ++i ) + { + block( i ); + common( i ); + position2( i ); + } + return findmoves( ); +} + +/* Helper: sort based on index */ +static +int +cmpindex( const void * a, const void * b ) +{ + return GET_INDEX( *((const int *)b) ) - GET_INDEX( *((const int *)a) ); +} + +/* Return number of hints. The hints mechanism should attempt to find + * 'easy' moves first, and if none are possible, then try for more + * cryptic moves. + */ +int +findhints( void ) +{ + int i, n, mutated = 0; + + n = findmoves( ); + if( n < 2 ) + { + /* Each call to pairs() can mutate the board state, making the + * hints very, very cryptic... so later undo the mutations. + */ + for( i = 0 ; i < 9 ; ++i ) + { + count_set_digits( i, idx_row ); + pairs( i, idx_row ); + + count_set_digits( i, idx_column ); + pairs( i, idx_column ); + + count_set_digits( i, idx_block ); + pairs( i, idx_block ); + } + mutated = 1; + n = findmoves( ); + } + if( n < 2 ) + { + for( i = 0 ; i < 9 ; ++i ) + { + block( i ); + common( i ); + } + mutated = 1; + n = findmoves( ); + } + + /* Sort the possible moves, and allow just one hint per square */ + if( 0 < n ) + { + int i, j; + + rb->qsort( possible, n, sizeof( int ), cmpindex ); + for( i = 0, j = 1 ; j < n ; ++j ) + { + if( GET_INDEX( possible[ i ] ) == GET_INDEX( possible[ j ] ) ) + { + /* Let the user make mistakes - do not assume the + * board is in a consistent state. + */ + if( GET_DIGIT( possible[i] ) == GET_DIGIT( possible[j] ) ) + possible[ i ] |= possible[ j ]; + } + else + i = j; + } + n = i + 1; + } + + /* Undo any mutations of the board state */ + if( mutated ) + reapply( ); + + return n; +} + +/* Deterministic solver; return 0 on success, else -1 on error. + */ +static +int +deterministic( void ) +{ + int i, n; + + n = allmoves( ); + while( 0 < n ) + { + ++pass; + for( i = 0 ; i < n ; ++i ) + if( -1 == fill( GET_INDEX( possible[ i ] ), + GET_DIGIT( possible[ i ] ) ) ) + return -1; + n = allmoves( ); + } + return 0; +} + +/* Return index of square for choice. + * + * If no choice is possible (i.e. board solved or inconsistent), + * return -1. + * + * The current implementation finds a square with the minimum + * number of unknown digits (i.e. maximum # masked digits). + */ +static +int +cmp( const void * e1, const void * e2 ) +{ + return GET_DIGIT( *(const int *)e2 ) - GET_DIGIT( *(const int *)e1 ); +} + +static +int +choice( void ) +{ + int i, n; + for( n = i = 0 ; i < 81 ; ++i ) + if( IS_EMPTY( i ) ) + { + possible[ n ] = SET_INDEX( i ) | SET_DIGIT( numset( board[ i ] ) ); + + /* Inconsistency if square unknown, but nothing possible */ + if( 9 == GET_DIGIT( possible[ n ] ) ) + return -2; + ++n; + } + + if( 0 == n ) + return -1; /* All squares known */ + + rb->qsort( possible, n, sizeof( possible[ 0 ] ), cmp ); + return GET_INDEX( possible[ 0 ] ); +} + +/* Choose a digit for the given square. + * The starting digit is passed as a parameter. + * Returns -1 if no choice possible. + */ +static +int +choose( int idx, int digit ) +{ + for( ; digit <= 9 ; ++digit ) + if( !DISALLOWED( idx, digit ) ) + { + board[ idx ] = SET_DIGIT( digit ); + update( idx ); + add_move( idx, digit, CHOICE ); + return digit; + } + + return -1; +} + +/* Backtrack to a previous choice point, and attempt to reseed + * the search. Return -1 if no further choice possible, or + * the index of the changed square. + * + * Assumes that the move history and board are valid. + */ +static +int +backtrack( void ) +{ + int digit, idx; + + for( ; 0 <= --idx_history ; ) + if( history[ idx_history ] & CHOICE ) + { + /* Remember the last choice, and advance */ + idx = GET_INDEX( history[ idx_history ] ); + digit = GET_DIGIT( history[ idx_history ] ) + 1; + reapply( ); + if( -1 != choose( idx, digit ) ) + return idx; + } + + return -1; +} + +/* Attempt to solve 'board'; return 0 on success else -1 on error. + * + * The solution process attempts to fill-in deterministically as + * much of the board as possible. Once that is no longer possible, + * need to choose a square to fill in. + */ +static +int +solve( void ) +{ + int idx; + + while( 1 ) + { + if( 0 == deterministic( ) ) + { + /* Solved, make a new choice, or rewind a previous choice */ + idx = choice( ); + if( -1 == idx ) + return 0; + else + if( ( idx < 0 || -1 == choose( idx, 1 ) ) && -1 == backtrack( ) ) + return -1; + } + else /* rewind to a previous choice */ + if( -1 == backtrack( ) ) + return -1; + } + return -1; +} + +static +int +init_template( int template ) +{ + int i, row, col; + int mask; + + reset( ); + len_tmplt = 0; + + /* Consume grid - allow leading spaces and comments at end */ + for( row = 0 ; row < 9 ; ++row ) + { + mask=0x100; + for( col = 0 ; col < 9 ; ++col ) + { + if (templates[template][row] & mask) + tmplt[ len_tmplt++ ] = INDEX( row, col ); + mask /= 2; + } + } + + /* Construct move history for a template */ + idx_history = 0; + for( i = 0 ; i < 81 ; ++i ) + if( 0 != DIGIT( i ) ) + history[ idx_history++ ] = i | (DIGIT( i )<<8); + + /* Finally, markup all of these moves as 'fixed' */ + for( i = 0 ; i < idx_history ; ++i ) + history[ i ] |= FIXED; + + return 0; +} + +/* Classify a SuDoKu, given its solution. + * + * The classification is based on the average number of possible moves + * for each pass of the deterministic solver - it is a rather simplistic + * measure, but gives reasonable results. Note also that the classification + * is based on the first solution found (but does handle the pathological + * case of multiple solutions). Note that the average moves per pass + * depends just on the number of squares initially set... this simplifies + * the statistics collection immensely, requiring just the number of passes + * to be counted. + * + * Return 0 on error, else a string classification. + */ + +static +char * +classify( void ) +{ + int i, score; + + pass = 0; + clear_moves( ); + if( -1 == solve( ) ) + return 0; + + score = 81; + for( i = 0 ; i < 81 ; ++i ) + if( IS_FIXED( i ) ) + --score; + + assert( 81 == idx_history ); + + for( i = 0 ; i < 81 ; ++i ) + if( history[ i ] & CHOICE ) + score -= 5; + + if( 15 * pass < score ) + return "very easy"; + else + if( 11 * pass < score ) + return "easy"; + else + if( 7 * pass < score ) + return "medium"; + else + if( 4 * pass < score ) + return "hard"; + else + return "fiendish"; +} + +/* exchange disjoint, identical length blocks of data */ +static +void +exchange( int * a, int * b, int len ) +{ + int i, tmp; + for( i = 0 ; i < len ; ++i ) + { + tmp = a[ i ]; + a[ i ] = b[ i ]; + b[ i ] = tmp; + } +} + +/* rotate left */ +static +void +rotate1_left( int * a, int len ) +{ + int i, tmp; + tmp = a[ 0 ]; + for( i = 1 ; i < len ; ++i ) + a[ i - 1 ] = a[ i ]; + a[ len - 1 ] = tmp; +} + +/* rotate right */ +static +void +rotate1_right( int * a, int len ) +{ + int i, tmp; + tmp = a[ len - 1 ]; + for( i = len - 1 ; 0 < i ; --i ) + a[ i ] = a[ i - 1 ]; + a[ 0 ] = tmp; +} + +/* Generalised left rotation - there is a naturally recursive + * solution that is best implementation using iteration. + * Note that it is not necessary to do repeated unit rotations. + * + * This function is analogous to 'cutting' a 'pack of cards'. + * + * On entry: 0 < idx < len + */ +static +void +rotate( int * a, int len, int idx ) +{ + int xdi = len - idx; + int delta = idx - xdi; + + while( 0 != delta && 0 != idx ) + { + if( delta < 0 ) + { + if( 1 == idx ) + { + rotate1_left( a, len ); + idx = 0; + } + else + { + exchange( a, a + xdi, idx ); + len = xdi; + } + } + else /* 0 < delta */ + { + if( 1 == xdi ) + { + rotate1_right( a, len ); + idx = 0; + } + else + { + exchange( a, a + idx, xdi ); + a += xdi; + len = idx; + idx -= xdi; + } + } + xdi = len - idx; + delta = idx - xdi; + } + if( 0 < idx ) + exchange( a, a + idx, idx ); +} + +/* Shuffle an array of integers */ +static +void +shuffle( int * a, int len ) +{ + int i, j, tmp; + + i = len; + while( 1 <= i ) + { + j = rb->rand( ) % i; + tmp = a[ --i ]; + a[ i ] = a[ j ]; + a[ j ] = tmp; + } +} + +/* Generate a SuDoKu puzzle + * + * The generation process selects a random template, and then attempts + * to fill in the exposed squares to generate a board. The order of the + * digits and of filling in the exposed squares are random. + */ + +/* Select random template; sets tmplt, len_tmplt */ +static +void +select_template( void ) +{ + int i = rb->rand( ) % NUM_TEMPLATES; + init_template( i ); +} + + +static +void +generate( void ) +{ + static int digits[ 9 ]; + + int i; + +start: + for( i = 0 ; i < 9 ; ++i ) + digits[ i ] = i + 1; + + rotate( digits, 9, 1 + rb->rand( ) % 8 ); + shuffle( digits, 9 ); + select_template( ); + + rotate( tmplt, len_tmplt, 1 + rb->rand( ) % ( len_tmplt - 1 ) ); + shuffle( tmplt, len_tmplt ); + + reset( ); /* construct a new board */ + + for( i = 0 ; i < len_tmplt ; ++i ) + fill( tmplt[ i ], digits[ i % 9 ] ); + + if( 0 != solve( ) || idx_history < 81 ) + goto start; + + for( i = 0 ; i < len_tmplt ; ++i ) + board[ tmplt[ i ] ] |= FIXED; + + /* Construct fixed squares */ + for( idx_history = i = 0 ; i < 81 ; ++i ) + if( IS_FIXED( i ) ) + history[ idx_history++ ] = SET_INDEX( i ) + | SET_DIGIT( DIGIT( i ) ) + | FIXED; + clear_moves( ); + + if( 0 != solve( ) || idx_history < 81 ) + goto start; + if( -1 != backtrack( ) && 0 == solve( ) ) + goto start; + + clear_moves( ); +} + +bool sudoku_generate_board(struct sudoku_state_t* state, char** difficulty) +{ + int r,c,i; + + rb->srand(*rb->current_tick); + + generate(); + + i=0; + for (r=0;r<9;r++) { + for (c=0;c<9;c++) { + if( IS_EMPTY( i ) ) + state->startboard[r][c]='0'; + else + state->startboard[r][c]='0'+GET_DIGIT( board[ i ] ); + + state->currentboard[r][c]=state->startboard[r][c]; + i++; + } + } + + *difficulty = classify( ); + return true; +} diff --git a/apps/plugins/sudoku/generator.h b/apps/plugins/sudoku/generator.h new file mode 100644 index 0000000000..3caa98ee19 --- /dev/null +++ b/apps/plugins/sudoku/generator.h @@ -0,0 +1 @@ +bool sudoku_generate_board(struct sudoku_state_t* state, char** difficulty); diff --git a/apps/plugins/sudoku/sudoku.c b/apps/plugins/sudoku/sudoku.c new file mode 100644 index 0000000000..798936b384 --- /dev/null +++ b/apps/plugins/sudoku/sudoku.c @@ -0,0 +1,1124 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/*** +Sudoku by Dave Chapman + +User instructions +----------------- + +Use the arrow keys to move cursor, and press SELECT/ON/F2 to increment +the number under the cursor. + +At any time during the game, press On to bring up the game menu with +further options: + + Save + Reload + Clear + Solve + +Sudoku is implemented as a "viewer" for a ".ss" file, as generated by +Simple Sudoku and other applications - http://angusj.com/sudoku/ + +In-progress game positions are saved in the original .ss file, with +A-I used to indicate numbers entered by the user. + +Example ".ss" file, and one with a saved state: + +...|...|... ...|...|... +2..|8.4|9.1 2.C|8.4|9.1 +...|1.6|32. E..|1.6|32. +----------- ----------- +...|..5|.4. ...|..5|.4. +8..|423|..6 8..|423|..6 +.3.|9..|... .3D|9..|A.. +----------- ----------- +.63|7.9|... .63|7.9|... +4.9|5.2|..8 4.9|5.2|.C8 +...|...|... ...|...|... + +*/ + +#include "plugin.h" + +#ifdef HAVE_LCD_BITMAP + +#include "sudoku.h" +#include "generator.h" + +PLUGIN_HEADER + +struct plugin_api* rb; + +/* The bitmaps */ +extern const fb_data sudoku_normal[]; +extern const fb_data sudoku_start[]; +extern const fb_data sudoku_inverse[]; + +#if (LCD_HEIGHT==128) && (LCD_WIDTH==160) +/* For iriver H1x0 - 160x128, 9 cells @ 12x12 with 14 border lines*/ + +/* Internal dimensions of a cell */ +#define CELL_WIDTH 12 +#define CELL_HEIGHT 12 + +#define BOARD_WIDTH (CELL_WIDTH*9+10+4) +#define BOARD_HEIGHT (CELL_HEIGHT*9+10+4) + +#define XOFS (((LCD_WIDTH-BOARD_WIDTH)/2)+10) +#define YOFS ((LCD_HEIGHT-BOARD_HEIGHT)/2) + +#define XOFSSCRATCHPAD 3 + +/* Locations of each cell */ +static unsigned char cellxpos[9]={ 2, 15, 28, 42, 55, 68, 82, 95, 108 }; +static unsigned char cellypos[9]={ 2, 15, 28, 42, 55, 68, 82, 95, 108 }; + +/* The height of one cell in the bitmap */ +#define BITMAP_HEIGHT 12 +#define BITMAP_STRIDE 12 + +#elif (LCD_HEIGHT==64) && (LCD_WIDTH==112) +/* For Archos Recorder, FM and Ondio (112x64): + 9 cells @ 8x6 with 10 border lines +*/ + +/* Internal dimensions of a cell */ +#define CELL_WIDTH 8 +#define CELL_HEIGHT 6 + +#define BOARD_WIDTH (CELL_WIDTH*9+10) +#define BOARD_HEIGHT (CELL_HEIGHT*9+10) + +#define XOFS (((LCD_WIDTH-BOARD_WIDTH)/2)+7) +#define YOFS ((LCD_HEIGHT-BOARD_HEIGHT)/2) + +#define XOFSSCRATCHPAD 2 + +/* Locations of each cell */ +static unsigned char cellxpos[9]={ 1, 10, 19, 28, 37, 46, 55, 64, 73 }; +static unsigned char cellypos[9]={ 1, 8, 15, 22, 29, 36, 43, 50, 57 }; + +/* The height of one cell in the bitmap */ +#define BITMAP_HEIGHT 8 +#define BITMAP_STRIDE 8 + +#elif (LCD_HEIGHT>=176) && (LCD_WIDTH>=220) +/* iriver h300 */ + +/* Internal dimensions of a cell */ +#define CELL_WIDTH 16 +#define CELL_HEIGHT 16 + +#define BOARD_WIDTH (CELL_WIDTH*9+10+4) +#define BOARD_HEIGHT (CELL_HEIGHT*9+10+4) + +#define XOFS (((LCD_WIDTH-BOARD_WIDTH)/2)+15) +#define YOFS ((LCD_HEIGHT-BOARD_HEIGHT)/2) + +#define XOFSSCRATCHPAD 10 + +/* Locations of each cell */ +static unsigned char cellxpos[9]={ 2, 19, 36, 54, 71, 88, 106, 123, 140 }; +static unsigned char cellypos[9]={ 2, 19, 36, 54, 71, 88, 106, 123, 140 }; + +/* The height of one cell in the bitmap */ +#define BITMAP_HEIGHT 16 +#define BITMAP_STRIDE 16 + +#else + #error SUDOKU: Unsupported LCD size +#endif + +/****** Solver routine by Tom Shackell + +Downloaded from: + +http://www-users.cs.york.ac.uk/~shackell/sudoku/Sudoku.html + +Released under GPLv2 + +*/ + +typedef unsigned int Bitset; + +#define BLOCK 3 +#define SIZE (BLOCK*BLOCK) + +#define true 1 +#define false 0 + +typedef struct _Sudoku { + Bitset table[SIZE][SIZE]; +}Sudoku; + +typedef struct _Stats { + int numTries; + int backTracks; + int numEmpty; + bool solutionFound; +}Stats; + +typedef struct _Options { + bool allSolutions; + bool uniquenessCheck; +}Options; + +void sudoku_init(Sudoku* sud); +void sudoku_set(Sudoku* sud, int x, int y, int num, bool original); +int sudoku_get(Sudoku* sud, int x, int y, bool* original); + +#define BIT(n) ((Bitset)(1<<(n))) +#define BIT_TEST(v,n) ((((Bitset)v) & BIT(n)) != 0) +#define BIT_CLEAR(v,n) (v) &= ~BIT(n) +#define MARK_BIT BIT(0) +#define ORIGINAL_BIT BIT(SIZE+1) + +#define ALL_BITS (BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9)) + +/* initialize a sudoku problem, should be called before using set or get */ +void sudoku_init(Sudoku* sud) +{ + int y, x; + for (y = 0; y < SIZE; y++){ + for (x = 0; x < SIZE; x++){ + sud->table[x][y] = ALL_BITS; + } + } +} + +/* set the number at a particular x and y column */ +void sudoku_set(Sudoku* sud, int x, int y, int num, bool original) +{ + int i, j; + int bx, by; + Bitset orig; + + /* clear the row and columns */ + for (i = 0; i < SIZE; i++){ + BIT_CLEAR(sud->table[i][y], num); + BIT_CLEAR(sud->table[x][i], num); + } + /* clear the block */ + bx = x - (x % BLOCK); + by = y - (y % BLOCK); + for (i = 0; i < BLOCK; i++){ + for (j = 0; j < BLOCK; j++){ + BIT_CLEAR(sud->table[bx+j][by+i], num); + } + } + /* mark the table */ + orig = original ? ORIGINAL_BIT : 0; + sud->table[x][y] = BIT(num) | MARK_BIT | orig; +} + +/* get the number at a particular x and y column, if this + is not unique return 0 */ +int sudoku_get(Sudoku* sud, int x, int y, bool* original) +{ + Bitset val = sud->table[x][y]; + int result = 0; + int i; + + if (original) { + *original = val & ORIGINAL_BIT; + } + for (i = 1; i <= SIZE; i++){ + if (BIT_TEST(val, i)){ + if (result != 0){ + return 0; + } + result = i; + } + } + return result; +} + +/* returns true if this is a valid problem, this is necessary because the input + problem might be degenerate which breaks the solver algorithm. */ +static bool is_valid(const Sudoku* sud) +{ + int x, y; + + for (y = 0; y < SIZE; y++){ + for (x = 0; x < SIZE; x++){ + if ((sud->table[x][y] & ALL_BITS) == 0){ + return false; + } + } + } + return true; +} + +/* scan the table for the most constrained item, giving all it's options, sets + the best x and y coordinates, the number of options and the options for + that coordinate and returns true if the puzzle is finished */ +static bool scan(const Sudoku* sud, int* rX, int* rY, int *num, int* options) +{ + int x, y, i, j; + int bestCount = SIZE+1; + Bitset val; + bool allMarked = true; + + for (y = 0; y < SIZE; y++){ + for (x = 0; x < SIZE; x++){ + Bitset val = sud->table[x][y]; + int i; + int count = 0; + + if (val & MARK_BIT) { + /* already set */ + continue; + } + allMarked = false; + for (i = 1; i <= SIZE; i++){ + if (BIT_TEST(val, i)){ + count++; + } + } + if (count < bestCount){ + bestCount = count; + *rX = x; + *rY = y; + if (count == 0){ + /* can't possibly be beaten */ + *num = 0; + return false; + } + } + } + } + /* now copy into options */ + *num = bestCount; + val = sud->table[*rX][*rY]; + for (i = 1, j = 0; i <= SIZE; i++){ + if (BIT_TEST(val, i)){ + options[j++] = i; + } + } + return allMarked; +} + +static bool solve(Sudoku* sud, Stats* stats, const Options* options); + +/* try a particular option and return true if that gives a solution or false + if it doesn't, restores board on backtracking */ +static bool spawn_option(Sudoku* sud, Stats* stats, const Options* options, + int x, int y, int num) +{ + Sudoku copy; + + rb->memcpy(©,sud,sizeof(Sudoku)); + sudoku_set(©, x, y, num, false); + stats->numTries += 1; + if (solve(©, stats, options)){ + if (!options->allSolutions && stats->solutionFound){ + rb->memcpy(sud,©,sizeof(Sudoku)); + } + return true; + }else{ + stats->backTracks++; + } + return false; +} + +/* solve a sudoku problem, returns true if there is a solution and false + otherwise. stats is used to track statisticss */ +static bool solve(Sudoku* sud, Stats* stats, const Options* options) +{ + while (true){ + int x, y, i, num; + int places[SIZE]; + + if (scan(sud, &x, &y, &num, places)){ + /* a solution was found! */ + if (options->uniquenessCheck && stats->solutionFound){ + /*printf("\n\t... But the solution is not unique!\n"); */ + return true; + } + stats->solutionFound = true; + if (options->allSolutions || options->uniquenessCheck){ + /*printf("\n\tSolution after %d iterations\n", stats->numTries); */ + /*sudoku_print(sud); */ + return false; + } + else{ + return true; + } + } + if (num == 0){ + /* can't be satisfied */ + return false; + } + /* try all the places (except the last one) */ + for (i = 0; i < num-1; i++){ + if (spawn_option(sud, stats, options, x, y, places[i])){ + /* solution found! */ + if (!options->allSolutions && stats->solutionFound){ + return true; + } + } + } + /* take the last place ourself */ + stats->numTries += 1; + sudoku_set(sud, x, y, places[num-1], false); + } +} + +/******** END OF IMPORTED CODE */ + + +/* A wrapper function between the Sudoku plugin and the above solver code */ +void sudoku_solve(struct sudoku_state_t* state) +{ + bool ret; + Stats stats; + Options options; + Sudoku sud; + bool original; + int r,c; + + /* Initialise the parameters */ + sudoku_init(&sud); + rb->memset(&stats,0,sizeof(stats)); + options.allSolutions=false; + options.uniquenessCheck=false; + + /* Convert Rockbox format into format for solver */ + for (r=0;r<9;r++) { + for (c=0;c<9;c++) { + if (state->startboard[r][c]!='0') { + sudoku_set(&sud, c, r, state->startboard[r][c]-'0', true); + } + } + } + + /* need to check for degenerate input problems ... */ + if (is_valid(&sud)){ + ret = solve(&sud, &stats, &options); + } else { + ret = false; + } + + if (ret) { + /* Populate the board with the solution. */ + for (r=0;r<9;r++) { + for (c=0;c<9;c++) { + state->currentboard[r][c]='0'+ + sudoku_get(&sud, c, r, &original); + } + } + } else { + rb->splash(HZ*2, true, "Solve failed"); + } + + return; +} + + +void clear_state(struct sudoku_state_t* state) +{ + int r,c; + + state->filename[0]=0; + for (r=0;r<9;r++) { + for (c=0;c<9;c++) { + state->startboard[r][c]='0'; + state->currentboard[r][c]='0'; +#ifdef SUDOKU_BUTTON_POSSIBLE + state->possiblevals[r][c]=0; +#endif + } + } + + state->x=0; + state->y=0; + state->editmode=0; +} + +/* Load game - only ".ss" is officially supported, but any sensible + text representation (one line per row) may load. +*/ +bool load_sudoku(struct sudoku_state_t* state, char* filename) +{ + int fd; + size_t n; + int r = 0, c = 0; + unsigned int i; + int valid=0; + char buf[300]; /* A buffer to read a sudoku board from */ + + fd=rb->open(filename, O_RDONLY); + if (fd < 0) { + LOGF("Invalid sudoku file: %s\n",filename); + return(false); + } + + rb->strncpy(state->filename,filename,MAX_PATH); + n=rb->read(fd,buf,300); + if (n <= 0) { + return(false); + } + rb->close(fd); + + r=0; + c=0; + i=0; + while ((i < n) && (r < 9)) { + switch (buf[i]){ + case ' ': case '\t': + if (c > 0) + valid=1; + break; + case '|': + case '*': + case '-': + case '\r': + break; + case '\n': + if (valid) { + r++; + valid=0; + } + c = 0; + break; + case '_': case '.': + valid=1; + if (c >= SIZE || r >= SIZE){ + LOGF("ERROR: sudoku problem is the wrong size (%d,%d)\n", + c, r); + return(false); + } + c++; + break; + default: + if (((buf[i]>='A') && (buf[i]<='I')) || + ((buf[i]>='0') && (buf[i]<='9'))) { + valid=1; + if (r >= SIZE || c >= SIZE){ + LOGF("ERROR: sudoku problem is the wrong size " + "(%d,%d)\n", c, r); + return(false); + } + if ((buf[i]>='0') && (buf[i]<='9')) { + state->startboard[r][c]=buf[i]; + state->currentboard[r][c]=buf[i]; + } else { + state->currentboard[r][c]='1'+(buf[i]-'A'); + } + c++; + } + /* Ignore any other characters */ + break; + } + i++; + } + + /* Save a copy of the saved state - so we can reload without using the + disk */ + rb->memcpy(state->savedboard,state->currentboard,81); + return(true); +} + +bool save_sudoku(struct sudoku_state_t* state) +{ + int fd; + int r,c; + int i; + char line[13]; + char sep[13]; + + rb->memcpy(line,"...|...|...\r\n",13); + rb->memcpy(sep,"-----------\r\n",13); + + if (state->filename[0]==0) { + return false; + } + + fd=rb->open(state->filename, O_WRONLY|O_CREAT); + if (fd >= 0) { + for (r=0;r<9;r++) { + i=0; + for (c=0;c<9;c++) { + if (state->startboard[r][c]!='0') { + line[i]=state->startboard[r][c]; + } else if (state->currentboard[r][c]!='0') { + line[i]='A'+(state->currentboard[r][c]-'1'); + } else { + line[i]='.'; + } + i++; + if ((c==2) || (c==5)) { + i++; + } + } + rb->write(fd,line,sizeof(line)); + if ((r==2) || (r==5)) { + rb->write(fd,sep,sizeof(sep)); + } + } + /* Add a blank line at end */ + rb->write(fd,"\r\n",2); + rb->close(fd); + /* Save a copy of the saved state - so we can reload without + using the disk */ + rb->memcpy(state->savedboard,state->currentboard,81); + return true; + } else { + return false; + } +} + +void restore_state(struct sudoku_state_t* state) +{ + rb->memcpy(state->currentboard,state->savedboard,81); +} + +void clear_board(struct sudoku_state_t* state) +{ + int r,c; + + for (r=0;r<9;r++) { + for (c=0;c<9;c++) { + state->currentboard[r][c]=state->startboard[r][c]; + } + } + state->x=0; + state->y=0; +} + +void update_cell(struct sudoku_state_t* state, int r, int c) +{ + /* We have four types of cell: + 1) User-entered number + 2) Starting number + 3) Cursor in cell + */ + + if ((r==state->y) && (c==state->x)) { + rb->lcd_bitmap_part(sudoku_inverse,0, + BITMAP_HEIGHT*(state->currentboard[r][c]-'0'), + BITMAP_STRIDE, + XOFS+cellxpos[c],YOFS+cellypos[r],CELL_WIDTH, + CELL_HEIGHT); + } else { + if (state->startboard[r][c]!='0') { + rb->lcd_bitmap_part(sudoku_start,0, + BITMAP_HEIGHT*(state->startboard[r][c]-'0'), + BITMAP_STRIDE, + XOFS+cellxpos[c],YOFS+cellypos[r], + CELL_WIDTH,CELL_HEIGHT); + } else { + rb->lcd_bitmap_part(sudoku_normal,0, + BITMAP_HEIGHT*(state->currentboard[r][c]-'0'), + BITMAP_STRIDE, + XOFS+cellxpos[c],YOFS+cellypos[r], + CELL_WIDTH,CELL_HEIGHT); + } + } + + rb->lcd_update_rect(cellxpos[c],cellypos[r],CELL_WIDTH,CELL_HEIGHT); +} + + +void display_board(struct sudoku_state_t* state) +{ + int r,c; + + /* Clear the display buffer */ + rb->lcd_clear_display(); + + /* Draw the gridlines - differently for different targets */ + +#if LCD_HEIGHT > 64 + /* Large targets - draw single/double lines */ + for (r=0;r<9;r++) { + rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-1); + rb->lcd_vline(XOFS+cellxpos[r]-1,YOFS,YOFS+BOARD_HEIGHT-1); + if ((r % 3)==0) { + rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-2); + rb->lcd_vline(XOFS+cellxpos[r]-2,YOFS,YOFS+BOARD_HEIGHT-1); + } + } + rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT); + rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT+1); + rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH,YOFS,YOFS+BOARD_HEIGHT-1); + rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH+1,YOFS,YOFS+BOARD_HEIGHT-1); +#elif (LCD_HEIGHT==64) + /* Small targets - draw dotted/single lines */ + for (r=0;r<9;r++) { + if ((r % 3)==0) { + /* Solid Line */ + rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-1); + rb->lcd_vline(XOFS+cellxpos[r]-1,YOFS,YOFS+BOARD_HEIGHT-1); + } else { + /* Dotted line */ + for (c=XOFS;clcd_drawpixel(c,YOFS+cellypos[r]-1); + } + for (c=YOFS;clcd_drawpixel(XOFS+cellxpos[r]-1,c); + } + } + } + rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT); + rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH,YOFS,YOFS+BOARD_HEIGHT-1); +#else +#error SUDOKU: Unsupported LCD height +#endif + +#ifdef SUDOKU_BUTTON_POSSIBLE + rb->lcd_vline(XOFSSCRATCHPAD,YOFS,YOFS+BOARD_HEIGHT-1); + rb->lcd_vline(XOFSSCRATCHPAD+CELL_WIDTH+1,YOFS,YOFS+BOARD_HEIGHT-1); + for (r=0;r<9;r++) { +#if LCD_HEIGHT > 64 + /* Large targets - draw single/double lines */ + rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, + YOFS+cellypos[r]-1); + if ((r % 3)==0) + rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, + YOFS+cellypos[r]-2); +#elif LCD_HEIGHT == 64 + /* Small targets - draw dotted/single lines */ + if ((r % 3)==0) { + /* Solid Line */ + rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, + YOFS+cellypos[r]-1); + } else { + /* Dotted line */ + for (c=XOFSSCRATCHPAD;clcd_drawpixel(c,YOFS+cellypos[r]-1); + } + } +#endif + if ((r>0) && state->possiblevals[state->y][state->x]&(1<<(r))) + rb->lcd_bitmap_part(sudoku_normal,0,BITMAP_HEIGHT*r,BITMAP_STRIDE, + XOFSSCRATCHPAD+1,YOFS+cellypos[r-1], + CELL_WIDTH,CELL_HEIGHT); + } + rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, + YOFS+cellypos[8]+CELL_HEIGHT); +#if LCD_HEIGHT > 64 + rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1, + YOFS+cellypos[8]+CELL_HEIGHT+1); +#endif + if (state->possiblevals[state->y][state->x]&(1<<(r))) + rb->lcd_bitmap_part(sudoku_normal,0,BITMAP_HEIGHT*r,BITMAP_STRIDE, + XOFSSCRATCHPAD+1,YOFS+cellypos[8], + CELL_WIDTH,CELL_HEIGHT); +#endif + + /* Draw the numbers */ + for (r=0;r<9;r++) { + for (c=0;c<9;c++) { + /* We have four types of cell: + 1) User-entered number + 2) Starting number + 3) Cursor in cell + */ + + if ((r==state->y) && (c==state->x)) { + rb->lcd_bitmap_part(sudoku_inverse,0, + BITMAP_HEIGHT*(state->currentboard[r][c]- + '0'), + BITMAP_STRIDE, + XOFS+cellxpos[c],YOFS+cellypos[r], + CELL_WIDTH,CELL_HEIGHT); + } else { + if (state->startboard[r][c]!='0') { + rb->lcd_bitmap_part(sudoku_start,0, + BITMAP_HEIGHT*(state->startboard[r][c]- + '0'), + BITMAP_STRIDE, + XOFS+cellxpos[c],YOFS+cellypos[r], + CELL_WIDTH,CELL_HEIGHT); + } else { + rb->lcd_bitmap_part(sudoku_normal,0, + BITMAP_HEIGHT* + (state->currentboard[r][c]-'0'), + BITMAP_STRIDE, + XOFS+cellxpos[c],YOFS+cellypos[r], + CELL_WIDTH,CELL_HEIGHT); + } + } + } + } + + /* update the screen */ + rb->lcd_update(); +} + +/* Check the status of the board, assuming a change at the cursor location */ +bool check_status(struct sudoku_state_t* state) +{ + int check[9]; + int r,c; + int r1,c1; + int cell; + + /* First, check the column */ + for (cell=0;cell<9;cell++) { + check[cell]=0; + } + for (r=0;r<9;r++) { + cell=state->currentboard[r][state->x]; + if (cell!='0') { + if (check[cell-'1']==1) { + return true; + } + check[cell-'1']=1; + } + } + + /* Second, check the row */ + for (cell=0;cell<9;cell++) { + check[cell]=0; + } + for (c=0;c<9;c++) { + cell=state->currentboard[state->y][c]; + if (cell!='0') { + if (check[cell-'1']==1) { + return true; + } + check[cell-'1']=1; + } + } + + /* Finally, check the 3x3 sub-grid */ + for (cell=0;cell<9;cell++) { + check[cell]=0; + } + r1=(state->y/3)*3; + c1=(state->x/3)*3; + for (r=r1;rcurrentboard[r][c]; + if (cell!='0') { + if (check[cell-'1']==1) { + return true; + } + check[cell-'1']=1; + } + } + } + + /* We passed all the checks :) */ + + return false; +} + +void sudoku_generate(struct sudoku_state_t* state) +{ + char* difficulty; + char str[80]; + + clear_state(state); + display_board(state); + rb->splash(0, true, "Generating..."); + + sudoku_generate_board(state,&difficulty); + + rb->snprintf(str,sizeof(str),"Difficulty: %s",difficulty); + display_board(state); + rb->splash(3*HZ, true, str); + rb->strncpy(state->filename,GAME_FILE,MAX_PATH); +} + +int sudoku_menu_cb(int key, int m) +{ + (void)m; + switch(key) + { +#ifdef MENU_ENTER2 + case MENU_ENTER2: +#endif + case MENU_ENTER: + key = BUTTON_NONE; /* eat the downpress, next menu reacts on release */ + break; + +#ifdef MENU_ENTER2 + case MENU_ENTER2 | BUTTON_REL: +#endif + case MENU_ENTER | BUTTON_REL: + key = MENU_ENTER; /* fake downpress, next menu doesn't like release */ + break; + } + + return key; +} + +bool sudoku_menu(struct sudoku_state_t* state) +{ + int m; + int result; + + static const struct menu_item items[] = { + { "Save", NULL }, + { "Reload", NULL }, + { "Clear", NULL }, + { "Solve", NULL }, + { "Generate", NULL }, + { "New", NULL }, + { "Quit", NULL }, + }; + + m = rb->menu_init(items, sizeof(items) / sizeof(*items), + sudoku_menu_cb, NULL, NULL, NULL); + + result=rb->menu_show(m); + + switch (result) { + case 0: /* Save state */ + save_sudoku(state); + break; + + case 1: /* Restore state */ + restore_state(state); + break; + + case 2: /* Clear all */ + clear_board(state); + break; + + case 3: /* Solve */ + sudoku_solve(state); + break; + + case 4: /* Generate Game */ + sudoku_generate(state); + break; + + case 5: /* Create a new game manually */ + clear_state(state); + state->editmode=1; + break; + + case 6: /* Quit */ + save_sudoku(state); + rb->menu_exit(m); + return true; + break; + + default: + break; + } + + rb->menu_exit(m); + + return (result==MENU_ATTACHED_USB); +} + +void move_cursor(struct sudoku_state_t* state, int newx, int newy) +{ + int oldx, oldy; + + /* Check that the character at the cursor position is legal */ + if (check_status(state)) { + rb->splash(HZ*2, true, "Illegal move!"); + /* Ignore any button presses during the splash */ + rb->button_clear_queue(); + return; + } + + /* Move Cursor */ + oldx=state->x; + oldy=state->y; + state->x=newx; + state->y=newy; + + /* Redraw current and old cells */ + update_cell(state,oldx,oldy); + update_cell(state,newx,newy); +} + +/* plugin entry point */ +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + bool exit; + int button; + int lastbutton = BUTTON_NONE; + long ticks; + struct sudoku_state_t state; + + /* plugin init */ + rb = api; + /* end of plugin init */ + + clear_state(&state); + + if (parameter==NULL) { + /* We have been started as a plugin - try default sudoku.ss */ + if (!load_sudoku(&state,GAME_FILE)) { + /* No previous game saved, generate one */ + sudoku_generate(&state); + } + } else { + if (!load_sudoku(&state,(char*)parameter)) { + rb->splash(HZ*2, true, "Load error"); + return(PLUGIN_ERROR); + } + } + + display_board(&state); + + /* The main game loop */ + exit=false; + ticks=0; + while(!exit) { + button = rb->button_get(true); + + switch(button){ + /* Exit game */ + case SUDOKU_BUTTON_QUIT: + exit=1; + break; + + /* Increment digit */ +#ifdef SUDOKU_BUTTON_ALTTOGGLE + case SUDOKU_BUTTON_ALTTOGGLE | BUTTON_REPEAT: +#endif + case SUDOKU_BUTTON_TOGGLE | BUTTON_REPEAT: + /* Slow down the repeat speed to 1/3 second */ + if ((*rb->current_tick-ticks) < (HZ/3)) { + break; + } + +#ifdef SUDOKU_BUTTON_ALTTOGGLE + case SUDOKU_BUTTON_ALTTOGGLE: +#endif + case SUDOKU_BUTTON_TOGGLE: +#ifdef SUDOKU_BUTTON_TOGGLE_PRE + if ((button == SUDOKU_BUTTON_TOGGLE) + && (lastbutton != SUDOKU_BUTTON_TOGGLE_PRE)) + break; +#endif + /* Increment digit */ + ticks=*rb->current_tick; + if (state.editmode) { + if (state.startboard[state.y][state.x]=='9') { + state.startboard[state.y][state.x]='0'; + state.currentboard[state.y][state.x]='0'; + } else { + state.startboard[state.y][state.x]++; + state.currentboard[state.y][state.x]++; + } + } else { + if (state.startboard[state.y][state.x]=='0') { + if (state.currentboard[state.y][state.x]=='9') { + state.currentboard[state.y][state.x]='0'; + } else { + state.currentboard[state.y][state.x]++; + } + } + } + update_cell(&state,state.y,state.x); + break; + + /* move cursor left */ + case BUTTON_LEFT: + case (BUTTON_LEFT | BUTTON_REPEAT): + if (state.x==0) { + move_cursor(&state,8,state.y); + } else { + move_cursor(&state,state.x-1,state.y); + } + break; + + /* move cursor right */ + case BUTTON_RIGHT: + case (BUTTON_RIGHT | BUTTON_REPEAT): + if (state.x==8) { + move_cursor(&state,0,state.y); + } else { + move_cursor(&state,state.x+1,state.y); + } + break; + + /* move cursor up */ + case SUDOKU_BUTTON_UP: + case (SUDOKU_BUTTON_UP | BUTTON_REPEAT): + if (state.y==0) { + move_cursor(&state,state.x,8); + } else { + move_cursor(&state,state.x,state.y-1); + } + break; + + /* move cursor down */ + case SUDOKU_BUTTON_DOWN: + case (SUDOKU_BUTTON_DOWN | BUTTON_REPEAT): + if (state.y==8) { + move_cursor(&state,state.x,0); + } else { + move_cursor(&state,state.x,state.y+1); + } + break; + + case SUDOKU_BUTTON_MENU: +#ifdef SUDOKU_BUTTON_MENU_PRE + if (lastbutton != SUDOKU_BUTTON_MENU_PRE) + break; +#endif + /* Don't let the user leave a game in a bad state */ + if (check_status(&state)) { + rb->splash(HZ*2, true, "Illegal move!"); + /* Ignore any button presses during the splash */ + rb->button_clear_queue(); + } else { + if (state.editmode) { + rb->kbd_input(state.filename,MAX_PATH); + if (save_sudoku(&state)) { + state.editmode=0; + } else { + rb->splash(HZ*2, true, "Save failed"); + } + } else { + if (sudoku_menu(&state)) { + return PLUGIN_USB_CONNECTED; + } + } + } + break; +#ifdef SUDOKU_BUTTON_POSSIBLE + case SUDOKU_BUTTON_POSSIBLE: + /* Toggle current number in the possiblevals structure */ + if (state.currentboard[state.y][state.x]!='0') { + state.possiblevals[state.y][state.x]^= + (1 << (state.currentboard[state.y][state.x] - '0')); + } + break; +#endif + default: + if (rb->default_event_handler(button) == SYS_USB_CONNECTED) { + /* Quit if USB has been connected */ + return PLUGIN_USB_CONNECTED; + } + break; + } + if (button != BUTTON_NONE) + lastbutton = button; + + display_board(&state); + } + + return PLUGIN_OK; +} + +#endif diff --git a/apps/plugins/sudoku/sudoku.h b/apps/plugins/sudoku/sudoku.h new file mode 100644 index 0000000000..cdad581767 --- /dev/null +++ b/apps/plugins/sudoku/sudoku.h @@ -0,0 +1,104 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _SUDOKU_H +#define _SUDOKU_H + +#include "plugin.h" + +/* here is a global api struct pointer. while not strictly necessary, + it's nice not to have to pass the api pointer in all function calls + in the plugin */ + +#define STATE_FILE PLUGIN_DIR "/sudoku.state" +#define GAME_FILE PLUGIN_DIR "/sudoku.ss" + +/* variable button definitions */ +#if CONFIG_KEYPAD == RECORDER_PAD +#define SUDOKU_BUTTON_QUIT BUTTON_OFF +#define SUDOKU_BUTTON_UP BUTTON_UP +#define SUDOKU_BUTTON_DOWN BUTTON_DOWN +#define SUDOKU_BUTTON_TOGGLE BUTTON_PLAY +#define SUDOKU_BUTTON_MENU BUTTON_F1 +#define SUDOKU_BUTTON_POSSIBLE BUTTON_F2 + +#elif CONFIG_KEYPAD == ONDIO_PAD +#define SUDOKU_BUTTON_QUIT BUTTON_OFF +#define SUDOKU_BUTTON_UP BUTTON_UP +#define SUDOKU_BUTTON_DOWN BUTTON_DOWN +#define SUDOKU_BUTTON_ALTTOGGLE (BUTTON_MENU | BUTTON_DOWN) +#define SUDOKU_BUTTON_TOGGLE_PRE BUTTON_MENU +#define SUDOKU_BUTTON_TOGGLE (BUTTON_MENU | BUTTON_REL) +#define SUDOKU_BUTTON_MENU_PRE BUTTON_MENU +#define SUDOKU_BUTTON_MENU (BUTTON_MENU | BUTTON_REPEAT) +#define SUDOKU_BUTTON_POSSIBLE (BUTTON_MENU | BUTTON_LEFT) + +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_PAD) +#define SUDOKU_BUTTON_QUIT BUTTON_OFF +#define SUDOKU_BUTTON_UP BUTTON_UP +#define SUDOKU_BUTTON_DOWN BUTTON_DOWN +#define SUDOKU_BUTTON_ALTTOGGLE BUTTON_ON +#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT +#define SUDOKU_BUTTON_MENU BUTTON_MODE +#define SUDOKU_BUTTON_POSSIBLE BUTTON_REC + +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ + (CONFIG_KEYPAD == IPOD_3G_PAD) +#define SUDOKU_BUTTON_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define SUDOKU_BUTTON_UP BUTTON_SCROLL_BACK +#define SUDOKU_BUTTON_DOWN BUTTON_SCROLL_FWD +#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT +#define SUDOKU_BUTTON_MENU BUTTON_MENU +#define SUDOKU_BUTTON_POSSIBLE (BUTTON_SELECT | BUTTON_LEFT) + +#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) +#define SUDOKU_BUTTON_QUIT BUTTON_POWER +#define SUDOKU_BUTTON_UP BUTTON_UP +#define SUDOKU_BUTTON_DOWN BUTTON_DOWN +#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT +#define SUDOKU_BUTTON_MENU BUTTON_PLAY +#define SUDOKU_BUTTON_POSSIBLE BUTTON_REC + +#elif (CONFIG_KEYPAD == GIGABEAT_PAD) +#define SUDOKU_BUTTON_QUIT BUTTON_A +#define SUDOKU_BUTTON_UP BUTTON_UP +#define SUDOKU_BUTTON_DOWN BUTTON_DOWN +#define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT +#define SUDOKU_BUTTON_MENU BUTTON_MENU +#define SUDOKU_BUTTON_POSSIBLE BUTTON_POWER + +#elif + #error SUDOKU: Unsupported keypad +#endif + +struct sudoku_state_t { + char filename[MAX_PATH]; /* Filename */ + char startboard[9][9]; /* The initial state of the game */ + char currentboard[9][9]; /* The current state of the game */ + char savedboard[9][9]; /* Cached copy of saved state */ + int x,y; /* Cursor position */ + int editmode; /* We are editing the start board */ +#ifdef SUDOKU_BUTTON_POSSIBLE + short possiblevals[9][9]; /* possible values a cell could be, user sets them */ +#endif +}; + + +#endif diff --git a/apps/plugins/sudoku/templates.c b/apps/plugins/sudoku/templates.c new file mode 100644 index 0000000000..9f2117d8d4 --- /dev/null +++ b/apps/plugins/sudoku/templates.c @@ -0,0 +1,2877 @@ +/* Template boards for the game generator */ + +#include "templates.h" + +const unsigned short templates[NUM_TEMPLATES][9] = { +{ + 0x016d, /* #.##.##.# */ + 0x006c, /* ..##.##.. */ + 0x0089, /* .#...#..# */ + 0x0116, /* #...#.##. */ + 0x0082, /* .#.....#. */ + 0x00d1, /* .##.#...# */ + 0x0122, /* #..#...#. */ + 0x006c, /* ..##.##.. */ + 0x016d, /* #.##.##.# */ +}, +{ + 0x0143, /* #.#....## */ + 0x0031, /* ...##...# */ + 0x01d1, /* ###.#...# */ + 0x0023, /* ...#...## */ + 0x016d, /* #.##.##.# */ + 0x0188, /* ##...#... */ + 0x0117, /* #...#.### */ + 0x0118, /* #...##... */ + 0x0185, /* ##....#.# */ +}, +{ + 0x0185, /* ##....#.# */ + 0x00e3, /* .###...## */ + 0x0132, /* #..##..#. */ + 0x002e, /* ...#.###. */ + 0x0054, /* ..#.#.#.. */ + 0x00e8, /* .###.#... */ + 0x0099, /* .#..##..# */ + 0x018e, /* ##...###. */ + 0x0143, /* #.#....## */ +}, +{ + 0x0189, /* ##...#..# */ + 0x001a, /* ....##.#. */ + 0x01e2, /* ####...#. */ + 0x0055, /* ..#.#.#.# */ + 0x0129, /* #..#.#..# */ + 0x0154, /* #.#.#.#.. */ + 0x008f, /* .#...#### */ + 0x00b0, /* .#.##.... */ + 0x0123, /* #..#...## */ +}, +{ + 0x018b, /* ##...#.## */ + 0x0199, /* ##..##..# */ + 0x0014, /* ....#.#.. */ + 0x008e, /* .#...###. */ + 0x006c, /* ..##.##.. */ + 0x00e2, /* .###...#. */ + 0x0050, /* ..#.#.... */ + 0x0133, /* #..##..## */ + 0x01a3, /* ##.#...## */ +}, +{ + 0x002e, /* ...#.###. */ + 0x018a, /* ##...#.#. */ + 0x0164, /* #.##..#.. */ + 0x01ad, /* ##.#.##.# */ + 0x0000, /* ......... */ + 0x016b, /* #.##.#.## */ + 0x004d, /* ..#..##.# */ + 0x00a3, /* .#.#...## */ + 0x00e8, /* .###.#... */ +}, +{ + 0x005c, /* ..#.###.. */ + 0x01a8, /* ##.#.#... */ + 0x00d4, /* .##.#.#.. */ + 0x0195, /* ##..#.#.# */ + 0x0082, /* .#.....#. */ + 0x0153, /* #.#.#..## */ + 0x0056, /* ..#.#.##. */ + 0x002b, /* ...#.#.## */ + 0x0074, /* ..###.#.. */ +}, +{ + 0x006c, /* ..##.##.. */ + 0x00e2, /* .###...#. */ + 0x0113, /* #...#..## */ + 0x0113, /* #...#..## */ + 0x006c, /* ..##.##.. */ + 0x0191, /* ##..#...# */ + 0x0191, /* ##..#...# */ + 0x008e, /* .#...###. */ + 0x006c, /* ..##.##.. */ +}, +{ + 0x0098, /* .#..##... */ + 0x0195, /* ##..#.#.# */ + 0x0066, /* ..##..##. */ + 0x00cb, /* .##..#.## */ + 0x0028, /* ...#.#... */ + 0x01a6, /* ##.#..##. */ + 0x00cc, /* .##..##.. */ + 0x0153, /* #.#.#..## */ + 0x0032, /* ...##..#. */ +}, +{ + 0x0164, /* #.##..#.. */ + 0x00a5, /* .#.#..#.# */ + 0x00aa, /* .#.#.#.#. */ + 0x005c, /* ..#.###.. */ + 0x0183, /* ##.....## */ + 0x0074, /* ..###.#.. */ + 0x00aa, /* .#.#.#.#. */ + 0x014a, /* #.#..#.#. */ + 0x004d, /* ..#..##.# */ +}, +{ + 0x0144, /* #.#...#.. */ + 0x00dc, /* .##.###.. */ + 0x00aa, /* .#.#.#.#. */ + 0x01a2, /* ##.#...#. */ + 0x0038, /* ...###... */ + 0x008b, /* .#...#.## */ + 0x00aa, /* .#.#.#.#. */ + 0x0076, /* ..###.##. */ + 0x0045, /* ..#...#.# */ +}, +{ + 0x0113, /* #...#..## */ + 0x01a2, /* ##.#...#. */ + 0x006c, /* ..##.##.. */ + 0x0056, /* ..#.#.##. */ + 0x0129, /* #..#.#..# */ + 0x00d4, /* .##.#.#.. */ + 0x006c, /* ..##.##.. */ + 0x008b, /* .#...#.## */ + 0x0191, /* ##..#...# */ +}, +{ + 0x006a, /* ..##.#.#. */ + 0x0174, /* #.###.#.. */ + 0x0083, /* .#.....## */ + 0x012b, /* #..#.#.## */ + 0x0092, /* .#..#..#. */ + 0x01a9, /* ##.#.#..# */ + 0x0182, /* ##.....#. */ + 0x005d, /* ..#.###.# */ + 0x00ac, /* .#.#.##.. */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x0129, /* #..#.#..# */ + 0x0092, /* .#..#..#. */ + 0x0044, /* ..#...#.. */ + 0x0183, /* ##.....## */ + 0x0044, /* ..#...#.. */ + 0x0092, /* .#..#..#. */ + 0x0129, /* #..#.#..# */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x00ba, /* .#.###.#. */ + 0x0082, /* .#.....#. */ + 0x00ba, /* .#.###.#. */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x00ba, /* .#.###.#. */ + 0x0101, /* #.......# */ + 0x0044, /* ..#...#.. */ + 0x01ab, /* ##.#.#.## */ + 0x0010, /* ....#.... */ + 0x01ab, /* ##.#.#.## */ + 0x0044, /* ..#...#.. */ + 0x0101, /* #.......# */ + 0x00ba, /* .#.###.#. */ +}, +{ + 0x0082, /* .#.....#. */ + 0x00d6, /* .##.#.##. */ + 0x0129, /* #..#.#..# */ + 0x006c, /* ..##.##.. */ + 0x0000, /* ......... */ + 0x006c, /* ..##.##.. */ + 0x0129, /* #..#.#..# */ + 0x00d6, /* .##.#.##. */ + 0x0082, /* .#.....#. */ +}, +{ + 0x000a, /* .....#.#. */ + 0x018c, /* ##...##.. */ + 0x00a4, /* .#.#..#.. */ + 0x009a, /* .#..##.#. */ + 0x0101, /* #.......# */ + 0x00b2, /* .#.##..#. */ + 0x004a, /* ..#..#.#. */ + 0x0063, /* ..##...## */ + 0x00a0, /* .#.#..... */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x0101, /* #.......# */ + 0x0054, /* ..#.#.#.. */ + 0x00d6, /* .##.#.##. */ + 0x0092, /* .#..#..#. */ + 0x00d6, /* .##.#.##. */ + 0x0054, /* ..#.#.#.. */ + 0x0101, /* #.......# */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x00c6, /* .##...##. */ + 0x0028, /* ...#.#... */ + 0x0193, /* ##..#..## */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0193, /* ##..#..## */ + 0x0028, /* ...#.#... */ + 0x00c6, /* .##...##. */ +}, +{ + 0x01b8, /* ##.###... */ + 0x0001, /* ........# */ + 0x00e4, /* .###..#.. */ + 0x0111, /* #...#...# */ + 0x0044, /* ..#...#.. */ + 0x0111, /* #...#...# */ + 0x004e, /* ..#..###. */ + 0x0100, /* #........ */ + 0x003b, /* ...###.## */ +}, +{ + 0x0000, /* ......... */ + 0x00aa, /* .#.#.#.#. */ + 0x00ee, /* .###.###. */ + 0x0129, /* #..#.#..# */ + 0x006c, /* ..##.##.. */ + 0x0129, /* #..#.#..# */ + 0x00ee, /* .###.###. */ + 0x00aa, /* .#.#.#.#. */ + 0x0000, /* ......... */ +}, +{ + 0x0031, /* ...##...# */ + 0x0154, /* #.#.#.#.. */ + 0x0009, /* .....#..# */ + 0x00f4, /* .####.#.. */ + 0x0044, /* ..#...#.. */ + 0x005e, /* ..#.####. */ + 0x0120, /* #..#..... */ + 0x0055, /* ..#.#.#.# */ + 0x0118, /* #...##... */ +}, +{ + 0x00b0, /* .#.##.... */ + 0x00a3, /* .#.#...## */ + 0x0064, /* ..##..#.. */ + 0x0007, /* ......### */ + 0x0111, /* #...#...# */ + 0x01c0, /* ###...... */ + 0x004c, /* ..#..##.. */ + 0x018a, /* ##...#.#. */ + 0x001a, /* ....##.#. */ +}, +{ + 0x0129, /* #..#.#..# */ + 0x0048, /* ..#..#... */ + 0x0012, /* ....#..#. */ + 0x0191, /* ##..#...# */ + 0x006c, /* ..##.##.. */ + 0x0113, /* #...#..## */ + 0x0090, /* .#..#.... */ + 0x0024, /* ...#..#.. */ + 0x0129, /* #..#.#..# */ +}, +{ + 0x00a0, /* .#.#..... */ + 0x0051, /* ..#.#...# */ + 0x005e, /* ..#.####. */ + 0x0041, /* ..#.....# */ + 0x00d6, /* .##.#.##. */ + 0x0104, /* #.....#.. */ + 0x00f4, /* .####.#.. */ + 0x0114, /* #...#.#.. */ + 0x000a, /* .....#.#. */ +}, +{ + 0x0008, /* .....#... */ + 0x0090, /* .#..#.... */ + 0x001f, /* ....##### */ + 0x00d3, /* .##.#..## */ + 0x006c, /* ..##.##.. */ + 0x0196, /* ##..#.##. */ + 0x01f0, /* #####.... */ + 0x0012, /* ....#..#. */ + 0x0020, /* ...#..... */ +}, +{ + 0x0145, /* #.#...#.# */ + 0x0155, /* #.#.#.#.# */ + 0x0028, /* ...#.#... */ + 0x006c, /* ..##.##.. */ + 0x0000, /* ......... */ + 0x006c, /* ..##.##.. */ + 0x0028, /* ...#.#... */ + 0x0155, /* #.#.#.#.# */ + 0x0145, /* #.#...#.# */ +}, +{ + 0x0006, /* ......##. */ + 0x0170, /* #.###.... */ + 0x0031, /* ...##...# */ + 0x00c3, /* .##....## */ + 0x0101, /* #.......# */ + 0x0186, /* ##....##. */ + 0x0118, /* #...##... */ + 0x001d, /* ....###.# */ + 0x00c0, /* .##...... */ +}, +{ + 0x0038, /* ...###... */ + 0x0129, /* #..#.#..# */ + 0x0044, /* ..#...#.. */ + 0x0145, /* #.#...#.# */ + 0x0082, /* .#.....#. */ + 0x0145, /* #.#...#.# */ + 0x0044, /* ..#...#.. */ + 0x0129, /* #..#.#..# */ + 0x0038, /* ...###... */ +}, +{ + 0x0082, /* .#.....#. */ + 0x0111, /* #...#...# */ + 0x0129, /* #..#.#..# */ + 0x006c, /* ..##.##.. */ + 0x0010, /* ....#.... */ + 0x006c, /* ..##.##.. */ + 0x0129, /* #..#.#..# */ + 0x0111, /* #...#...# */ + 0x0082, /* .#.....#. */ +}, +{ + 0x0183, /* ##.....## */ + 0x0092, /* .#..#..#. */ + 0x006c, /* ..##.##.. */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x006c, /* ..##.##.. */ + 0x0092, /* .#..#..#. */ + 0x0183, /* ##.....## */ +}, +{ + 0x00d0, /* .##.#.... */ + 0x0109, /* #....#..# */ + 0x0184, /* ##....#.. */ + 0x0160, /* #.##..... */ + 0x0044, /* ..#...#.. */ + 0x000d, /* .....##.# */ + 0x0043, /* ..#....## */ + 0x0121, /* #..#....# */ + 0x0016, /* ....#.##. */ +}, +{ + 0x0060, /* ..##..... */ + 0x0140, /* #.#...... */ + 0x0093, /* .#..#..## */ + 0x010e, /* #....###. */ + 0x0054, /* ..#.#.#.. */ + 0x00e1, /* .###....# */ + 0x0192, /* ##..#..#. */ + 0x0005, /* ......#.# */ + 0x000c, /* .....##.. */ +}, +{ + 0x001a, /* ....##.#. */ + 0x0091, /* .#..#...# */ + 0x00a1, /* .#.#....# */ + 0x00c2, /* .##....#. */ + 0x0028, /* ...#.#... */ + 0x0086, /* .#....##. */ + 0x010a, /* #....#.#. */ + 0x0112, /* #...#..#. */ + 0x00b0, /* .#.##.... */ +}, +{ + 0x0162, /* #.##...#. */ + 0x0049, /* ..#..#..# */ + 0x004c, /* ..#..##.. */ + 0x0016, /* ....#.##. */ + 0x0000, /* ......... */ + 0x00d0, /* .##.#.... */ + 0x0064, /* ..##..#.. */ + 0x0124, /* #..#..#.. */ + 0x008d, /* .#...##.# */ +}, +{ + 0x0025, /* ...#..#.# */ + 0x0050, /* ..#.#.... */ + 0x0053, /* ..#.#..## */ + 0x0032, /* ...##..#. */ + 0x0028, /* ...#.#... */ + 0x0098, /* .#..##... */ + 0x0194, /* ##..#.#.. */ + 0x0014, /* ....#.#.. */ + 0x0148, /* #.#..#... */ +}, +{ + 0x0129, /* #..#.#..# */ + 0x0000, /* ......... */ + 0x00c6, /* .##...##. */ + 0x00aa, /* .#.#.#.#. */ + 0x0092, /* .#..#..#. */ + 0x00aa, /* .#.#.#.#. */ + 0x00c6, /* .##...##. */ + 0x0000, /* ......... */ + 0x0129, /* #..#.#..# */ +}, +{ + 0x0095, /* .#..#.#.# */ + 0x002b, /* ...#.#.## */ + 0x0000, /* ......... */ + 0x00ca, /* .##..#.#. */ + 0x0028, /* ...#.#... */ + 0x00a6, /* .#.#..##. */ + 0x0000, /* ......... */ + 0x01a8, /* ##.#.#... */ + 0x0153, /* #.#.#..## */ +}, +{ + 0x0008, /* .....#... */ + 0x0153, /* #.#.#..## */ + 0x0070, /* ..###.... */ + 0x0141, /* #.#.....# */ + 0x0082, /* .#.....#. */ + 0x0105, /* #.....#.# */ + 0x001c, /* ....###.. */ + 0x0195, /* ##..#.#.# */ + 0x0020, /* ...#..... */ +}, +{ + 0x000c, /* .....##.. */ + 0x0100, /* #........ */ + 0x0076, /* ..###.##. */ + 0x0013, /* ....#..## */ + 0x0101, /* #.......# */ + 0x0190, /* ##..#.... */ + 0x00dc, /* .##.###.. */ + 0x0001, /* ........# */ + 0x0060, /* ..##..... */ +}, +{ + 0x00ba, /* .#.###.#. */ + 0x0101, /* #.......# */ + 0x0044, /* ..#...#.. */ + 0x00aa, /* .#.#.#.#. */ + 0x0000, /* ......... */ + 0x00aa, /* .#.#.#.#. */ + 0x0044, /* ..#...#.. */ + 0x0101, /* #.......# */ + 0x00ba, /* .#.###.#. */ +}, +{ + 0x0189, /* ##...#..# */ + 0x00a3, /* .#.#...## */ + 0x0010, /* ....#.... */ + 0x0102, /* #......#. */ + 0x0054, /* ..#.#.#.. */ + 0x0081, /* .#......# */ + 0x0010, /* ....#.... */ + 0x018a, /* ##...#.#. */ + 0x0123, /* #..#...## */ +}, +{ + 0x0189, /* ##...#..# */ + 0x00a3, /* .#.#...## */ + 0x0010, /* ....#.... */ + 0x0102, /* #......#. */ + 0x0054, /* ..#.#.#.. */ + 0x0081, /* .#......# */ + 0x0010, /* ....#.... */ + 0x018a, /* ##...#.#. */ + 0x0123, /* #..#...## */ +}, +{ + 0x0044, /* ..#...#.. */ + 0x00ee, /* .###.###. */ + 0x0183, /* ##.....## */ + 0x0038, /* ...###... */ + 0x0010, /* ....#.... */ + 0x0038, /* ...###... */ + 0x0183, /* ##.....## */ + 0x00ee, /* .###.###. */ + 0x0044, /* ..#...#.. */ +}, +{ + 0x0064, /* ..##..#.. */ + 0x0096, /* .#..#.##. */ + 0x0081, /* .#......# */ + 0x010a, /* #....#.#. */ + 0x0010, /* ....#.... */ + 0x00a1, /* .#.#....# */ + 0x0102, /* #......#. */ + 0x00d2, /* .##.#..#. */ + 0x004c, /* ..#..##.. */ +}, +{ + 0x0180, /* ##....... */ + 0x0190, /* ##..#.... */ + 0x00a8, /* .#.#.#... */ + 0x0124, /* #..#..#.. */ + 0x0145, /* #.#...#.# */ + 0x0049, /* ..#..#..# */ + 0x002a, /* ...#.#.#. */ + 0x0013, /* ....#..## */ + 0x0003, /* .......## */ +}, +{ + 0x010d, /* #....##.# */ + 0x0104, /* #.....#.. */ + 0x00a2, /* .#.#...#. */ + 0x0038, /* ...###... */ + 0x0044, /* ..#...#.. */ + 0x0038, /* ...###... */ + 0x008a, /* .#...#.#. */ + 0x0041, /* ..#.....# */ + 0x0161, /* #.##....# */ +}, +{ + 0x004c, /* ..#..##.. */ + 0x00b2, /* .#.##..#. */ + 0x0165, /* #.##..#.# */ + 0x0116, /* #...#.##. */ + 0x00aa, /* .#.#.#.#. */ + 0x00d1, /* .##.#...# */ + 0x014d, /* #.#..##.# */ + 0x009a, /* .#..##.#. */ + 0x0064, /* ..##..#.. */ +}, +{ + 0x0111, /* #...#...# */ + 0x0092, /* .#..#..#. */ + 0x0129, /* #..#.#..# */ + 0x0145, /* #.#...#.# */ + 0x006c, /* ..##.##.. */ + 0x0145, /* #.#...#.# */ + 0x0129, /* #..#.#..# */ + 0x0092, /* .#..#..#. */ + 0x0111, /* #...#...# */ +}, +{ + 0x00ac, /* .#.#.##.. */ + 0x0182, /* ##.....#. */ + 0x0032, /* ...##..#. */ + 0x001c, /* ....###.. */ + 0x0000, /* ......... */ + 0x0070, /* ..###.... */ + 0x0098, /* .#..##... */ + 0x0083, /* .#.....## */ + 0x006a, /* ..##.#.#. */ +}, +{ + 0x0052, /* ..#.#..#. */ + 0x0008, /* .....#... */ + 0x012a, /* #..#.#.#. */ + 0x01a4, /* ##.#..#.. */ + 0x0082, /* .#.....#. */ + 0x004b, /* ..#..#.## */ + 0x00a9, /* .#.#.#..# */ + 0x0020, /* ...#..... */ + 0x0094, /* .#..#.#.. */ +}, +{ + 0x0049, /* ..#..#..# */ + 0x0030, /* ...##.... */ + 0x0026, /* ...#..##. */ + 0x00c6, /* .##...##. */ + 0x0010, /* ....#.... */ + 0x00c6, /* .##...##. */ + 0x00c8, /* .##..#... */ + 0x0018, /* ....##... */ + 0x0124, /* #..#..#.. */ +}, +{ + 0x0029, /* ...#.#..# */ + 0x01a4, /* ##.#..#.. */ + 0x00a0, /* .#.#..... */ + 0x0005, /* ......#.# */ + 0x0183, /* ##.....## */ + 0x0140, /* #.#...... */ + 0x000a, /* .....#.#. */ + 0x004b, /* ..#..#.## */ + 0x0128, /* #..#.#... */ +}, +{ + 0x0014, /* ....#.#.. */ + 0x0164, /* #.##..#.. */ + 0x0161, /* #.##....# */ + 0x0040, /* ..#...... */ + 0x0038, /* ...###... */ + 0x0004, /* ......#.. */ + 0x010d, /* #....##.# */ + 0x004d, /* ..#..##.# */ + 0x0050, /* ..#.#.... */ +}, +{ + 0x0101, /* #.......# */ + 0x00c6, /* .##...##. */ + 0x0038, /* ...###... */ + 0x007c, /* ..#####.. */ + 0x0183, /* ##.....## */ + 0x007c, /* ..#####.. */ + 0x0038, /* ...###... */ + 0x00c6, /* .##...##. */ + 0x0101, /* #.......# */ +}, +{ + 0x0020, /* ...#..... */ + 0x0054, /* ..#.#.#.. */ + 0x0063, /* ..##...## */ + 0x0149, /* #.#..#..# */ + 0x0101, /* #.......# */ + 0x0125, /* #..#..#.# */ + 0x018c, /* ##...##.. */ + 0x0054, /* ..#.#.#.. */ + 0x0008, /* .....#... */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x0044, /* ..#...#.. */ + 0x002a, /* ...#.#.#. */ + 0x0081, /* .#......# */ + 0x0038, /* ...###... */ + 0x0102, /* #......#. */ + 0x00a8, /* .#.#.#... */ + 0x0044, /* ..#...#.. */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x0014, /* ....#.#.. */ + 0x0140, /* #.#...... */ + 0x000f, /* .....#### */ + 0x0003, /* .......## */ + 0x00aa, /* .#.#.#.#. */ + 0x0180, /* ##....... */ + 0x01e0, /* ####..... */ + 0x0005, /* ......#.# */ + 0x0050, /* ..#.#.... */ +}, +{ + 0x002d, /* ...#.##.# */ + 0x0010, /* ....#.... */ + 0x0091, /* .#..#...# */ + 0x0074, /* ..###.#.. */ + 0x0101, /* #.......# */ + 0x005c, /* ..#.###.. */ + 0x0112, /* #...#..#. */ + 0x0010, /* ....#.... */ + 0x0168, /* #.##.#... */ +}, +{ + 0x0096, /* .#..#.##. */ + 0x009a, /* .#..##.#. */ + 0x00e4, /* .###..#.. */ + 0x0190, /* ##..#.... */ + 0x01ab, /* ##.#.#.## */ + 0x0013, /* ....#..## */ + 0x004e, /* ..#..###. */ + 0x00b2, /* .#.##..#. */ + 0x00d2, /* .##.#..#. */ +}, +{ + 0x0150, /* #.#.#.... */ + 0x0022, /* ...#...#. */ + 0x0094, /* .#..#.#.. */ + 0x016c, /* #.##.##.. */ + 0x0082, /* .#.....#. */ + 0x006d, /* ..##.##.# */ + 0x0052, /* ..#.#..#. */ + 0x0088, /* .#...#... */ + 0x0015, /* ....#.#.# */ +}, +{ + 0x000d, /* .....##.# */ + 0x01b1, /* ##.##...# */ + 0x0080, /* .#....... */ + 0x014c, /* #.#..##.. */ + 0x0101, /* #.......# */ + 0x0065, /* ..##..#.# */ + 0x0002, /* .......#. */ + 0x011b, /* #...##.## */ + 0x0160, /* #.##..... */ +}, +{ + 0x0016, /* ....#.##. */ + 0x0160, /* #.##..... */ + 0x010a, /* #....#.#. */ + 0x0052, /* ..#.#..#. */ + 0x0129, /* #..#.#..# */ + 0x0094, /* .#..#.#.. */ + 0x00a1, /* .#.#....# */ + 0x000d, /* .....##.# */ + 0x00d0, /* .##.#.... */ +}, +{ + 0x00e9, /* .###.#..# */ + 0x00c1, /* .##.....# */ + 0x0120, /* #..#..... */ + 0x0188, /* ##...#... */ + 0x00c6, /* .##...##. */ + 0x0023, /* ...#...## */ + 0x0009, /* .....#..# */ + 0x0106, /* #.....##. */ + 0x012e, /* #..#.###. */ +}, +{ + 0x000d, /* .....##.# */ + 0x0090, /* .#..#.... */ + 0x0188, /* ##...#... */ + 0x0059, /* ..#.##..# */ + 0x0028, /* ...#.#... */ + 0x0134, /* #..##.#.. */ + 0x0023, /* ...#...## */ + 0x0012, /* ....#..#. */ + 0x0160, /* #.##..... */ +}, +{ + 0x0108, /* #....#... */ + 0x0116, /* #...#.##. */ + 0x0148, /* #.#..#... */ + 0x01c4, /* ###...#.. */ + 0x0101, /* #.......# */ + 0x0047, /* ..#...### */ + 0x0025, /* ...#..#.# */ + 0x00d1, /* .##.#...# */ + 0x0021, /* ...#....# */ +}, +{ + 0x0151, /* #.#.#...# */ + 0x0024, /* ...#..#.. */ + 0x004a, /* ..#..#.#. */ + 0x0042, /* ..#....#. */ + 0x006c, /* ..##.##.. */ + 0x0084, /* .#....#.. */ + 0x00a4, /* .#.#..#.. */ + 0x0048, /* ..#..#... */ + 0x0115, /* #...#.#.# */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x0044, /* ..#...#.. */ + 0x00aa, /* .#.#.#.#. */ + 0x00c6, /* .##...##. */ + 0x0101, /* #.......# */ + 0x00c6, /* .##...##. */ + 0x00aa, /* .#.#.#.#. */ + 0x0044, /* ..#...#.. */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x0004, /* ......#.. */ + 0x0061, /* ..##....# */ + 0x0023, /* ...#...## */ + 0x0184, /* ##....#.. */ + 0x0139, /* #..###..# */ + 0x0043, /* ..#....## */ + 0x0188, /* ##...#... */ + 0x010c, /* #....##.. */ + 0x0040, /* ..#...... */ +}, +{ + 0x0141, /* #.#.....# */ + 0x0082, /* .#.....#. */ + 0x00a2, /* .#.#...#. */ + 0x003d, /* ...####.# */ + 0x0010, /* ....#.... */ + 0x0178, /* #.####... */ + 0x008a, /* .#...#.#. */ + 0x0082, /* .#.....#. */ + 0x0105, /* #.....#.# */ +}, +{ + 0x01a3, /* ##.#...## */ + 0x01ac, /* ##.#.##.. */ + 0x0049, /* ..#..#..# */ + 0x0106, /* #.....##. */ + 0x0129, /* #..#.#..# */ + 0x00c1, /* .##.....# */ + 0x0124, /* #..#..#.. */ + 0x006b, /* ..##.#.## */ + 0x018b, /* ##...#.## */ +}, +{ + 0x0044, /* ..#...#.. */ + 0x0015, /* ....#.#.# */ + 0x0132, /* #..##..#. */ + 0x0021, /* ...#....# */ + 0x006c, /* ..##.##.. */ + 0x0108, /* #....#... */ + 0x0099, /* .#..##..# */ + 0x0150, /* #.#.#.... */ + 0x0044, /* ..#...#.. */ +}, +{ + 0x0112, /* #...#..#. */ + 0x0024, /* ...#..#.. */ + 0x014c, /* #.#..##.. */ + 0x0041, /* ..#.....# */ + 0x016d, /* #.##.##.# */ + 0x0104, /* #.....#.. */ + 0x0065, /* ..##..#.# */ + 0x0048, /* ..#..#... */ + 0x0091, /* .#..#...# */ +}, +{ + 0x0139, /* #..###..# */ + 0x008c, /* .#...##.. */ + 0x0010, /* ....#.... */ + 0x0142, /* #.#....#. */ + 0x00c6, /* .##...##. */ + 0x0085, /* .#....#.# */ + 0x0010, /* ....#.... */ + 0x0062, /* ..##...#. */ + 0x0139, /* #..###..# */ +}, +{ + 0x00e9, /* .###.#..# */ + 0x0078, /* ..####... */ + 0x00a0, /* .#.#..... */ + 0x0047, /* ..#...### */ + 0x0000, /* ......... */ + 0x01c4, /* ###...#.. */ + 0x000a, /* .....#.#. */ + 0x003c, /* ...####.. */ + 0x012e, /* #..#.###. */ +}, +{ + 0x0004, /* ......#.. */ + 0x0087, /* .#....### */ + 0x0023, /* ...#...## */ + 0x0025, /* ...#..#.# */ + 0x0111, /* #...#...# */ + 0x0148, /* #.#..#... */ + 0x0188, /* ##...#... */ + 0x01c2, /* ###....#. */ + 0x0040, /* ..#...... */ +}, +{ + 0x010e, /* #....###. */ + 0x0096, /* .#..#.##. */ + 0x0121, /* #..#....# */ + 0x0013, /* ....#..## */ + 0x0044, /* ..#...#.. */ + 0x0190, /* ##..#.... */ + 0x0109, /* #....#..# */ + 0x00d2, /* .##.#..#. */ + 0x00e1, /* .###....# */ +}, +{ + 0x010c, /* #....##.. */ + 0x0034, /* ...##.#.. */ + 0x0094, /* .#..#.#.. */ + 0x0138, /* #..###... */ + 0x0000, /* ......... */ + 0x0039, /* ...###..# */ + 0x0052, /* ..#.#..#. */ + 0x0058, /* ..#.##... */ + 0x0061, /* ..##....# */ +}, +{ + 0x0112, /* #...#..#. */ + 0x01a1, /* ##.#....# */ + 0x0048, /* ..#..#... */ + 0x0190, /* ##..#.... */ + 0x0082, /* .#.....#. */ + 0x0013, /* ....#..## */ + 0x0024, /* ...#..#.. */ + 0x010b, /* #....#.## */ + 0x0091, /* .#..#...# */ +}, +{ + 0x0031, /* ...##...# */ + 0x0004, /* ......#.. */ + 0x00a9, /* .#.#.#..# */ + 0x00c4, /* .##...#.. */ + 0x0054, /* ..#.#.#.. */ + 0x0046, /* ..#...##. */ + 0x012a, /* #..#.#.#. */ + 0x0040, /* ..#...... */ + 0x0118, /* #...##... */ +}, +{ + 0x01b0, /* ##.##.... */ + 0x010e, /* #....###. */ + 0x0000, /* ......... */ + 0x0102, /* #......#. */ + 0x00ba, /* .#.###.#. */ + 0x0081, /* .#......# */ + 0x0000, /* ......... */ + 0x00e1, /* .###....# */ + 0x001b, /* ....##.## */ +}, +{ + 0x006c, /* ..##.##.. */ + 0x00d2, /* .##.#..#. */ + 0x0147, /* #.#...### */ + 0x0129, /* #..#.#..# */ + 0x0092, /* .#..#..#. */ + 0x0129, /* #..#.#..# */ + 0x01c5, /* ###...#.# */ + 0x0096, /* .#..#.##. */ + 0x006c, /* ..##.##.. */ +}, +{ + 0x0111, /* #...#...# */ + 0x008e, /* .#...###. */ + 0x00b0, /* .#.##.... */ + 0x0084, /* .#....#.. */ + 0x0145, /* #.#...#.# */ + 0x0042, /* ..#....#. */ + 0x001a, /* ....##.#. */ + 0x00e2, /* .###...#. */ + 0x0111, /* #...#...# */ +}, +{ + 0x0040, /* ..#...... */ + 0x0096, /* .#..#.##. */ + 0x00cd, /* .##..##.# */ + 0x0050, /* ..#.#.... */ + 0x00ba, /* .#.###.#. */ + 0x0014, /* ....#.#.. */ + 0x0166, /* #.##..##. */ + 0x00d2, /* .##.#..#. */ + 0x0004, /* ......#.. */ +}, +{ + 0x000f, /* .....#### */ + 0x0152, /* #.#.#..#. */ + 0x011c, /* #...###.. */ + 0x00b1, /* .#.##...# */ + 0x0145, /* #.#...#.# */ + 0x011a, /* #...##.#. */ + 0x0071, /* ..###...# */ + 0x0095, /* .#..#.#.# */ + 0x01e0, /* ####..... */ +}, +{ + 0x0128, /* #..#.#... */ + 0x0183, /* ##.....## */ + 0x0094, /* .#..#.#.. */ + 0x00b1, /* .#.##...# */ + 0x0044, /* ..#...#.. */ + 0x011a, /* #...##.#. */ + 0x0052, /* ..#.#..#. */ + 0x0183, /* ##.....## */ + 0x0029, /* ...#.#..# */ +}, +{ + 0x0081, /* .#......# */ + 0x0060, /* ..##..... */ + 0x0159, /* #.#.##..# */ + 0x000b, /* .....#.## */ + 0x0054, /* ..#.#.#.. */ + 0x01a0, /* ##.#..... */ + 0x0135, /* #..##.#.# */ + 0x000c, /* .....##.. */ + 0x0102, /* #......#. */ +}, +{ + 0x00dc, /* .##.###.. */ + 0x0089, /* .#...#..# */ + 0x0030, /* ...##.... */ + 0x0046, /* ..#...##. */ + 0x0028, /* ...#.#... */ + 0x00c4, /* .##...#.. */ + 0x0018, /* ....##... */ + 0x0122, /* #..#...#. */ + 0x0076, /* ..###.##. */ +}, +{ + 0x00e0, /* .###..... */ + 0x0082, /* .#.....#. */ + 0x0081, /* .#......# */ + 0x0149, /* #.#..#..# */ + 0x0092, /* .#..#..#. */ + 0x0125, /* #..#..#.# */ + 0x0102, /* #......#. */ + 0x0082, /* .#.....#. */ + 0x000e, /* .....###. */ +}, +{ + 0x0199, /* ##..##..# */ + 0x0025, /* ...#..#.# */ + 0x0010, /* ....#.... */ + 0x00a2, /* .#.#...#. */ + 0x0044, /* ..#...#.. */ + 0x008a, /* .#...#.#. */ + 0x0010, /* ....#.... */ + 0x0148, /* #.#..#... */ + 0x0133, /* #..##..## */ +}, +{ + 0x0101, /* #.......# */ + 0x0129, /* #..#.#..# */ + 0x007c, /* ..#####.. */ + 0x00aa, /* .#.#.#.#. */ + 0x0082, /* .#.....#. */ + 0x00aa, /* .#.#.#.#. */ + 0x007c, /* ..#####.. */ + 0x0129, /* #..#.#..# */ + 0x0101, /* #.......# */ +}, +{ + 0x0112, /* #...#..#. */ + 0x014e, /* #.#..###. */ + 0x0002, /* .......#. */ + 0x0108, /* #....#... */ + 0x0038, /* ...###... */ + 0x0021, /* ...#....# */ + 0x0080, /* .#....... */ + 0x00e5, /* .###..#.# */ + 0x0091, /* .#..#...# */ +}, +{ + 0x01c3, /* ###....## */ + 0x0032, /* ...##..#. */ + 0x0008, /* .....#... */ + 0x00c4, /* .##...#.. */ + 0x0028, /* ...#.#... */ + 0x0046, /* ..#...##. */ + 0x0020, /* ...#..... */ + 0x0098, /* .#..##... */ + 0x0187, /* ##....### */ +}, +{ + 0x00e2, /* .###...#. */ + 0x0001, /* ........# */ + 0x00e0, /* .###..... */ + 0x0052, /* ..#.#..#. */ + 0x0145, /* #.#...#.# */ + 0x0094, /* .#..#.#.. */ + 0x000e, /* .....###. */ + 0x0100, /* #........ */ + 0x008e, /* .#...###. */ +}, +{ + 0x0185, /* ##....#.# */ + 0x0124, /* #..#..#.. */ + 0x0060, /* ..##..... */ + 0x0011, /* ....#...# */ + 0x016d, /* #.##.##.# */ + 0x0110, /* #...#.... */ + 0x000c, /* .....##.. */ + 0x0049, /* ..#..#..# */ + 0x0143, /* #.#....## */ +}, +{ + 0x0082, /* .#.....#. */ + 0x0155, /* #.#.#.#.# */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x0028, /* ...#.#... */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x0155, /* #.#.#.#.# */ + 0x0082, /* .#.....#. */ +}, +{ + 0x008a, /* .#...#.#. */ + 0x0169, /* #.##.#..# */ + 0x014d, /* #.#..##.# */ + 0x0118, /* #...##... */ + 0x00c6, /* .##...##. */ + 0x0031, /* ...##...# */ + 0x0165, /* #.##..#.# */ + 0x012d, /* #..#.##.# */ + 0x00a2, /* .#.#...#. */ +}, +{ + 0x0145, /* #.#...#.# */ + 0x00aa, /* .#.#.#.#. */ + 0x0129, /* #..#.#..# */ + 0x006c, /* ..##.##.. */ + 0x0000, /* ......... */ + 0x006c, /* ..##.##.. */ + 0x0129, /* #..#.#..# */ + 0x00aa, /* .#.#.#.#. */ + 0x0145, /* #.#...#.# */ +}, +{ + 0x0122, /* #..#...#. */ + 0x0011, /* ....#...# */ + 0x010a, /* #....#.#. */ + 0x0154, /* #.#.#.#.. */ + 0x0000, /* ......... */ + 0x0055, /* ..#.#.#.# */ + 0x00a1, /* .#.#....# */ + 0x0110, /* #...#.... */ + 0x0089, /* .#...#..# */ +}, +{ + 0x01c9, /* ###..#..# */ + 0x00e6, /* .###..##. */ + 0x0114, /* #...#.#.. */ + 0x001e, /* ....####. */ + 0x0028, /* ...#.#... */ + 0x00f0, /* .####.... */ + 0x0051, /* ..#.#...# */ + 0x00ce, /* .##..###. */ + 0x0127, /* #..#..### */ +}, +{ + 0x0117, /* #...#.### */ + 0x0009, /* .....#..# */ + 0x005c, /* ..#.###.. */ + 0x011c, /* #...###.. */ + 0x0000, /* ......... */ + 0x0071, /* ..###...# */ + 0x0074, /* ..###.#.. */ + 0x0120, /* #..#..... */ + 0x01d1, /* ###.#...# */ +}, +{ + 0x0091, /* .#..#...# */ + 0x0023, /* ...#...## */ + 0x0044, /* ..#...#.. */ + 0x0031, /* ...##...# */ + 0x0111, /* #...#...# */ + 0x0118, /* #...##... */ + 0x0044, /* ..#...#.. */ + 0x0188, /* ##...#... */ + 0x0112, /* #...#..#. */ +}, +{ + 0x0020, /* ...#..... */ + 0x011a, /* #...##.#. */ + 0x00d7, /* .##.#.### */ + 0x0086, /* .#....##. */ + 0x0028, /* ...#.#... */ + 0x00c2, /* .##....#. */ + 0x01d6, /* ###.#.##. */ + 0x00b1, /* .#.##...# */ + 0x0008, /* .....#... */ +}, +{ + 0x000c, /* .....##.. */ + 0x0034, /* ...##.#.. */ + 0x01c4, /* ###...#.. */ + 0x012a, /* #..#.#.#. */ + 0x0082, /* .#.....#. */ + 0x00a9, /* .#.#.#..# */ + 0x0047, /* ..#...### */ + 0x0058, /* ..#.##... */ + 0x0060, /* ..##..... */ +}, +{ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x00ee, /* .###.###. */ + 0x0092, /* .#..#..#. */ + 0x0101, /* #.......# */ + 0x0092, /* .#..#..#. */ + 0x00ee, /* .###.###. */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ +}, +{ + 0x0111, /* #...#...# */ + 0x0155, /* #.#.#.#.# */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0155, /* #.#.#.#.# */ + 0x0111, /* #...#...# */ +}, +{ + 0x0188, /* ##...#... */ + 0x0110, /* #...#.... */ + 0x008c, /* .#...##.. */ + 0x0091, /* .#..#...# */ + 0x0155, /* #.#.#.#.# */ + 0x0112, /* #...#..#. */ + 0x0062, /* ..##...#. */ + 0x0011, /* ....#...# */ + 0x0023, /* ...#...## */ +}, +{ + 0x00b5, /* .#.##.#.# */ + 0x0100, /* #........ */ + 0x0048, /* ..#..#... */ + 0x0019, /* ....##..# */ + 0x0183, /* ##.....## */ + 0x0130, /* #..##.... */ + 0x0024, /* ...#..#.. */ + 0x0001, /* ........# */ + 0x015a, /* #.#.##.#. */ +}, +{ + 0x0195, /* ##..#.#.# */ + 0x0041, /* ..#.....# */ + 0x010a, /* #....#.#. */ + 0x0068, /* ..##.#... */ + 0x0111, /* #...#...# */ + 0x002c, /* ...#.##.. */ + 0x00a1, /* .#.#....# */ + 0x0104, /* #.....#.. */ + 0x0153, /* #.#.#..## */ +}, +{ + 0x0000, /* ......... */ + 0x0032, /* ...##..#. */ + 0x007b, /* ..####.## */ + 0x004e, /* ..#..###. */ + 0x0000, /* ......... */ + 0x00e4, /* .###..#.. */ + 0x01bc, /* ##.####.. */ + 0x0098, /* .#..##... */ + 0x0000, /* ......... */ +}, +{ + 0x0019, /* ....##..# */ + 0x0060, /* ..##..... */ + 0x0105, /* #.....#.# */ + 0x0142, /* #.#....#. */ + 0x0044, /* ..#...#.. */ + 0x0085, /* .#....#.# */ + 0x0141, /* #.#.....# */ + 0x000c, /* .....##.. */ + 0x0130, /* #..##.... */ +}, +{ + 0x00f0, /* .####.... */ + 0x008f, /* .#...#### */ + 0x00a9, /* .#.#.#..# */ + 0x00c5, /* .##...#.# */ + 0x0111, /* #...#...# */ + 0x0146, /* #.#...##. */ + 0x012a, /* #..#.#.#. */ + 0x01e2, /* ####...#. */ + 0x001e, /* ....####. */ +}, +{ + 0x0105, /* #.....#.# */ + 0x0068, /* ..##.#... */ + 0x0108, /* #....#... */ + 0x0042, /* ..#....#. */ + 0x00fe, /* .#######. */ + 0x0084, /* .#....#.. */ + 0x0021, /* ...#....# */ + 0x002c, /* ...#.##.. */ + 0x0141, /* #.#.....# */ +}, +{ + 0x01b0, /* ##.##.... */ + 0x0071, /* ..###...# */ + 0x010e, /* #....###. */ + 0x014a, /* #.#..#.#. */ + 0x00aa, /* .#.#.#.#. */ + 0x00a5, /* .#.#..#.# */ + 0x00e1, /* .###....# */ + 0x011c, /* #...###.. */ + 0x001b, /* ....##.## */ +}, +{ + 0x0038, /* ...###... */ + 0x0092, /* .#..#..#. */ + 0x00c6, /* .##...##. */ + 0x0044, /* ..#...#.. */ + 0x0155, /* #.#.#.#.# */ + 0x0044, /* ..#...#.. */ + 0x00c6, /* .##...##. */ + 0x0092, /* .#..#..#. */ + 0x0038, /* ...###... */ +}, +{ + 0x00a2, /* .#.#...#. */ + 0x0051, /* ..#.#...# */ + 0x0080, /* .#....... */ + 0x0191, /* ##..#...# */ + 0x0054, /* ..#.#.#.. */ + 0x0113, /* #...#..## */ + 0x0002, /* .......#. */ + 0x0114, /* #...#.#.. */ + 0x008a, /* .#...#.#. */ +}, +{ + 0x0139, /* #..###..# */ + 0x000c, /* .....##.. */ + 0x00e4, /* .###..#.. */ + 0x01ad, /* ##.#.##.# */ + 0x0101, /* #.......# */ + 0x016b, /* #.##.#.## */ + 0x004e, /* ..#..###. */ + 0x0060, /* ..##..... */ + 0x0139, /* #..###..# */ +}, +{ + 0x00c4, /* .##...#.. */ + 0x0031, /* ...##...# */ + 0x0109, /* #....#..# */ + 0x006a, /* ..##.#.#. */ + 0x0092, /* .#..#..#. */ + 0x00ac, /* .#.#.##.. */ + 0x0121, /* #..#....# */ + 0x0118, /* #...##... */ + 0x0046, /* ..#...##. */ +}, +{ + 0x0122, /* #..#...#. */ + 0x0024, /* ...#..#.. */ + 0x008a, /* .#...#.#. */ + 0x0112, /* #...#..#. */ + 0x0054, /* ..#.#.#.. */ + 0x0091, /* .#..#...# */ + 0x00a2, /* .#.#...#. */ + 0x0048, /* ..#..#... */ + 0x0089, /* .#...#..# */ +}, +{ + 0x0052, /* ..#.#..#. */ + 0x0004, /* ......#.. */ + 0x01f1, /* #####...# */ + 0x0164, /* #.##..#.. */ + 0x0010, /* ....#.... */ + 0x004d, /* ..#..##.# */ + 0x011f, /* #...##### */ + 0x0040, /* ..#...... */ + 0x0094, /* .#..#.#.. */ +}, +{ + 0x00e4, /* .###..#.. */ + 0x0015, /* ....#.#.# */ + 0x0189, /* ##...#..# */ + 0x0041, /* ..#.....# */ + 0x0082, /* .#.....#. */ + 0x0104, /* #.....#.. */ + 0x0123, /* #..#...## */ + 0x0150, /* #.#.#.... */ + 0x004e, /* ..#..###. */ +}, +{ + 0x0063, /* ..##...## */ + 0x0120, /* #..#..... */ + 0x0080, /* .#....... */ + 0x0052, /* ..#.#..#. */ + 0x00ee, /* .###.###. */ + 0x0094, /* .#..#.#.. */ + 0x0002, /* .......#. */ + 0x0009, /* .....#..# */ + 0x018c, /* ##...##.. */ +}, +{ + 0x0082, /* .#.....#. */ + 0x0044, /* ..#...#.. */ + 0x01bb, /* ##.###.## */ + 0x00aa, /* .#.#.#.#. */ + 0x0101, /* #.......# */ + 0x00aa, /* .#.#.#.#. */ + 0x01bb, /* ##.###.## */ + 0x0044, /* ..#...#.. */ + 0x0082, /* .#.....#. */ +}, +{ + 0x0028, /* ...#.#... */ + 0x0044, /* ..#...#.. */ + 0x01ab, /* ##.#.#.## */ + 0x0082, /* .#.....#. */ + 0x0145, /* #.#...#.# */ + 0x0082, /* .#.....#. */ + 0x01ab, /* ##.#.#.## */ + 0x0044, /* ..#...#.. */ + 0x0028, /* ...#.#... */ +}, +{ + 0x0121, /* #..#....# */ + 0x0034, /* ...##.#.. */ + 0x0088, /* .#...#... */ + 0x0043, /* ..#....## */ + 0x0092, /* .#..#..#. */ + 0x0184, /* ##....#.. */ + 0x0022, /* ...#...#. */ + 0x0058, /* ..#.##... */ + 0x0109, /* #....#..# */ +}, +{ + 0x00ac, /* .#.#.##.. */ + 0x0098, /* .#..##... */ + 0x0042, /* ..#....#. */ + 0x0049, /* ..#..#..# */ + 0x0101, /* #.......# */ + 0x0124, /* #..#..#.. */ + 0x0084, /* .#....#.. */ + 0x0032, /* ...##..#. */ + 0x006a, /* ..##.#.#. */ +}, +{ + 0x0092, /* .#..#..#. */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x0145, /* #.#...#.# */ + 0x0028, /* ...#.#... */ + 0x0145, /* #.#...#.# */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0092, /* .#..#..#. */ +}, +{ + 0x000c, /* .....##.. */ + 0x0091, /* .#..#...# */ + 0x0089, /* .#...#..# */ + 0x0048, /* ..#..#... */ + 0x0183, /* ##.....## */ + 0x0024, /* ...#..#.. */ + 0x0122, /* #..#...#. */ + 0x0112, /* #...#..#. */ + 0x0060, /* ..##..... */ +}, +{ + 0x006c, /* ..##.##.. */ + 0x0146, /* #.#...##. */ + 0x0018, /* ....##... */ + 0x001d, /* ....###.# */ + 0x0101, /* #.......# */ + 0x0170, /* #.###.... */ + 0x0030, /* ...##.... */ + 0x00c5, /* .##...#.# */ + 0x006c, /* ..##.##.. */ +}, +{ + 0x0015, /* ....#.#.# */ + 0x0088, /* .#...#... */ + 0x0140, /* #.#...... */ + 0x009a, /* .#..##.#. */ + 0x0101, /* #.......# */ + 0x00b2, /* .#.##..#. */ + 0x0005, /* ......#.# */ + 0x0022, /* ...#...#. */ + 0x0150, /* #.#.#.... */ +}, +{ + 0x0000, /* ......... */ + 0x00aa, /* .#.#.#.#. */ + 0x01c7, /* ###...### */ + 0x007c, /* ..#####.. */ + 0x0000, /* ......... */ + 0x007c, /* ..#####.. */ + 0x01c7, /* ###...### */ + 0x00aa, /* .#.#.#.#. */ + 0x0000, /* ......... */ +}, +{ + 0x0192, /* ##..#..#. */ + 0x0093, /* .#..#..## */ + 0x0088, /* .#...#... */ + 0x0068, /* ..##.#... */ + 0x0101, /* #.......# */ + 0x002c, /* ...#.##.. */ + 0x0022, /* ...#...#. */ + 0x0192, /* ##..#..#. */ + 0x0093, /* .#..#..## */ +}, +{ + 0x0129, /* #..#.#..# */ + 0x00aa, /* .#.#.#.#. */ + 0x0044, /* ..#...#.. */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0044, /* ..#...#.. */ + 0x00aa, /* .#.#.#.#. */ + 0x0129, /* #..#.#..# */ +}, +{ + 0x0113, /* #...#..## */ + 0x0130, /* #..##.... */ + 0x01c0, /* ###...... */ + 0x0025, /* ...#..#.# */ + 0x0082, /* .#.....#. */ + 0x0148, /* #.#..#... */ + 0x0007, /* ......### */ + 0x0019, /* ....##..# */ + 0x0191, /* ##..#...# */ +}, +{ + 0x0094, /* .#..#.#.. */ + 0x0013, /* ....#..## */ + 0x001d, /* ....###.# */ + 0x018a, /* ##...#.#. */ + 0x0010, /* ....#.... */ + 0x00a3, /* .#.#...## */ + 0x0170, /* #.###.... */ + 0x0190, /* ##..#.... */ + 0x0052, /* ..#.#..#. */ +}, +{ + 0x0017, /* ....#.### */ + 0x01b2, /* ##.##..#. */ + 0x0004, /* ......#.. */ + 0x0021, /* ...#....# */ + 0x01ab, /* ##.#.#.## */ + 0x0108, /* #....#... */ + 0x0040, /* ..#...... */ + 0x009b, /* .#..##.## */ + 0x01d0, /* ###.#.... */ +}, +{ + 0x0129, /* #..#.#..# */ + 0x0000, /* ......... */ + 0x01c7, /* ###...### */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x01c7, /* ###...### */ + 0x0000, /* ......... */ + 0x0129, /* #..#.#..# */ +}, +{ + 0x00d8, /* .##.##... */ + 0x0093, /* .#..#..## */ + 0x008a, /* .#...#.#. */ + 0x0110, /* #...#.... */ + 0x0145, /* #.#...#.# */ + 0x0011, /* ....#...# */ + 0x00a2, /* .#.#...#. */ + 0x0192, /* ##..#..#. */ + 0x0036, /* ...##.##. */ +}, +{ + 0x0056, /* ..#.#.##. */ + 0x01a2, /* ##.#...#. */ + 0x0048, /* ..#..#... */ + 0x0050, /* ..#.#.... */ + 0x0145, /* #.#...#.# */ + 0x0014, /* ....#.#.. */ + 0x0024, /* ...#..#.. */ + 0x008b, /* .#...#.## */ + 0x00d4, /* .##.#.#.. */ +}, +{ + 0x0066, /* ..##..##. */ + 0x0105, /* #.....#.# */ + 0x0091, /* .#..#...# */ + 0x008c, /* .#...##.. */ + 0x0028, /* ...#.#... */ + 0x0062, /* ..##...#. */ + 0x0112, /* #...#..#. */ + 0x0141, /* #.#.....# */ + 0x00cc, /* .##..##.. */ +}, +{ + 0x01a0, /* ##.#..... */ + 0x00b9, /* .#.###..# */ + 0x000b, /* .....#.## */ + 0x0120, /* #..#..... */ + 0x0101, /* #.......# */ + 0x0009, /* .....#..# */ + 0x01a0, /* ##.#..... */ + 0x013a, /* #..###.#. */ + 0x000b, /* .....#.## */ +}, +{ + 0x0000, /* ......... */ + 0x01ad, /* ##.#.##.# */ + 0x0056, /* ..#.#.##. */ + 0x0018, /* ....##... */ + 0x0145, /* #.#...#.# */ + 0x0030, /* ...##.... */ + 0x00d4, /* .##.#.#.. */ + 0x016b, /* #.##.#.## */ + 0x0000, /* ......... */ +}, +{ + 0x0028, /* ...#.#... */ + 0x0082, /* .#.....#. */ + 0x01c7, /* ###...### */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x01c7, /* ###...### */ + 0x0082, /* .#.....#. */ + 0x0028, /* ...#.#... */ +}, +{ + 0x0024, /* ...#..#.. */ + 0x0152, /* #.#.#..#. */ + 0x0124, /* #..#..#.. */ + 0x0059, /* ..#.##..# */ + 0x0082, /* .#.....#. */ + 0x0134, /* #..##.#.. */ + 0x0049, /* ..#..#..# */ + 0x0095, /* .#..#.#.# */ + 0x0048, /* ..#..#... */ +}, +{ + 0x016d, /* #.##.##.# */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x016d, /* #.##.##.# */ +}, +{ + 0x0091, /* .#..#...# */ + 0x0069, /* ..##.#..# */ + 0x0038, /* ...###... */ + 0x0084, /* .#....#.. */ + 0x0183, /* ##.....## */ + 0x0042, /* ..#....#. */ + 0x0038, /* ...###... */ + 0x012c, /* #..#.##.. */ + 0x0112, /* #...#..#. */ +}, +{ + 0x0101, /* #.......# */ + 0x0021, /* ...#....# */ + 0x01d4, /* ###.#.#.. */ + 0x012a, /* #..#.#.#. */ + 0x0082, /* .#.....#. */ + 0x00a9, /* .#.#.#..# */ + 0x0057, /* ..#.#.### */ + 0x0108, /* #....#... */ + 0x0101, /* #.......# */ +}, +{ + 0x0156, /* #.#.#.##. */ + 0x00c0, /* .##...... */ + 0x0021, /* ...#....# */ + 0x0160, /* #.##..... */ + 0x0129, /* #..#.#..# */ + 0x000d, /* .....##.# */ + 0x0108, /* #....#... */ + 0x0006, /* ......##. */ + 0x00d5, /* .##.#.#.# */ +}, +{ + 0x00c2, /* .##....#. */ + 0x010a, /* #....#.#. */ + 0x012c, /* #..#.##.. */ + 0x0095, /* .#..#.#.# */ + 0x0000, /* ......... */ + 0x0152, /* #.#.#..#. */ + 0x0069, /* ..##.#..# */ + 0x00a1, /* .#.#....# */ + 0x0086, /* .#....##. */ +}, +{ + 0x0003, /* .......## */ + 0x0048, /* ..#..#... */ + 0x0168, /* #.##.#... */ + 0x0195, /* ##..#.#.# */ + 0x0028, /* ...#.#... */ + 0x0153, /* #.#.#..## */ + 0x002d, /* ...#.##.# */ + 0x0024, /* ...#..#.. */ + 0x0180, /* ##....... */ +}, +{ + 0x00c2, /* .##....#. */ + 0x01b0, /* ##.##.... */ + 0x000d, /* .....##.# */ + 0x0007, /* ......### */ + 0x0082, /* .#.....#. */ + 0x01c0, /* ###...... */ + 0x0160, /* #.##..... */ + 0x001b, /* ....##.## */ + 0x0086, /* .#....##. */ +}, +{ + 0x016d, /* #.##.##.# */ + 0x0044, /* ..#...#.. */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x0044, /* ..#...#.. */ + 0x016d, /* #.##.##.# */ +}, +{ + 0x0022, /* ...#...#. */ + 0x0006, /* ......##. */ + 0x0135, /* #..##.#.# */ + 0x0112, /* #...#..#. */ + 0x0183, /* ##.....## */ + 0x0091, /* .#..#...# */ + 0x0159, /* #.#.##..# */ + 0x00c0, /* .##...... */ + 0x0088, /* .#...#... */ +}, +{ + 0x0044, /* ..#...#.. */ + 0x006c, /* ..##.##.. */ + 0x0111, /* #...#...# */ + 0x00ee, /* .###.###. */ + 0x0000, /* ......... */ + 0x00ee, /* .###.###. */ + 0x0111, /* #...#...# */ + 0x006c, /* ..##.##.. */ + 0x0044, /* ..#...#.. */ +}, +{ + 0x0043, /* ..#....## */ + 0x014c, /* #.#..##.. */ + 0x0050, /* ..#.#.... */ + 0x0034, /* ...##.#.. */ + 0x0129, /* #..#.#..# */ + 0x0058, /* ..#.##... */ + 0x0014, /* ....#.#.. */ + 0x0065, /* ..##..#.# */ + 0x0184, /* ##....#.. */ +}, +{ + 0x00a8, /* .#.#.#... */ + 0x018c, /* ##...##.. */ + 0x0010, /* ....#.... */ + 0x0184, /* ##....#.. */ + 0x0101, /* #.......# */ + 0x0043, /* ..#....## */ + 0x0010, /* ....#.... */ + 0x0063, /* ..##...## */ + 0x002a, /* ...#.#.#. */ +}, +{ + 0x0145, /* #.#...#.# */ + 0x00ee, /* .###.###. */ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x0092, /* .#..#..#. */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ + 0x00ee, /* .###.###. */ + 0x0145, /* #.#...#.# */ +}, +{ + 0x01a0, /* ##.#..... */ + 0x0054, /* ..#.#.#.. */ + 0x0021, /* ...#....# */ + 0x008a, /* .#...#.#. */ + 0x0129, /* #..#.#..# */ + 0x00a2, /* .#.#...#. */ + 0x0108, /* #....#... */ + 0x0054, /* ..#.#.#.. */ + 0x000b, /* .....#.## */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x0054, /* ..#.#.#.. */ + 0x0101, /* #.......# */ + 0x0054, /* ..#.#.#.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x0074, /* ..###.#.. */ + 0x0041, /* ..#.....# */ + 0x0126, /* #..#..##. */ + 0x00d8, /* .##.##... */ + 0x0000, /* ......... */ + 0x0036, /* ...##.##. */ + 0x00c9, /* .##..#..# */ + 0x0104, /* #.....#.. */ + 0x005c, /* ..#.###.. */ +}, +{ + 0x0111, /* #...#...# */ + 0x0183, /* ##.....## */ + 0x0028, /* ...#.#... */ + 0x0093, /* .#..#..## */ + 0x0044, /* ..#...#.. */ + 0x0192, /* ##..#..#. */ + 0x0028, /* ...#.#... */ + 0x0183, /* ##.....## */ + 0x0111, /* #...#...# */ +}, +{ + 0x0044, /* ..#...#.. */ + 0x0028, /* ...#.#... */ + 0x0183, /* ##.....## */ + 0x006c, /* ..##.##.. */ + 0x0183, /* ##.....## */ + 0x006c, /* ..##.##.. */ + 0x0183, /* ##.....## */ + 0x0028, /* ...#.#... */ + 0x0044, /* ..#...#.. */ +}, +{ + 0x0037, /* ...##.### */ + 0x0013, /* ....#..## */ + 0x0044, /* ..#...#.. */ + 0x0122, /* #..#...#. */ + 0x0044, /* ..#...#.. */ + 0x0089, /* .#...#..# */ + 0x0044, /* ..#...#.. */ + 0x0190, /* ##..#.... */ + 0x01d8, /* ###.##... */ +}, +{ + 0x0007, /* ......### */ + 0x014a, /* #.#..#.#. */ + 0x0094, /* .#..#.#.. */ + 0x0112, /* #...#..#. */ + 0x0082, /* .#.....#. */ + 0x0091, /* .#..#...# */ + 0x0052, /* ..#.#..#. */ + 0x00a5, /* .#.#..#.# */ + 0x01c0, /* ###...... */ +}, +{ + 0x00ee, /* .###.###. */ + 0x0000, /* ......... */ + 0x0183, /* ##.....## */ + 0x006c, /* ..##.##.. */ + 0x0092, /* .#..#..#. */ + 0x006c, /* ..##.##.. */ + 0x0183, /* ##.....## */ + 0x0000, /* ......... */ + 0x00ee, /* .###.###. */ +}, +{ + 0x01ab, /* ##.#.#.## */ + 0x00aa, /* .#.#.#.#. */ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x0082, /* .#.....#. */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ + 0x00aa, /* .#.#.#.#. */ + 0x01ab, /* ##.#.#.## */ +}, +{ + 0x01aa, /* ##.#.#.#. */ + 0x0152, /* #.#.#..#. */ + 0x0012, /* ....#..#. */ + 0x002c, /* ...#.##.. */ + 0x0000, /* ......... */ + 0x0068, /* ..##.#... */ + 0x0090, /* .#..#.... */ + 0x0095, /* .#..#.#.# */ + 0x00ab, /* .#.#.#.## */ +}, +{ + 0x0046, /* ..#...##. */ + 0x0182, /* ##.....#. */ + 0x002c, /* ...#.##.. */ + 0x004d, /* ..#..##.# */ + 0x0028, /* ...#.#... */ + 0x0164, /* #.##..#.. */ + 0x0068, /* ..##.#... */ + 0x0083, /* .#.....## */ + 0x00c4, /* .##...#.. */ +}, +{ + 0x00a9, /* .#.#.#..# */ + 0x0015, /* ....#.#.# */ + 0x0016, /* ....#.##. */ + 0x0083, /* .#.....## */ + 0x0028, /* ...#.#... */ + 0x0182, /* ##.....#. */ + 0x00d0, /* .##.#.... */ + 0x0150, /* #.#.#.... */ + 0x012a, /* #..#.#.#. */ +}, +{ + 0x00a4, /* .#.#..#.. */ + 0x0121, /* #..#....# */ + 0x0059, /* ..#.##..# */ + 0x0059, /* ..#.##..# */ + 0x0000, /* ......... */ + 0x0134, /* #..##.#.. */ + 0x0134, /* #..##.#.. */ + 0x0109, /* #....#..# */ + 0x004a, /* ..#..#.#. */ +}, +{ + 0x00e4, /* .###..#.. */ + 0x0094, /* .#..#.#.. */ + 0x00a8, /* .#.#.#... */ + 0x0022, /* ...#...#. */ + 0x0129, /* #..#.#..# */ + 0x0088, /* .#...#... */ + 0x002a, /* ...#.#.#. */ + 0x0052, /* ..#.#..#. */ + 0x004e, /* ..#..###. */ +}, +{ + 0x0128, /* #..#.#... */ + 0x0044, /* ..#...#.. */ + 0x0025, /* ...#..#.# */ + 0x004e, /* ..#..###. */ + 0x0111, /* #...#...# */ + 0x00e4, /* .###..#.. */ + 0x0148, /* #.#..#... */ + 0x0044, /* ..#...#.. */ + 0x0029, /* ...#.#..# */ +}, +{ + 0x002d, /* ...#.##.# */ + 0x0062, /* ..##...#. */ + 0x01c1, /* ###.....# */ + 0x0010, /* ....#.... */ + 0x0183, /* ##.....## */ + 0x0010, /* ....#.... */ + 0x0107, /* #.....### */ + 0x008c, /* .#...##.. */ + 0x0168, /* #.##.#... */ +}, +{ + 0x0101, /* #.......# */ + 0x00ba, /* .#.###.#. */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x00ba, /* .#.###.#. */ + 0x0101, /* #.......# */ +}, +{ + 0x016d, /* #.##.##.# */ + 0x0044, /* ..#...#.. */ + 0x0183, /* ##.....## */ + 0x0028, /* ...#.#... */ + 0x0082, /* .#.....#. */ + 0x0028, /* ...#.#... */ + 0x0183, /* ##.....## */ + 0x0044, /* ..#...#.. */ + 0x016d, /* #.##.##.# */ +}, +{ + 0x00e1, /* .###....# */ + 0x001b, /* ....##.## */ + 0x00c0, /* .##...... */ + 0x0051, /* ..#.#...# */ + 0x0082, /* .#.....#. */ + 0x0114, /* #...#.#.. */ + 0x0006, /* ......##. */ + 0x01b0, /* ##.##.... */ + 0x010e, /* #....###. */ +}, +{ + 0x0103, /* #......## */ + 0x01a9, /* ##.#.#..# */ + 0x0110, /* #...#.... */ + 0x0088, /* .#...#... */ + 0x0145, /* #.#...#.# */ + 0x0022, /* ...#...#. */ + 0x0011, /* ....#...# */ + 0x012b, /* #..#.#.## */ + 0x0181, /* ##......# */ +}, +{ + 0x0082, /* .#.....#. */ + 0x00ee, /* .###.###. */ + 0x0145, /* #.#...#.# */ + 0x0038, /* ...###... */ + 0x0010, /* ....#.... */ + 0x0038, /* ...###... */ + 0x0145, /* #.#...#.# */ + 0x00ee, /* .###.###. */ + 0x0082, /* .#.....#. */ +}, +{ + 0x0052, /* ..#.#..#. */ + 0x00d0, /* .##.#.... */ + 0x0148, /* #.#..#... */ + 0x00c1, /* .##.....# */ + 0x00aa, /* .#.#.#.#. */ + 0x0106, /* #.....##. */ + 0x0025, /* ...#..#.# */ + 0x0016, /* ....#.##. */ + 0x0094, /* .#..#.#.. */ +}, +{ + 0x0017, /* ....#.### */ + 0x0041, /* ..#.....# */ + 0x008a, /* .#...#.#. */ + 0x0024, /* ...#..#.. */ + 0x01ab, /* ##.#.#.## */ + 0x0048, /* ..#..#... */ + 0x00a2, /* .#.#...#. */ + 0x0104, /* #.....#.. */ + 0x01d0, /* ###.#.... */ +}, +{ + 0x0162, /* #.##...#. */ + 0x0010, /* ....#.... */ + 0x0019, /* ....##..# */ + 0x014c, /* #.#..##.. */ + 0x0145, /* #.#...#.# */ + 0x0065, /* ..##..#.# */ + 0x0130, /* #..##.... */ + 0x0010, /* ....#.... */ + 0x008d, /* .#...##.# */ +}, +{ + 0x00a6, /* .#.#..##. */ + 0x0032, /* ...##..#. */ + 0x0100, /* #........ */ + 0x00e9, /* .###.#..# */ + 0x0082, /* .#.....#. */ + 0x012e, /* #..#.###. */ + 0x0001, /* ........# */ + 0x0098, /* .#..##... */ + 0x00ca, /* .##..#.#. */ +}, +{ + 0x0123, /* #..#...## */ + 0x0090, /* .#..#.... */ + 0x018a, /* ##...#.#. */ + 0x0158, /* #.#.##... */ + 0x0000, /* ......... */ + 0x0035, /* ...##.#.# */ + 0x00a3, /* .#.#...## */ + 0x0012, /* ....#..#. */ + 0x0189, /* ##...#..# */ +}, +{ + 0x0145, /* #.#...#.# */ + 0x00aa, /* .#.#.#.#. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x00aa, /* .#.#.#.#. */ + 0x0145, /* #.#...#.# */ +}, +{ + 0x002d, /* ...#.##.# */ + 0x01a1, /* ##.#....# */ + 0x0008, /* .....#... */ + 0x00e3, /* .###...## */ + 0x0000, /* ......... */ + 0x018e, /* ##...###. */ + 0x0020, /* ...#..... */ + 0x010b, /* #....#.## */ + 0x0168, /* #.##.#... */ +}, +{ + 0x019c, /* ##..###.. */ + 0x00a5, /* .#.#..#.# */ + 0x0180, /* ##....... */ + 0x0021, /* ...#....# */ + 0x0028, /* ...#.#... */ + 0x0108, /* #....#... */ + 0x0003, /* .......## */ + 0x014a, /* #.#..#.#. */ + 0x0073, /* ..###..## */ +}, +{ + 0x0068, /* ..##.#... */ + 0x0086, /* .#....##. */ + 0x018c, /* ##...##.. */ + 0x0162, /* #.##...#. */ + 0x0010, /* ....#.... */ + 0x008d, /* .#...##.# */ + 0x0063, /* ..##...## */ + 0x00c2, /* .##....#. */ + 0x002c, /* ...#.##.. */ +}, +{ + 0x0023, /* ...#...## */ + 0x0188, /* ##...#... */ + 0x0113, /* #...#..## */ + 0x0094, /* .#..#.#.. */ + 0x0101, /* #.......# */ + 0x0052, /* ..#.#..#. */ + 0x0191, /* ##..#...# */ + 0x0023, /* ...#...## */ + 0x0188, /* ##...#... */ +}, +{ + 0x00f3, /* .####..## */ + 0x0040, /* ..#...... */ + 0x01a4, /* ##.#..#.. */ + 0x0094, /* .#..#.#.. */ + 0x0000, /* ......... */ + 0x0052, /* ..#.#..#. */ + 0x004b, /* ..#..#.## */ + 0x0004, /* ......#.. */ + 0x019e, /* ##..####. */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x00c6, /* .##...##. */ + 0x0101, /* #.......# */ + 0x007c, /* ..#####.. */ + 0x0000, /* ......... */ + 0x007c, /* ..#####.. */ + 0x0101, /* #.......# */ + 0x00c6, /* .##...##. */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x00ae, /* .#.#.###. */ + 0x0009, /* .....#..# */ + 0x0105, /* #.....#.# */ + 0x00a6, /* .#.#..##. */ + 0x0010, /* ....#.... */ + 0x00ca, /* .##..#.#. */ + 0x0141, /* #.#.....# */ + 0x0120, /* #..#..... */ + 0x00ea, /* .###.#.#. */ +}, +{ + 0x0009, /* .....#..# */ + 0x0194, /* ##..#.#.. */ + 0x0029, /* ...#.#..# */ + 0x0034, /* ...##.#.. */ + 0x0145, /* #.#...#.# */ + 0x0058, /* ..#.##... */ + 0x0128, /* #..#.#... */ + 0x0053, /* ..#.#..## */ + 0x0120, /* #..#..... */ +}, +{ + 0x0106, /* #.....##. */ + 0x011a, /* #...##.#. */ + 0x0080, /* .#....... */ + 0x002c, /* ...#.##.. */ + 0x00ee, /* .###.###. */ + 0x0068, /* ..##.#... */ + 0x0002, /* .......#. */ + 0x00b1, /* .#.##...# */ + 0x00c1, /* .##.....# */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x006c, /* ..##.##.. */ + 0x00c6, /* .##...##. */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x00c6, /* .##...##. */ + 0x006c, /* ..##.##.. */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x0024, /* ...#..#.. */ + 0x0182, /* ##.....#. */ + 0x004a, /* ..#..#.#. */ + 0x00f2, /* .####..#. */ + 0x0101, /* #.......# */ + 0x009e, /* .#..####. */ + 0x00a4, /* .#.#..#.. */ + 0x0083, /* .#.....## */ + 0x0048, /* ..#..#... */ +}, +{ + 0x010b, /* #....#.## */ + 0x0021, /* ...#....# */ + 0x0122, /* #..#...#. */ + 0x003a, /* ...###.#. */ + 0x0082, /* .#.....#. */ + 0x00b8, /* .#.###... */ + 0x0089, /* .#...#..# */ + 0x0108, /* #....#... */ + 0x01a1, /* ##.#....# */ +}, +{ + 0x0064, /* ..##..#.. */ + 0x0198, /* ##..##... */ + 0x0122, /* #..#...#. */ + 0x0111, /* #...#...# */ + 0x0044, /* ..#...#.. */ + 0x0111, /* #...#...# */ + 0x0089, /* .#...#..# */ + 0x0033, /* ...##..## */ + 0x004c, /* ..#..##.. */ +}, +{ + 0x00a2, /* .#.#...#. */ + 0x0023, /* ...#...## */ + 0x006e, /* ..##.###. */ + 0x00c0, /* .##...... */ + 0x0101, /* #.......# */ + 0x0006, /* ......##. */ + 0x00ec, /* .###.##.. */ + 0x0188, /* ##...#... */ + 0x008a, /* .#...#.#. */ +}, +{ + 0x0075, /* ..###.#.# */ + 0x0161, /* #.##....# */ + 0x0080, /* .#....... */ + 0x0148, /* #.#..#... */ + 0x0044, /* ..#...#.. */ + 0x0025, /* ...#..#.# */ + 0x0002, /* .......#. */ + 0x010d, /* #....##.# */ + 0x015c, /* #.#.###.. */ +}, +{ + 0x0088, /* .#...#... */ + 0x0136, /* #..##.##. */ + 0x0142, /* #.#....#. */ + 0x00d0, /* .##.#.... */ + 0x0028, /* ...#.#... */ + 0x0016, /* ....#.##. */ + 0x0085, /* .#....#.# */ + 0x00d9, /* .##.##..# */ + 0x0022, /* ...#...#. */ +}, +{ + 0x0023, /* ...#...## */ + 0x00a2, /* .#.#...#. */ + 0x004c, /* ..#..##.. */ + 0x0118, /* #...##... */ + 0x00c6, /* .##...##. */ + 0x0031, /* ...##...# */ + 0x0064, /* ..##..#.. */ + 0x008a, /* .#...#.#. */ + 0x0188, /* ##...#... */ +}, +{ + 0x012c, /* #..#.##.. */ + 0x006a, /* ..##.#.#. */ + 0x0004, /* ......#.. */ + 0x0098, /* .#..##... */ + 0x006c, /* ..##.##.. */ + 0x0032, /* ...##..#. */ + 0x0040, /* ..#...... */ + 0x00ac, /* .#.#.##.. */ + 0x0069, /* ..##.#..# */ +}, +{ + 0x00d4, /* .##.#.#.. */ + 0x0101, /* #.......# */ + 0x0150, /* #.#.#.... */ + 0x0164, /* #.##..#.. */ + 0x0082, /* .#.....#. */ + 0x004d, /* ..#..##.# */ + 0x0015, /* ....#.#.# */ + 0x0101, /* #.......# */ + 0x0056, /* ..#.#.##. */ +}, +{ + 0x000e, /* .....###. */ + 0x0164, /* #.##..#.. */ + 0x0010, /* ....#.... */ + 0x0103, /* #......## */ + 0x01ab, /* ##.#.#.## */ + 0x0181, /* ##......# */ + 0x0010, /* ....#.... */ + 0x004d, /* ..#..##.# */ + 0x00e0, /* .###..... */ +}, +{ + 0x010a, /* #....#.#. */ + 0x0032, /* ...##..#. */ + 0x00a1, /* .#.#....# */ + 0x00d0, /* .##.#.... */ + 0x0129, /* #..#.#..# */ + 0x0016, /* ....#.##. */ + 0x010a, /* #....#.#. */ + 0x0098, /* .#..##... */ + 0x00a1, /* .#.#....# */ +}, +{ + 0x014a, /* #.#..#.#. */ + 0x0019, /* ....##..# */ + 0x0114, /* #...#.#.. */ + 0x0042, /* ..#....#. */ + 0x006c, /* ..##.##.. */ + 0x0084, /* .#....#.. */ + 0x0051, /* ..#.#...# */ + 0x0130, /* #..##.... */ + 0x00a5, /* .#.#..#.# */ +}, +{ + 0x0120, /* #..#..... */ + 0x0159, /* #.#.##..# */ + 0x00e0, /* .###..... */ + 0x0006, /* ......##. */ + 0x0145, /* #.#...#.# */ + 0x00c0, /* .##...... */ + 0x000e, /* .....###. */ + 0x0135, /* #..##.#.# */ + 0x0009, /* .....#..# */ +}, +{ + 0x0131, /* #..##...# */ + 0x0086, /* .#....##. */ + 0x0099, /* .#..##..# */ + 0x0009, /* .....#..# */ + 0x0044, /* ..#...#.. */ + 0x0120, /* #..#..... */ + 0x0132, /* #..##..#. */ + 0x00c2, /* .##....#. */ + 0x0119, /* #...##..# */ +}, +{ + 0x0044, /* ..#...#.. */ + 0x00aa, /* .#.#.#.#. */ + 0x0183, /* ##.....## */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0183, /* ##.....## */ + 0x00aa, /* .#.#.#.#. */ + 0x0044, /* ..#...#.. */ +}, +{ + 0x0168, /* #.##.#... */ + 0x010c, /* #....##.. */ + 0x008a, /* .#...#.#. */ + 0x0091, /* .#..#...# */ + 0x0082, /* .#.....#. */ + 0x0112, /* #...#..#. */ + 0x00a2, /* .#.#...#. */ + 0x0061, /* ..##....# */ + 0x002d, /* ...#.##.# */ +}, +{ + 0x0043, /* ..#....## */ + 0x00d8, /* .##.##... */ + 0x0120, /* #..#..... */ + 0x0168, /* #.##.#... */ + 0x0082, /* .#.....#. */ + 0x002d, /* ...#.##.# */ + 0x0009, /* .....#..# */ + 0x0036, /* ...##.##. */ + 0x0184, /* ##....#.. */ +}, +{ + 0x01ab, /* ##.#.#.## */ + 0x0010, /* ....#.... */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x0010, /* ....#.... */ + 0x01ab, /* ##.#.#.## */ +}, +{ + 0x0120, /* #..#..... */ + 0x0190, /* ##..#.... */ + 0x0046, /* ..#...##. */ + 0x00a9, /* .#.#.#..# */ + 0x0129, /* #..#.#..# */ + 0x012a, /* #..#.#.#. */ + 0x00c4, /* .##...#.. */ + 0x0013, /* ....#..## */ + 0x0009, /* .....#..# */ +}, +{ + 0x00a0, /* .#.#..... */ + 0x0185, /* ##....#.# */ + 0x0051, /* ..#.#...# */ + 0x0158, /* #.#.##... */ + 0x0082, /* .#.....#. */ + 0x0035, /* ...##.#.# */ + 0x0114, /* #...#.#.. */ + 0x0143, /* #.#....## */ + 0x000a, /* .....#.#. */ +}, +{ + 0x0101, /* #.......# */ + 0x00d6, /* .##.#.##. */ + 0x0145, /* #.#...#.# */ + 0x006c, /* ..##.##.. */ + 0x0000, /* ......... */ + 0x006c, /* ..##.##.. */ + 0x0145, /* #.#...#.# */ + 0x00d6, /* .##.#.##. */ + 0x0101, /* #.......# */ +}, +{ + 0x00e0, /* .###..... */ + 0x0111, /* #...#...# */ + 0x0011, /* ....#...# */ + 0x014a, /* #.#..#.#. */ + 0x0183, /* ##.....## */ + 0x00a5, /* .#.#..#.# */ + 0x0110, /* #...#.... */ + 0x0111, /* #...#...# */ + 0x000e, /* .....###. */ +}, +{ + 0x0183, /* ##.....## */ + 0x0028, /* ...#.#... */ + 0x0145, /* #.#...#.# */ + 0x006c, /* ..##.##.. */ + 0x0082, /* .#.....#. */ + 0x006c, /* ..##.##.. */ + 0x0145, /* #.#...#.# */ + 0x0028, /* ...#.#... */ + 0x0183, /* ##.....## */ +}, +{ + 0x018c, /* ##...##.. */ + 0x0131, /* #..##...# */ + 0x000c, /* .....##.. */ + 0x0051, /* ..#.#...# */ + 0x0082, /* .#.....#. */ + 0x0114, /* #...#.#.. */ + 0x0060, /* ..##..... */ + 0x0119, /* #...##..# */ + 0x0063, /* ..##...## */ +}, +{ + 0x0163, /* #.##...## */ + 0x0018, /* ....##... */ + 0x000b, /* .....#.## */ + 0x0043, /* ..#....## */ + 0x0000, /* ......... */ + 0x0184, /* ##....#.. */ + 0x01a0, /* ##.#..... */ + 0x0030, /* ...##.... */ + 0x018d, /* ##...##.# */ +}, +{ + 0x0155, /* #.#.#.#.# */ + 0x0000, /* ......... */ + 0x0027, /* ...#..### */ + 0x0031, /* ...##...# */ + 0x0129, /* #..#.#..# */ + 0x0118, /* #...##... */ + 0x01c8, /* ###..#... */ + 0x0000, /* ......... */ + 0x0155, /* #.#.#.#.# */ +}, +{ + 0x0033, /* ...##..## */ + 0x0199, /* ##..##..# */ + 0x0000, /* ......... */ + 0x008a, /* .#...#.#. */ + 0x00c6, /* .##...##. */ + 0x00a2, /* .#.#...#. */ + 0x0000, /* ......... */ + 0x0133, /* #..##..## */ + 0x0198, /* ##..##... */ +}, +{ + 0x0183, /* ##.....## */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0183, /* ##.....## */ +}, +{ + 0x008e, /* .#...###. */ + 0x0043, /* ..#....## */ + 0x0015, /* ....#.#.# */ + 0x0031, /* ...##...# */ + 0x0082, /* .#.....#. */ + 0x0118, /* #...##... */ + 0x0150, /* #.#.#.... */ + 0x0184, /* ##....#.. */ + 0x00e2, /* .###...#. */ +}, +{ + 0x00b8, /* .#.###... */ + 0x0021, /* ...#....# */ + 0x0081, /* .#......# */ + 0x0103, /* #......## */ + 0x00ee, /* .###.###. */ + 0x0181, /* ##......# */ + 0x0102, /* #......#. */ + 0x0108, /* #....#... */ + 0x003a, /* ...###.#. */ +}, +{ + 0x0162, /* #.##...#. */ + 0x0034, /* ...##.#.. */ + 0x0108, /* #....#... */ + 0x0103, /* #......## */ + 0x0145, /* #.#...#.# */ + 0x0181, /* ##......# */ + 0x0021, /* ...#....# */ + 0x0058, /* ..#.##... */ + 0x008d, /* .#...##.# */ +}, +{ + 0x0132, /* #..##..#. */ + 0x00c8, /* .##..#... */ + 0x0090, /* .#..#.... */ + 0x005e, /* ..#.####. */ + 0x0010, /* ....#.... */ + 0x00f4, /* .####.#.. */ + 0x0012, /* ....#..#. */ + 0x0026, /* ...#..##. */ + 0x0099, /* .#..##..# */ +}, +{ + 0x0031, /* ...##...# */ + 0x0107, /* #.....### */ + 0x0042, /* ..#....#. */ + 0x0031, /* ...##...# */ + 0x00aa, /* .#.#.#.#. */ + 0x0118, /* #...##... */ + 0x0084, /* .#....#.. */ + 0x01c1, /* ###.....# */ + 0x0118, /* #...##... */ +}, +{ + 0x0042, /* ..#....#. */ + 0x0183, /* ##.....## */ + 0x0066, /* ..##..##. */ + 0x011a, /* #...##.#. */ + 0x0010, /* ....#.... */ + 0x00b1, /* .#.##...# */ + 0x00cc, /* .##..##.. */ + 0x0183, /* ##.....## */ + 0x0084, /* .#....#.. */ +}, +{ + 0x00aa, /* .#.#.#.#. */ + 0x0028, /* ...#.#... */ + 0x0145, /* #.#...#.# */ + 0x006c, /* ..##.##.. */ + 0x0101, /* #.......# */ + 0x006c, /* ..##.##.. */ + 0x0145, /* #.#...#.# */ + 0x0028, /* ...#.#... */ + 0x00aa, /* .#.#.#.#. */ +}, +{ + 0x0032, /* ...##..#. */ + 0x003a, /* ...###.#. */ + 0x010c, /* #....##.. */ + 0x0105, /* #.....#.# */ + 0x0028, /* ...#.#... */ + 0x0141, /* #.#.....# */ + 0x0061, /* ..##....# */ + 0x00b8, /* .#.###... */ + 0x0098, /* .#..##... */ +}, +{ + 0x0106, /* #.....##. */ + 0x00c8, /* .##..#... */ + 0x004c, /* ..#..##.. */ + 0x0112, /* #...#..#. */ + 0x00c6, /* .##...##. */ + 0x0091, /* .#..#...# */ + 0x0064, /* ..##..#.. */ + 0x0026, /* ...#..##. */ + 0x00c1, /* .##.....# */ +}, +{ + 0x0049, /* ..#..#..# */ + 0x0110, /* #...#.... */ + 0x0046, /* ..#...##. */ + 0x0131, /* #..##...# */ + 0x0129, /* #..#.#..# */ + 0x0119, /* #...##..# */ + 0x00c4, /* .##...#.. */ + 0x0011, /* ....#...# */ + 0x0124, /* #..#..#.. */ +}, +{ + 0x0095, /* .#..#.#.# */ + 0x0118, /* #...##... */ + 0x0021, /* ...#....# */ + 0x003e, /* ...#####. */ + 0x0010, /* ....#.... */ + 0x00f8, /* .#####... */ + 0x0108, /* #....#... */ + 0x0031, /* ...##...# */ + 0x0152, /* #.#.#..#. */ +}, +{ + 0x0009, /* .....#..# */ + 0x014c, /* #.#..##.. */ + 0x0083, /* .#.....## */ + 0x0051, /* ..#.#...# */ + 0x0028, /* ...#.#... */ + 0x0114, /* #...#.#.. */ + 0x0182, /* ##.....#. */ + 0x0065, /* ..##..#.# */ + 0x0120, /* #..#..... */ +}, +{ + 0x0014, /* ....#.#.. */ + 0x008b, /* .#...#.## */ + 0x0110, /* #...#.... */ + 0x004b, /* ..#..#.## */ + 0x0101, /* #.......# */ + 0x01a4, /* ##.#..#.. */ + 0x0011, /* ....#...# */ + 0x01a2, /* ##.#...#. */ + 0x0050, /* ..#.#.... */ +}, +{ + 0x0114, /* #...#.#.. */ + 0x010d, /* #....##.# */ + 0x0024, /* ...#..#.. */ + 0x006d, /* ..##.##.# */ + 0x0000, /* ......... */ + 0x016c, /* #.##.##.. */ + 0x0048, /* ..#..#... */ + 0x0161, /* #.##....# */ + 0x0051, /* ..#.#...# */ +}, +{ + 0x0092, /* .#..#..#. */ + 0x002a, /* ...#.#.#. */ + 0x0013, /* ....#..## */ + 0x010e, /* #....###. */ + 0x00aa, /* .#.#.#.#. */ + 0x00e1, /* .###....# */ + 0x0190, /* ##..#.... */ + 0x00a8, /* .#.#.#... */ + 0x0092, /* .#..#..#. */ +}, +{ + 0x00d1, /* .##.#...# */ + 0x0084, /* .#....#.. */ + 0x0158, /* #.#.##... */ + 0x0064, /* ..##..#.. */ + 0x0028, /* ...#.#... */ + 0x004c, /* ..#..##.. */ + 0x0035, /* ...##.#.# */ + 0x0042, /* ..#....#. */ + 0x0116, /* #...#.##. */ +}, +{ + 0x000b, /* .....#.## */ + 0x0180, /* ##....... */ + 0x000d, /* .....##.# */ + 0x019a, /* ##..##.#. */ + 0x0082, /* .#.....#. */ + 0x00b3, /* .#.##..## */ + 0x0160, /* #.##..... */ + 0x0003, /* .......## */ + 0x01a0, /* ##.#..... */ +}, +{ + 0x00a6, /* .#.#..##. */ + 0x0115, /* #...#.#.# */ + 0x0110, /* #...#.... */ + 0x00ca, /* .##..#.#. */ + 0x0010, /* ....#.... */ + 0x00a6, /* .#.#..##. */ + 0x0011, /* ....#...# */ + 0x0151, /* #.#.#...# */ + 0x00ca, /* .##..#.#. */ +}, +{ + 0x0058, /* ..#.##... */ + 0x0064, /* ..##..#.. */ + 0x0023, /* ...#...## */ + 0x0065, /* ..##..#.# */ + 0x0082, /* .#.....#. */ + 0x014c, /* #.#..##.. */ + 0x0188, /* ##...#... */ + 0x004c, /* ..#..##.. */ + 0x0034, /* ...##.#.. */ +}, +{ + 0x0120, /* #..#..... */ + 0x00b9, /* .#.###..# */ + 0x005a, /* ..#.##.#. */ + 0x0108, /* #....#... */ + 0x0044, /* ..#...#.. */ + 0x0021, /* ...#....# */ + 0x00b4, /* .#.##.#.. */ + 0x013a, /* #..###.#. */ + 0x0009, /* .....#..# */ +}, +{ + 0x0183, /* ##.....## */ + 0x0064, /* ..##..#.. */ + 0x0128, /* #..#.#... */ + 0x0116, /* #...#.##. */ + 0x0010, /* ....#.... */ + 0x00d1, /* .##.#...# */ + 0x0029, /* ...#.#..# */ + 0x004c, /* ..#..##.. */ + 0x0183, /* ##.....## */ +}, +{ + 0x006c, /* ..##.##.. */ + 0x00aa, /* .#.#.#.#. */ + 0x0101, /* #.......# */ + 0x007c, /* ..#####.. */ + 0x0000, /* ......... */ + 0x007c, /* ..#####.. */ + 0x0101, /* #.......# */ + 0x00aa, /* .#.#.#.#. */ + 0x006c, /* ..##.##.. */ +}, +{ + 0x009a, /* .#..##.#. */ + 0x0100, /* #........ */ + 0x001b, /* ....##.## */ + 0x0154, /* #.#.#.#.. */ + 0x0028, /* ...#.#... */ + 0x0055, /* ..#.#.#.# */ + 0x01b0, /* ##.##.... */ + 0x0001, /* ........# */ + 0x00b2, /* .#.##..#. */ +}, +{ + 0x0188, /* ##...#... */ + 0x0023, /* ...#...## */ + 0x0171, /* #.###...# */ + 0x00b0, /* .#.##.... */ + 0x0000, /* ......... */ + 0x001a, /* ....##.#. */ + 0x011d, /* #...###.# */ + 0x0188, /* ##...#... */ + 0x0023, /* ...#...## */ +}, +{ + 0x011d, /* #...###.# */ + 0x0182, /* ##.....#. */ + 0x001a, /* ....##.#. */ + 0x0084, /* .#....#.. */ + 0x0028, /* ...#.#... */ + 0x0042, /* ..#....#. */ + 0x00b0, /* .#.##.... */ + 0x0083, /* .#.....## */ + 0x0171, /* #.###...# */ +}, +{ + 0x0082, /* .#.....#. */ + 0x0054, /* ..#.#.#.. */ + 0x0183, /* ##.....## */ + 0x007c, /* ..#####.. */ + 0x0000, /* ......... */ + 0x007c, /* ..#####.. */ + 0x0183, /* ##.....## */ + 0x0054, /* ..#.#.#.. */ + 0x0082, /* .#.....#. */ +}, +{ + 0x0028, /* ...#.#... */ + 0x0082, /* .#.....#. */ + 0x0145, /* #.#...#.# */ + 0x007c, /* ..#####.. */ + 0x0101, /* #.......# */ + 0x007c, /* ..#####.. */ + 0x0145, /* #.#...#.# */ + 0x0082, /* .#.....#. */ + 0x0028, /* ...#.#... */ +}, +{ + 0x0044, /* ..#...#.. */ + 0x000b, /* .....#.## */ + 0x01b0, /* ##.##.... */ + 0x0003, /* .......## */ + 0x01c7, /* ###...### */ + 0x0180, /* ##....... */ + 0x001b, /* ....##.## */ + 0x01a0, /* ##.#..... */ + 0x0044, /* ..#...#.. */ +}, +{ + 0x0116, /* #...#.##. */ + 0x00b4, /* .#.##.#.. */ + 0x0008, /* .....#... */ + 0x00c5, /* .##...#.# */ + 0x0101, /* #.......# */ + 0x0146, /* #.#...##. */ + 0x0020, /* ...#..... */ + 0x005a, /* ..#.##.#. */ + 0x00d1, /* .##.#...# */ +}, +{ + 0x0081, /* .#......# */ + 0x0039, /* ...###..# */ + 0x010e, /* #....###. */ + 0x0088, /* .#...#... */ + 0x0044, /* ..#...#.. */ + 0x0022, /* ...#...#. */ + 0x00e1, /* .###....# */ + 0x0138, /* #..###... */ + 0x0102, /* #......#. */ +}, +{ + 0x0014, /* ....#.#.. */ + 0x0182, /* ##.....#. */ + 0x00e4, /* .###..#.. */ + 0x0066, /* ..##..##. */ + 0x0028, /* ...#.#... */ + 0x00cc, /* .##..##.. */ + 0x004e, /* ..#..###. */ + 0x0083, /* .#.....## */ + 0x0050, /* ..#.#.... */ +}, +{ + 0x00a1, /* .#.#....# */ + 0x0023, /* ...#...## */ + 0x01a0, /* ##.#..... */ + 0x00b5, /* .#.##.#.# */ + 0x0000, /* ......... */ + 0x015a, /* #.#.##.#. */ + 0x000b, /* .....#.## */ + 0x0188, /* ##...#... */ + 0x010a, /* #....#.#. */ +}, +{ + 0x0159, /* #.#.##..# */ + 0x00a1, /* .#.#....# */ + 0x00a2, /* .#.#...#. */ + 0x0102, /* #......#. */ + 0x006c, /* ..##.##.. */ + 0x0081, /* .#......# */ + 0x008a, /* .#...#.#. */ + 0x010a, /* #....#.#. */ + 0x0134, /* #..##.#.. */ +}, +{ + 0x008b, /* .#...#.## */ + 0x004c, /* ..#..##.. */ + 0x0001, /* ........# */ + 0x01a4, /* ##.#..#.. */ + 0x0129, /* #..#.#..# */ + 0x004b, /* ..#..#.## */ + 0x0100, /* #........ */ + 0x0064, /* ..##..#.. */ + 0x01a2, /* ##.#...#. */ +}, +{ + 0x0028, /* ...#.#... */ + 0x00ee, /* .###.###. */ + 0x00c6, /* .##...##. */ + 0x0028, /* ...#.#... */ + 0x0101, /* #.......# */ + 0x0028, /* ...#.#... */ + 0x00c6, /* .##...##. */ + 0x00ee, /* .###.###. */ + 0x0028, /* ...#.#... */ +}, +{ + 0x0159, /* #.#.##..# */ + 0x005c, /* ..#.###.. */ + 0x0000, /* ......... */ + 0x0052, /* ..#.#..#. */ + 0x0145, /* #.#...#.# */ + 0x0094, /* .#..#.#.. */ + 0x0000, /* ......... */ + 0x0074, /* ..###.#.. */ + 0x0135, /* #..##.#.# */ +}, +{ + 0x0130, /* #..##.... */ + 0x0116, /* #...#.##. */ + 0x0088, /* .#...#... */ + 0x0107, /* #.....### */ + 0x0028, /* ...#.#... */ + 0x01c1, /* ###.....# */ + 0x0022, /* ...#...#. */ + 0x00d1, /* .##.#...# */ + 0x0019, /* ....##..# */ +}, +{ + 0x0102, /* #......#. */ + 0x012c, /* #..#.##.. */ + 0x000b, /* .....#.## */ + 0x01c8, /* ###..#... */ + 0x0044, /* ..#...#.. */ + 0x0027, /* ...#..### */ + 0x01a0, /* ##.#..... */ + 0x0069, /* ..##.#..# */ + 0x0081, /* .#......# */ +} +}; diff --git a/apps/plugins/sudoku/templates.h b/apps/plugins/sudoku/templates.h new file mode 100644 index 0000000000..a8d639b4f6 --- /dev/null +++ b/apps/plugins/sudoku/templates.h @@ -0,0 +1,8 @@ + +#ifndef _TEMPLATES_H +#define _TEMPLATES_H + +#define NUM_TEMPLATES 261 +extern const unsigned short templates[NUM_TEMPLATES][9]; + +#endif -- cgit v1.2.3