Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / apps / plugins / minesweeper.c
blob16cc0fcd8724d511f1d3f3670cb767cf963efd52
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004-2006 Antoine Cellerier <dionoea -at- videolan -dot- org>
12 * 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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
24 #ifdef HAVE_LCD_BITMAP
26 PLUGIN_HEADER
28 /* what the minesweeper() function can return */
29 enum minesweeper_status {
30 MINESWEEPER_WIN,
31 MINESWEEPER_LOSE,
32 MINESWEEPER_QUIT,
33 MINESWEEPER_USB
36 /* variable button definitions */
37 #if CONFIG_KEYPAD == RECORDER_PAD
38 # define MINESWP_LEFT BUTTON_LEFT
39 # define MINESWP_RIGHT BUTTON_RIGHT
40 # define MINESWP_UP BUTTON_UP
41 # define MINESWP_DOWN BUTTON_DOWN
42 # define MINESWP_QUIT BUTTON_OFF
43 # define MINESWP_TOGGLE BUTTON_ON
44 # define MINESWP_TOGGLE2 BUTTON_F1
45 # define MINESWP_DISCOVER BUTTON_PLAY
46 # define MINESWP_DISCOVER2 BUTTON_F2
47 # define MINESWP_INFO BUTTON_F3
49 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
50 # define MINESWP_LEFT BUTTON_LEFT
51 # define MINESWP_RIGHT BUTTON_RIGHT
52 # define MINESWP_UP BUTTON_UP
53 # define MINESWP_DOWN BUTTON_DOWN
54 # define MINESWP_QUIT BUTTON_OFF
55 # define MINESWP_TOGGLE BUTTON_ON
56 # define MINESWP_TOGGLE2 BUTTON_F1
57 # define MINESWP_DISCOVER BUTTON_SELECT
58 # define MINESWP_DISCOVER2 BUTTON_F2
59 # define MINESWP_INFO BUTTON_F3
61 #elif CONFIG_KEYPAD == ONDIO_PAD
62 # define MINESWP_LEFT BUTTON_LEFT
63 # define MINESWP_RIGHT BUTTON_RIGHT
64 # define MINESWP_UP BUTTON_UP
65 # define MINESWP_DOWN BUTTON_DOWN
66 # define MINESWP_QUIT BUTTON_OFF
67 # define MINESWP_TOGGLE_PRE BUTTON_MENU
68 # define MINESWP_TOGGLE (BUTTON_MENU | BUTTON_REL)
69 # define MINESWP_DISCOVER (BUTTON_MENU | BUTTON_REPEAT)
70 # define MINESWP_INFO (BUTTON_MENU | BUTTON_OFF)
72 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
73 (CONFIG_KEYPAD == IRIVER_H300_PAD)
74 # define MINESWP_LEFT BUTTON_LEFT
75 # define MINESWP_RIGHT BUTTON_RIGHT
76 # define MINESWP_UP BUTTON_UP
77 # define MINESWP_DOWN BUTTON_DOWN
78 # define MINESWP_QUIT BUTTON_OFF
79 # define MINESWP_TOGGLE BUTTON_ON
80 # define MINESWP_TOGGLE2 BUTTON_REC
81 # define MINESWP_DISCOVER BUTTON_SELECT
82 # define MINESWP_INFO BUTTON_MODE
84 # define MINESWP_RC_QUIT BUTTON_RC_STOP
86 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
87 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
88 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
89 # define MINESWP_SCROLLWHEEL
90 # define MINESWP_LEFT BUTTON_LEFT
91 # define MINESWP_RIGHT BUTTON_RIGHT
92 # define MINESWP_UP BUTTON_MENU
93 # define MINESWP_DOWN BUTTON_PLAY
94 # define MINESWP_NEXT BUTTON_SCROLL_FWD
95 # define MINESWP_PREV BUTTON_SCROLL_BACK
96 # define MINESWP_QUIT (BUTTON_SELECT | BUTTON_MENU)
97 # define MINESWP_TOGGLE_PRE BUTTON_SELECT
98 # define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
99 # define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
100 # define MINESWP_INFO (BUTTON_SELECT | BUTTON_PLAY)
102 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
103 # define MINESWP_LEFT BUTTON_LEFT
104 # define MINESWP_RIGHT BUTTON_RIGHT
105 # define MINESWP_UP BUTTON_UP
106 # define MINESWP_DOWN BUTTON_DOWN
107 # define MINESWP_QUIT BUTTON_POWER
108 # define MINESWP_TOGGLE BUTTON_PLAY
109 # define MINESWP_DISCOVER BUTTON_SELECT
110 # define MINESWP_INFO BUTTON_REC
112 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
113 # define MINESWP_LEFT BUTTON_LEFT
114 # define MINESWP_RIGHT BUTTON_RIGHT
115 # define MINESWP_UP BUTTON_UP
116 # define MINESWP_DOWN BUTTON_DOWN
117 # define MINESWP_QUIT BUTTON_POWER
118 # define MINESWP_TOGGLE BUTTON_A
119 # define MINESWP_DISCOVER BUTTON_SELECT
120 # define MINESWP_INFO BUTTON_MENU
122 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
123 # define MINESWP_SCROLLWHEEL
124 # define MINESWP_LEFT BUTTON_LEFT
125 # define MINESWP_RIGHT BUTTON_RIGHT
126 # define MINESWP_UP BUTTON_UP
127 # define MINESWP_DOWN BUTTON_DOWN
128 # define MINESWP_QUIT BUTTON_POWER
129 # define MINESWP_NEXT BUTTON_SCROLL_FWD
130 # define MINESWP_PREV BUTTON_SCROLL_BACK
131 # define MINESWP_TOGGLE BUTTON_REC
132 # define MINESWP_DISCOVER BUTTON_SELECT
133 # define MINESWP_INFO (BUTTON_REC|BUTTON_REPEAT)
135 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
136 # define MINESWP_LEFT BUTTON_LEFT
137 # define MINESWP_RIGHT BUTTON_RIGHT
138 # define MINESWP_UP BUTTON_UP
139 # define MINESWP_DOWN BUTTON_DOWN
140 # define MINESWP_QUIT BUTTON_POWER
141 # define MINESWP_TOGGLE_PRE BUTTON_SELECT
142 # define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
143 # define MINESWP_TOGGLE2 BUTTON_VOL_DOWN
144 # define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
145 # define MINESWP_DISCOVER2 BUTTON_VOL_UP
146 # define MINESWP_INFO BUTTON_REC
148 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
149 # define MINESWP_LEFT BUTTON_LEFT
150 # define MINESWP_RIGHT BUTTON_RIGHT
151 # define MINESWP_UP BUTTON_SCROLL_UP
152 # define MINESWP_DOWN BUTTON_SCROLL_DOWN
153 # define MINESWP_QUIT BUTTON_POWER
154 # define MINESWP_TOGGLE BUTTON_PLAY
155 # define MINESWP_DISCOVER BUTTON_REW
156 # define MINESWP_INFO (BUTTON_REW | BUTTON_PLAY)
158 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
159 # define MINESWP_LEFT BUTTON_LEFT
160 # define MINESWP_RIGHT BUTTON_RIGHT
161 # define MINESWP_UP BUTTON_UP
162 # define MINESWP_DOWN BUTTON_DOWN
163 # define MINESWP_QUIT BUTTON_BACK
164 # define MINESWP_TOGGLE BUTTON_PLAY
165 # define MINESWP_DISCOVER BUTTON_SELECT
166 # define MINESWP_INFO BUTTON_MENU
168 #elif (CONFIG_KEYPAD == MROBE100_PAD)
169 # define MINESWP_LEFT BUTTON_LEFT
170 # define MINESWP_RIGHT BUTTON_RIGHT
171 # define MINESWP_UP BUTTON_UP
172 # define MINESWP_DOWN BUTTON_DOWN
173 # define MINESWP_QUIT BUTTON_POWER
174 # define MINESWP_TOGGLE BUTTON_DISPLAY
175 # define MINESWP_DISCOVER BUTTON_SELECT
176 # define MINESWP_INFO BUTTON_MENU
178 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
179 # define MINESWP_LEFT BUTTON_RC_REW
180 # define MINESWP_RIGHT BUTTON_RC_FF
181 # define MINESWP_UP BUTTON_RC_VOL_UP
182 # define MINESWP_DOWN BUTTON_RC_VOL_DOWN
183 # define MINESWP_QUIT BUTTON_RC_REC
184 # define MINESWP_TOGGLE BUTTON_RC_MODE
185 # define MINESWP_DISCOVER BUTTON_RC_PLAY
186 # define MINESWP_INFO BUTTON_RC_MENU
188 #elif (CONFIG_KEYPAD == COWOND2_PAD)
189 # define MINESWP_QUIT BUTTON_POWER
191 #else
192 #error No keymap defined!
193 #endif
195 #ifdef HAVE_TOUCHPAD
196 #ifndef MINESWP_QUIT
197 # define MINESWP_QUIT BUTTON_TOPLEFT
198 #endif
199 #ifndef MINESWP_LEFT
200 # define MINESWP_LEFT BUTTON_MIDLEFT
201 #endif
202 #ifndef MINESWP_RIGHT
203 # define MINESWP_RIGHT BUTTON_MIDRIGHT
204 #endif
205 #ifndef MINESWP_UP
206 # define MINESWP_UP BUTTON_TOPMIDDLE
207 #endif
208 #ifndef MINESWP_DOWN
209 # define MINESWP_DOWN BUTTON_BOTTOMMIDDLE
210 #endif
211 #ifndef MINESWP_TOGGLE
212 # define MINESWP_TOGGLE BUTTON_CENTER
213 #endif
214 #ifndef MINESWP_DISCOVER
215 # define MINESWP_DISCOVER BUTTON_BOTTOMLEFT
216 #endif
217 #ifndef MINESWP_INFO
218 # define MINESWP_INFO BUTTON_BOTTOMRIGHT
219 #endif
220 #endif
222 /* here is a global api struct pointer. while not strictly necessary,
223 * it's nice not to have to pass the api pointer in all function calls
224 * in the plugin
226 static const struct plugin_api *rb;
228 extern const fb_data minesweeper_tiles[];
230 #ifdef HAVE_LCD_COLOR
231 # if ( LCD_HEIGHT * LCD_WIDTH ) / ( 16 * 16 ) >= 130
232 /* We want to have at least 130 tiles on the screen */
233 # define TileSize 16
234 # elif ( LCD_HEIGHT * LCD_WIDTH ) / ( 12 * 12 ) >= 130
235 # define TileSize 12
236 # else
237 # define TileSize 10
238 # endif
239 # define BackgroundColor LCD_RGBPACK( 128, 128, 128 )
240 #elif LCD_DEPTH > 1
241 # define TileSize 12
242 #else
243 # define TileSize 8
244 #endif
246 #define Mine 9
247 #define Flag 10
248 #define Unknown 11
249 #define ExplodedMine 12
251 #define draw_tile( num, x, y ) \
252 rb->lcd_bitmap_part( minesweeper_tiles, 0, num * TileSize, \
253 TileSize, left+x*TileSize, top+y*TileSize, \
254 TileSize, TileSize )
256 #define invert_tile( x, y ) \
257 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); \
258 rb->lcd_fillrect( left+x*TileSize, top+y*TileSize, TileSize, TileSize ); \
259 rb->lcd_set_drawmode(DRMODE_SOLID);
262 /* the tile struct
263 * if there is a mine, mine is true
264 * if tile is known by player, known is true
265 * if tile has a flag, flag is true
266 * neighbors is the total number of mines arround tile
268 typedef struct tile
270 unsigned char mine : 1;
271 unsigned char known : 1;
272 unsigned char flag : 1;
273 unsigned char neighbors : 4;
274 } tile;
276 /* the height and width of the field */
277 #define MAX_HEIGHT (LCD_HEIGHT/TileSize)
278 #define MAX_WIDTH (LCD_WIDTH/TileSize)
279 int height = MAX_HEIGHT;
280 int width = MAX_WIDTH;
281 int top;
282 int left;
284 /* The Minefield. Caution it is defined as Y, X! Not the opposite. */
285 tile minefield[MAX_HEIGHT][MAX_WIDTH];
287 /* total number of mines on the game */
288 int mine_num = 0;
290 /* percentage of mines on minefield used during generation */
291 int p = 16;
293 /* number of tiles left on the game */
294 int tiles_left;
296 /* number of used flags on the game */
297 int flags_used;
299 /* Because mines are set after the first move... */
300 bool no_mines = true;
302 /* We need a stack (created on discover()) for the cascade algorithm. */
303 int stack_pos = 0;
305 /* a usefull string for snprintf */
306 char str[30];
308 #ifdef HAVE_TOUCHPAD
310 #include "lib/touchscreen.h"
311 static struct ts_raster mine_raster = { 0, 0, MAX_WIDTH, MAX_HEIGHT, TileSize, TileSize };
312 #endif
315 void push( int *stack, int y, int x )
317 if( stack_pos <= height*width )
319 stack[++stack_pos] = y;
320 stack[++stack_pos] = x;
324 /* Unveil tiles and push them to stack if they are empty. */
325 void unveil( int *stack, int y, int x )
327 if( x < 0 || y < 0 || x > width - 1 || y > height - 1
328 || minefield[y][x].known
329 || minefield[y][x].mine || minefield[y][x].flag ) return;
331 minefield[y][x].known = 1;
333 if( minefield[y][x].neighbors == 0 )
334 push( stack, y, x );
337 void discover( int y, int x )
339 int stack[height*width];
341 /* Selected tile. */
342 if( x < 0 || y < 0 || x > width - 1 || y > height - 1
343 || minefield[y][x].known
344 || minefield[y][x].mine || minefield[y][x].flag ) return;
346 minefield[y][x].known = 1;
347 /* Exit if the tile is not empty. (no mines nearby) */
348 if( minefield[y][x].neighbors ) return;
350 push( stack, y, x );
352 /* Scan all nearby tiles. If we meet a tile with a number we just unveil
353 * it. If we meet an empty tile, we push the location in stack. For each
354 * location in stack we do the same thing. (scan again all nearby tiles)
356 while( stack_pos )
358 /* Pop x, y from stack. */
359 x = stack[stack_pos--];
360 y = stack[stack_pos--];
362 unveil( stack, y-1, x-1 );
363 unveil( stack, y-1, x );
364 unveil( stack, y-1, x+1 );
365 unveil( stack, y, x+1 );
366 unveil( stack, y+1, x+1 );
367 unveil( stack, y+1, x );
368 unveil( stack, y+1, x-1 );
369 unveil( stack, y, x-1 );
373 /* Reset the whole board for a new game. */
374 void minesweeper_init( void )
376 int i,j;
378 for( i = 0; i < MAX_HEIGHT; i++ )
380 for( j = 0; j < MAX_WIDTH; j++ )
382 minefield[i][j].known = 0;
383 minefield[i][j].flag = 0;
384 minefield[i][j].mine = 0;
385 minefield[i][j].neighbors = 0;
388 no_mines = true;
389 tiles_left = width*height;
393 /* put mines on the mine field */
394 /* there is p% chance that a tile is a mine */
395 /* if the tile has coordinates (x,y), then it can't be a mine */
396 void minesweeper_putmines( int p, int x, int y )
398 int i,j;
400 mine_num = 0;
401 for( i = 0; i < height; i++ )
403 for( j = 0; j < width; j++ )
405 if( rb->rand()%100 < p && !( y==i && x==j ) )
407 minefield[i][j].mine = 1;
408 mine_num++;
410 else
412 minefield[i][j].mine = 0;
414 minefield[i][j].neighbors = 0;
418 /* we need to compute the neighbor element for each tile */
419 for( i = 0; i < height; i++ )
421 for( j = 0; j < width; j++ )
423 if( i > 0 )
425 if( j > 0 )
426 minefield[i][j].neighbors += minefield[i-1][j-1].mine;
427 minefield[i][j].neighbors += minefield[i-1][j].mine;
428 if( j < width - 1 )
429 minefield[i][j].neighbors += minefield[i-1][j+1].mine;
431 if( j > 0 )
432 minefield[i][j].neighbors += minefield[i][j-1].mine;
433 if( j < width - 1 )
434 minefield[i][j].neighbors += minefield[i][j+1].mine;
435 if( i < height - 1 )
437 if( j > 0 )
438 minefield[i][j].neighbors += minefield[i+1][j-1].mine;
439 minefield[i][j].neighbors += minefield[i+1][j].mine;
440 if( j < width - 1 )
441 minefield[i][j].neighbors += minefield[i+1][j+1].mine;
446 no_mines = false;
448 /* In case the user is lucky and there are no mines positioned. */
449 if( !mine_num && height*width != 1 )
451 minesweeper_putmines(p, x, y);
455 /* A function that will uncover all the board, when the user wins or loses.
456 can easily be expanded, (just a call assigned to a button) as a solver. */
457 void mine_show( void )
459 int i, j, button;
461 for( i = 0; i < height; i++ )
463 for( j = 0; j < width; j++ )
465 if( minefield[i][j].mine )
467 if( minefield[i][j].known )
469 draw_tile( ExplodedMine, j, i );
471 else
473 draw_tile( Mine, j, i );
476 else
478 draw_tile( minefield[i][j].neighbors, j, i );
482 rb->lcd_update();
485 button = rb->button_get(true);
486 while( ( button == BUTTON_NONE )
487 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
488 #ifdef HAVE_TOUCHPAD
489 button = BUTTON_NONE;
490 #endif
493 int count_tiles_left( void )
495 int tiles_left = 0;
496 int i, j;
497 for( i = 0; i < height; i++ )
498 for( j = 0; j < width; j++ )
499 if( minefield[i][j].known == 0 )
500 tiles_left++;
501 return tiles_left;
504 int count_flags( void )
506 int flags_used = 0;
507 int i, j;
508 for( i = 0; i < height; i++ )
509 for( j = 0; j < width; j++ )
510 if( minefield[i][j].flag == 1 )
511 flags_used++;
512 return flags_used;
515 /* welcome screen where player can chose mine percentage */
516 enum minesweeper_status menu( void )
518 int selection, result = MINESWEEPER_QUIT;
519 bool menu_quit = false;
521 MENUITEM_STRINGLIST( menu, "Minesweeper Menu", NULL, "Play Minesweeper",
522 "Mine Percentage", "Number of Rows",
523 "Number of Columns", "Quit" );
525 #ifdef HAVE_LCD_COLOR
526 rb->lcd_set_foreground( rb->global_settings->fg_color );
527 rb->lcd_set_background( rb->global_settings->bg_color );
528 #endif
530 while( !menu_quit )
532 switch( rb->do_menu( &menu, &selection, NULL, false ) )
534 case 0:
535 result = MINESWEEPER_WIN; /* start playing */
536 menu_quit = true;
537 break;
539 case 1:
540 rb->set_int( "Mine Percentage", "%", UNIT_INT, &p, NULL,
541 1, 2, 98, NULL );
542 break;
544 case 2:
545 rb->set_int( "Number of Rows", "", UNIT_INT, &height, NULL,
546 1, 1, MAX_HEIGHT, NULL );
547 break;
549 case 3:
550 rb->set_int( "Number of Columns", "", UNIT_INT, &width, NULL,
551 1, 1, MAX_WIDTH, NULL );
552 break;
554 default:
555 result = MINESWEEPER_QUIT; /* quit program */
556 menu_quit = true;
557 break;
561 return result;
564 /* the big and ugly game function */
565 enum minesweeper_status minesweeper( void )
567 int i, j;
568 int button;
569 int lastbutton = BUTTON_NONE;
571 /* the cursor coordinates */
572 int x=0, y=0;
575 * Show the menu
577 if( ( i = menu() ) != MINESWEEPER_WIN ) return i;
580 * Init game
582 top = (LCD_HEIGHT-height*TileSize)/2;
583 left = (LCD_WIDTH-width*TileSize)/2;
585 #ifdef HAVE_TOUCHPAD
586 mine_raster.tl_x = left;
587 mine_raster.tl_y = top;
588 mine_raster.width = width*TileSize;
589 mine_raster.height = height*TileSize;
590 #endif
592 rb->srand( *rb->current_tick );
593 minesweeper_init();
594 x = 0;
595 y = 0;
598 * Play
600 while( true )
603 /* clear the screen buffer */
604 #ifdef HAVE_LCD_COLOR
605 rb->lcd_set_background( BackgroundColor );
606 #endif
607 rb->lcd_clear_display();
609 /* display the mine field */
610 for( i = 0; i < height; i++ )
612 for( j = 0; j < width; j++ )
614 if( minefield[i][j].known )
616 draw_tile( minefield[i][j].neighbors, j, i );
618 else if(minefield[i][j].flag)
620 draw_tile( Flag, j, i );
622 else
624 draw_tile( Unknown, j, i );
629 /* display the cursor */
630 invert_tile( x, y );
632 /* update the screen */
633 rb->lcd_update();
635 button = rb->button_get(true);
636 #ifdef HAVE_TOUCHPAD
637 if(button & BUTTON_TOUCHPAD)
639 struct ts_raster_result res;
640 if(touchscreen_map_raster(&mine_raster, rb->button_get_data() >> 16, rb->button_get_data() & 0xffff, &res) == 1)
642 button &= ~BUTTON_TOUCHPAD;
643 lastbutton &= ~BUTTON_TOUCHPAD;
645 if(button & BUTTON_REPEAT && lastbutton != MINESWP_TOGGLE && lastbutton ^ BUTTON_REPEAT)
646 button = MINESWP_TOGGLE;
647 else if(button == BUTTON_REL && lastbutton ^ BUTTON_REPEAT)
648 button = MINESWP_DISCOVER;
649 else
650 button |= BUTTON_TOUCHPAD;
652 x = res.x;
653 y = res.y;
656 #endif
657 switch(button)
659 /* quit minesweeper (you really shouldn't use this button ...) */
660 #ifdef MINESWP_RC_QUIT
661 case MINESWP_RC_QUIT:
662 #endif
663 case MINESWP_QUIT:
664 return MINESWEEPER_QUIT;
666 /* move cursor left */
667 case MINESWP_LEFT:
668 case MINESWP_LEFT|BUTTON_REPEAT:
669 x = ( x + width - 1 )%width;
670 break;
672 /* move cursor right */
673 case MINESWP_RIGHT:
674 case MINESWP_RIGHT|BUTTON_REPEAT:
675 x = ( x + 1 )%width;
676 break;
678 /* move cursor down */
679 case MINESWP_DOWN:
680 case MINESWP_DOWN|BUTTON_REPEAT:
681 y = ( y + 1 )%height;
682 break;
684 /* move cursor up */
685 case MINESWP_UP:
686 case MINESWP_UP|BUTTON_REPEAT:
687 y = ( y + height - 1 )%height;
688 break;
690 /*move cursor though the entire field*/
691 #ifdef MINESWP_SCROLLWHEEL
692 case MINESWP_NEXT:
693 case MINESWP_NEXT|BUTTON_REPEAT:
694 if (x == width -1 ) {
695 y = ( y + 1 )%height;
697 x = ( x + 1 )%width;
698 break;
700 case MINESWP_PREV:
701 case MINESWP_PREV|BUTTON_REPEAT:
702 if (x == 0) {
703 y = ( y + height - 1 )%height;
705 x = ( x + width - 1 )%width;
706 break;
707 #endif
708 /* discover a tile (and it's neighbors if .neighbors == 0) */
709 case MINESWP_DISCOVER:
710 #ifdef MINESWP_DISCOVER2
711 case MINESWP_DISCOVER2:
712 #endif
713 if( minefield[y][x].flag ) break;
714 /* we put the mines on the first "click" so that you don't
715 * lose on the first "click" */
716 if( tiles_left == width*height && no_mines )
717 minesweeper_putmines(p,x,y);
719 discover(y, x);
721 if( minefield[y][x].mine )
723 minefield[y][x].known = 1;
724 return MINESWEEPER_LOSE;
726 tiles_left = count_tiles_left();
727 if( tiles_left == mine_num )
729 return MINESWEEPER_WIN;
731 break;
733 /* toggle flag under cursor */
734 case MINESWP_TOGGLE:
735 #ifdef MINESWP_TOGGLE_PRE
736 if( lastbutton != MINESWP_TOGGLE_PRE )
737 break;
738 #endif
739 #ifdef MINESWP_TOGGLE2
740 case MINESWP_TOGGLE2:
741 #endif
742 minefield[y][x].flag = ( minefield[y][x].flag + 1 )%2;
743 break;
745 /* show how many mines you think you have found and how many
746 * there really are on the game */
747 case MINESWP_INFO:
748 if( no_mines )
749 break;
750 flags_used = count_flags();
751 if (flags_used == 1) {
752 rb->splash( HZ*2, "You marked 1 field. There are %d mines.",
753 mine_num );
755 else
757 rb->splash( HZ*2, "You marked %d fields. There are %d mines.",
758 flags_used, mine_num );
760 break;
762 default:
763 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
764 return MINESWEEPER_USB;
765 break;
767 if( button != BUTTON_NONE )
768 lastbutton = button;
773 /* plugin entry point */
774 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
776 bool exit = false;
778 (void)parameter;
779 rb = api;
780 #if LCD_DEPTH > 1
781 rb->lcd_set_backdrop(NULL);
782 #endif
784 while( !exit )
786 switch( minesweeper() )
788 case MINESWEEPER_WIN:
789 rb->splash( HZ, "You Win!" );
790 rb->lcd_clear_display();
791 mine_show();
792 break;
794 case MINESWEEPER_LOSE:
795 rb->splash( HZ, "You Lose!" );
796 rb->lcd_clear_display();
797 mine_show();
798 break;
800 case MINESWEEPER_USB:
801 return PLUGIN_USB_CONNECTED;
803 case MINESWEEPER_QUIT:
804 exit = true;
805 break;
807 default:
808 break;
812 return PLUGIN_OK;
815 #endif