blob: 3910e140112c41c568d0391982ff44681c47638f [file] [log] [blame]
Dave Chapman6afb0172005-09-22 08:53:04 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Dave Chapman6afb0172005-09-22 08:53:04 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/***
23Sudoku by Dave Chapman
24
25User instructions
26-----------------
27
28Use the arrow keys to move cursor, and press SELECT/ON/F2 to increment
29the number under the cursor.
30
31At any time during the game, press On to bring up the game menu with
32further options:
33
34 Save
35 Reload
36 Clear
37 Solve
38
39Sudoku is implemented as a "viewer" for a ".ss" file, as generated by
40Simple Sudoku and other applications - http://angusj.com/sudoku/
41
42In-progress game positions are saved in the original .ss file, with
43A-I used to indicate numbers entered by the user.
44
45Example ".ss" file, and one with a saved state:
46
47...|...|... ...|...|...
482..|8.4|9.1 2.C|8.4|9.1
49...|1.6|32. E..|1.6|32.
50----------- -----------
51...|..5|.4. ...|..5|.4.
528..|423|..6 8..|423|..6
53.3.|9..|... .3D|9..|A..
54----------- -----------
55.63|7.9|... .63|7.9|...
564.9|5.2|..8 4.9|5.2|.C8
57...|...|... ...|...|...
58
59*/
60
61#include "plugin.h"
Jens Arnold65b4aae2007-09-16 18:46:39 +000062#include "lib/configfile.h"
Jonathan Gordon77a458a2007-05-08 11:55:43 +000063#include "lib/oldmenuapi.h"
Dave Chapman6afb0172005-09-22 08:53:04 +000064
65#ifdef HAVE_LCD_BITMAP
66
Dave Chapmanbf999522006-04-01 23:23:07 +000067#include <lib/playback_control.h>
Dave Chapman0f619c62006-04-01 18:38:34 +000068#include "sudoku.h"
69#include "generator.h"
70
Jens Arnoldf742c352006-08-09 20:31:38 +000071/* The bitmaps */
72#include "sudoku_normal.h"
73#include "sudoku_inverse.h"
74#include "sudoku_start.h"
75
76#define BITMAP_HEIGHT (BMPHEIGHT_sudoku_normal/10)
77#define BITMAP_STRIDE BMPWIDTH_sudoku_normal
78
Jens Arnolda36b1d42006-01-15 18:20:18 +000079PLUGIN_HEADER
80
Dave Chapmana698c3e2006-04-02 00:09:33 +000081/* here is a global api struct pointer. while not strictly necessary,
82 it's nice not to have to pass the api pointer in all function calls
83 in the plugin */
84
Steve Bavin65265772008-05-13 09:57:56 +000085const struct plugin_api* rb;
Dave Chapman6afb0172005-09-22 08:53:04 +000086
Dave Chapman506bac92006-05-15 20:08:37 +000087/* Default game - used to initialise sudoku.ss if it doesn't exist. */
88static const char default_game[9][9] =
89{
90 { '0','1','0', '3','0','7', '0','0','4' },
91 { '0','0','0', '0','6','0', '1','0','2' },
92 { '0','0','0', '0','8','0', '5','6','0' },
93
94 { '0','6','0', '0','0','0', '0','2','9' },
95 { '0','0','0', '5','0','3', '0','0','0' },
96 { '7','9','0', '0','0','0', '0','3','0' },
97
98 { '0','8','5', '0','3','0', '0','0','0' },
99 { '1','0','2', '0','7','0', '0','0','0' },
100 { '0','0','0', '4','0','8', '0','5','0' },
101};
102
Jens Arnoldf742c352006-08-09 20:31:38 +0000103#if LCD_HEIGHT <= LCD_WIDTH /* Horizontal layout, scratchpad at the left */
104
105#if (LCD_HEIGHT==64) && (LCD_WIDTH==112)
106/* Archos Recorders and Ondios - 112x64, 9 cells @ 8x6 with 10 border lines */
Dave Chapman6afb0172005-09-22 08:53:04 +0000107
108/* Internal dimensions of a cell */
Jens Arnoldf742c352006-08-09 20:31:38 +0000109#define CELL_WIDTH 8
110#define CELL_HEIGHT 6
111#define SMALL_BOARD
112
Marianne Arnold12ddb8e2007-09-20 10:49:48 +0000113#elif ((LCD_HEIGHT==80) && (LCD_WIDTH==132))
114/* C200, 9 cells @ 8x8 with 8 border lines */
115
116/* Internal dimensions of a cell */
117#define CELL_WIDTH 8
118#define CELL_HEIGHT 8
119#define SMALL_BOARD
120
Jens Arnold106ac752008-03-22 14:20:04 +0000121#elif ((LCD_HEIGHT==96) && (LCD_WIDTH==128))
122/* iAudio M3, 9 cells @ 9x9 with 14 border lines */
Jens Arnoldf742c352006-08-09 20:31:38 +0000123
124/* Internal dimensions of a cell */
Jens Arnold106ac752008-03-22 14:20:04 +0000125#define CELL_WIDTH 9
126#define CELL_HEIGHT 9
Jens Arnoldf742c352006-08-09 20:31:38 +0000127
Jens Arnold106ac752008-03-22 14:20:04 +0000128#elif (LCD_HEIGHT==110) && (LCD_WIDTH==138) \
129 || (LCD_HEIGHT==128) && (LCD_WIDTH==128)
130/* iPod Mini - 138x110, 9 cells @ 10x10 with 14 border lines */
Jens Arnoldf36d0de2006-09-18 21:44:24 +0000131/* iriver H10 5-6GB - 128x128, 9 cells @ 10x10 with 14 border lines */
132
133/* Internal dimensions of a cell */
134#define CELL_WIDTH 10
135#define CELL_HEIGHT 10
136
Jens Arnold106ac752008-03-22 14:20:04 +0000137#elif ((LCD_HEIGHT==128) && (LCD_WIDTH==160)) \
138 || ((LCD_HEIGHT==132) && (LCD_WIDTH==176))
Jens Arnoldf742c352006-08-09 20:31:38 +0000139/* iAudio X5, Iriver H1x0, iPod G3, G4 - 160x128; */
140/* iPod Nano - 176x132, 9 cells @ 12x12 with 14 border lines */
141
142/* Internal dimensions of a cell */
143#define CELL_WIDTH 12
Dave Chapman6afb0172005-09-22 08:53:04 +0000144#define CELL_HEIGHT 12
145
Barry Wardell41ee9e32007-01-15 20:40:48 +0000146#elif ((LCD_HEIGHT==176) && (LCD_WIDTH==220))
Jens Arnoldf742c352006-08-09 20:31:38 +0000147/* Iriver h300, iPod Color/Photo - 220x176, 9 cells @ 16x16 with 14 border lines */
Dave Chapman6afb0172005-09-22 08:53:04 +0000148
149/* Internal dimensions of a cell */
Jens Arnoldf742c352006-08-09 20:31:38 +0000150#define CELL_WIDTH 16
Dave Chapmanf1c02472005-11-27 23:59:05 +0000151#define CELL_HEIGHT 16
152
Jens Arnoldf742c352006-08-09 20:31:38 +0000153#elif (LCD_HEIGHT>=240) && (LCD_WIDTH>=320)
Jens Arnoldd158da22006-08-10 11:14:26 +0000154/* iPod Video - 320x240, 9 cells @ 24x24 with 14 border lines */
Dave Chapmanf1c02472005-11-27 23:59:05 +0000155
Jens Arnoldf742c352006-08-09 20:31:38 +0000156/* Internal dimensions of a cell */
Jens Arnoldd158da22006-08-10 11:14:26 +0000157#define CELL_WIDTH 24
158#define CELL_HEIGHT 24
Dave Chapmanf1c02472005-11-27 23:59:05 +0000159
Dave Chapmanf1c02472005-11-27 23:59:05 +0000160#else
Dave Chapman6afb0172005-09-22 08:53:04 +0000161 #error SUDOKU: Unsupported LCD size
162#endif
163
Jens Arnoldf742c352006-08-09 20:31:38 +0000164#else /* Vertical layout, scratchpad at the bottom */
165#define VERTICAL_LAYOUT
166
Barry Wardell41ee9e32007-01-15 20:40:48 +0000167#if ((LCD_HEIGHT==220) && (LCD_WIDTH==176))
168/* e200, 9 cells @ 16x16 with 14 border lines */
169
170/* Internal dimensions of a cell */
171#define CELL_WIDTH 16
172#define CELL_HEIGHT 16
173
174#elif (LCD_HEIGHT>=320) && (LCD_WIDTH>=240)
Jens Arnoldd158da22006-08-10 11:14:26 +0000175/* Gigabeat - 240x320, 9 cells @ 24x24 with 14 border lines */
Jens Arnoldf742c352006-08-09 20:31:38 +0000176
177/* Internal dimensions of a cell */
Jens Arnoldd158da22006-08-10 11:14:26 +0000178#define CELL_WIDTH 24
179#define CELL_HEIGHT 24
Jens Arnoldf742c352006-08-09 20:31:38 +0000180
181#else
182 #error SUDOKU: Unsupported LCD size
183#endif
184
185#endif /* Layout */
186
Jens Arnold65b4aae2007-09-16 18:46:39 +0000187#define CFGFILE_VERSION 0 /* Current config file version */
188#define CFGFILE_MINVERSION 0 /* Minimum config file version to accept */
189
190#ifdef HAVE_LCD_COLOR
191/* settings */
192struct sudoku_config {
193 int number_display;
194};
195struct sudoku_config sudcfg_disk = { 0 };
196struct sudoku_config sudcfg;
197
198static const char cfg_filename[] = "sudoku.cfg";
199static char *number_str[2] = { "black", "coloured" };
200
201struct configdata disk_config[] = {
202 { TYPE_ENUM, 0, 2, &sudcfg_disk.number_display, "numbers", number_str, NULL },
203};
204#define NUMBER_TYPE (sudcfg.number_display*CELL_WIDTH)
205#else
206#define NUMBER_TYPE 0
207#endif
208
Jens Arnoldf742c352006-08-09 20:31:38 +0000209/* Size dependent build-time calculations */
210#ifdef SMALL_BOARD
211#define BOARD_WIDTH (CELL_WIDTH*9+10)
212#define BOARD_HEIGHT (CELL_HEIGHT*9+10)
213static unsigned char cellxpos[9]={
214 1, (CELL_WIDTH+2), (2*CELL_WIDTH+3),
215 (3*CELL_WIDTH+4), (4*CELL_WIDTH+5), (5*CELL_WIDTH+6),
216 (6*CELL_WIDTH+7), (7*CELL_WIDTH+8), (8*CELL_WIDTH+9)
217};
218static unsigned char cellypos[9]={
219 1, (CELL_HEIGHT+2), (2*CELL_HEIGHT+3),
220 (3*CELL_HEIGHT+4), (4*CELL_HEIGHT+5), (5*CELL_HEIGHT+6),
221 (6*CELL_HEIGHT+7), (7*CELL_HEIGHT+8), (8*CELL_HEIGHT+9)
222};
223#else /* !SMALL_BOARD */
224#define BOARD_WIDTH (CELL_WIDTH*9+10+4)
225#define BOARD_HEIGHT (CELL_HEIGHT*9+10+4)
226static unsigned char cellxpos[9]={
227 2, (CELL_WIDTH +3), (2*CELL_WIDTH +4),
228 (3*CELL_WIDTH +6), (4*CELL_WIDTH +7), (5*CELL_WIDTH +8),
229 (6*CELL_WIDTH+10), (7*CELL_WIDTH+11), (8*CELL_WIDTH+12)
230};
231static unsigned char cellypos[9]={
232 2, (CELL_HEIGHT +3), (2*CELL_HEIGHT +4),
233 (3*CELL_HEIGHT +6), (4*CELL_HEIGHT +7), (5*CELL_HEIGHT +8),
234 (6*CELL_HEIGHT+10), (7*CELL_HEIGHT+11), (8*CELL_HEIGHT+12)
235};
236#endif
237
238#ifdef VERTICAL_LAYOUT
239#define XOFS ((LCD_WIDTH-BOARD_WIDTH)/2)
240#define YOFS ((LCD_HEIGHT-(BOARD_HEIGHT+CELL_HEIGHT*2+2))/2)
241#define YOFSSCRATCHPAD (YOFS+BOARD_HEIGHT+CELL_WIDTH)
242#else
243#define XOFSSCRATCHPAD ((LCD_WIDTH-(BOARD_WIDTH+CELL_WIDTH*2+2))/2)
244#define XOFS (XOFSSCRATCHPAD+CELL_WIDTH*2+2)
245#define YOFS ((LCD_HEIGHT-BOARD_HEIGHT)/2)
246#endif
247
Dave Chapman6afb0172005-09-22 08:53:04 +0000248/****** Solver routine by Tom Shackell <shackell@cs.york.ac.uk>
249
250Downloaded from:
251
252http://www-users.cs.york.ac.uk/~shackell/sudoku/Sudoku.html
253
254Released under GPLv2
255
256*/
257
258typedef unsigned int Bitset;
259
260#define BLOCK 3
261#define SIZE (BLOCK*BLOCK)
262
263#define true 1
264#define false 0
265
266typedef struct _Sudoku {
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000267 Bitset table[SIZE][SIZE];
Dave Chapman6afb0172005-09-22 08:53:04 +0000268}Sudoku;
269
270typedef struct _Stats {
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000271 int numTries;
272 int backTracks;
273 int numEmpty;
274 bool solutionFound;
Dave Chapman6afb0172005-09-22 08:53:04 +0000275}Stats;
276
277typedef struct _Options {
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000278 bool allSolutions;
279 bool uniquenessCheck;
Dave Chapman6afb0172005-09-22 08:53:04 +0000280}Options;
281
282void sudoku_init(Sudoku* sud);
283void sudoku_set(Sudoku* sud, int x, int y, int num, bool original);
284int sudoku_get(Sudoku* sud, int x, int y, bool* original);
285
286#define BIT(n) ((Bitset)(1<<(n)))
287#define BIT_TEST(v,n) ((((Bitset)v) & BIT(n)) != 0)
288#define BIT_CLEAR(v,n) (v) &= ~BIT(n)
289#define MARK_BIT BIT(0)
290#define ORIGINAL_BIT BIT(SIZE+1)
291
292#define ALL_BITS (BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9))
293
294/* initialize a sudoku problem, should be called before using set or get */
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000295void sudoku_init(Sudoku* sud)
296{
297 int y, x;
298 for (y = 0; y < SIZE; y++){
299 for (x = 0; x < SIZE; x++){
300 sud->table[x][y] = ALL_BITS;
301 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000302 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000303}
304
305/* set the number at a particular x and y column */
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000306void sudoku_set(Sudoku* sud, int x, int y, int num, bool original)
307{
308 int i, j;
309 int bx, by;
310 Bitset orig;
Dave Chapman6afb0172005-09-22 08:53:04 +0000311
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000312 /* clear the row and columns */
313 for (i = 0; i < SIZE; i++){
314 BIT_CLEAR(sud->table[i][y], num);
315 BIT_CLEAR(sud->table[x][i], num);
Dave Chapman6afb0172005-09-22 08:53:04 +0000316 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000317 /* clear the block */
318 bx = x - (x % BLOCK);
319 by = y - (y % BLOCK);
320 for (i = 0; i < BLOCK; i++){
321 for (j = 0; j < BLOCK; j++){
322 BIT_CLEAR(sud->table[bx+j][by+i], num);
323 }
324 }
325 /* mark the table */
326 orig = original ? ORIGINAL_BIT : 0;
327 sud->table[x][y] = BIT(num) | MARK_BIT | orig;
Dave Chapman6afb0172005-09-22 08:53:04 +0000328}
329
330/* get the number at a particular x and y column, if this
331 is not unique return 0 */
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000332int sudoku_get(Sudoku* sud, int x, int y, bool* original)
333{
334 Bitset val = sud->table[x][y];
335 int result = 0;
336 int i;
Dave Chapman6afb0172005-09-22 08:53:04 +0000337
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000338 if (original) {
339 *original = val & ORIGINAL_BIT;
Dave Chapman6afb0172005-09-22 08:53:04 +0000340 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000341 for (i = 1; i <= SIZE; i++){
342 if (BIT_TEST(val, i)){
343 if (result != 0){
344 return 0;
345 }
346 result = i;
347 }
348 }
349 return result;
Dave Chapman6afb0172005-09-22 08:53:04 +0000350}
351
352/* returns true if this is a valid problem, this is necessary because the input
353 problem might be degenerate which breaks the solver algorithm. */
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000354static bool is_valid(const Sudoku* sud)
355{
356 int x, y;
357
358 for (y = 0; y < SIZE; y++){
359 for (x = 0; x < SIZE; x++){
360 if ((sud->table[x][y] & ALL_BITS) == 0){
361 return false;
362 }
363 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000364 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000365 return true;
Dave Chapman6afb0172005-09-22 08:53:04 +0000366}
367
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000368/* scan the table for the most constrained item, giving all it's options, sets
369 the best x and y coordinates, the number of options and the options for
370 that coordinate and returns true if the puzzle is finished */
371static bool scan(const Sudoku* sud, int* rX, int* rY, int *num, int* options)
372{
373 int x, y, i, j;
374 int bestCount = SIZE+1;
375 Bitset val;
376 bool allMarked = true;
Dave Chapman6afb0172005-09-22 08:53:04 +0000377
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000378 for (y = 0; y < SIZE; y++){
379 for (x = 0; x < SIZE; x++){
380 Bitset val = sud->table[x][y];
381 int i;
382 int count = 0;
Dave Chapman6afb0172005-09-22 08:53:04 +0000383
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000384 if (val & MARK_BIT) {
385 /* already set */
386 continue;
387 }
388 allMarked = false;
389 for (i = 1; i <= SIZE; i++){
390 if (BIT_TEST(val, i)){
391 count++;
392 }
393 }
394 if (count < bestCount){
395 bestCount = count;
396 *rX = x;
397 *rY = y;
398 if (count == 0){
399 /* can't possibly be beaten */
400 *num = 0;
401 return false;
402 }
403 }
404 }
405 }
406 /* now copy into options */
407 *num = bestCount;
408 val = sud->table[*rX][*rY];
409 for (i = 1, j = 0; i <= SIZE; i++){
Dave Chapman6afb0172005-09-22 08:53:04 +0000410 if (BIT_TEST(val, i)){
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000411 options[j++] = i;
Dave Chapman6afb0172005-09-22 08:53:04 +0000412 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000413 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000414 return allMarked;
Dave Chapman6afb0172005-09-22 08:53:04 +0000415}
416
417static bool solve(Sudoku* sud, Stats* stats, const Options* options);
418
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000419/* try a particular option and return true if that gives a solution or false
420 if it doesn't, restores board on backtracking */
421static bool spawn_option(Sudoku* sud, Stats* stats, const Options* options,
422 int x, int y, int num)
423{
424 Sudoku copy;
Dave Chapman6afb0172005-09-22 08:53:04 +0000425
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000426 rb->memcpy(&copy,sud,sizeof(Sudoku));
427 sudoku_set(&copy, x, y, num, false);
428 stats->numTries += 1;
429 if (solve(&copy, stats, options)){
430 if (!options->allSolutions && stats->solutionFound){
431 rb->memcpy(sud,&copy,sizeof(Sudoku));
432 }
433 return true;
434 }else{
435 stats->backTracks++;
Dave Chapman6afb0172005-09-22 08:53:04 +0000436 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000437 return false;
Dave Chapman6afb0172005-09-22 08:53:04 +0000438}
439
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000440/* solve a sudoku problem, returns true if there is a solution and false
441 otherwise. stats is used to track statisticss */
442static bool solve(Sudoku* sud, Stats* stats, const Options* options)
443{
444 while (true){
Jens Arnoldf376eb52006-04-30 12:24:55 +0000445 int x = 0;
446 int y = 0;
447 int i, num;
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000448 int places[SIZE];
449
450 if (scan(sud, &x, &y, &num, places)){
451 /* a solution was found! */
452 if (options->uniquenessCheck && stats->solutionFound){
453 /*printf("\n\t... But the solution is not unique!\n"); */
454 return true;
455 }
456 stats->solutionFound = true;
457 if (options->allSolutions || options->uniquenessCheck){
458 /*printf("\n\tSolution after %d iterations\n", stats->numTries); */
459 /*sudoku_print(sud); */
460 return false;
461 }
462 else{
463 return true;
464 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000465 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000466 if (num == 0){
467 /* can't be satisfied */
468 return false;
469 }
470 /* try all the places (except the last one) */
471 for (i = 0; i < num-1; i++){
472 if (spawn_option(sud, stats, options, x, y, places[i])){
473 /* solution found! */
474 if (!options->allSolutions && stats->solutionFound){
475 return true;
476 }
477 }
478 }
479 /* take the last place ourself */
480 stats->numTries += 1;
481 sudoku_set(sud, x, y, places[num-1], false);
Dave Chapman6afb0172005-09-22 08:53:04 +0000482 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000483}
484
485/******** END OF IMPORTED CODE */
486
487
488/* A wrapper function between the Sudoku plugin and the above solver code */
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000489void sudoku_solve(struct sudoku_state_t* state)
490{
491 bool ret;
492 Stats stats;
493 Options options;
494 Sudoku sud;
495 bool original;
496 int r,c;
497
498 /* Initialise the parameters */
499 sudoku_init(&sud);
500 rb->memset(&stats,0,sizeof(stats));
501 options.allSolutions=false;
502 options.uniquenessCheck=false;
Dave Chapman6afb0172005-09-22 08:53:04 +0000503
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000504 /* Convert Rockbox format into format for solver */
Dave Chapman6afb0172005-09-22 08:53:04 +0000505 for (r=0;r<9;r++) {
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000506 for (c=0;c<9;c++) {
507 if (state->startboard[r][c]!='0') {
508 sudoku_set(&sud, c, r, state->startboard[r][c]-'0', true);
509 }
510 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000511 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000512
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000513 /* need to check for degenerate input problems ... */
514 if (is_valid(&sud)){
515 ret = solve(&sud, &stats, &options);
516 } else {
517 ret = false;
518 }
519
520 if (ret) {
521 /* Populate the board with the solution. */
522 for (r=0;r<9;r++) {
523 for (c=0;c<9;c++) {
524 state->currentboard[r][c]='0'+
525 sudoku_get(&sud, c, r, &original);
526 }
527 }
528 } else {
Jens Arnold4d6374c2007-03-16 21:56:08 +0000529 rb->splash(HZ*2, "Solve failed");
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000530 }
531
532 return;
Dave Chapman6afb0172005-09-22 08:53:04 +0000533}
534
Dave Chapman506bac92006-05-15 20:08:37 +0000535void default_state(struct sudoku_state_t* state)
536{
537 int r,c;
538
539 rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
540 for (r=0;r<9;r++) {
541 for (c=0;c<9;c++) {
542 state->startboard[r][c]=default_game[r][c];
543 state->currentboard[r][c]=default_game[r][c];
544#ifdef SUDOKU_BUTTON_POSSIBLE
545 state->possiblevals[r][c]=0;
546#endif
547 }
548 }
549
550 state->x=0;
551 state->y=0;
552 state->editmode=0;
553}
Dave Chapman6afb0172005-09-22 08:53:04 +0000554
555void clear_state(struct sudoku_state_t* state)
556{
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000557 int r,c;
Dave Chapman6afb0172005-09-22 08:53:04 +0000558
Dave Chapman506bac92006-05-15 20:08:37 +0000559 rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000560 for (r=0;r<9;r++) {
561 for (c=0;c<9;c++) {
562 state->startboard[r][c]='0';
563 state->currentboard[r][c]='0';
Dave Chapman61eac112005-11-29 00:02:00 +0000564#ifdef SUDOKU_BUTTON_POSSIBLE
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000565 state->possiblevals[r][c]=0;
Dave Chapman61eac112005-11-29 00:02:00 +0000566#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000567 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000568 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000569
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000570 state->x=0;
571 state->y=0;
572 state->editmode=0;
Dave Chapman6afb0172005-09-22 08:53:04 +0000573}
574
Dave Chapman506bac92006-05-15 20:08:37 +0000575/* Check the status of the board, assuming a change at the cursor location */
576bool check_status(struct sudoku_state_t* state)
577{
578 int check[9];
579 int r,c;
580 int r1,c1;
581 int cell;
582
583 /* First, check the column */
584 for (cell=0;cell<9;cell++) {
585 check[cell]=0;
586 }
587 for (r=0;r<9;r++) {
588 cell=state->currentboard[r][state->x];
589 if (cell!='0') {
590 if (check[cell-'1']==1) {
591 return true;
592 }
593 check[cell-'1']=1;
594 }
595 }
596
597 /* Second, check the row */
598 for (cell=0;cell<9;cell++) {
599 check[cell]=0;
600 }
601 for (c=0;c<9;c++) {
602 cell=state->currentboard[state->y][c];
603 if (cell!='0') {
604 if (check[cell-'1']==1) {
605 return true;
606 }
607 check[cell-'1']=1;
608 }
609 }
610
611 /* Finally, check the 3x3 sub-grid */
612 for (cell=0;cell<9;cell++) {
613 check[cell]=0;
614 }
615 r1=(state->y/3)*3;
616 c1=(state->x/3)*3;
617 for (r=r1;r<r1+3;r++) {
618 for (c=c1;c<c1+3;c++) {
619 cell=state->currentboard[r][c];
620 if (cell!='0') {
621 if (check[cell-'1']==1) {
622 return true;
623 }
624 check[cell-'1']=1;
625 }
626 }
627 }
628
629 /* We passed all the checks :) */
630
631 return false;
632}
633
Dave Chapman6afb0172005-09-22 08:53:04 +0000634/* Load game - only ".ss" is officially supported, but any sensible
635 text representation (one line per row) may load.
636*/
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000637bool load_sudoku(struct sudoku_state_t* state, char* filename)
638{
639 int fd;
640 size_t n;
641 int r = 0, c = 0;
642 unsigned int i;
643 int valid=0;
644 char buf[300]; /* A buffer to read a sudoku board from */
Dave Chapman6afb0172005-09-22 08:53:04 +0000645
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000646 fd=rb->open(filename, O_RDONLY);
647 if (fd < 0) {
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000648 LOGF("Invalid sudoku file: %s\n",filename);
Dave Chapman6afb0172005-09-22 08:53:04 +0000649 return(false);
Dave Chapman6afb0172005-09-22 08:53:04 +0000650 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000651
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000652 rb->strncpy(state->filename,filename,MAX_PATH);
653 n=rb->read(fd,buf,300);
654 if (n <= 0) {
655 return(false);
656 }
657 rb->close(fd);
Dave Chapman6afb0172005-09-22 08:53:04 +0000658
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000659 r=0;
660 c=0;
661 i=0;
662 while ((i < n) && (r < 9)) {
663 switch (buf[i]){
664 case ' ': case '\t':
665 if (c > 0)
666 valid=1;
667 break;
668 case '|':
669 case '*':
670 case '-':
671 case '\r':
672 break;
673 case '\n':
674 if (valid) {
675 r++;
676 valid=0;
677 }
678 c = 0;
679 break;
680 case '_': case '.':
681 valid=1;
682 if (c >= SIZE || r >= SIZE){
683 LOGF("ERROR: sudoku problem is the wrong size (%d,%d)\n",
684 c, r);
685 return(false);
686 }
687 c++;
688 break;
689 default:
690 if (((buf[i]>='A') && (buf[i]<='I')) ||
691 ((buf[i]>='0') && (buf[i]<='9'))) {
692 valid=1;
693 if (r >= SIZE || c >= SIZE){
694 LOGF("ERROR: sudoku problem is the wrong size "
695 "(%d,%d)\n", c, r);
696 return(false);
697 }
698 if ((buf[i]>='0') && (buf[i]<='9')) {
699 state->startboard[r][c]=buf[i];
700 state->currentboard[r][c]=buf[i];
701 } else {
702 state->currentboard[r][c]='1'+(buf[i]-'A');
703 }
704 c++;
705 }
706 /* Ignore any other characters */
707 break;
Dave Chapman6afb0172005-09-22 08:53:04 +0000708 }
709 i++;
Dave Chapman6afb0172005-09-22 08:53:04 +0000710 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000711
Dave Chapman506bac92006-05-15 20:08:37 +0000712 /* Check that the board is valid - we need to check every row/column
713 individually, so we check the diagonal from top-left to bottom-right */
714 for (state->x = 0; state->x < 9; state->x++) {
715 state->y = state->x;
716 if (check_status(state)) return false;
717 }
718 state->x = 0;
719 state->y = 0;
720
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000721 /* Save a copy of the saved state - so we can reload without using the
722 disk */
Dave Chapman6afb0172005-09-22 08:53:04 +0000723 rb->memcpy(state->savedboard,state->currentboard,81);
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000724 return(true);
725}
726
727bool save_sudoku(struct sudoku_state_t* state)
728{
729 int fd;
730 int r,c;
731 int i;
Dave Chapman0f619c62006-04-01 18:38:34 +0000732 char line[13];
733 char sep[13];
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000734
Jens Arnold4d6374c2007-03-16 21:56:08 +0000735 rb->splash(0, "Saving...");
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000736 rb->memcpy(line,"...|...|...\r\n",13);
737 rb->memcpy(sep,"-----------\r\n",13);
738
739 if (state->filename[0]==0) {
740 return false;
741 }
742
743 fd=rb->open(state->filename, O_WRONLY|O_CREAT);
744 if (fd >= 0) {
745 for (r=0;r<9;r++) {
746 i=0;
747 for (c=0;c<9;c++) {
748 if (state->startboard[r][c]!='0') {
749 line[i]=state->startboard[r][c];
750 } else if (state->currentboard[r][c]!='0') {
751 line[i]='A'+(state->currentboard[r][c]-'1');
752 } else {
753 line[i]='.';
754 }
755 i++;
756 if ((c==2) || (c==5)) {
757 i++;
758 }
759 }
Dave Chapman0f619c62006-04-01 18:38:34 +0000760 rb->write(fd,line,sizeof(line));
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000761 if ((r==2) || (r==5)) {
Dave Chapman0f619c62006-04-01 18:38:34 +0000762 rb->write(fd,sep,sizeof(sep));
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000763 }
764 }
765 /* Add a blank line at end */
766 rb->write(fd,"\r\n",2);
767 rb->close(fd);
Hardeep Sidhuab3e71c2006-06-04 16:36:49 +0000768 rb->reload_directory();
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000769 /* Save a copy of the saved state - so we can reload without
770 using the disk */
771 rb->memcpy(state->savedboard,state->currentboard,81);
772 return true;
773 } else {
774 return false;
775 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000776}
777
778void restore_state(struct sudoku_state_t* state)
779{
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000780 rb->memcpy(state->currentboard,state->savedboard,81);
Dave Chapman6afb0172005-09-22 08:53:04 +0000781}
782
783void clear_board(struct sudoku_state_t* state)
784{
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000785 int r,c;
Dave Chapman6afb0172005-09-22 08:53:04 +0000786
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000787 for (r=0;r<9;r++) {
788 for (c=0;c<9;c++) {
789 state->currentboard[r][c]=state->startboard[r][c];
790 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000791 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000792 state->x=0;
793 state->y=0;
Dave Chapman6afb0172005-09-22 08:53:04 +0000794}
795
796void update_cell(struct sudoku_state_t* state, int r, int c)
797{
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000798 /* We have four types of cell:
799 1) User-entered number
800 2) Starting number
801 3) Cursor in cell
802 */
Dave Chapman6afb0172005-09-22 08:53:04 +0000803
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000804 if ((r==state->y) && (c==state->x)) {
Jens Arnold65b4aae2007-09-16 18:46:39 +0000805 rb->lcd_bitmap_part(sudoku_inverse,NUMBER_TYPE,
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000806 BITMAP_HEIGHT*(state->currentboard[r][c]-'0'),
807 BITMAP_STRIDE,
808 XOFS+cellxpos[c],YOFS+cellypos[r],CELL_WIDTH,
809 CELL_HEIGHT);
810 } else {
Dave Chapman6afb0172005-09-22 08:53:04 +0000811 if (state->startboard[r][c]!='0') {
Jens Arnold65b4aae2007-09-16 18:46:39 +0000812 rb->lcd_bitmap_part(sudoku_start,NUMBER_TYPE,
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000813 BITMAP_HEIGHT*(state->startboard[r][c]-'0'),
814 BITMAP_STRIDE,
815 XOFS+cellxpos[c],YOFS+cellypos[r],
816 CELL_WIDTH,CELL_HEIGHT);
Dave Chapman6afb0172005-09-22 08:53:04 +0000817 } else {
Jens Arnold65b4aae2007-09-16 18:46:39 +0000818 rb->lcd_bitmap_part(sudoku_normal,NUMBER_TYPE,
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000819 BITMAP_HEIGHT*(state->currentboard[r][c]-'0'),
820 BITMAP_STRIDE,
821 XOFS+cellxpos[c],YOFS+cellypos[r],
822 CELL_WIDTH,CELL_HEIGHT);
Dave Chapman6afb0172005-09-22 08:53:04 +0000823 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000824 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000825
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000826 rb->lcd_update_rect(cellxpos[c],cellypos[r],CELL_WIDTH,CELL_HEIGHT);
Dave Chapman6afb0172005-09-22 08:53:04 +0000827}
828
829
830void display_board(struct sudoku_state_t* state)
831{
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000832 int r,c;
Dave Chapman6afb0172005-09-22 08:53:04 +0000833
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000834 /* Clear the display buffer */
835 rb->lcd_clear_display();
Dave Chapman6afb0172005-09-22 08:53:04 +0000836
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000837 /* Draw the gridlines - differently for different targets */
Dave Chapman6afb0172005-09-22 08:53:04 +0000838
Jens Arnoldf742c352006-08-09 20:31:38 +0000839#ifdef SMALL_BOARD
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000840 /* Small targets - draw dotted/single lines */
841 for (r=0;r<9;r++) {
842 if ((r % 3)==0) {
843 /* Solid Line */
844 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-1);
845 rb->lcd_vline(XOFS+cellxpos[r]-1,YOFS,YOFS+BOARD_HEIGHT-1);
846 } else {
847 /* Dotted line */
848 for (c=XOFS;c<XOFS+BOARD_WIDTH;c+=2) {
849 rb->lcd_drawpixel(c,YOFS+cellypos[r]-1);
850 }
851 for (c=YOFS;c<YOFS+BOARD_HEIGHT;c+=2) {
852 rb->lcd_drawpixel(XOFS+cellxpos[r]-1,c);
853 }
854 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000855 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000856 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT);
857 rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH,YOFS,YOFS+BOARD_HEIGHT-1);
Dave Chapman6afb0172005-09-22 08:53:04 +0000858#else
Jens Arnoldf742c352006-08-09 20:31:38 +0000859 /* Large targets - draw single/double lines */
860 for (r=0;r<9;r++) {
861 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-1);
862 rb->lcd_vline(XOFS+cellxpos[r]-1,YOFS,YOFS+BOARD_HEIGHT-1);
863 if ((r % 3)==0) {
864 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[r]-2);
865 rb->lcd_vline(XOFS+cellxpos[r]-2,YOFS,YOFS+BOARD_HEIGHT-1);
866 }
867 }
868 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT);
869 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFS+cellypos[8]+CELL_HEIGHT+1);
870 rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH,YOFS,YOFS+BOARD_HEIGHT-1);
871 rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH+1,YOFS,YOFS+BOARD_HEIGHT-1);
Dave Chapman6afb0172005-09-22 08:53:04 +0000872#endif
873
Dave Chapman61eac112005-11-29 00:02:00 +0000874#ifdef SUDOKU_BUTTON_POSSIBLE
Jens Arnoldf742c352006-08-09 20:31:38 +0000875#ifdef VERTICAL_LAYOUT
876 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFSSCRATCHPAD);
877 rb->lcd_hline(XOFS,XOFS+BOARD_WIDTH-1,YOFSSCRATCHPAD+CELL_HEIGHT+1);
878 for (r=0;r<9;r++) {
879#ifdef SMALL_BOARD
880 /* Small targets - draw dotted/single lines */
881 if ((r % 3)==0) {
882 /* Solid Line */
883 rb->lcd_vline(XOFS+cellxpos[r]-1,YOFSSCRATCHPAD,
884 YOFSSCRATCHPAD+CELL_HEIGHT+1);
885 } else {
886 /* Dotted line */
887 for (c=YOFSSCRATCHPAD;c<YOFSSCRATCHPAD+CELL_HEIGHT+1;c+=2) {
888 rb->lcd_drawpixel(XOFS+cellxpos[r]-1,c);
889 }
890 }
891#else
892 /* Large targets - draw single/double lines */
893 rb->lcd_vline(XOFS+cellxpos[r]-1,YOFSSCRATCHPAD,
894 YOFSSCRATCHPAD+CELL_HEIGHT+1);
895 if ((r % 3)==0)
896 rb->lcd_vline(XOFS+cellxpos[r]-2,YOFSSCRATCHPAD,
897 YOFSSCRATCHPAD+CELL_HEIGHT+1);
898#endif
899 if ((r>0) && state->possiblevals[state->y][state->x]&(1<<(r)))
Jens Arnold65b4aae2007-09-16 18:46:39 +0000900 rb->lcd_bitmap_part(sudoku_normal,NUMBER_TYPE,BITMAP_HEIGHT*r,
901 BITMAP_STRIDE,XOFS+cellxpos[r-1],
902 YOFSSCRATCHPAD+1,CELL_WIDTH,CELL_HEIGHT);
Jens Arnoldf742c352006-08-09 20:31:38 +0000903 }
904 rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH,YOFSSCRATCHPAD,
905 YOFSSCRATCHPAD+CELL_HEIGHT+1);
906#ifndef SMALL_BOARD
907 rb->lcd_vline(XOFS+cellxpos[8]+CELL_WIDTH+1,YOFSSCRATCHPAD,
908 YOFSSCRATCHPAD+CELL_HEIGHT+1);
909#endif
910 if (state->possiblevals[state->y][state->x]&(1<<(r)))
Jens Arnold65b4aae2007-09-16 18:46:39 +0000911 rb->lcd_bitmap_part(sudoku_normal,NUMBER_TYPE,BITMAP_HEIGHT*r,
912 BITMAP_STRIDE,XOFS+cellxpos[8],YOFSSCRATCHPAD+1,
Jens Arnoldf742c352006-08-09 20:31:38 +0000913 CELL_WIDTH,CELL_HEIGHT);
914#else /* Horizontal layout */
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000915 rb->lcd_vline(XOFSSCRATCHPAD,YOFS,YOFS+BOARD_HEIGHT-1);
916 rb->lcd_vline(XOFSSCRATCHPAD+CELL_WIDTH+1,YOFS,YOFS+BOARD_HEIGHT-1);
917 for (r=0;r<9;r++) {
Jens Arnoldf742c352006-08-09 20:31:38 +0000918#ifdef SMALL_BOARD
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000919 /* Small targets - draw dotted/single lines */
920 if ((r % 3)==0) {
921 /* Solid Line */
922 rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1,
923 YOFS+cellypos[r]-1);
Dave Chapman6afb0172005-09-22 08:53:04 +0000924 } else {
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000925 /* Dotted line */
926 for (c=XOFSSCRATCHPAD;c<XOFSSCRATCHPAD+CELL_WIDTH+1;c+=2) {
927 rb->lcd_drawpixel(c,YOFS+cellypos[r]-1);
928 }
Dave Chapman6afb0172005-09-22 08:53:04 +0000929 }
Jens Arnoldf742c352006-08-09 20:31:38 +0000930#else
931 /* Large targets - draw single/double lines */
932 rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1,
933 YOFS+cellypos[r]-1);
934 if ((r % 3)==0)
935 rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1,
936 YOFS+cellypos[r]-2);
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000937#endif
938 if ((r>0) && state->possiblevals[state->y][state->x]&(1<<(r)))
Jens Arnold65b4aae2007-09-16 18:46:39 +0000939 rb->lcd_bitmap_part(sudoku_normal,NUMBER_TYPE,BITMAP_HEIGHT*r,
940 BITMAP_STRIDE,XOFSSCRATCHPAD+1,
941 YOFS+cellypos[r-1],CELL_WIDTH,CELL_HEIGHT);
Dave Chapman6afb0172005-09-22 08:53:04 +0000942 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000943 rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1,
944 YOFS+cellypos[8]+CELL_HEIGHT);
Jens Arnoldf742c352006-08-09 20:31:38 +0000945#ifndef SMALL_BOARD
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000946 rb->lcd_hline(XOFSSCRATCHPAD,XOFSSCRATCHPAD+CELL_WIDTH+1,
947 YOFS+cellypos[8]+CELL_HEIGHT+1);
948#endif
949 if (state->possiblevals[state->y][state->x]&(1<<(r)))
Jens Arnold65b4aae2007-09-16 18:46:39 +0000950 rb->lcd_bitmap_part(sudoku_normal,NUMBER_TYPE,BITMAP_HEIGHT*r,
951 BITMAP_STRIDE,XOFSSCRATCHPAD+1,YOFS+cellypos[8],
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000952 CELL_WIDTH,CELL_HEIGHT);
Jens Arnoldf742c352006-08-09 20:31:38 +0000953#endif /* Layout */
954#endif /* SUDOKU_BUTTON_POSSIBLE */
Dave Chapman6afb0172005-09-22 08:53:04 +0000955
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000956 /* Draw the numbers */
957 for (r=0;r<9;r++) {
958 for (c=0;c<9;c++) {
959 /* We have four types of cell:
960 1) User-entered number
961 2) Starting number
962 3) Cursor in cell
963 */
964
965 if ((r==state->y) && (c==state->x)) {
Jens Arnold65b4aae2007-09-16 18:46:39 +0000966 rb->lcd_bitmap_part(sudoku_inverse,NUMBER_TYPE,
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000967 BITMAP_HEIGHT*(state->currentboard[r][c]-
968 '0'),
969 BITMAP_STRIDE,
970 XOFS+cellxpos[c],YOFS+cellypos[r],
971 CELL_WIDTH,CELL_HEIGHT);
972 } else {
973 if (state->startboard[r][c]!='0') {
Jens Arnold65b4aae2007-09-16 18:46:39 +0000974 rb->lcd_bitmap_part(sudoku_start,NUMBER_TYPE,
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000975 BITMAP_HEIGHT*(state->startboard[r][c]-
976 '0'),
977 BITMAP_STRIDE,
978 XOFS+cellxpos[c],YOFS+cellypos[r],
979 CELL_WIDTH,CELL_HEIGHT);
980 } else {
Jens Arnold65b4aae2007-09-16 18:46:39 +0000981 rb->lcd_bitmap_part(sudoku_normal,NUMBER_TYPE,
Daniel Stenberg220fafd2006-03-03 08:14:44 +0000982 BITMAP_HEIGHT*
983 (state->currentboard[r][c]-'0'),
984 BITMAP_STRIDE,
985 XOFS+cellxpos[c],YOFS+cellypos[r],
986 CELL_WIDTH,CELL_HEIGHT);
987 }
988 }
989 }
990 }
991
992 /* update the screen */
993 rb->lcd_update();
Dave Chapman6afb0172005-09-22 08:53:04 +0000994}
995
Dave Chapman506bac92006-05-15 20:08:37 +0000996bool sudoku_generate(struct sudoku_state_t* state)
Dave Chapman0f619c62006-04-01 18:38:34 +0000997{
998 char* difficulty;
999 char str[80];
Dave Chapman506bac92006-05-15 20:08:37 +00001000 bool res;
1001 struct sudoku_state_t new_state;
Dave Chapman0f619c62006-04-01 18:38:34 +00001002
Dave Chapman506bac92006-05-15 20:08:37 +00001003 clear_state(&new_state);
1004 display_board(&new_state);
Jens Arnold4d6374c2007-03-16 21:56:08 +00001005 rb->splash(0, "Generating...");
Dave Chapman0f619c62006-04-01 18:38:34 +00001006
Dave Chapman65293be2006-04-09 14:20:14 +00001007#ifdef HAVE_ADJUSTABLE_CPU_FREQ
Christian Gmeinerf03e0532006-04-09 13:47:28 +00001008 rb->cpu_boost(true);
1009#endif
Dave Chapman65293be2006-04-09 14:20:14 +00001010
Dave Chapman506bac92006-05-15 20:08:37 +00001011 res = sudoku_generate_board(&new_state,&difficulty);
Dave Chapman65293be2006-04-09 14:20:14 +00001012
1013#ifdef HAVE_ADJUSTABLE_CPU_FREQ
Christian Gmeinerf03e0532006-04-09 13:47:28 +00001014 rb->cpu_boost(false);
1015#endif
Dave Chapman0f619c62006-04-01 18:38:34 +00001016
Dave Chapman506bac92006-05-15 20:08:37 +00001017 if (res) {
1018 rb->memcpy(state,&new_state,sizeof(new_state));
1019 rb->snprintf(str,sizeof(str),"Difficulty: %s",difficulty);
1020 display_board(state);
Jens Arnold4d6374c2007-03-16 21:56:08 +00001021 rb->splash(HZ*3, str);
Dave Chapman506bac92006-05-15 20:08:37 +00001022 rb->strncpy(state->filename,GAME_FILE,MAX_PATH);
1023 } else {
1024 display_board(&new_state);
Jens Arnold4d6374c2007-03-16 21:56:08 +00001025 rb->splash(HZ*2, "Aborted");
Dave Chapman506bac92006-05-15 20:08:37 +00001026 }
1027 return res;
Dave Chapman0f619c62006-04-01 18:38:34 +00001028}
1029
Jens Arnold65b4aae2007-09-16 18:46:39 +00001030#ifdef HAVE_LCD_COLOR
1031static bool numdisplay_setting(void)
1032{
1033 static const struct opt_items names[] = {
1034 {"Black", -1},
1035 {"Coloured", -1},
1036 };
1037
1038 return rb->set_option("Number Display", &sudcfg.number_display, INT, names,
1039 sizeof(names) / sizeof(names[0]), NULL);
1040}
1041#endif
1042
1043enum {
1044 SM_AUDIO_PLAYBACK = 0,
1045#ifdef HAVE_LCD_COLOR
1046 SM_NUMBER_DISPLAY,
1047#endif
1048 SM_SAVE,
1049 SM_RELOAD,
1050 SM_CLEAR,
1051 SM_SOLVE,
1052 SM_GENERATE,
1053 SM_NEW,
1054 SM_QUIT,
1055};
1056
Dave Chapman6afb0172005-09-22 08:53:04 +00001057bool sudoku_menu(struct sudoku_state_t* state)
1058{
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001059 int m;
1060 int result;
Dave Chapman6afb0172005-09-22 08:53:04 +00001061
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001062 static const struct menu_item items[] = {
Jens Arnold65b4aae2007-09-16 18:46:39 +00001063 [SM_AUDIO_PLAYBACK] = { "Audio Playback", NULL },
1064#ifdef HAVE_LCD_COLOR
1065 [SM_NUMBER_DISPLAY] = { "Number Display", NULL },
1066#endif
1067 [SM_SAVE] = { "Save", NULL },
1068 [SM_RELOAD] = { "Reload", NULL },
1069 [SM_CLEAR] = { "Clear", NULL },
1070 [SM_SOLVE] = { "Solve", NULL },
1071 [SM_GENERATE] = { "Generate", NULL },
1072 [SM_NEW] = { "New", NULL },
1073 [SM_QUIT] = { "Quit", NULL },
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001074 };
1075
Jonathan Gordon77a458a2007-05-08 11:55:43 +00001076 m = menu_init(rb,items, sizeof(items) / sizeof(*items),
Shachar Liberman0ed49042006-08-12 13:43:20 +00001077 NULL, NULL, NULL, NULL);
Dave Chapman6afb0172005-09-22 08:53:04 +00001078
Jonathan Gordon77a458a2007-05-08 11:55:43 +00001079 result=menu_show(m);
Dave Chapman6afb0172005-09-22 08:53:04 +00001080
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001081 switch (result) {
Jens Arnold65b4aae2007-09-16 18:46:39 +00001082 case SM_AUDIO_PLAYBACK:
Jonathan Gordon33b785e2008-04-23 10:28:34 +00001083 playback_control(rb, NULL);
Dave Chapmanbf999522006-04-01 23:23:07 +00001084 break;
1085
Jens Arnold65b4aae2007-09-16 18:46:39 +00001086#ifdef HAVE_LCD_COLOR
1087 case SM_NUMBER_DISPLAY:
1088 numdisplay_setting();
1089 break;
1090#endif
1091 case SM_SAVE:
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001092 save_sudoku(state);
1093 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001094
Jens Arnold65b4aae2007-09-16 18:46:39 +00001095 case SM_RELOAD:
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001096 restore_state(state);
1097 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001098
Jens Arnold65b4aae2007-09-16 18:46:39 +00001099 case SM_CLEAR:
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001100 clear_board(state);
1101 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001102
Jens Arnold65b4aae2007-09-16 18:46:39 +00001103 case SM_SOLVE:
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001104 sudoku_solve(state);
1105 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001106
Jens Arnold65b4aae2007-09-16 18:46:39 +00001107 case SM_GENERATE:
Dave Chapman0f619c62006-04-01 18:38:34 +00001108 sudoku_generate(state);
1109 break;
1110
Jens Arnold65b4aae2007-09-16 18:46:39 +00001111 case SM_NEW:
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001112 clear_state(state);
1113 state->editmode=1;
1114 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001115
Jens Arnold65b4aae2007-09-16 18:46:39 +00001116 case SM_QUIT:
Dave Chapman0f619c62006-04-01 18:38:34 +00001117 save_sudoku(state);
Jonathan Gordon77a458a2007-05-08 11:55:43 +00001118 menu_exit(m);
Dave Chapman0f619c62006-04-01 18:38:34 +00001119 return true;
1120 break;
1121
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001122 default:
1123 break;
1124 }
Dave Chapman33e935c2005-10-04 23:36:03 +00001125
Jonathan Gordon77a458a2007-05-08 11:55:43 +00001126 menu_exit(m);
Dave Chapman6afb0172005-09-22 08:53:04 +00001127
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001128 return (result==MENU_ATTACHED_USB);
Dave Chapman6afb0172005-09-22 08:53:04 +00001129}
1130
Dave Chapman506bac92006-05-15 20:08:37 +00001131/* Menu used when user is in edit mode - i.e. creating a new game manually */
1132int sudoku_edit_menu(struct sudoku_state_t* state)
1133{
1134 int m;
1135 int result;
1136
1137 static const struct menu_item items[] = {
1138 { "Save as", NULL },
1139 { "Quit", NULL },
1140 };
1141
Jonathan Gordon77a458a2007-05-08 11:55:43 +00001142 m = menu_init(rb,items, sizeof(items) / sizeof(*items),
Shachar Liberman0ed49042006-08-12 13:43:20 +00001143 NULL, NULL, NULL, NULL);
Dave Chapman506bac92006-05-15 20:08:37 +00001144
Jonathan Gordon77a458a2007-05-08 11:55:43 +00001145 result=menu_show(m);
Dave Chapman506bac92006-05-15 20:08:37 +00001146
1147 switch (result) {
1148 case 0: /* Save new game */
1149 rb->kbd_input(state->filename,MAX_PATH);
1150 if (save_sudoku(state)) {
1151 state->editmode=0;
1152 } else {
Jens Arnold4d6374c2007-03-16 21:56:08 +00001153 rb->splash(HZ*2, "Save failed");
Dave Chapman506bac92006-05-15 20:08:37 +00001154 }
1155 break;
1156
1157 case 1: /* Quit */
1158 break;
1159
1160 default:
1161 break;
1162 }
1163
Jonathan Gordon77a458a2007-05-08 11:55:43 +00001164 menu_exit(m);
Dave Chapman506bac92006-05-15 20:08:37 +00001165
1166 return result;
1167}
1168
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001169void move_cursor(struct sudoku_state_t* state, int newx, int newy)
1170{
1171 int oldx, oldy;
Dave Chapman6afb0172005-09-22 08:53:04 +00001172
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001173 /* Check that the character at the cursor position is legal */
1174 if (check_status(state)) {
Jens Arnold4d6374c2007-03-16 21:56:08 +00001175 rb->splash(HZ*2, "Illegal move!");
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001176 /* Ignore any button presses during the splash */
1177 rb->button_clear_queue();
1178 return;
1179 }
Dave Chapman6afb0172005-09-22 08:53:04 +00001180
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001181 /* Move Cursor */
1182 oldx=state->x;
1183 oldy=state->y;
1184 state->x=newx;
1185 state->y=newy;
Dave Chapman6afb0172005-09-22 08:53:04 +00001186
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001187 /* Redraw current and old cells */
1188 update_cell(state,oldx,oldy);
1189 update_cell(state,newx,newy);
Dave Chapman6afb0172005-09-22 08:53:04 +00001190}
1191
1192/* plugin entry point */
Steve Bavin65265772008-05-13 09:57:56 +00001193enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
Dave Chapman6afb0172005-09-22 08:53:04 +00001194{
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001195 bool exit;
1196 int button;
1197 int lastbutton = BUTTON_NONE;
Dave Chapman506bac92006-05-15 20:08:37 +00001198 int res;
Jens Arnold65b4aae2007-09-16 18:46:39 +00001199 int rc = PLUGIN_OK;
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001200 long ticks;
1201 struct sudoku_state_t state;
Dave Chapman6afb0172005-09-22 08:53:04 +00001202
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001203 /* plugin init */
1204 rb = api;
1205 /* end of plugin init */
Jens Arnold65b4aae2007-09-16 18:46:39 +00001206
1207#ifdef HAVE_LCD_COLOR
1208 configfile_init(rb);
1209 configfile_load(cfg_filename, disk_config,
1210 sizeof(disk_config) / sizeof(disk_config[0]),
1211 CFGFILE_MINVERSION);
1212 rb->memcpy(&sudcfg, &sudcfg_disk, sizeof(sudcfg)); /* copy to running config */
1213#endif
Karl Kurbjun1a9442c2006-11-15 06:46:35 +00001214
1215#if LCD_DEPTH > 1
Karl Kurbjund6b0c972006-11-15 06:14:27 +00001216 rb->lcd_set_backdrop(NULL);
Jonathan Gordoncf887d62006-12-18 02:33:39 +00001217 rb->lcd_set_foreground(LCD_BLACK);
1218 rb->lcd_set_background(LCD_WHITE);
Karl Kurbjun1a9442c2006-11-15 06:46:35 +00001219#endif
Dave Chapman6afb0172005-09-22 08:53:04 +00001220
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001221 clear_state(&state);
Dave Chapman33e935c2005-10-04 23:36:03 +00001222
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001223 if (parameter==NULL) {
Dave Chapman0f619c62006-04-01 18:38:34 +00001224 /* We have been started as a plugin - try default sudoku.ss */
1225 if (!load_sudoku(&state,GAME_FILE)) {
Dave Chapman506bac92006-05-15 20:08:37 +00001226 /* No previous game saved, use the default */
1227 default_state(&state);
Dave Chapman0f619c62006-04-01 18:38:34 +00001228 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001229 } else {
1230 if (!load_sudoku(&state,(char*)parameter)) {
Jens Arnold4d6374c2007-03-16 21:56:08 +00001231 rb->splash(HZ*2, "Load error");
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001232 return(PLUGIN_ERROR);
1233 }
Dave Chapman6afb0172005-09-22 08:53:04 +00001234 }
Dave Chapman6afb0172005-09-22 08:53:04 +00001235
Jonathan Gordoncf887d62006-12-18 02:33:39 +00001236
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001237 display_board(&state);
Dave Chapman6afb0172005-09-22 08:53:04 +00001238
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001239 /* The main game loop */
1240 exit=false;
1241 ticks=0;
1242 while(!exit) {
1243 button = rb->button_get(true);
Dave Chapman6afb0172005-09-22 08:53:04 +00001244
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001245 switch(button){
Dave Chapmana698c3e2006-04-02 00:09:33 +00001246#ifdef SUDOKU_BUTTON_QUIT
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001247 /* Exit game */
1248 case SUDOKU_BUTTON_QUIT:
Dave Chapman506bac92006-05-15 20:08:37 +00001249 if (check_status(&state)) {
Jens Arnold4d6374c2007-03-16 21:56:08 +00001250 rb->splash(HZ*2, "Illegal move!");
Dave Chapman506bac92006-05-15 20:08:37 +00001251 /* Ignore any button presses during the splash */
1252 rb->button_clear_queue();
1253 } else {
1254 save_sudoku(&state);
Jens Arnold65b4aae2007-09-16 18:46:39 +00001255 exit=true;
Dave Chapman506bac92006-05-15 20:08:37 +00001256 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001257 break;
Dave Chapmana698c3e2006-04-02 00:09:33 +00001258#endif
Dave Chapman6afb0172005-09-22 08:53:04 +00001259
1260 /* Increment digit */
Dave Chapman567718d2005-09-22 20:17:21 +00001261#ifdef SUDOKU_BUTTON_ALTTOGGLE
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001262 case SUDOKU_BUTTON_ALTTOGGLE | BUTTON_REPEAT:
Dave Chapman567718d2005-09-22 20:17:21 +00001263#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001264 case SUDOKU_BUTTON_TOGGLE | BUTTON_REPEAT:
1265 /* Slow down the repeat speed to 1/3 second */
1266 if ((*rb->current_tick-ticks) < (HZ/3)) {
1267 break;
1268 }
Dave Chapman6afb0172005-09-22 08:53:04 +00001269
Dave Chapman567718d2005-09-22 20:17:21 +00001270#ifdef SUDOKU_BUTTON_ALTTOGGLE
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001271 case SUDOKU_BUTTON_ALTTOGGLE:
Dave Chapman567718d2005-09-22 20:17:21 +00001272#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001273 case SUDOKU_BUTTON_TOGGLE:
Jens Arnolde85fe092005-09-22 21:00:03 +00001274#ifdef SUDOKU_BUTTON_TOGGLE_PRE
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001275 if ((button == SUDOKU_BUTTON_TOGGLE)
1276 && (lastbutton != SUDOKU_BUTTON_TOGGLE_PRE))
1277 break;
Jens Arnolde85fe092005-09-22 21:00:03 +00001278#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001279 /* Increment digit */
1280 ticks=*rb->current_tick;
1281 if (state.editmode) {
1282 if (state.startboard[state.y][state.x]=='9') {
1283 state.startboard[state.y][state.x]='0';
1284 state.currentboard[state.y][state.x]='0';
1285 } else {
1286 state.startboard[state.y][state.x]++;
1287 state.currentboard[state.y][state.x]++;
1288 }
1289 } else {
1290 if (state.startboard[state.y][state.x]=='0') {
1291 if (state.currentboard[state.y][state.x]=='9') {
1292 state.currentboard[state.y][state.x]='0';
1293 } else {
Dave Chapman506bac92006-05-15 20:08:37 +00001294 state.currentboard[state.y][state.x]++;
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001295 }
1296 }
1297 }
1298 update_cell(&state,state.y,state.x);
1299 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001300
Dave Chapmana698c3e2006-04-02 00:09:33 +00001301#ifdef SUDOKU_BUTTON_TOGGLEBACK
1302 case SUDOKU_BUTTON_TOGGLEBACK | BUTTON_REPEAT:
1303 /* Slow down the repeat speed to 1/3 second */
1304 if ((*rb->current_tick-ticks) < (HZ/3)) {
1305 break;
1306 }
1307
1308 case SUDOKU_BUTTON_TOGGLEBACK:
1309 /* Decrement digit */
1310 ticks=*rb->current_tick;
1311 if (state.editmode) {
1312 if (state.startboard[state.y][state.x]=='0') {
1313 state.startboard[state.y][state.x]='9';
1314 state.currentboard[state.y][state.x]='9';
1315 } else {
1316 state.startboard[state.y][state.x]--;
1317 state.currentboard[state.y][state.x]--;
1318 }
1319 } else {
1320 if (state.startboard[state.y][state.x]=='0') {
1321 if (state.currentboard[state.y][state.x]=='0') {
1322 state.currentboard[state.y][state.x]='9';
1323 } else {
1324 state.currentboard[state.y][state.x]--;
1325 }
1326 }
1327 }
1328 update_cell(&state,state.y,state.x);
1329 break;
1330#endif
1331
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001332 /* move cursor left */
Dave Chapmana698c3e2006-04-02 00:09:33 +00001333 case SUDOKU_BUTTON_LEFT:
1334 case (SUDOKU_BUTTON_LEFT | BUTTON_REPEAT):
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001335 if (state.x==0) {
Dave Chapmana698c3e2006-04-02 00:09:33 +00001336#ifndef SUDOKU_BUTTON_UP
1337 if (state.y==0) {
1338 move_cursor(&state,8,8);
1339 } else {
1340 move_cursor(&state,8,state.y-1);
1341 }
1342#else
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001343 move_cursor(&state,8,state.y);
Dave Chapmana698c3e2006-04-02 00:09:33 +00001344#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001345 } else {
1346 move_cursor(&state,state.x-1,state.y);
1347 }
1348 break;
1349
1350 /* move cursor right */
Dave Chapmana698c3e2006-04-02 00:09:33 +00001351 case SUDOKU_BUTTON_RIGHT:
1352 case (SUDOKU_BUTTON_RIGHT | BUTTON_REPEAT):
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001353 if (state.x==8) {
Dave Chapmana698c3e2006-04-02 00:09:33 +00001354#ifndef SUDOKU_BUTTON_DOWN
1355 if (state.y==8) {
1356 move_cursor(&state,0,0);
1357 } else {
1358 move_cursor(&state,0,state.y+1);
1359 }
1360#else
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001361 move_cursor(&state,0,state.y);
Dave Chapmana698c3e2006-04-02 00:09:33 +00001362#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001363 } else {
1364 move_cursor(&state,state.x+1,state.y);
1365 }
1366 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001367
Dave Chapmana698c3e2006-04-02 00:09:33 +00001368#ifdef SUDOKU_BUTTON_UP
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001369 /* move cursor up */
1370 case SUDOKU_BUTTON_UP:
1371 case (SUDOKU_BUTTON_UP | BUTTON_REPEAT):
1372 if (state.y==0) {
1373 move_cursor(&state,state.x,8);
1374 } else {
1375 move_cursor(&state,state.x,state.y-1);
1376 }
1377 break;
Dave Chapmana698c3e2006-04-02 00:09:33 +00001378#endif
Dave Chapman6afb0172005-09-22 08:53:04 +00001379
Dave Chapmana698c3e2006-04-02 00:09:33 +00001380#ifdef SUDOKU_BUTTON_DOWN
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001381 /* move cursor down */
1382 case SUDOKU_BUTTON_DOWN:
1383 case (SUDOKU_BUTTON_DOWN | BUTTON_REPEAT):
1384 if (state.y==8) {
1385 move_cursor(&state,state.x,0);
1386 } else {
1387 move_cursor(&state,state.x,state.y+1);
1388 }
1389 break;
Dave Chapmana698c3e2006-04-02 00:09:33 +00001390#endif
Dave Chapman6afb0172005-09-22 08:53:04 +00001391
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001392 case SUDOKU_BUTTON_MENU:
Jens Arnolde85fe092005-09-22 21:00:03 +00001393#ifdef SUDOKU_BUTTON_MENU_PRE
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001394 if (lastbutton != SUDOKU_BUTTON_MENU_PRE)
1395 break;
Jens Arnolde85fe092005-09-22 21:00:03 +00001396#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001397 /* Don't let the user leave a game in a bad state */
1398 if (check_status(&state)) {
Jens Arnold4d6374c2007-03-16 21:56:08 +00001399 rb->splash(HZ*2, "Illegal move!");
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001400 /* Ignore any button presses during the splash */
1401 rb->button_clear_queue();
1402 } else {
1403 if (state.editmode) {
Dave Chapman506bac92006-05-15 20:08:37 +00001404 res = sudoku_edit_menu(&state);
1405 if (res == MENU_ATTACHED_USB) {
Jens Arnold65b4aae2007-09-16 18:46:39 +00001406 rc = PLUGIN_USB_CONNECTED;
1407 exit = true;
Dave Chapman506bac92006-05-15 20:08:37 +00001408 } else if (res == 1) { /* Quit */
Jens Arnold65b4aae2007-09-16 18:46:39 +00001409 exit = true;
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001410 }
1411 } else {
1412 if (sudoku_menu(&state)) {
Jens Arnold65b4aae2007-09-16 18:46:39 +00001413 rc = PLUGIN_USB_CONNECTED;
1414 exit = true;
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001415 }
1416 }
1417 }
1418 break;
Dave Chapman61eac112005-11-29 00:02:00 +00001419#ifdef SUDOKU_BUTTON_POSSIBLE
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001420 case SUDOKU_BUTTON_POSSIBLE:
1421 /* Toggle current number in the possiblevals structure */
1422 if (state.currentboard[state.y][state.x]!='0') {
1423 state.possiblevals[state.y][state.x]^=
1424 (1 << (state.currentboard[state.y][state.x] - '0'));
1425 }
1426 break;
Dave Chapman61eac112005-11-29 00:02:00 +00001427#endif
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001428 default:
1429 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
1430 /* Quit if USB has been connected */
Jens Arnold65b4aae2007-09-16 18:46:39 +00001431 rc = PLUGIN_USB_CONNECTED;
1432 exit = true;
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001433 }
1434 break;
Dave Chapman6afb0172005-09-22 08:53:04 +00001435 }
Daniel Stenberg220fafd2006-03-03 08:14:44 +00001436 if (button != BUTTON_NONE)
1437 lastbutton = button;
1438
1439 display_board(&state);
Dave Chapman6afb0172005-09-22 08:53:04 +00001440 }
Jens Arnold65b4aae2007-09-16 18:46:39 +00001441#ifdef HAVE_LCD_COLOR
1442 if (rb->memcmp(&sudcfg, &sudcfg_disk, sizeof(sudcfg))) /* save settings if changed */
1443 {
1444 rb->memcpy(&sudcfg_disk, &sudcfg, sizeof(sudcfg));
1445 configfile_save(cfg_filename, disk_config,
1446 sizeof(disk_config) / sizeof(disk_config[0]),
1447 CFGFILE_VERSION);
1448 }
1449#endif
1450 return rc;
Dave Chapman6afb0172005-09-22 08:53:04 +00001451}
1452
1453#endif