1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Matthias Wientapper
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 ****************************************************************************/
21 /* This is the implementation of a maze generation algorithm.
22 * The generated mazes are "perfect", i.e. there is one and only
23 * one path from any point in the maze to any other point.
26 * The implemented algorithm is called "Depth-First search", the
27 * solving is done by a dead-end filler routine.
32 #include "pluginlib_actions.h"
37 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
38 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
39 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
40 # undef __PLUGINLIB_ACTIONS_H__
41 # define MAZE_NEW (BUTTON_SELECT | BUTTON_REPEAT)
42 # define MAZE_NEW_PRE BUTTON_SELECT
43 # define MAZE_QUIT (BUTTON_SELECT | BUTTON_MENU)
44 # define MAZE_SOLVE (BUTTON_SELECT | BUTTON_PLAY)
45 # define MAZE_RIGHT BUTTON_RIGHT
46 # define MAZE_LEFT BUTTON_LEFT
47 # define MAZE_UP BUTTON_MENU
48 # define MAZE_DOWN BUTTON_PLAY
49 # define MAZE_RRIGHT (BUTTON_RIGHT | BUTTON_REPEAT)
50 # define MAZE_RLEFT (BUTTON_LEFT | BUTTON_REPEAT)
51 # define MAZE_RUP (BUTTON_MENU | BUTTON_REPEAT)
52 # define MAZE_RDOWN (BUTTON_PLAY | BUTTON_REPEAT)
55 # define MAZE_NEW PLA_START
56 # define MAZE_QUIT PLA_QUIT
57 # define MAZE_SOLVE PLA_FIRE
58 # define MAZE_RIGHT PLA_RIGHT
59 # define MAZE_LEFT PLA_LEFT
60 # define MAZE_UP PLA_UP
61 # define MAZE_DOWN PLA_DOWN
62 # define MAZE_RRIGHT PLA_RIGHT_REPEAT
63 # define MAZE_RLEFT PLA_LEFT_REPEAT
64 # define MAZE_RUP PLA_UP_REPEAT
65 # define MAZE_RDOWN PLA_DOWN_REPEAT
69 /* propertie bits of the cell */
70 #define WALL_N 0x00000001
71 #define WALL_E 0x00000002
72 #define WALL_S 0x00000004
73 #define WALL_W 0x00000008
74 #define WALL_ALL 0x0000000F
76 #define BORDER_N 0x00000010
77 #define BORDER_E 0x00000020
78 #define BORDER_S 0x00000040
79 #define BORDER_W 0x00000080
80 #define PATH 0x00000100
82 static struct plugin_api
* rb
;
84 #ifdef __PLUGINLIB_ACTIONS_H__
85 const struct button_mapping
*plugin_contexts
[]
86 = {generic_directions
, generic_actions
};
89 #if ( LCD_WIDTH == 112 )
91 #define MAZE_HEIGHT 12
92 #elif( LCD_WIDTH == 132 )
94 #define MAZE_HEIGHT 16
97 #define MAZE_HEIGHT 24
102 int data
[MAZE_WIDTH
*MAZE_HEIGHT
];
106 void coord_stack_init(struct coord_stack
* stack
)
111 void coord_stack_push(struct coord_stack
* stack
, int x
, int y
)
113 stack
->data
[stack
->stp
] = ((x
<<8)|y
);
117 void coord_stack_get(struct coord_stack
* stack
, int index
, int* x
, int* y
)
119 *y
= stack
->data
[index
];
121 *x
= (stack
->data
[index
])>>8;
124 void coord_stack_pop(struct coord_stack
* stack
, int* x
, int* y
)
127 coord_stack_get(stack
, stack
->stp
, x
, y
);
130 int coord_stack_count(struct coord_stack
* stack
)
140 unsigned short maze
[MAZE_WIDTH
][MAZE_HEIGHT
];
143 void maze_init(struct maze
* maze
)
146 rb
->memset(maze
->maze
, 0, sizeof(maze
->maze
));
147 maze
->solved
= false;
151 for(y
=0; y
<MAZE_HEIGHT
; y
++){
152 for(x
=0; x
<MAZE_WIDTH
; x
++){
154 /* all walls are up */
155 maze
->maze
[x
][y
] |= WALL_ALL
| PATH
;
159 maze
->maze
[x
][y
]|= BORDER_W
;
161 maze
->maze
[x
][y
]|= BORDER_N
;
162 if(x
== MAZE_WIDTH
-1)
163 maze
->maze
[x
][y
]|= BORDER_E
;
164 if(y
== MAZE_HEIGHT
-1)
165 maze
->maze
[x
][y
]|= BORDER_S
;
170 void maze_draw(struct maze
* maze
, struct screen
* display
)
174 int point_width
, point_height
, point_offset_x
, point_offset_y
;
177 wx
= (int) display
->width
/ MAZE_WIDTH
;
178 wy
= (int) display
->height
/ MAZE_HEIGHT
;
196 display
->clear_display();
198 for(y
=0; y
<MAZE_HEIGHT
; y
++){
199 for(x
=0; x
<MAZE_WIDTH
; x
++){
201 cell
= maze
->maze
[x
][y
];
205 display
->drawline(x
*wx
, y
*wy
, x
*wx
+wx
, y
*wy
);
207 display
->drawline(x
*wx
+wx
, y
*wy
, x
*wx
+wx
, y
*wy
+wy
);
209 display
->drawline(x
*wx
, y
*wy
+wy
, x
*wx
+wx
, y
*wy
+wy
);
211 display
->drawline(x
*wx
, y
*wy
, x
*wx
, y
*wy
+wy
);
214 display
->drawline(x
*wx
, y
*wy
, x
*wx
+wx
, y
*wy
);
216 display
->drawline(x
*wx
+wx
, y
*wy
, x
*wx
+wx
, y
*wy
+wy
);
218 display
->drawline(x
*wx
, y
*wy
+wy
, x
*wx
+wx
, y
*wy
+wy
);
220 display
->drawline(x
*wx
, y
*wy
, x
*wx
, y
*wy
+wy
);
225 if(display
->depth
>=16)
226 display
->set_foreground(LCD_RGBPACK(127,127,127));
229 if(display
->depth
==2)
230 display
->set_foreground(1);
232 for(y
=0; y
<MAZE_HEIGHT
; y
++){
233 for(x
=0; x
<MAZE_WIDTH
; x
++){
234 cell
= maze
->maze
[x
][y
];
236 display
->fillrect(x
*wx
+point_offset_x
,
238 point_width
, point_height
);
242 if(display
->depth
>=16)
243 display
->set_foreground(LCD_RGBPACK(0,0,0));
246 if(display
->depth
==2)
247 display
->set_foreground(0);
251 /* mark start and end */
252 display
->drawline(0, 0, wx
, wy
);
253 display
->drawline(0, wy
, wx
, 0);
254 display
->drawline((MAZE_WIDTH
-1)*wx
,(MAZE_HEIGHT
-1)*wy
,
255 (MAZE_WIDTH
-1)*wx
+wx
, (MAZE_HEIGHT
-1)*wy
+wy
);
256 display
->drawline((MAZE_WIDTH
-1)*wx
,(MAZE_HEIGHT
-1)*wy
+wy
,
257 (MAZE_WIDTH
-1)*wx
+wx
, (MAZE_HEIGHT
-1)*wy
);
260 /* draw current position */
261 display
->fillrect(maze
->player_x
*wx
+point_offset_x
,
262 maze
->player_y
*wy
+point_offset_y
,
263 point_width
, point_height
);
269 int maze_pick_random_neighbour_cell_with_walls(struct maze
* maze
,
270 int x
, int y
, int *pnx
, int *pny
)
274 struct coord_stack neighbours
;
275 unsigned short current_cell
=maze
->maze
[x
][y
];
277 coord_stack_init(&neighbours
);
278 /* look for neighbour cells with walls */
281 if(!(current_cell
& BORDER_N
)){
282 if((maze
->maze
[x
][y
-1] & WALL_ALL
) == WALL_ALL
){
283 coord_stack_push(&neighbours
, x
, y
-1);
288 if(!(current_cell
& BORDER_W
)){
289 if((maze
->maze
[x
-1][y
] & WALL_ALL
) == WALL_ALL
){
290 coord_stack_push(&neighbours
, x
-1, y
);
295 if(!(current_cell
& BORDER_E
)){
296 if((maze
->maze
[x
+1][y
] & WALL_ALL
) == WALL_ALL
){
297 coord_stack_push(&neighbours
, x
+1, y
);
302 if(!(current_cell
& BORDER_S
)){
303 if((maze
->maze
[x
][y
+1] & WALL_ALL
) == WALL_ALL
){
304 coord_stack_push(&neighbours
, x
, y
+1);
308 /* randomly select neighbour cell with walls */
309 ncount
=coord_stack_count(&neighbours
);
311 coord_stack_get(&neighbours
, rb
->rand()%ncount
, pnx
, pny
);
315 /* Removes the wall between the cell (x,y) and the cell (nx,ny) */
316 void maze_remove_wall(struct maze
* maze
, int x
, int y
, int nx
, int ny
)
318 /* where is our neighbour? */
324 maze
->maze
[x
][y
] &= ~WALL_S
;
325 maze
->maze
[nx
][ny
] &= ~WALL_N
;
328 maze
->maze
[x
][y
] &= ~WALL_N
;
329 maze
->maze
[nx
][ny
] &= ~WALL_S
;
336 maze
->maze
[x
][y
] &= ~WALL_E
;
337 maze
->maze
[nx
][ny
] &= ~WALL_W
;
340 maze
->maze
[x
][y
] &= ~WALL_W
;
341 maze
->maze
[nx
][ny
] &= ~WALL_E
;
347 void maze_generate(struct maze
* maze
)
349 int total_cells
= MAZE_WIDTH
* MAZE_HEIGHT
;
351 int available_neighbours
;
355 struct coord_stack done_cells
;
357 coord_stack_init(&done_cells
);
359 x
= rb
->rand()%MAZE_WIDTH
;
360 y
= rb
->rand()%MAZE_HEIGHT
;
363 while (visited_cells
< total_cells
){
364 available_neighbours
=
365 maze_pick_random_neighbour_cell_with_walls(maze
, x
, y
, &nx
, &ny
);
366 if(available_neighbours
== 0){
368 coord_stack_pop(&done_cells
, &x
, &y
);
370 maze_remove_wall(maze
, x
, y
, nx
, ny
);
372 /* save position on the stack */
373 coord_stack_push(&done_cells
, x
, y
);
375 /* current cell = neighbour cell */
385 void maze_solve(struct maze
* maze
)
391 unsigned short solved_maze
[MAZE_WIDTH
][MAZE_HEIGHT
];
393 maze
->solved
= ~(maze
->solved
);
395 /* copy maze for solving */
396 rb
->memcpy(solved_maze
, maze
->maze
,
397 (MAZE_HEIGHT
*MAZE_WIDTH
*sizeof(maze
->maze
[0][0])));
400 /* remove some borders and walls on start and end point */
401 solved_maze
[0][0] &= ~(WALL_N
|BORDER_N
);
402 solved_maze
[MAZE_WIDTH
-1][MAZE_HEIGHT
-1] &= ~(WALL_S
|BORDER_S
);
406 /* scan for dead ends */
407 for(y
=0; y
<MAZE_HEIGHT
; y
++){
409 for(x
=0; x
<MAZE_WIDTH
; x
++){
410 cell
= solved_maze
[x
][y
];
416 /* found dead end, clear path bit and fill it up */
417 maze
->maze
[x
][y
] &= ~PATH
;
418 solved_maze
[x
][y
] |= WALL_ALL
;
419 /* don't forget the neighbours */
420 if(!(cell
& BORDER_N
))
421 solved_maze
[x
][y
-1]|=WALL_S
;
422 if(!(cell
& BORDER_E
))
423 solved_maze
[x
+1][y
]|=WALL_W
;
424 if(!(cell
& BORDER_S
))
425 solved_maze
[x
][y
+1]|=WALL_N
;
426 if(!(cell
& BORDER_W
))
427 solved_maze
[x
-1][y
]|=WALL_E
;
435 void maze_move_player_down(struct maze
* maze
)
437 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
438 if( !(cell
& WALL_S
) &&
444 void maze_move_player_up(struct maze
* maze
)
446 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
447 if( !(cell
& WALL_N
) &&
453 void maze_move_player_left(struct maze
* maze
)
455 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
456 if( !(cell
& WALL_W
) &&
462 void maze_move_player_right(struct maze
* maze
)
464 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
465 if( !(cell
& WALL_E
) &&
470 /**********************************/
471 /* this is the plugin entry point */
472 /**********************************/
473 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
475 int button
, lastbutton
= BUTTON_NONE
;
482 /* Turn off backlight timeout */
483 backlight_force_on(rb
); /* backlight control in lib/helper.c */
486 rb
->lcd_set_backdrop(NULL
);
487 rb
->lcd_set_background(LCD_DEFAULT_BG
);
489 rb
->lcd_set_foreground( LCD_RGBPACK( 0, 0, 0));
491 rb
->lcd_set_foreground(0);
495 maze_generate(&maze
);
497 maze_draw(&maze
, rb
->screens
[i
]);
500 #ifdef __PLUGINLIB_ACTIONS_H__
501 button
= pluginlib_getaction(rb
, TIMEOUT_BLOCK
, plugin_contexts
, 2);
503 button
= rb
->button_get(true);
508 if(lastbutton
!= MAZE_NEW_PRE
)
512 maze_generate(&maze
);
514 maze_draw(&maze
, rb
->screens
[i
]);
519 maze_draw(&maze
, rb
->screens
[i
]);
523 maze_move_player_right(&maze
);
525 maze_draw(&maze
, rb
->screens
[i
]);
529 maze_move_player_left(&maze
);
531 maze_draw(&maze
, rb
->screens
[i
]);
535 maze_move_player_up(&maze
);
537 maze_draw(&maze
, rb
->screens
[i
]);
541 maze_move_player_down(&maze
);
543 maze_draw(&maze
, rb
->screens
[i
]);
550 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
) {
556 if( button
!= BUTTON_NONE
)
559 rb
->yield(); /* BUG alert: always yielding causes data abort */
561 /* Turn on backlight timeout (revert to settings) */
562 backlight_use_settings(rb
); /* backlight control in lib/helper.c */
563 return ((quit
== 1) ? PLUGIN_OK
: PLUGIN_USB_CONNECTED
);