diff options
author | Björn Stenberg <bjorn@haxx.se> | 2004-08-17 06:50:14 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2004-08-17 06:50:14 +0000 |
commit | 619a5ca1d3dfbc86839245b9ce8977002efd187e (patch) | |
tree | 546dbcd5d22de4f7b730ba48c8565cbdce204326 /apps/plugins/minesweeper.c | |
parent | 0ceaa5e365b3f6dc78269ed5c4cd43df5c0144eb (diff) | |
download | rockbox-619a5ca1d3dfbc86839245b9ce8977002efd187e.tar.gz rockbox-619a5ca1d3dfbc86839245b9ce8977002efd187e.zip |
Minesweeper and Solitaire plugins by Antoine Cellerier
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4997 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/minesweeper.c')
-rw-r--r-- | apps/plugins/minesweeper.c | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/apps/plugins/minesweeper.c b/apps/plugins/minesweeper.c new file mode 100644 index 0000000000..b155c3fbad --- /dev/null +++ b/apps/plugins/minesweeper.c | |||
@@ -0,0 +1,436 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2004 dionoea (Antoine Cellerier) | ||
11 | * | ||
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. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | /***************************************************************************** | ||
21 | Mine Sweeper by dionoea | ||
22 | |||
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) | ||
27 | |||
28 | *****************************************************************************/ | ||
29 | |||
30 | #include "plugin.h" | ||
31 | #include "button.h" | ||
32 | #include "lcd.h" | ||
33 | |||
34 | #ifdef HAVE_LCD_BITMAP | ||
35 | |||
36 | //what the minesweeper() function can return | ||
37 | #define MINESWEEPER_QUIT 2 | ||
38 | #define MINESWEEPER_LOSE 1 | ||
39 | #define MINESWEEPER_WIN 0 | ||
40 | |||
41 | |||
42 | /* here is a global api struct pointer. while not strictly necessary, | ||
43 | it's nice not to have to pass the api pointer in all function calls | ||
44 | in the plugin */ | ||
45 | static struct plugin_api* rb; | ||
46 | |||
47 | |||
48 | //define how numbers are displayed (that way we don't have to | ||
49 | //worry about fonts) | ||
50 | static unsigned char num[9][8] = { | ||
51 | /*reading the sprites: | ||
52 | on screen f123 | ||
53 | 4567 | ||
54 | 890a | ||
55 | bcde | ||
56 | |||
57 | in binary b84f | ||
58 | c951 | ||
59 | d062 | ||
60 | ea73 | ||
61 | */ | ||
62 | |||
63 | //0 | ||
64 | {0x00, //........ | ||
65 | 0x00, //........ | ||
66 | 0x00, //........ | ||
67 | 0x00, //........ | ||
68 | 0x00, //........ | ||
69 | 0x00, //........ | ||
70 | 0x00, //........ | ||
71 | 0x00},//........ | ||
72 | //1 | ||
73 | {0x00, //........ | ||
74 | 0x00, //........ | ||
75 | 0x00, //...OO... | ||
76 | 0x44, //....O... | ||
77 | 0x7c, //....O... | ||
78 | 0x40, //....O... | ||
79 | 0x00, //...OOO.. | ||
80 | 0x00},//........ | ||
81 | //2 | ||
82 | {0x00, //........ | ||
83 | 0x00, //........ | ||
84 | 0x48, //...OO... | ||
85 | 0x64, //..O..O.. | ||
86 | 0x54, //....O... | ||
87 | 0x48, //...O.... | ||
88 | 0x00, //..OOOO.. | ||
89 | 0x00},//........ | ||
90 | //3 | ||
91 | {0x00, //........ | ||
92 | 0x00, //........ | ||
93 | 0x44, //..OOO... | ||
94 | 0x54, //.....O.. | ||
95 | 0x54, //...OO... | ||
96 | 0x28, //.....O.. | ||
97 | 0x00, //..OOO... | ||
98 | 0x00},//........ | ||
99 | //4 | ||
100 | {0x00, //........ | ||
101 | 0x00, //........ | ||
102 | 0x1c, //..O..... | ||
103 | 0x10, //..O..... | ||
104 | 0x70, //..OOOO.. | ||
105 | 0x10, //....O... | ||
106 | 0x00, //....O... | ||
107 | 0x00},//........ | ||
108 | //5 | ||
109 | {0x00, //........ | ||
110 | 0x00, //........ | ||
111 | 0x5c, //..OOOO.. | ||
112 | 0x54, //..O..... | ||
113 | 0x54, //..OOO... | ||
114 | 0x24, //.....O.. | ||
115 | 0x00, //..OOO... | ||
116 | 0x00},//........ | ||
117 | //6 | ||
118 | {0x00, //........ | ||
119 | 0x00, //........ | ||
120 | 0x38, //...OOO.. | ||
121 | 0x54, //..O..... | ||
122 | 0x54, //..OOO... | ||
123 | 0x24, //..O..O.. | ||
124 | 0x00, //...OO... | ||
125 | 0x00},//........ | ||
126 | //7 | ||
127 | {0x00, //........ | ||
128 | 0x00, //........ | ||
129 | 0x44, //..OOOO.. | ||
130 | 0x24, //.....O.. | ||
131 | 0x14, //....O... | ||
132 | 0x0c, //...O.... | ||
133 | 0x00, //..O..... | ||
134 | 0x00},//........ | ||
135 | //8 | ||
136 | {0x00, //........ | ||
137 | 0x00, //........ | ||
138 | 0x28, //...OO... | ||
139 | 0x54, //..O..O.. | ||
140 | 0x54, //...OO... | ||
141 | 0x28, //..O..O.. | ||
142 | 0x00, //...OO... | ||
143 | 0x00},//........ | ||
144 | }; | ||
145 | |||
146 | /* the tile struct | ||
147 | if there is a mine, mine is true | ||
148 | if tile is known by player, known is true | ||
149 | if tile has a flag, flag is true | ||
150 | neighbors is the total number of mines arround tile | ||
151 | */ | ||
152 | typedef struct tile { | ||
153 | unsigned char mine : 1; | ||
154 | unsigned char known : 1; | ||
155 | unsigned char flag : 1; | ||
156 | unsigned char neighbors : 4; | ||
157 | } tile; | ||
158 | |||
159 | //the height and width of the field | ||
160 | //could be variable if malloc worked in the API :) | ||
161 | const int height = LCD_HEIGHT/8; | ||
162 | const int width = LCD_WIDTH/8; | ||
163 | |||
164 | //the minefield | ||
165 | tile minefield[LCD_HEIGHT/8][LCD_WIDTH/8]; | ||
166 | |||
167 | //total number of mines on the game | ||
168 | int mine_num = 0; | ||
169 | |||
170 | //discovers the tile when player clears one of them | ||
171 | //a chain reaction (of discovery) occurs if tile has no mines | ||
172 | //as neighbors | ||
173 | void discover(int, int); | ||
174 | void discover(int x, int y){ | ||
175 | |||
176 | if(x<0) return; | ||
177 | if(y<0) return; | ||
178 | if(x>width-1) return; | ||
179 | if(y>height-1) return; | ||
180 | if(minefield[y][x].known) return; | ||
181 | |||
182 | minefield[y][x].known = 1; | ||
183 | if(minefield[y][x].neighbors == 0){ | ||
184 | discover(x-1,y-1); | ||
185 | discover(x,y-1); | ||
186 | discover(x+1,y-1); | ||
187 | discover(x+1,y); | ||
188 | discover(x+1,y+1); | ||
189 | discover(x,y+1); | ||
190 | discover(x-1,y+1); | ||
191 | discover(x-1,y); | ||
192 | } | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | |||
197 | //init not mine related elements of the mine field | ||
198 | void minesweeper_init(void){ | ||
199 | int i,j; | ||
200 | |||
201 | for(i=0;i<height;i++){ | ||
202 | for(j=0;j<width;j++){ | ||
203 | minefield[i][j].known = 0; | ||
204 | minefield[i][j].flag = 0; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | |||
210 | //put mines on the mine field | ||
211 | //there is p% chance that a tile is a mine | ||
212 | //if the tile has coordinates (x,y), then it can't be a mine | ||
213 | void minesweeper_putmines(int p, int x, int y){ | ||
214 | int i,j; | ||
215 | |||
216 | for(i=0;i<height;i++){ | ||
217 | for(j=0;j<width;j++){ | ||
218 | if(rb->rand()%100<p && !(y==i && x==j)){ | ||
219 | minefield[i][j].mine = 1; | ||
220 | mine_num++; | ||
221 | } else { | ||
222 | minefield[i][j].mine = 0; | ||
223 | } | ||
224 | minefield[i][j].neighbors = 0; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | //we need to compute the neighbor element for each tile | ||
229 | for(i=0;i<height;i++){ | ||
230 | for(j=0;j<width;j++){ | ||
231 | if(i>0){ | ||
232 | if(j>0) minefield[i][j].neighbors += minefield[i-1][j-1].mine; | ||
233 | minefield[i][j].neighbors += minefield[i-1][j].mine; | ||
234 | if(j<width-1) minefield[i][j].neighbors += minefield[i-1][j+1].mine; | ||
235 | } | ||
236 | if(j>0) minefield[i][j].neighbors += minefield[i][j-1].mine; | ||
237 | if(j<width-1) minefield[i][j].neighbors += minefield[i][j+1].mine; | ||
238 | if(i<height-1){ | ||
239 | if(j>0) minefield[i][j].neighbors += minefield[i+1][j-1].mine; | ||
240 | minefield[i][j].neighbors += minefield[i+1][j].mine; | ||
241 | if(j<width-1) minefield[i][j].neighbors += minefield[i+1][j+1].mine; | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | //the big and ugly function that is the game | ||
248 | int minesweeper(void){ | ||
249 | |||
250 | |||
251 | int i,j; | ||
252 | |||
253 | //the cursor coordinates | ||
254 | int x=0,y=0; | ||
255 | |||
256 | //number of tiles left on the game | ||
257 | int tiles_left=width*height; | ||
258 | |||
259 | //percentage of mines on minefield used durring generation | ||
260 | int p=16; | ||
261 | |||
262 | //a usefull string for snprintf | ||
263 | char str[30]; | ||
264 | |||
265 | //welcome screen where player can chose mine percentage | ||
266 | i = 0; | ||
267 | while(true){ | ||
268 | rb->lcd_clear_display(); | ||
269 | |||
270 | rb->lcd_putsxy(1,1,"Mine Sweeper"); | ||
271 | |||
272 | rb->snprintf(str, 20, "%d%% mines", p); | ||
273 | rb->lcd_putsxy(1,19,str); | ||
274 | rb->lcd_putsxy(1,28,"down / up"); | ||
275 | rb->lcd_putsxy(1,44,"ON to start"); | ||
276 | |||
277 | rb->lcd_update(); | ||
278 | |||
279 | |||
280 | switch(rb->button_get(true)){ | ||
281 | case BUTTON_DOWN: | ||
282 | case BUTTON_LEFT: | ||
283 | p = (p + 98)%100; | ||
284 | break; | ||
285 | |||
286 | case BUTTON_UP: | ||
287 | case BUTTON_RIGHT: | ||
288 | p = (p + 2)%100; | ||
289 | break; | ||
290 | |||
291 | case BUTTON_ON://start playing | ||
292 | i = 1; | ||
293 | break; | ||
294 | |||
295 | case BUTTON_OFF://quit program | ||
296 | return MINESWEEPER_QUIT; | ||
297 | } | ||
298 | if(i==1) break; | ||
299 | } | ||
300 | |||
301 | |||
302 | /******************** | ||
303 | * init * | ||
304 | ********************/ | ||
305 | |||
306 | minesweeper_init(); | ||
307 | |||
308 | /********************** | ||
309 | * play * | ||
310 | **********************/ | ||
311 | |||
312 | while(true){ | ||
313 | |||
314 | //clear the screen buffer | ||
315 | rb->lcd_clear_display(); | ||
316 | |||
317 | //display the mine field | ||
318 | for(i=0;i<height;i++){ | ||
319 | for(j=0;j<width;j++){ | ||
320 | rb->lcd_drawrect(j*8,i*8,8,8); | ||
321 | if(minefield[i][j].known){ | ||
322 | if(minefield[i][j].mine){ | ||
323 | rb->lcd_putsxy(j*8+1,i*8+1,"b"); | ||
324 | } else if(minefield[i][j].neighbors){ | ||
325 | rb->lcd_bitmap(num[minefield[i][j].neighbors],j*8,i*8,8,8,false); | ||
326 | } | ||
327 | } else if(minefield[i][j].flag) { | ||
328 | rb->lcd_drawline(j*8+2,i*8+2,j*8+5,i*8+5); | ||
329 | rb->lcd_drawline(j*8+2,i*8+5,j*8+5,i*8+2); | ||
330 | } else { | ||
331 | rb->lcd_fillrect(j*8+2,i*8+2,4,4); | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | //display the cursor | ||
337 | rb->lcd_invertrect(x*8,y*8,8,8); | ||
338 | |||
339 | //update the screen | ||
340 | rb->lcd_update(); | ||
341 | |||
342 | switch(rb->button_get(true)){ | ||
343 | //quit minesweeper (you really shouldn't use this button ...) | ||
344 | case BUTTON_OFF: | ||
345 | return MINESWEEPER_QUIT; | ||
346 | |||
347 | //move cursor left | ||
348 | case BUTTON_LEFT: | ||
349 | x = (x + width - 1)%width; | ||
350 | break; | ||
351 | |||
352 | //move cursor right | ||
353 | case BUTTON_RIGHT: | ||
354 | x = (x + 1)%width; | ||
355 | break; | ||
356 | |||
357 | //move cursor down | ||
358 | case BUTTON_DOWN: | ||
359 | y = (y + 1)%height; | ||
360 | break; | ||
361 | |||
362 | //move cursor up | ||
363 | case BUTTON_UP: | ||
364 | y = (y + height - 1)%height; | ||
365 | break; | ||
366 | |||
367 | //discover a tile (and it's neighbors if .neighbors == 0) | ||
368 | case BUTTON_ON: | ||
369 | case BUTTON_F2: | ||
370 | if(minefield[y][x].flag) break; | ||
371 | //we put the mines on the first "click" so that you don't | ||
372 | //lose on the first "click" | ||
373 | if(tiles_left == width*height) minesweeper_putmines(p,x,y); | ||
374 | discover(x,y); | ||
375 | if(minefield[y][x].mine){ | ||
376 | return MINESWEEPER_LOSE; | ||
377 | } | ||
378 | tiles_left = 0; | ||
379 | for(i=0;i<height;i++){ | ||
380 | for(j=0;j<width;j++){ | ||
381 | if(minefield[i][j].known == 0) tiles_left++; | ||
382 | } | ||
383 | } | ||
384 | if(tiles_left == mine_num){ | ||
385 | return MINESWEEPER_WIN; | ||
386 | } | ||
387 | break; | ||
388 | |||
389 | //toggle flag under cursor | ||
390 | case BUTTON_PLAY: | ||
391 | case BUTTON_F1: | ||
392 | minefield[y][x].flag = (minefield[y][x].flag + 1)%2; | ||
393 | break; | ||
394 | |||
395 | //show how many mines you think you have found and how many | ||
396 | //there really are on the game | ||
397 | case BUTTON_F3: | ||
398 | tiles_left = 0; | ||
399 | for(i=0;i<height;i++){ | ||
400 | for(j=0;j<width;j++){ | ||
401 | if(minefield[i][j].flag) tiles_left++; | ||
402 | } | ||
403 | } | ||
404 | rb->splash(HZ*2, true, "You found %d mines out of %d", tiles_left, mine_num); | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | } | ||
410 | |||
411 | //plugin entry point | ||
412 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
413 | { | ||
414 | //plugin init | ||
415 | TEST_PLUGIN_API(api); | ||
416 | (void)parameter; | ||
417 | rb = api; | ||
418 | //end of plugin init | ||
419 | |||
420 | switch(minesweeper()){ | ||
421 | case MINESWEEPER_WIN: | ||
422 | rb->splash(HZ*2, true, "You Win :)"); | ||
423 | break; | ||
424 | |||
425 | case MINESWEEPER_LOSE: | ||
426 | rb->splash(HZ*2, true, "You Lost :("); | ||
427 | break; | ||
428 | |||
429 | default: | ||
430 | break; | ||
431 | } | ||
432 | |||
433 | return PLUGIN_OK; | ||
434 | } | ||
435 | |||
436 | #endif | ||