1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Matthias Wientapper
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 ****************************************************************************/
23 /* This is the implementation of a maze generation algorithm.
24 * The generated mazes are "perfect", i.e. there is one and only
25 * one path from any point in the maze to any other point.
28 * The implemented algorithm is called "Depth-First search", the
29 * solving is done by a dead-end filler routine.
34 #include "pluginlib_actions.h"
39 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
40 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
41 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
42 # undef __PLUGINLIB_ACTIONS_H__
43 # define MAZE_NEW (BUTTON_SELECT | BUTTON_REPEAT)
44 # define MAZE_NEW_PRE BUTTON_SELECT
45 # define MAZE_QUIT (BUTTON_SELECT | BUTTON_MENU)
46 # define MAZE_SOLVE (BUTTON_SELECT | BUTTON_PLAY)
47 # define MAZE_RIGHT BUTTON_RIGHT
48 # define MAZE_LEFT BUTTON_LEFT
49 # define MAZE_UP BUTTON_MENU
50 # define MAZE_DOWN BUTTON_PLAY
51 # define MAZE_RRIGHT (BUTTON_RIGHT | BUTTON_REPEAT)
52 # define MAZE_RLEFT (BUTTON_LEFT | BUTTON_REPEAT)
53 # define MAZE_RUP (BUTTON_MENU | BUTTON_REPEAT)
54 # define MAZE_RDOWN (BUTTON_PLAY | BUTTON_REPEAT)
57 # define MAZE_NEW PLA_START
58 # define MAZE_QUIT PLA_QUIT
59 # define MAZE_SOLVE PLA_FIRE
60 # define MAZE_RIGHT PLA_RIGHT
61 # define MAZE_LEFT PLA_LEFT
62 # define MAZE_UP PLA_UP
63 # define MAZE_DOWN PLA_DOWN
64 # define MAZE_RRIGHT PLA_RIGHT_REPEAT
65 # define MAZE_RLEFT PLA_LEFT_REPEAT
66 # define MAZE_RUP PLA_UP_REPEAT
67 # define MAZE_RDOWN PLA_DOWN_REPEAT
71 /* propertie bits of the cell */
72 #define WALL_N 0x00000001
73 #define WALL_E 0x00000002
74 #define WALL_S 0x00000004
75 #define WALL_W 0x00000008
76 #define WALL_ALL 0x0000000F
78 #define BORDER_N 0x00000010
79 #define BORDER_E 0x00000020
80 #define BORDER_S 0x00000040
81 #define BORDER_W 0x00000080
82 #define PATH 0x00000100
84 static const struct plugin_api
* rb
;
86 #ifdef __PLUGINLIB_ACTIONS_H__
87 const struct button_mapping
*plugin_contexts
[]
88 = {generic_directions
, generic_actions
};
91 #if ( LCD_WIDTH == 112 )
93 #define MAZE_HEIGHT 12
94 #elif( LCD_WIDTH == 132 )
96 #define MAZE_HEIGHT 16
99 #define MAZE_HEIGHT 24
104 int data
[MAZE_WIDTH
*MAZE_HEIGHT
];
108 void coord_stack_init(struct coord_stack
* stack
)
113 void coord_stack_push(struct coord_stack
* stack
, int x
, int y
)
115 stack
->data
[stack
->stp
] = ((x
<<8)|y
);
119 void coord_stack_get(struct coord_stack
* stack
, int index
, int* x
, int* y
)
121 *y
= stack
->data
[index
];
123 *x
= (stack
->data
[index
])>>8;
126 void coord_stack_pop(struct coord_stack
* stack
, int* x
, int* y
)
129 coord_stack_get(stack
, stack
->stp
, x
, y
);
132 int coord_stack_count(struct coord_stack
* stack
)
142 unsigned short maze
[MAZE_WIDTH
][MAZE_HEIGHT
];
145 void maze_init(struct maze
* maze
)
148 rb
->memset(maze
->maze
, 0, sizeof(maze
->maze
));
149 maze
->solved
= false;
153 for(y
=0; y
<MAZE_HEIGHT
; y
++){
154 for(x
=0; x
<MAZE_WIDTH
; x
++){
156 /* all walls are up */
157 maze
->maze
[x
][y
] |= WALL_ALL
| PATH
;
161 maze
->maze
[x
][y
]|= BORDER_W
;
163 maze
->maze
[x
][y
]|= BORDER_N
;
164 if(x
== MAZE_WIDTH
-1)
165 maze
->maze
[x
][y
]|= BORDER_E
;
166 if(y
== MAZE_HEIGHT
-1)
167 maze
->maze
[x
][y
]|= BORDER_S
;
172 void maze_draw(struct maze
* maze
, struct screen
* display
)
176 int point_width
, point_height
, point_offset_x
, point_offset_y
;
179 wx
= (int) display
->getwidth() / MAZE_WIDTH
;
180 wy
= (int) display
->getheight() / MAZE_HEIGHT
;
198 display
->clear_display();
200 for(y
=0; y
<MAZE_HEIGHT
; y
++){
201 for(x
=0; x
<MAZE_WIDTH
; x
++){
203 cell
= maze
->maze
[x
][y
];
207 display
->hline(x
*wx
, x
*wx
+wx
, y
*wy
);
209 display
->vline(x
*wx
+wx
, y
*wy
, y
*wy
+wy
);
211 display
->hline(x
*wx
, x
*wx
+wx
, y
*wy
+wy
);
213 display
->vline(x
*wx
, y
*wy
, y
*wy
+wy
);
216 display
->hline(x
*wx
, x
*wx
+wx
, y
*wy
);
218 display
->vline(x
*wx
+wx
, y
*wy
, y
*wy
+wy
);
220 display
->hline(x
*wx
, x
*wx
+wx
, y
*wy
+wy
);
222 display
->vline(x
*wx
, y
*wy
, y
*wy
+wy
);
227 if(display
->depth
>=16)
228 display
->set_foreground(LCD_RGBPACK(127,127,127));
231 if(display
->depth
==2)
232 display
->set_foreground(1);
234 for(y
=0; y
<MAZE_HEIGHT
; y
++){
235 for(x
=0; x
<MAZE_WIDTH
; x
++){
236 cell
= maze
->maze
[x
][y
];
238 display
->fillrect(x
*wx
+point_offset_x
,
240 point_width
, point_height
);
244 if(display
->depth
>=16)
245 display
->set_foreground(LCD_RGBPACK(0,0,0));
248 if(display
->depth
==2)
249 display
->set_foreground(0);
253 /* mark start and end */
254 display
->drawline(0, 0, wx
, wy
);
255 display
->drawline(0, wy
, wx
, 0);
256 display
->drawline((MAZE_WIDTH
-1)*wx
,(MAZE_HEIGHT
-1)*wy
,
257 (MAZE_WIDTH
-1)*wx
+wx
, (MAZE_HEIGHT
-1)*wy
+wy
);
258 display
->drawline((MAZE_WIDTH
-1)*wx
,(MAZE_HEIGHT
-1)*wy
+wy
,
259 (MAZE_WIDTH
-1)*wx
+wx
, (MAZE_HEIGHT
-1)*wy
);
262 /* draw current position */
263 display
->fillrect(maze
->player_x
*wx
+point_offset_x
,
264 maze
->player_y
*wy
+point_offset_y
,
265 point_width
, point_height
);
271 int maze_pick_random_neighbour_cell_with_walls(struct maze
* maze
,
272 int x
, int y
, int *pnx
, int *pny
)
276 struct coord_stack neighbours
;
277 unsigned short current_cell
=maze
->maze
[x
][y
];
279 coord_stack_init(&neighbours
);
280 /* look for neighbour cells with walls */
283 if(!(current_cell
& BORDER_N
)){
284 if((maze
->maze
[x
][y
-1] & WALL_ALL
) == WALL_ALL
){
285 coord_stack_push(&neighbours
, x
, y
-1);
290 if(!(current_cell
& BORDER_W
)){
291 if((maze
->maze
[x
-1][y
] & WALL_ALL
) == WALL_ALL
){
292 coord_stack_push(&neighbours
, x
-1, y
);
297 if(!(current_cell
& BORDER_E
)){
298 if((maze
->maze
[x
+1][y
] & WALL_ALL
) == WALL_ALL
){
299 coord_stack_push(&neighbours
, x
+1, y
);
304 if(!(current_cell
& BORDER_S
)){
305 if((maze
->maze
[x
][y
+1] & WALL_ALL
) == WALL_ALL
){
306 coord_stack_push(&neighbours
, x
, y
+1);
310 /* randomly select neighbour cell with walls */
311 ncount
=coord_stack_count(&neighbours
);
313 coord_stack_get(&neighbours
, rb
->rand()%ncount
, pnx
, pny
);
317 /* Removes the wall between the cell (x,y) and the cell (nx,ny) */
318 void maze_remove_wall(struct maze
* maze
, int x
, int y
, int nx
, int ny
)
320 /* where is our neighbour? */
326 maze
->maze
[x
][y
] &= ~WALL_S
;
327 maze
->maze
[nx
][ny
] &= ~WALL_N
;
330 maze
->maze
[x
][y
] &= ~WALL_N
;
331 maze
->maze
[nx
][ny
] &= ~WALL_S
;
338 maze
->maze
[x
][y
] &= ~WALL_E
;
339 maze
->maze
[nx
][ny
] &= ~WALL_W
;
342 maze
->maze
[x
][y
] &= ~WALL_W
;
343 maze
->maze
[nx
][ny
] &= ~WALL_E
;
349 void maze_generate(struct maze
* maze
)
351 int total_cells
= MAZE_WIDTH
* MAZE_HEIGHT
;
353 int available_neighbours
;
357 struct coord_stack done_cells
;
359 coord_stack_init(&done_cells
);
361 x
= rb
->rand()%MAZE_WIDTH
;
362 y
= rb
->rand()%MAZE_HEIGHT
;
365 while (visited_cells
< total_cells
){
366 available_neighbours
=
367 maze_pick_random_neighbour_cell_with_walls(maze
, x
, y
, &nx
, &ny
);
368 if(available_neighbours
== 0){
370 coord_stack_pop(&done_cells
, &x
, &y
);
372 maze_remove_wall(maze
, x
, y
, nx
, ny
);
374 /* save position on the stack */
375 coord_stack_push(&done_cells
, x
, y
);
377 /* current cell = neighbour cell */
387 void maze_solve(struct maze
* maze
)
393 unsigned short solved_maze
[MAZE_WIDTH
][MAZE_HEIGHT
];
395 maze
->solved
= ~(maze
->solved
);
397 /* copy maze for solving */
398 rb
->memcpy(solved_maze
, maze
->maze
,
399 (MAZE_HEIGHT
*MAZE_WIDTH
*sizeof(maze
->maze
[0][0])));
402 /* remove some borders and walls on start and end point */
403 solved_maze
[0][0] &= ~(WALL_N
|BORDER_N
);
404 solved_maze
[MAZE_WIDTH
-1][MAZE_HEIGHT
-1] &= ~(WALL_S
|BORDER_S
);
408 /* scan for dead ends */
409 for(y
=0; y
<MAZE_HEIGHT
; y
++){
411 for(x
=0; x
<MAZE_WIDTH
; x
++){
412 cell
= solved_maze
[x
][y
];
418 /* found dead end, clear path bit and fill it up */
419 maze
->maze
[x
][y
] &= ~PATH
;
420 solved_maze
[x
][y
] |= WALL_ALL
;
421 /* don't forget the neighbours */
422 if(!(cell
& BORDER_N
))
423 solved_maze
[x
][y
-1]|=WALL_S
;
424 if(!(cell
& BORDER_E
))
425 solved_maze
[x
+1][y
]|=WALL_W
;
426 if(!(cell
& BORDER_S
))
427 solved_maze
[x
][y
+1]|=WALL_N
;
428 if(!(cell
& BORDER_W
))
429 solved_maze
[x
-1][y
]|=WALL_E
;
437 void maze_move_player_down(struct maze
* maze
)
439 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
440 if( !(cell
& WALL_S
) &&
446 void maze_move_player_up(struct maze
* maze
)
448 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
449 if( !(cell
& WALL_N
) &&
455 void maze_move_player_left(struct maze
* maze
)
457 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
458 if( !(cell
& WALL_W
) &&
464 void maze_move_player_right(struct maze
* maze
)
466 unsigned short cell
=maze
->maze
[maze
->player_x
][maze
->player_y
];
467 if( !(cell
& WALL_E
) &&
472 /**********************************/
473 /* this is the plugin entry point */
474 /**********************************/
475 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
)
477 int button
, lastbutton
= BUTTON_NONE
;
484 /* Turn off backlight timeout */
485 backlight_force_on(rb
); /* backlight control in lib/helper.c */
488 rb
->lcd_set_backdrop(NULL
);
490 rb
->lcd_set_foreground( LCD_RGBPACK( 0, 0, 0));
491 rb
->lcd_set_background(LCD_RGBPACK(182, 198, 229)); /* rockbox blue */
493 rb
->lcd_set_foreground(0);
494 rb
->lcd_set_background(LCD_DEFAULT_BG
);
498 maze_generate(&maze
);
500 maze_draw(&maze
, rb
->screens
[i
]);
503 #ifdef __PLUGINLIB_ACTIONS_H__
504 button
= pluginlib_getaction(rb
, TIMEOUT_BLOCK
, plugin_contexts
, 2);
506 button
= rb
->button_get(true);
511 if(lastbutton
!= MAZE_NEW_PRE
)
515 maze_generate(&maze
);
517 maze_draw(&maze
, rb
->screens
[i
]);
522 maze_draw(&maze
, rb
->screens
[i
]);
526 maze_move_player_right(&maze
);
528 maze_draw(&maze
, rb
->screens
[i
]);
532 maze_move_player_left(&maze
);
534 maze_draw(&maze
, rb
->screens
[i
]);
538 maze_move_player_up(&maze
);
540 maze_draw(&maze
, rb
->screens
[i
]);
544 maze_move_player_down(&maze
);
546 maze_draw(&maze
, rb
->screens
[i
]);
553 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
) {
559 if( button
!= BUTTON_NONE
)
562 rb
->yield(); /* BUG alert: always yielding causes data abort */
564 /* Turn on backlight timeout (revert to settings) */
565 backlight_use_settings(rb
); /* backlight control in lib/helper.c */
566 return ((quit
== 1) ? PLUGIN_OK
: PLUGIN_USB_CONNECTED
);