2007-06-28 21:13:04 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2007 Matthias Wientapper
|
|
|
|
*
|
2008-06-28 18:10:04 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2007-06-28 21:13:04 +00:00
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the implementation of a maze generation algorithm.
|
|
|
|
* The generated mazes are "perfect", i.e. there is one and only
|
|
|
|
* one path from any point in the maze to any other point.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The implemented algorithm is called "Depth-First search", the
|
|
|
|
* solving is done by a dead-end filler routine.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "plugin.h"
|
2008-11-20 11:27:31 +00:00
|
|
|
#include "lib/helper.h"
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2010-08-24 14:30:46 +00:00
|
|
|
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* key assignments */
|
|
|
|
|
2010-05-20 17:41:28 +00:00
|
|
|
#if (CONFIG_KEYPAD == IPOD_3G_PAD)
|
|
|
|
# define MAZE_NEW (BUTTON_SELECT | BUTTON_REPEAT)
|
|
|
|
# define MAZE_NEW_PRE BUTTON_SELECT
|
|
|
|
# define MAZE_QUIT BUTTON_MENU
|
|
|
|
# define MAZE_SOLVE (BUTTON_SELECT | BUTTON_PLAY)
|
|
|
|
# define MAZE_RIGHT BUTTON_RIGHT
|
|
|
|
# define MAZE_RIGHT_REPEAT BUTTON_RIGHT|BUTTON_REPEAT
|
|
|
|
# define MAZE_LEFT BUTTON_LEFT
|
|
|
|
# define MAZE_LEFT_REPEAT BUTTON_LEFT|BUTTON_REPEAT
|
|
|
|
# define MAZE_UP BUTTON_SCROLL_BACK
|
|
|
|
# define MAZE_UP_REPEAT BUTTON_SCROLL_BACK|BUTTON_REPEAT
|
|
|
|
# define MAZE_DOWN BUTTON_SCROLL_FWD
|
|
|
|
# define MAZE_DOWN_REPEAT BUTTON_SCROLL_FWD|BUTTON_REPEAT
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2007-06-29 19:30:35 +00:00
|
|
|
#else
|
2008-11-20 11:27:31 +00:00
|
|
|
# include "lib/pluginlib_actions.h"
|
2010-05-20 17:41:28 +00:00
|
|
|
# define MAZE_NEW PLA_SELECT_REPEAT
|
|
|
|
# define MAZE_QUIT PLA_CANCEL
|
|
|
|
# define MAZE_SOLVE PLA_SELECT_REL
|
|
|
|
# define MAZE_RIGHT PLA_RIGHT
|
|
|
|
# define MAZE_RIGHT_REPEAT PLA_RIGHT_REPEAT
|
|
|
|
# define MAZE_LEFT PLA_LEFT
|
|
|
|
# define MAZE_LEFT_REPEAT PLA_LEFT_REPEAT
|
|
|
|
# define MAZE_UP PLA_UP
|
|
|
|
# define MAZE_UP_REPEAT PLA_UP_REPEAT
|
|
|
|
# define MAZE_DOWN PLA_DOWN
|
|
|
|
# define MAZE_DOWN_REPEAT PLA_DOWN_REPEAT
|
2008-07-15 13:49:07 +00:00
|
|
|
static const struct button_mapping *plugin_contexts[]
|
2010-05-20 17:41:28 +00:00
|
|
|
= {pla_main_ctx};
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2007-06-29 19:30:35 +00:00
|
|
|
#endif
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* cell property bits */
|
|
|
|
#define WALL_N 0x0001
|
|
|
|
#define WALL_E 0x0002
|
|
|
|
#define WALL_S 0x0004
|
|
|
|
#define WALL_W 0x0008
|
|
|
|
#define WALL_ALL (WALL_N | WALL_E | WALL_S | WALL_W)
|
|
|
|
#define PATH 0x0010
|
|
|
|
|
|
|
|
/* border tests */
|
|
|
|
#define BORDER_N(y) ((y) == 0)
|
|
|
|
#define BORDER_E(x) ((x) == MAZE_WIDTH-1)
|
|
|
|
#define BORDER_S(y) ((y) == MAZE_HEIGHT-1)
|
|
|
|
#define BORDER_W(x) ((x) == 0)
|
|
|
|
|
|
|
|
// we can and should change this to make square boxes
|
2007-06-28 21:13:04 +00:00
|
|
|
#if ( LCD_WIDTH == 112 )
|
|
|
|
#define MAZE_WIDTH 16
|
|
|
|
#define MAZE_HEIGHT 12
|
2007-09-20 10:49:48 +00:00
|
|
|
#elif( LCD_WIDTH == 132 )
|
|
|
|
#define MAZE_WIDTH 26
|
|
|
|
#define MAZE_HEIGHT 16
|
2007-06-28 21:13:04 +00:00
|
|
|
#else
|
|
|
|
#define MAZE_WIDTH 32
|
|
|
|
#define MAZE_HEIGHT 24
|
|
|
|
#endif
|
|
|
|
|
2007-08-31 21:53:32 +00:00
|
|
|
struct maze
|
|
|
|
{
|
2008-07-15 13:49:07 +00:00
|
|
|
int show_path;
|
2007-07-26 11:25:24 +00:00
|
|
|
int solved;
|
|
|
|
int player_x;
|
|
|
|
int player_y;
|
2008-07-15 13:49:07 +00:00
|
|
|
uint8_t maze[MAZE_WIDTH][MAZE_HEIGHT];
|
2007-07-26 11:25:24 +00:00
|
|
|
};
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_init(struct maze* maze)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2007-07-26 11:25:24 +00:00
|
|
|
int x, y;
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* initialize the properties */
|
|
|
|
maze->show_path = false;
|
2007-07-26 11:25:24 +00:00
|
|
|
maze->solved = false;
|
|
|
|
maze->player_x = 0;
|
|
|
|
maze->player_y = 0;
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* all walls are up */
|
2007-06-28 21:13:04 +00:00
|
|
|
for(y=0; y<MAZE_HEIGHT; y++){
|
|
|
|
for(x=0; x<MAZE_WIDTH; x++){
|
2008-07-15 13:49:07 +00:00
|
|
|
maze->maze[x][y] = WALL_ALL;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_draw(struct maze* maze, struct screen* display)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2007-06-28 21:13:04 +00:00
|
|
|
int x, y;
|
|
|
|
int wx, wy;
|
2007-07-26 11:25:24 +00:00
|
|
|
int point_width, point_height, point_offset_x, point_offset_y;
|
2008-07-15 13:49:07 +00:00
|
|
|
uint8_t cell;
|
|
|
|
|
|
|
|
/* calculate the size variables */
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-13 07:23:08 +00:00
|
|
|
wx = (int) display->lcdwidth / MAZE_WIDTH;
|
|
|
|
wy = (int) display->lcdheight / MAZE_HEIGHT;
|
2007-07-26 11:25:24 +00:00
|
|
|
|
|
|
|
if(wx>3){
|
|
|
|
point_width=wx-3;
|
|
|
|
point_offset_x=2;
|
|
|
|
}else{
|
|
|
|
point_width=1;
|
|
|
|
point_offset_x=1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(wy>3){
|
|
|
|
point_height=wy-3;
|
|
|
|
point_offset_y=2;
|
|
|
|
}else{
|
|
|
|
point_height=1;
|
|
|
|
point_offset_y=1;
|
|
|
|
}
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* start drawing */
|
|
|
|
|
2007-07-26 11:25:24 +00:00
|
|
|
display->clear_display();
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* draw the walls */
|
2007-06-28 21:13:04 +00:00
|
|
|
for(y=0; y<MAZE_HEIGHT; y++){
|
|
|
|
for(x=0; x<MAZE_WIDTH; x++){
|
2007-07-26 11:25:24 +00:00
|
|
|
cell = maze->maze[x][y];
|
2007-06-28 21:13:04 +00:00
|
|
|
if(cell & WALL_N)
|
2008-04-12 08:57:28 +00:00
|
|
|
display->hline(x*wx, x*wx+wx, y*wy);
|
2007-06-28 21:13:04 +00:00
|
|
|
if(cell & WALL_E)
|
2008-04-12 08:57:28 +00:00
|
|
|
display->vline(x*wx+wx, y*wy, y*wy+wy);
|
2007-06-28 21:13:04 +00:00
|
|
|
if(cell & WALL_S)
|
2008-04-12 08:57:28 +00:00
|
|
|
display->hline(x*wx, x*wx+wx, y*wy+wy);
|
2007-06-28 21:13:04 +00:00
|
|
|
if(cell & WALL_W)
|
2008-04-12 08:57:28 +00:00
|
|
|
display->vline(x*wx, y*wy, y*wy+wy);
|
2007-07-26 11:25:24 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* draw the path */
|
|
|
|
if(maze->show_path){
|
2007-07-26 11:59:36 +00:00
|
|
|
#if LCD_DEPTH >= 16
|
|
|
|
if(display->depth>=16)
|
|
|
|
display->set_foreground(LCD_RGBPACK(127,127,127));
|
|
|
|
#endif
|
|
|
|
#if LCD_DEPTH >= 2
|
|
|
|
if(display->depth==2)
|
|
|
|
display->set_foreground(1);
|
|
|
|
#endif
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* highlight the path */
|
2007-07-26 11:25:24 +00:00
|
|
|
for(y=0; y<MAZE_HEIGHT; y++){
|
|
|
|
for(x=0; x<MAZE_WIDTH; x++){
|
|
|
|
cell = maze->maze[x][y];
|
|
|
|
if(cell & PATH)
|
|
|
|
display->fillrect(x*wx+point_offset_x,
|
|
|
|
y*wy+point_offset_y,
|
|
|
|
point_width, point_height);
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* link the cells in the path together */
|
|
|
|
for(y=0; y<MAZE_HEIGHT; y++){
|
|
|
|
for(x=0; x<MAZE_WIDTH; x++){
|
|
|
|
cell = maze->maze[x][y];
|
|
|
|
if(cell & PATH){
|
|
|
|
if(!(cell & WALL_N) && (maze->maze[x][y-1] & PATH))
|
|
|
|
display->fillrect(x*wx+point_offset_x,
|
|
|
|
y*wy,
|
|
|
|
point_width, wy-point_height);
|
|
|
|
if(!(cell & WALL_E) && (maze->maze[x+1][y] & PATH))
|
|
|
|
display->fillrect(x*wx+wx-point_offset_x,
|
|
|
|
y*wy+point_offset_y,
|
|
|
|
wx-point_width, point_height);
|
|
|
|
if(!(cell & WALL_S) && (maze->maze[x][y+1] & PATH))
|
|
|
|
display->fillrect(x*wx+point_offset_x,
|
|
|
|
y*wy+wy-point_offset_y,
|
|
|
|
point_width, wy-point_height);
|
|
|
|
if(!(cell & WALL_W) && (maze->maze[x-1][y] & PATH))
|
|
|
|
display->fillrect(x*wx,
|
|
|
|
y*wy+point_offset_y,
|
|
|
|
wx-point_width, point_height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-26 11:59:36 +00:00
|
|
|
#if LCD_DEPTH >= 16
|
|
|
|
if(display->depth>=16)
|
|
|
|
display->set_foreground(LCD_RGBPACK(0,0,0));
|
2007-07-26 11:25:24 +00:00
|
|
|
#endif
|
2007-07-26 11:59:36 +00:00
|
|
|
#if LCD_DEPTH >= 2
|
|
|
|
if(display->depth==2)
|
|
|
|
display->set_foreground(0);
|
|
|
|
#endif
|
|
|
|
}
|
2007-06-28 21:13:04 +00:00
|
|
|
|
|
|
|
/* mark start and end */
|
2007-07-26 11:25:24 +00:00
|
|
|
display->drawline(0, 0, wx, wy);
|
|
|
|
display->drawline(0, wy, wx, 0);
|
|
|
|
display->drawline((MAZE_WIDTH-1)*wx,(MAZE_HEIGHT-1)*wy,
|
2007-06-28 21:13:04 +00:00
|
|
|
(MAZE_WIDTH-1)*wx+wx, (MAZE_HEIGHT-1)*wy+wy);
|
2007-07-26 11:25:24 +00:00
|
|
|
display->drawline((MAZE_WIDTH-1)*wx,(MAZE_HEIGHT-1)*wy+wy,
|
2007-06-28 21:13:04 +00:00
|
|
|
(MAZE_WIDTH-1)*wx+wx, (MAZE_HEIGHT-1)*wy);
|
|
|
|
|
|
|
|
/* draw current position */
|
2007-07-26 11:25:24 +00:00
|
|
|
display->fillrect(maze->player_x*wx+point_offset_x,
|
|
|
|
maze->player_y*wy+point_offset_y,
|
|
|
|
point_width, point_height);
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* update the display */
|
2007-07-26 11:25:24 +00:00
|
|
|
display->update();
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
struct coord_stack
|
|
|
|
{
|
|
|
|
uint8_t x[MAZE_WIDTH*MAZE_HEIGHT];
|
|
|
|
uint8_t y[MAZE_WIDTH*MAZE_HEIGHT];
|
|
|
|
int stp;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void coord_stack_init(struct coord_stack* stack)
|
|
|
|
{
|
|
|
|
rb->memset(stack->x, 0, sizeof(stack->x));
|
|
|
|
rb->memset(stack->y, 0, sizeof(stack->y));
|
|
|
|
stack->stp = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void coord_stack_push(struct coord_stack* stack, int x, int y)
|
|
|
|
{
|
|
|
|
stack->x[stack->stp] = x;
|
|
|
|
stack->y[stack->stp] = y;
|
|
|
|
stack->stp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void coord_stack_pop(struct coord_stack* stack, int* x, int* y)
|
|
|
|
{
|
|
|
|
stack->stp--;
|
|
|
|
*x = stack->x[stack->stp];
|
|
|
|
*y = stack->y[stack->stp];
|
|
|
|
}
|
|
|
|
|
|
|
|
static int maze_pick_random_neighbour_cell_with_walls(struct maze* maze,
|
2007-08-31 21:53:32 +00:00
|
|
|
int x, int y, int *pnx, int *pny)
|
|
|
|
{
|
2008-07-15 13:49:07 +00:00
|
|
|
int n, i;
|
|
|
|
int px[4], py[4];
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
n = 0;
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* look for neighbours with all walls set up */
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
if(!BORDER_N(y) && ((maze->maze[x][y-1] & WALL_ALL) == WALL_ALL)){
|
|
|
|
px[n] = x;
|
|
|
|
py[n] = y-1;
|
|
|
|
n++;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
if(!BORDER_E(x) && ((maze->maze[x+1][y] & WALL_ALL) == WALL_ALL)){
|
|
|
|
px[n] = x+1;
|
|
|
|
py[n] = y;
|
|
|
|
n++;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
if(!BORDER_S(y) && ((maze->maze[x][y+1] & WALL_ALL) == WALL_ALL)){
|
|
|
|
px[n] = x;
|
|
|
|
py[n] = y+1;
|
|
|
|
n++;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
if(!BORDER_W(x) && ((maze->maze[x-1][y] & WALL_ALL) == WALL_ALL)){
|
|
|
|
px[n] = x-1;
|
|
|
|
py[n] = y;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* then choose one */
|
|
|
|
if (n > 0){
|
|
|
|
i = rb->rand() % n;
|
|
|
|
*pnx = px[i];
|
|
|
|
*pny = py[i];
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
return n;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
|
2007-07-26 11:25:24 +00:00
|
|
|
/* Removes the wall between the cell (x,y) and the cell (nx,ny) */
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_remove_wall(struct maze* maze, int x, int y, int nx, int ny)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2007-06-28 21:13:04 +00:00
|
|
|
/* where is our neighbour? */
|
|
|
|
|
|
|
|
/* north or south */
|
2007-07-26 11:25:24 +00:00
|
|
|
if(x==nx){
|
|
|
|
if(y<ny){
|
2007-06-28 21:13:04 +00:00
|
|
|
/*south*/
|
2007-07-26 11:25:24 +00:00
|
|
|
maze->maze[x][y] &= ~WALL_S;
|
|
|
|
maze->maze[nx][ny] &= ~WALL_N;
|
2007-06-28 21:13:04 +00:00
|
|
|
} else {
|
|
|
|
/*north*/
|
2007-07-26 11:25:24 +00:00
|
|
|
maze->maze[x][y] &= ~WALL_N;
|
|
|
|
maze->maze[nx][ny] &= ~WALL_S;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* east or west */
|
2007-07-26 11:25:24 +00:00
|
|
|
if(y==ny){
|
|
|
|
if(x<nx){
|
2007-06-28 21:13:04 +00:00
|
|
|
/* east */
|
2007-07-26 11:25:24 +00:00
|
|
|
maze->maze[x][y] &= ~WALL_E;
|
|
|
|
maze->maze[nx][ny] &= ~WALL_W;
|
2007-06-28 21:13:04 +00:00
|
|
|
} else {
|
|
|
|
/*west*/
|
2007-07-26 11:25:24 +00:00
|
|
|
maze->maze[x][y] &= ~WALL_W;
|
|
|
|
maze->maze[nx][ny] &= ~WALL_E;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_generate(struct maze* maze)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2007-06-28 21:13:04 +00:00
|
|
|
int total_cells = MAZE_WIDTH * MAZE_HEIGHT;
|
|
|
|
int visited_cells;
|
2007-07-26 11:25:24 +00:00
|
|
|
int available_neighbours;
|
2007-06-28 21:13:04 +00:00
|
|
|
int x, y;
|
|
|
|
int nx = 0;
|
|
|
|
int ny = 0;
|
2007-07-26 11:25:24 +00:00
|
|
|
struct coord_stack done_cells;
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2007-07-26 11:25:24 +00:00
|
|
|
coord_stack_init(&done_cells);
|
2007-06-28 21:13:04 +00:00
|
|
|
|
|
|
|
x = rb->rand()%MAZE_WIDTH;
|
|
|
|
y = rb->rand()%MAZE_HEIGHT;
|
|
|
|
|
|
|
|
visited_cells = 1;
|
|
|
|
while (visited_cells < total_cells){
|
2007-07-26 11:25:24 +00:00
|
|
|
available_neighbours =
|
|
|
|
maze_pick_random_neighbour_cell_with_walls(maze, x, y, &nx, &ny);
|
|
|
|
if(available_neighbours == 0){
|
2007-06-28 21:13:04 +00:00
|
|
|
/* pop from stack */
|
2007-07-26 11:25:24 +00:00
|
|
|
coord_stack_pop(&done_cells, &x, &y);
|
2007-06-28 21:13:04 +00:00
|
|
|
} else {
|
2008-07-15 13:49:07 +00:00
|
|
|
/* remove the wall */
|
2007-07-26 11:25:24 +00:00
|
|
|
maze_remove_wall(maze, x, y, nx, ny);
|
2008-07-15 13:49:07 +00:00
|
|
|
/* save our position on the stack */
|
2007-07-26 11:25:24 +00:00
|
|
|
coord_stack_push(&done_cells, x, y);
|
2008-07-15 13:49:07 +00:00
|
|
|
/* move to the next cell */
|
2007-06-28 21:13:04 +00:00
|
|
|
x=nx;
|
|
|
|
y=ny;
|
2008-07-15 13:49:07 +00:00
|
|
|
/* keep track of visited cells count */
|
2007-06-28 21:13:04 +00:00
|
|
|
visited_cells++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_solve(struct maze* maze)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2007-06-28 21:13:04 +00:00
|
|
|
int x, y;
|
2007-08-31 21:53:32 +00:00
|
|
|
int dead_ends = 1;
|
2008-07-15 13:49:07 +00:00
|
|
|
uint8_t cell;
|
|
|
|
uint8_t wall;
|
|
|
|
uint8_t solved_maze[MAZE_WIDTH][MAZE_HEIGHT];
|
|
|
|
|
|
|
|
/* toggle the visibility of the path */
|
|
|
|
maze->show_path = ~(maze->show_path);
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* no need to solve the maze if already solved */
|
|
|
|
if (maze->solved)
|
|
|
|
return;
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* work on a copy of the maze */
|
|
|
|
rb->memcpy(solved_maze, maze->maze, sizeof(maze->maze));
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* remove walls on start and end point */
|
|
|
|
solved_maze[0][0] &= ~WALL_N;
|
|
|
|
solved_maze[MAZE_WIDTH-1][MAZE_HEIGHT-1] &= ~WALL_S;
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* first, mark all the cells as reachable */
|
|
|
|
for(y=0; y<MAZE_HEIGHT; y++){
|
|
|
|
for(x=0; x<MAZE_WIDTH; x++){
|
|
|
|
solved_maze[x][y] |= PATH;
|
|
|
|
}
|
|
|
|
}
|
2007-06-28 21:13:04 +00:00
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* start solving */
|
2007-06-28 21:13:04 +00:00
|
|
|
while(dead_ends){
|
2008-07-15 13:49:07 +00:00
|
|
|
/* solve by blocking off dead ends -- backward approach */
|
2007-06-28 21:13:04 +00:00
|
|
|
dead_ends = 0;
|
|
|
|
/* scan for dead ends */
|
|
|
|
for(y=0; y<MAZE_HEIGHT; y++){
|
|
|
|
rb->yield();
|
|
|
|
for(x=0; x<MAZE_WIDTH; x++){
|
|
|
|
cell = solved_maze[x][y];
|
2008-07-15 13:49:07 +00:00
|
|
|
wall = cell & WALL_ALL;
|
|
|
|
if((wall == (WALL_E | WALL_S | WALL_W)) ||
|
|
|
|
(wall == (WALL_N | WALL_S | WALL_W)) ||
|
|
|
|
(wall == (WALL_N | WALL_E | WALL_W)) ||
|
|
|
|
(wall == (WALL_N | WALL_E | WALL_S))){
|
|
|
|
/* found dead end, clear path bit and set all its walls */
|
|
|
|
solved_maze[x][y] &= ~PATH;
|
2007-06-28 21:13:04 +00:00
|
|
|
solved_maze[x][y] |= WALL_ALL;
|
|
|
|
/* don't forget the neighbours */
|
2008-07-15 13:49:07 +00:00
|
|
|
if(!BORDER_S(y))
|
|
|
|
solved_maze[x][y+1] |= WALL_N;
|
|
|
|
if(!BORDER_W(x))
|
|
|
|
solved_maze[x-1][y] |= WALL_E;
|
|
|
|
if(!BORDER_N(y))
|
|
|
|
solved_maze[x][y-1] |= WALL_S;
|
|
|
|
if(!BORDER_E(x))
|
|
|
|
solved_maze[x+1][y] |= WALL_W;
|
2007-06-28 21:13:04 +00:00
|
|
|
dead_ends++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
/* copy all the path bits to the maze */
|
|
|
|
for(y=0; y<MAZE_HEIGHT; y++){
|
|
|
|
for(x=0; x<MAZE_WIDTH; x++){
|
|
|
|
maze->maze[x][y] |= solved_maze[x][y] & PATH;
|
|
|
|
}
|
2007-07-26 11:25:24 +00:00
|
|
|
}
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* mark the maze as solved */
|
|
|
|
maze->solved = true;
|
2007-07-26 11:25:24 +00:00
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_move_player_up(struct maze* maze)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2008-07-15 13:49:07 +00:00
|
|
|
uint8_t cell = maze->maze[maze->player_x][maze->player_y];
|
|
|
|
if(!BORDER_N(maze->player_y) && !(cell & WALL_N))
|
2007-07-26 11:25:24 +00:00
|
|
|
maze->player_y--;
|
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_move_player_right(struct maze* maze)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2008-07-15 13:49:07 +00:00
|
|
|
uint8_t cell = maze->maze[maze->player_x][maze->player_y];
|
|
|
|
if(!BORDER_E(maze->player_x) && !(cell & WALL_E))
|
|
|
|
maze->player_x++;
|
2007-07-26 11:25:24 +00:00
|
|
|
}
|
|
|
|
|
2008-07-15 13:49:07 +00:00
|
|
|
static void maze_move_player_down(struct maze* maze)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2008-07-15 13:49:07 +00:00
|
|
|
uint8_t cell = maze->maze[maze->player_x][maze->player_y];
|
|
|
|
if(!BORDER_S(maze->player_y) && !(cell & WALL_S))
|
|
|
|
maze->player_y++;
|
2007-07-26 11:25:24 +00:00
|
|
|
}
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
static void maze_move_player_left(struct maze* maze)
|
|
|
|
{
|
|
|
|
uint8_t cell = maze->maze[maze->player_x][maze->player_y];
|
|
|
|
if(!BORDER_W(maze->player_x) && !(cell & WALL_W))
|
|
|
|
maze->player_x--;
|
|
|
|
}
|
|
|
|
|
2007-06-28 21:13:04 +00:00
|
|
|
/**********************************/
|
|
|
|
/* this is the plugin entry point */
|
|
|
|
/**********************************/
|
2009-01-16 10:34:40 +00:00
|
|
|
enum plugin_status plugin_start(const void* parameter)
|
2007-08-31 21:53:32 +00:00
|
|
|
{
|
2011-03-28 21:44:23 +00:00
|
|
|
int button;
|
|
|
|
#ifdef MAZE_NEW_PRE
|
|
|
|
int lastbutton = BUTTON_NONE;
|
|
|
|
#endif
|
2007-06-28 21:13:04 +00:00
|
|
|
int quit = 0;
|
2007-07-26 11:25:24 +00:00
|
|
|
int i;
|
|
|
|
struct maze maze;
|
2007-06-28 21:13:04 +00:00
|
|
|
(void)parameter;
|
|
|
|
|
2007-08-31 21:53:32 +00:00
|
|
|
/* Turn off backlight timeout */
|
2011-01-24 12:29:16 +00:00
|
|
|
backlight_ignore_timeout();
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* Seed the RNG */
|
|
|
|
rb->srand(*rb->current_tick);
|
|
|
|
|
2008-07-13 07:23:08 +00:00
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
rb->screens[i]->set_viewport(NULL);
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* Draw the background */
|
2007-06-28 21:13:04 +00:00
|
|
|
#if LCD_DEPTH > 1
|
|
|
|
rb->lcd_set_backdrop(NULL);
|
2007-07-26 11:59:36 +00:00
|
|
|
#if LCD_DEPTH >= 16
|
2008-07-15 13:49:07 +00:00
|
|
|
rb->lcd_set_foreground(LCD_RGBPACK( 0, 0, 0));
|
2008-05-05 17:14:45 +00:00
|
|
|
rb->lcd_set_background(LCD_RGBPACK(182, 198, 229)); /* rockbox blue */
|
2007-07-26 11:59:36 +00:00
|
|
|
#elif LCD_DEPTH == 2
|
|
|
|
rb->lcd_set_foreground(0);
|
2008-05-05 17:14:45 +00:00
|
|
|
rb->lcd_set_background(LCD_DEFAULT_BG);
|
2007-07-26 11:59:36 +00:00
|
|
|
#endif
|
2007-06-28 21:13:04 +00:00
|
|
|
#endif
|
2008-07-15 13:49:07 +00:00
|
|
|
|
|
|
|
/* Initialize and draw the maze */
|
2007-07-26 11:25:24 +00:00
|
|
|
maze_init(&maze);
|
|
|
|
maze_generate(&maze);
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
maze_draw(&maze, rb->screens[i]);
|
2007-06-28 21:13:04 +00:00
|
|
|
|
|
|
|
while(!quit) {
|
2007-06-29 19:30:35 +00:00
|
|
|
#ifdef __PLUGINLIB_ACTIONS_H__
|
2010-05-20 17:41:28 +00:00
|
|
|
button = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts,
|
|
|
|
ARRAYLEN(plugin_contexts));
|
2007-06-29 19:30:35 +00:00
|
|
|
#else
|
|
|
|
button = rb->button_get(true);
|
|
|
|
#endif
|
2007-06-28 21:13:04 +00:00
|
|
|
switch(button) {
|
|
|
|
case MAZE_NEW:
|
2007-06-29 19:30:35 +00:00
|
|
|
#ifdef MAZE_NEW_PRE
|
|
|
|
if(lastbutton != MAZE_NEW_PRE)
|
|
|
|
break;
|
|
|
|
#endif
|
2007-07-26 11:25:24 +00:00
|
|
|
maze_init(&maze);
|
|
|
|
maze_generate(&maze);
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
maze_draw(&maze, rb->screens[i]);
|
2007-06-28 21:13:04 +00:00
|
|
|
break;
|
|
|
|
case MAZE_SOLVE:
|
2007-07-26 11:25:24 +00:00
|
|
|
maze_solve(&maze);
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
maze_draw(&maze, rb->screens[i]);
|
2007-06-28 21:13:04 +00:00
|
|
|
break;
|
|
|
|
case MAZE_UP:
|
2010-05-20 17:41:28 +00:00
|
|
|
case MAZE_UP_REPEAT:
|
2007-07-26 11:25:24 +00:00
|
|
|
maze_move_player_up(&maze);
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
maze_draw(&maze, rb->screens[i]);
|
2007-06-28 21:13:04 +00:00
|
|
|
break;
|
2008-07-15 13:49:07 +00:00
|
|
|
case MAZE_RIGHT:
|
2010-05-20 17:41:28 +00:00
|
|
|
case MAZE_RIGHT_REPEAT:
|
2008-07-15 13:49:07 +00:00
|
|
|
maze_move_player_right(&maze);
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
maze_draw(&maze, rb->screens[i]);
|
|
|
|
break;
|
2007-06-28 21:13:04 +00:00
|
|
|
case MAZE_DOWN:
|
2010-05-20 17:41:28 +00:00
|
|
|
case MAZE_DOWN_REPEAT:
|
2007-07-26 11:25:24 +00:00
|
|
|
maze_move_player_down(&maze);
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
maze_draw(&maze, rb->screens[i]);
|
2007-06-28 21:13:04 +00:00
|
|
|
break;
|
2008-07-15 13:49:07 +00:00
|
|
|
case MAZE_LEFT:
|
2010-05-20 17:41:28 +00:00
|
|
|
case MAZE_LEFT_REPEAT:
|
2008-07-15 13:49:07 +00:00
|
|
|
maze_move_player_left(&maze);
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
maze_draw(&maze, rb->screens[i]);
|
|
|
|
break;
|
2007-06-28 21:13:04 +00:00
|
|
|
case MAZE_QUIT:
|
|
|
|
/* quit plugin */
|
2007-08-31 21:53:32 +00:00
|
|
|
quit=1;
|
2007-06-28 21:13:04 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
|
2007-08-31 21:53:32 +00:00
|
|
|
/* quit plugin */
|
|
|
|
quit=2;
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2011-03-28 21:44:23 +00:00
|
|
|
#ifdef MAZE_NEW_PRE
|
2007-06-29 19:30:35 +00:00
|
|
|
if( button != BUTTON_NONE )
|
|
|
|
lastbutton = button;
|
2011-03-28 21:44:23 +00:00
|
|
|
#endif
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|
2007-08-31 21:53:32 +00:00
|
|
|
/* Turn on backlight timeout (revert to settings) */
|
2011-01-24 12:29:16 +00:00
|
|
|
backlight_use_settings();
|
2007-08-31 21:53:32 +00:00
|
|
|
return ((quit == 1) ? PLUGIN_OK : PLUGIN_USB_CONNECTED);
|
2007-06-28 21:13:04 +00:00
|
|
|
}
|