1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2004 dionoea (Antoine Cellerier)
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 /*****************************************************************************
21 Mine Sweeper by dionoea
23 use arrow keys to move cursor
24 use ON or F2 to clear a tile
25 use PLAY or F1 to put a flag on a tile
26 use F3 to see how many mines are left (supposing all your flags are correct)
28 *****************************************************************************/
32 #ifdef HAVE_LCD_BITMAP
36 //what the minesweeper() function can return
37 #define MINESWEEPER_USB 3
38 #define MINESWEEPER_QUIT 2
39 #define MINESWEEPER_LOSE 1
40 #define MINESWEEPER_WIN 0
42 /* variable button definitions */
43 #if CONFIG_KEYPAD == RECORDER_PAD
44 #define MINESWP_UP BUTTON_UP
45 #define MINESWP_DOWN BUTTON_DOWN
46 #define MINESWP_QUIT BUTTON_OFF
47 #define MINESWP_START BUTTON_ON
48 #define MINESWP_TOGGLE BUTTON_PLAY
49 #define MINESWP_TOGGLE2 BUTTON_F1
50 #define MINESWP_DISCOVER BUTTON_ON
51 #define MINESWP_DISCOVER2 BUTTON_F2
52 #define MINESWP_INFO BUTTON_F3
54 #elif CONFIG_KEYPAD == ONDIO_PAD
55 #define MINESWP_UP BUTTON_UP
56 #define MINESWP_DOWN BUTTON_DOWN
57 #define MINESWP_QUIT BUTTON_OFF
58 #define MINESWP_START BUTTON_MENU
59 #define MINESWP_TOGGLE_PRE BUTTON_MENU
60 #define MINESWP_TOGGLE (BUTTON_MENU | BUTTON_REL)
61 #define MINESWP_DISCOVER (BUTTON_MENU | BUTTON_REPEAT)
62 #define MINESWP_INFO (BUTTON_MENU | BUTTON_OFF)
64 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
65 (CONFIG_KEYPAD == IRIVER_H300_PAD)
66 #define MINESWP_UP BUTTON_UP
67 #define MINESWP_DOWN BUTTON_DOWN
68 #define MINESWP_QUIT BUTTON_OFF
69 #define MINESWP_START BUTTON_SELECT
70 #define MINESWP_TOGGLE BUTTON_SELECT
71 #define MINESWP_DISCOVER BUTTON_ON
72 #define MINESWP_INFO BUTTON_MODE
74 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
75 (CONFIG_KEYPAD == IPOD_3G_PAD)
76 #define MINESWP_UP BUTTON_SCROLL_BACK
77 #define MINESWP_DOWN BUTTON_SCROLL_FWD
78 #define MINESWP_QUIT BUTTON_MENU
79 #define MINESWP_START BUTTON_SELECT
80 #define MINESWP_TOGGLE BUTTON_PLAY
81 #define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_PLAY)
82 #define MINESWP_INFO (BUTTON_SELECT | BUTTON_MENU)
84 #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
85 #define MINESWP_UP BUTTON_UP
86 #define MINESWP_DOWN BUTTON_DOWN
87 #define MINESWP_QUIT BUTTON_POWER
88 #define MINESWP_START BUTTON_REC
89 #define MINESWP_TOGGLE BUTTON_PLAY
90 #define MINESWP_DISCOVER BUTTON_SELECT
91 #define MINESWP_INFO (BUTTON_REC | BUTTON_PLAY)
93 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
94 #define MINESWP_UP BUTTON_UP
95 #define MINESWP_DOWN BUTTON_DOWN
96 #define MINESWP_QUIT BUTTON_A
97 #define MINESWP_START BUTTON_SELECT
98 #define MINESWP_TOGGLE BUTTON_SELECT
99 #define MINESWP_DISCOVER BUTTON_POWER
100 #define MINESWP_INFO BUTTON_MENU
104 /* here is a global api struct pointer. while not strictly necessary,
105 it's nice not to have to pass the api pointer in all function calls
107 static struct plugin_api
* rb
;
110 /* define how numbers are displayed (that way we don't have to */
111 /* worry about fonts) */
112 static unsigned char num
[9][8] = {
113 /*reading the sprites:
126 {0x00, /* ........ */
135 {0x00, /* ........ */
144 {0x00, /* ........ */
153 {0x00, /* ........ */
162 {0x00, /* ........ */
171 {0x00, /* ........ */
180 {0x00, /* ........ */
189 {0x00, /* ........ */
198 {0x00, /* ........ */
209 if there is a mine, mine is true
210 if tile is known by player, known is true
211 if tile has a flag, flag is true
212 neighbors is the total number of mines arround tile
214 typedef struct tile
{
215 unsigned char mine
: 1;
216 unsigned char known
: 1;
217 unsigned char flag
: 1;
218 unsigned char neighbors
: 4;
221 /* the height and width of the field */
222 int height
= LCD_HEIGHT
/8;
223 int width
= LCD_WIDTH
/8;
226 tile minefield
[LCD_HEIGHT
/8][LCD_WIDTH
/8];
228 /* total number of mines on the game */
231 /* discovers the tile when player clears one of them */
232 /* a chain reaction (of discovery) occurs if tile has no mines */
234 void discover(int, int);
235 void discover(int x
, int y
){
239 if(x
>width
-1) return;
240 if(y
>height
-1) return;
241 if(minefield
[y
][x
].known
) return;
243 minefield
[y
][x
].known
= 1;
244 if(minefield
[y
][x
].neighbors
== 0){
258 /* init not mine related elements of the mine field */
259 void minesweeper_init(void){
262 for(i
=0;i
<height
;i
++){
263 for(j
=0;j
<width
;j
++){
264 minefield
[i
][j
].known
= 0;
265 minefield
[i
][j
].flag
= 0;
271 /* put mines on the mine field */
272 /* there is p% chance that a tile is a mine */
273 /* if the tile has coordinates (x,y), then it can't be a mine */
274 void minesweeper_putmines(int p
, int x
, int y
){
278 for(i
=0;i
<height
;i
++){
279 for(j
=0;j
<width
;j
++){
280 if(rb
->rand()%100<p
&& !(y
==i
&& x
==j
)){
281 minefield
[i
][j
].mine
= 1;
284 minefield
[i
][j
].mine
= 0;
286 minefield
[i
][j
].neighbors
= 0;
290 /* we need to compute the neighbor element for each tile */
291 for(i
=0;i
<height
;i
++){
292 for(j
=0;j
<width
;j
++){
295 minefield
[i
][j
].neighbors
+= minefield
[i
-1][j
-1].mine
;
296 minefield
[i
][j
].neighbors
+= minefield
[i
-1][j
].mine
;
298 minefield
[i
][j
].neighbors
+= minefield
[i
-1][j
+1].mine
;
301 minefield
[i
][j
].neighbors
+= minefield
[i
][j
-1].mine
;
303 minefield
[i
][j
].neighbors
+= minefield
[i
][j
+1].mine
;
306 minefield
[i
][j
].neighbors
+= minefield
[i
+1][j
-1].mine
;
307 minefield
[i
][j
].neighbors
+= minefield
[i
+1][j
].mine
;
309 minefield
[i
][j
].neighbors
+= minefield
[i
+1][j
+1].mine
;
315 /* the big and ugly function that is the game */
316 int minesweeper(void)
320 int lastbutton
= BUTTON_NONE
;
322 /* the cursor coordinates */
325 /* number of tiles left on the game */
326 int tiles_left
=width
*height
;
328 /* percentage of mines on minefield used durring generation */
331 /* a usefull string for snprintf */
334 /* welcome screen where player can chose mine percentage */
337 rb
->lcd_clear_display();
339 rb
->lcd_puts(0,0,"Mine Sweeper");
341 rb
->snprintf(str
, 20, "%d%% mines", p
);
342 rb
->lcd_puts(0,2,str
);
343 rb
->lcd_puts(0,3,"down / up");
344 rb
->snprintf(str
, 20, "%d cols x %d rows", width
, height
);
345 rb
->lcd_puts(0,4,str
);
346 rb
->lcd_puts(0,5,"left x right ");
347 #if CONFIG_KEYPAD == RECORDER_PAD
348 rb
->lcd_puts(0,6,"ON to start");
349 #elif CONFIG_KEYPAD == ONDIO_PAD
350 rb
->lcd_puts(0,6,"MODE to start");
351 #elif CONFIG_KEYPAD == IRIVER_H100_PAD
352 rb
->lcd_puts(0,6,"SELECT to start");
358 button
= rb
->button_get(true);
369 height
= height
%(LCD_HEIGHT
/8)+1;
373 width
= width
%(LCD_WIDTH
/8)+1;
376 case MINESWP_START
:/* start playing */
380 case MINESWP_QUIT
:/* quit program */
381 return MINESWEEPER_QUIT
;
384 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
385 return MINESWEEPER_USB
;
393 /********************
395 ********************/
399 /**********************
401 **********************/
405 //clear the screen buffer
406 rb
->lcd_clear_display();
408 //display the mine field
409 for(i
=0;i
<height
;i
++){
410 for(j
=0;j
<width
;j
++){
412 rb
->lcd_set_foreground(LCD_DARKGRAY
);
413 rb
->lcd_drawrect(j
*8,i
*8,8,8);
414 rb
->lcd_set_foreground(LCD_BLACK
);
416 rb
->lcd_drawrect(j
*8,i
*8,8,8);
418 if(minefield
[i
][j
].known
){
419 if(minefield
[i
][j
].mine
){
420 rb
->lcd_putsxy(j
*8+1,i
*8+1,"b");
421 } else if(minefield
[i
][j
].neighbors
){
422 rb
->lcd_set_drawmode(DRMODE_FG
);
423 rb
->lcd_mono_bitmap(num
[minefield
[i
][j
].neighbors
],j
*8,i
*8,8,8);
424 rb
->lcd_set_drawmode(DRMODE_SOLID
);
426 } else if(minefield
[i
][j
].flag
) {
427 rb
->lcd_drawline(j
*8+2,i
*8+2,j
*8+5,i
*8+5);
428 rb
->lcd_drawline(j
*8+2,i
*8+5,j
*8+5,i
*8+2);
431 rb
->lcd_set_foreground(LCD_LIGHTGRAY
);
432 rb
->lcd_fillrect(j
*8+1,i
*8+1,6,6);
433 rb
->lcd_set_foreground(LCD_BLACK
);
435 rb
->lcd_fillrect(j
*8+2,i
*8+2,4,4);
441 /* display the cursor */
442 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
443 rb
->lcd_fillrect(x
*8,y
*8,8,8);
444 rb
->lcd_set_drawmode(DRMODE_SOLID
);
446 /* update the screen */
449 button
= rb
->button_get(true);
451 /* quit minesweeper (you really shouldn't use this button ...) */
453 return MINESWEEPER_QUIT
;
455 /* move cursor left */
457 case (BUTTON_LEFT
| BUTTON_REPEAT
):
458 x
= (x
+ width
- 1)%width
;
461 /* move cursor right */
463 case (BUTTON_RIGHT
| BUTTON_REPEAT
):
467 /* move cursor down */
469 case (MINESWP_DOWN
| BUTTON_REPEAT
):
475 case (MINESWP_UP
| BUTTON_REPEAT
):
476 y
= (y
+ height
- 1)%height
;
479 /* discover a tile (and it's neighbors if .neighbors == 0) */
480 case MINESWP_DISCOVER
:
481 #ifdef MINESWP_DISCOVER2
482 case MINESWP_DISCOVER2
:
484 if(minefield
[y
][x
].flag
) break;
485 /* we put the mines on the first "click" so that you don't */
486 /* lose on the first "click" */
487 if(tiles_left
== width
*height
) minesweeper_putmines(p
,x
,y
);
489 if(minefield
[y
][x
].mine
){
490 return MINESWEEPER_LOSE
;
493 for(i
=0;i
<height
;i
++){
494 for(j
=0;j
<width
;j
++){
495 if(minefield
[i
][j
].known
== 0) tiles_left
++;
498 if(tiles_left
== mine_num
){
499 return MINESWEEPER_WIN
;
503 /* toggle flag under cursor */
505 #ifdef MINESWP_TOGGLE_PRE
506 if (lastbutton
!= MINESWP_TOGGLE_PRE
)
509 #ifdef MINESWP_TOGGLE2
510 case MINESWP_TOGGLE2
:
512 minefield
[y
][x
].flag
= (minefield
[y
][x
].flag
+ 1)%2;
515 /* show how many mines you think you have found and how many */
516 /* there really are on the game */
519 for(i
=0;i
<height
;i
++){
520 for(j
=0;j
<width
;j
++){
521 if(minefield
[i
][j
].flag
) tiles_left
++;
524 rb
->splash(HZ
*2, true, "You found %d mines out of %d", tiles_left
, mine_num
);
528 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
529 return MINESWEEPER_USB
;
532 if (button
!= BUTTON_NONE
)
538 /* plugin entry point */
539 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
545 /* end of plugin init */
548 switch(minesweeper()){
549 case MINESWEEPER_WIN
:
550 rb
->splash(HZ
*2, true, "You Win :)");
553 case MINESWEEPER_LOSE
:
554 rb
->splash(HZ
*2, true, "You Lost :(");
557 case MINESWEEPER_USB
:
558 return PLUGIN_USB_CONNECTED
;
560 case MINESWEEPER_QUIT
: