summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2006-05-15 20:08:37 +0000
committerDave Chapman <dave@dchapman.com>2006-05-15 20:08:37 +0000
commit506bac9cf792d4dbe58c5dc26432192670696f6e (patch)
tree4e8c81bce9c0685f22afa4209c6460b8498865ba
parent254751f9fc408c8bf1d230e056f95fd92b92cab2 (diff)
downloadrockbox-506bac9cf792d4dbe58c5dc26432192670696f6e.zip
rockbox-506bac9cf792d4dbe58c5dc26432192670696f6e.tar.gz
rockbox-506bac9cf792d4dbe58c5dc26432192670696f6e.tar.bz2
rockbox-506bac9cf792d4dbe58c5dc26432192670696f6e.tar.xz
Various clean-ups in preparation for 3.0: 1) Add a built-in default game which is used for the case when Sudoku is started as a plugin and no sudoku.ss exists - this prevents a time-consuming game generation; 2) Allow the user to abort a game generation by pressing any button; 3) Save the current state when user exits via the Quit button (previously, Sudoku only saved when quitting from the main menu); 4) Add a new "edit menu" for when the user is manually entering a new game, rather than displaying all options.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9944 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/sudoku/generator.c28
-rw-r--r--apps/plugins/sudoku/sudoku.c254
2 files changed, 203 insertions, 79 deletions
diff --git a/apps/plugins/sudoku/generator.c b/apps/plugins/sudoku/generator.c
index 037798d..eaef8c0 100644
--- a/apps/plugins/sudoku/generator.c
+++ b/apps/plugins/sudoku/generator.c
@@ -1056,9 +1056,14 @@ select_template( void )
init_template( i );
}
+static bool check_buttons(void)
+{
+ int button = rb->button_get(false);
+ return (button && (!(button & BUTTON_REL)) && (!(button & BUTTON_REPEAT)));
+}
static
-void
+bool
generate( void )
{
static int digits[ 9 ];
@@ -1066,6 +1071,10 @@ generate( void )
int i;
start:
+ /* Allow the user to abort generation by pressing any button */
+ if (check_buttons())
+ return false;
+
for( i = 0 ; i < 9 ; ++i )
digits[ i ] = i + 1;
@@ -1081,11 +1090,19 @@ start:
for( i = 0 ; i < len_tmplt ; ++i )
fill( tmplt[ i ], digits[ i % 9 ] );
+ /* Allow the user to abort generation by pressing any button */
+ if (check_buttons())
+ return false;
+
rb->yield();
if( 0 != solve( ) || idx_history < 81 )
goto start;
+ /* Allow the user to abort generation by pressing any button */
+ if (check_buttons())
+ return false;
+
rb->yield();
for( i = 0 ; i < len_tmplt ; ++i )
@@ -1105,6 +1122,8 @@ start:
goto start;
clear_moves( );
+
+ return true;
}
bool sudoku_generate_board(struct sudoku_state_t* state, char** difficulty)
@@ -1113,7 +1132,12 @@ bool sudoku_generate_board(struct sudoku_state_t* state, char** difficulty)
rb->srand(*rb->current_tick);
- generate();
+ rb->button_clear_queue();
+
+ if (!generate()) {
+ /* User has aborted with a button press */
+ return false;
+ }
i=0;
for (r=0;r<9;r++) {
diff --git a/apps/plugins/sudoku/sudoku.c b/apps/plugins/sudoku/sudoku.c
index 4be10cc..0c39c46 100644
--- a/apps/plugins/sudoku/sudoku.c
+++ b/apps/plugins/sudoku/sudoku.c
@@ -77,6 +77,22 @@ extern const fb_data sudoku_normal[];
extern const fb_data sudoku_start[];
extern const fb_data sudoku_inverse[];
+/* Default game - used to initialise sudoku.ss if it doesn't exist. */
+static const char default_game[9][9] =
+{
+ { '0','1','0', '3','0','7', '0','0','4' },
+ { '0','0','0', '0','6','0', '1','0','2' },
+ { '0','0','0', '0','8','0', '5','6','0' },
+
+ { '0','6','0', '0','0','0', '0','2','9' },
+ { '0','0','0', '5','0','3', '0','0','0' },
+ { '7','9','0', '0','0','0', '0','3','0' },
+
+ { '0','8','5', '0','3','0', '0','0','0' },
+ { '1','0','2', '0','7','0', '0','0','0' },
+ { '0','0','0', '4','0','8', '0','5','0' },
+};
+
#if ((LCD_HEIGHT==128) && (LCD_WIDTH==160)) || \
((LCD_HEIGHT==132) && (LCD_WIDTH==176))
/* For iriver H1x0 - 160x128, 9 cells @ 12x12 with 14 border lines*/
@@ -440,12 +456,31 @@ void sudoku_solve(struct sudoku_state_t* state)
return;
}
+void default_state(struct sudoku_state_t* state)
+{
+ int r,c;
+
+ rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
+ for (r=0;r<9;r++) {
+ for (c=0;c<9;c++) {
+ state->startboard[r][c]=default_game[r][c];
+ state->currentboard[r][c]=default_game[r][c];
+#ifdef SUDOKU_BUTTON_POSSIBLE
+ state->possiblevals[r][c]=0;
+#endif
+ }
+ }
+
+ state->x=0;
+ state->y=0;
+ state->editmode=0;
+}
void clear_state(struct sudoku_state_t* state)
{
int r,c;
- state->filename[0]=0;
+ rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
for (r=0;r<9;r++) {
for (c=0;c<9;c++) {
state->startboard[r][c]='0';
@@ -461,6 +496,65 @@ void clear_state(struct sudoku_state_t* state)
state->editmode=0;
}
+/* 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;r<r1+3;r++) {
+ for (c=c1;c<c1+3;c++) {
+ cell=state->currentboard[r][c];
+ if (cell!='0') {
+ if (check[cell-'1']==1) {
+ return true;
+ }
+ check[cell-'1']=1;
+ }
+ }
+ }
+
+ /* We passed all the checks :) */
+
+ return false;
+}
+
/* Load game - only ".ss" is officially supported, but any sensible
text representation (one line per row) may load.
*/
@@ -539,6 +633,15 @@ bool load_sudoku(struct sudoku_state_t* state, char* filename)
i++;
}
+ /* Check that the board is valid - we need to check every row/column
+ individually, so we check the diagonal from top-left to bottom-right */
+ for (state->x = 0; state->x < 9; state->x++) {
+ state->y = state->x;
+ if (check_status(state)) return false;
+ }
+ state->x = 0;
+ state->y = 0;
+
/* Save a copy of the saved state - so we can reload without using the
disk */
rb->memcpy(state->savedboard,state->currentboard,81);
@@ -553,6 +656,7 @@ bool save_sudoku(struct sudoku_state_t* state)
char line[13];
char sep[13];
+ rb->splash(0, true, "Saving...");
rb->memcpy(line,"...|...|...\r\n",13);
rb->memcpy(sep,"-----------\r\n",13);
@@ -773,88 +877,38 @@ void display_board(struct sudoku_state_t* state)
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;r<r1+3;r++) {
- for (c=c1;c<c1+3;c++) {
- cell=state->currentboard[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)
+bool sudoku_generate(struct sudoku_state_t* state)
{
char* difficulty;
char str[80];
+ bool res;
+ struct sudoku_state_t new_state;
- clear_state(state);
- display_board(state);
+ clear_state(&new_state);
+ display_board(&new_state);
rb->splash(0, true, "Generating...");
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);
#endif
- sudoku_generate_board(state,&difficulty);
+ res = sudoku_generate_board(&new_state,&difficulty);
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
- 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);
+ if (res) {
+ rb->memcpy(state,&new_state,sizeof(new_state));
+ 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);
+ } else {
+ display_board(&new_state);
+ rb->splash(2*HZ, true, "Aborted");
+ }
+ return res;
}
int sudoku_menu_cb(int key, int m)
@@ -946,6 +1000,44 @@ bool sudoku_menu(struct sudoku_state_t* state)
return (result==MENU_ATTACHED_USB);
}
+/* Menu used when user is in edit mode - i.e. creating a new game manually */
+int sudoku_edit_menu(struct sudoku_state_t* state)
+{
+ int m;
+ int result;
+
+ static const struct menu_item items[] = {
+ { "Save as", 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 new game */
+ rb->kbd_input(state->filename,MAX_PATH);
+ if (save_sudoku(state)) {
+ state->editmode=0;
+ } else {
+ rb->splash(HZ*2, true, "Save failed");
+ }
+ break;
+
+ case 1: /* Quit */
+ break;
+
+ default:
+ break;
+ }
+
+ rb->menu_exit(m);
+
+ return result;
+}
+
void move_cursor(struct sudoku_state_t* state, int newx, int newy)
{
int oldx, oldy;
@@ -975,6 +1067,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
bool exit;
int button;
int lastbutton = BUTTON_NONE;
+ int res;
long ticks;
struct sudoku_state_t state;
@@ -987,8 +1080,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
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);
+ /* No previous game saved, use the default */
+ default_state(&state);
}
} else {
if (!load_sudoku(&state,(char*)parameter)) {
@@ -1009,7 +1102,14 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
#ifdef SUDOKU_BUTTON_QUIT
/* Exit game */
case SUDOKU_BUTTON_QUIT:
- exit=1;
+ if (check_status(&state)) {
+ rb->splash(HZ*2, true, "Illegal move!");
+ /* Ignore any button presses during the splash */
+ rb->button_clear_queue();
+ } else {
+ save_sudoku(&state);
+ exit=1;
+ }
break;
#endif
@@ -1047,7 +1147,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
if (state.currentboard[state.y][state.x]=='9') {
state.currentboard[state.y][state.x]='0';
} else {
- state.currentboard[state.y][state.x]++;
+ state.currentboard[state.y][state.x]++;
}
}
}
@@ -1157,11 +1257,11 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
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");
+ res = sudoku_edit_menu(&state);
+ if (res == MENU_ATTACHED_USB) {
+ return PLUGIN_USB_CONNECTED;
+ } else if (res == 1) { /* Quit */
+ return PLUGIN_OK;
}
} else {
if (sudoku_menu(&state)) {