/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2004 dionoea (Antoine Cellerier) * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ /***************************************************************************** Mine Sweeper by dionoea use arrow keys to move cursor use ON or F2 to clear a tile use PLAY or F1 to put a flag on a tile use F3 to see how many mines are left (supposing all your flags are correct) *****************************************************************************/ #include "plugin.h" #include "button.h" #include "lcd.h" #ifdef HAVE_LCD_BITMAP //what the minesweeper() function can return #define MINESWEEPER_USB 3 #define MINESWEEPER_QUIT 2 #define MINESWEEPER_LOSE 1 #define MINESWEEPER_WIN 0 /* variable button definitions */ #if CONFIG_KEYPAD == RECORDER_PAD #define MINESWP_UP BUTTON_UP #define MINESWP_DOWN BUTTON_DOWN #define MINESWP_QUIT BUTTON_OFF #define MINESWP_START BUTTON_ON #define MINESWP_TOGGLE BUTTON_PLAY #define MINESWP_TOGGLE2 BUTTON_F1 #define MINESWP_DISCOVER BUTTON_ON #define MINESWP_DISCOVER2 BUTTON_F2 #define MINESWP_INFO BUTTON_F3 #elif CONFIG_KEYPAD == ONDIO_PAD #define MINESWP_UP BUTTON_UP #define MINESWP_DOWN BUTTON_DOWN #define MINESWP_QUIT BUTTON_OFF #define MINESWP_START BUTTON_MENU #define MINESWP_TOGGLE_PRE BUTTON_MENU #define MINESWP_TOGGLE (BUTTON_MENU | BUTTON_REL) #define MINESWP_DISCOVER (BUTTON_MENU | BUTTON_REPEAT) #define MINESWP_INFO (BUTTON_MENU | BUTTON_OFF) #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ (CONFIG_KEYPAD == IRIVER_H300_PAD) #define MINESWP_UP BUTTON_UP #define MINESWP_DOWN BUTTON_DOWN #define MINESWP_QUIT BUTTON_OFF #define MINESWP_START BUTTON_SELECT #define MINESWP_TOGGLE BUTTON_SELECT #define MINESWP_DISCOVER BUTTON_ON #define MINESWP_INFO BUTTON_MODE #elif (CONFIG_KEYPAD == IPOD_4G_PAD) #define MINESWP_UP BUTTON_SCROLL_BACK #define MINESWP_DOWN BUTTON_SCROLL_FWD #define MINESWP_QUIT BUTTON_MENU #define MINESWP_START BUTTON_SELECT #define MINESWP_TOGGLE BUTTON_PLAY #define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_PLAY) #define MINESWP_INFO (BUTTON_SELECT | BUTTON_MENU) #endif /* here is a global api struct pointer. while not strictly necessary, it's nice not to have to pass the api pointer in all function calls in the plugin */ static struct plugin_api* rb; /* define how numbers are displayed (that way we don't have to */ /* worry about fonts) */ static unsigned char num[9][8] = { /*reading the sprites: on screen f123 4567 890a bcde in binary b84f c951 d062 ea73 */ /* 0 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x00, /* ........ */ 0x00, /* ........ */ 0x00, /* ........ */ 0x00, /* ........ */ 0x00, /* ........ */ 0x00},/* ........ */ /* 1 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x00, /* ...OO... */ 0x44, /* ....O... */ 0x7c, /* ....O... */ 0x40, /* ....O... */ 0x00, /* ...OOO.. */ 0x00},/* ........ */ /* 2 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x48, /* ...OO... */ 0x64, /* ..O..O.. */ 0x54, /* ....O... */ 0x48, /* ...O.... */ 0x00, /* ..OOOO.. */ 0x00},/* ........ */ /* 3 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x44, /* ..OOO... */ 0x54, /* .....O.. */ 0x54, /* ...OO... */ 0x28, /* .....O.. */ 0x00, /* ..OOO... */ 0x00},/* ........ */ /* 4 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x1c, /* ..O..... */ 0x10, /* ..O..... */ 0x70, /* ..OOOO.. */ 0x10, /* ....O... */ 0x00, /* ....O... */ 0x00},/* ........ */ /* 5 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x5c, /* ..OOOO.. */ 0x54, /* ..O..... */ 0x54, /* ..OOO... */ 0x24, /* .....O.. */ 0x00, /* ..OOO... */ 0x00},/* ........ */ /* 6 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x38, /* ...OOO.. */ 0x54, /* ..O..... */ 0x54, /* ..OOO... */ 0x24, /* ..O..O.. */ 0x00, /* ...OO... */ 0x00},/* ........ */ /* 7 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x44, /* ..OOOO.. */ 0x24, /* .....O.. */ 0x14, /* ....O... */ 0x0c, /* ...O.... */ 0x00, /* ..O..... */ 0x00},/* ........ */ /* 8 */ {0x00, /* ........ */ 0x00, /* ........ */ 0x28, /* ...OO... */ 0x54, /* ..O..O.. */ 0x54, /* ...OO... */ 0x28, /* ..O..O.. */ 0x00, /* ...OO... */ 0x00},/* ........ */ }; /* the tile struct if there is a mine, mine is true if tile is known by player, known is true if tile has a flag, flag is true neighbors is the total number of mines arround tile */ typedef struct tile { unsigned char mine : 1; unsigned char known : 1; unsigned char flag : 1; unsigned char neighbors : 4; } tile; /* the height and width of the field */ int height = LCD_HEIGHT/8; int width = LCD_WIDTH/8; /* the minefield */ tile minefield[LCD_HEIGHT/8][LCD_WIDTH/8]; /* total number of mines on the game */ int mine_num = 0; /* discovers the tile when player clears one of them */ /* a chain reaction (of discovery) occurs if tile has no mines */ /* as neighbors */ void discover(int, int); void discover(int x, int y){ if(x<0) return; if(y<0) return; if(x>width-1) return; if(y>height-1) return; if(minefield[y][x].known) return; minefield[y][x].known = 1; if(minefield[y][x].neighbors == 0){ discover(x-1,y-1); discover(x,y-1); discover(x+1,y-1); discover(x+1,y); discover(x+1,y+1); discover(x,y+1); discover(x-1,y+1); discover(x-1,y); } return; } /* init not mine related elements of the mine field */ void minesweeper_init(void){ int i,j; for(i=0;irand()%100

0){ if(j>0) minefield[i][j].neighbors += minefield[i-1][j-1].mine; minefield[i][j].neighbors += minefield[i-1][j].mine; if(j0) minefield[i][j].neighbors += minefield[i][j-1].mine; if(j0) minefield[i][j].neighbors += minefield[i+1][j-1].mine; minefield[i][j].neighbors += minefield[i+1][j].mine; if(jlcd_clear_display(); rb->lcd_puts(0,0,"Mine Sweeper"); rb->snprintf(str, 20, "%d%% mines", p); rb->lcd_puts(0,2,str); rb->lcd_puts(0,3,"down / up"); rb->snprintf(str, 20, "%d cols x %d rows", width, height); rb->lcd_puts(0,4,str); rb->lcd_puts(0,5,"left x right "); #if CONFIG_KEYPAD == RECORDER_PAD rb->lcd_puts(0,6,"ON to start"); #elif CONFIG_KEYPAD == ONDIO_PAD rb->lcd_puts(0,6,"MODE to start"); #elif CONFIG_KEYPAD == IRIVER_H100_PAD rb->lcd_puts(0,6,"SELECT to start"); #endif rb->lcd_update(); button = rb->button_get(true); switch(button){ case MINESWP_DOWN: p = (p + 98)%100; break; case MINESWP_UP: p = (p + 2)%100; break; case BUTTON_RIGHT: height = height%(LCD_HEIGHT/8)+1; break; case BUTTON_LEFT: width = width%(LCD_WIDTH/8)+1; break; case MINESWP_START:/* start playing */ i = 1; break; case MINESWP_QUIT:/* quit program */ return MINESWEEPER_QUIT; default: if (rb->default_event_handler(button) == SYS_USB_CONNECTED) return MINESWEEPER_USB; break; } if(i==1) break; } /******************** * init * ********************/ minesweeper_init(); /********************** * play * **********************/ while(true){ //clear the screen buffer rb->lcd_clear_display(); //display the mine field for(i=0;i 1 rb->lcd_set_foreground(LCD_DARKGRAY); rb->lcd_drawrect(j*8,i*8,8,8); rb->lcd_set_foreground(LCD_BLACK); #else rb->lcd_drawrect(j*8,i*8,8,8); #endif if(minefield[i][j].known){ if(minefield[i][j].mine){ rb->lcd_putsxy(j*8+1,i*8+1,"b"); } else if(minefield[i][j].neighbors){ rb->lcd_set_drawmode(DRMODE_FG); rb->lcd_mono_bitmap(num[minefield[i][j].neighbors],j*8,i*8,8,8); rb->lcd_set_drawmode(DRMODE_SOLID); } } else if(minefield[i][j].flag) { rb->lcd_drawline(j*8+2,i*8+2,j*8+5,i*8+5); rb->lcd_drawline(j*8+2,i*8+5,j*8+5,i*8+2); } else { #if LCD_DEPTH > 1 rb->lcd_set_foreground(LCD_LIGHTGRAY); rb->lcd_fillrect(j*8+1,i*8+1,6,6); rb->lcd_set_foreground(LCD_BLACK); #else rb->lcd_fillrect(j*8+2,i*8+2,4,4); #endif } } } /* display the cursor */ rb->lcd_set_drawmode(DRMODE_COMPLEMENT); rb->lcd_fillrect(x*8,y*8,8,8); rb->lcd_set_drawmode(DRMODE_SOLID); /* update the screen */ rb->lcd_update(); button = rb->button_get(true); switch(button){ /* quit minesweeper (you really shouldn't use this button ...) */ case MINESWP_QUIT: return MINESWEEPER_QUIT; /* move cursor left */ case BUTTON_LEFT: case (BUTTON_LEFT | BUTTON_REPEAT): x = (x + width - 1)%width; break; /* move cursor right */ case BUTTON_RIGHT: case (BUTTON_RIGHT | BUTTON_REPEAT): x = (x + 1)%width; break; /* move cursor down */ case MINESWP_DOWN: case (MINESWP_DOWN | BUTTON_REPEAT): y = (y + 1)%height; break; /* move cursor up */ case MINESWP_UP: case (MINESWP_UP | BUTTON_REPEAT): y = (y + height - 1)%height; break; /* discover a tile (and it's neighbors if .neighbors == 0) */ case MINESWP_DISCOVER: #ifdef MINESWP_DISCOVER2 case MINESWP_DISCOVER2: #endif if(minefield[y][x].flag) break; /* we put the mines on the first "click" so that you don't */ /* lose on the first "click" */ if(tiles_left == width*height) minesweeper_putmines(p,x,y); discover(x,y); if(minefield[y][x].mine){ return MINESWEEPER_LOSE; } tiles_left = 0; for(i=0;isplash(HZ*2, true, "You found %d mines out of %d", tiles_left, mine_num); break; default: if (rb->default_event_handler(button) == SYS_USB_CONNECTED) return MINESWEEPER_USB; break; } if (button != BUTTON_NONE) lastbutton = button; } } /* plugin entry point */ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { bool exit = false; /* plugin init */ TEST_PLUGIN_API(api); (void)parameter; rb = api; /* end of plugin init */ while(!exit) { switch(minesweeper()){ case MINESWEEPER_WIN: rb->splash(HZ*2, true, "You Win :)"); break; case MINESWEEPER_LOSE: rb->splash(HZ*2, true, "You Lost :("); break; case MINESWEEPER_USB: return PLUGIN_USB_CONNECTED; case MINESWEEPER_QUIT: exit = true; break; default: break; } } return PLUGIN_OK; } #endif