/*************************************************************************** * __________ __ ___. * 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" #ifdef HAVE_LCD_BITMAP PLUGIN_HEADER /*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) || \ (CONFIG_KEYPAD == IPOD_3G_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) #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) #define MINESWP_UP BUTTON_UP #define MINESWP_DOWN BUTTON_DOWN #define MINESWP_QUIT BUTTON_POWER #define MINESWP_START BUTTON_REC #define MINESWP_TOGGLE BUTTON_PLAY #define MINESWP_DISCOVER BUTTON_SELECT #define MINESWP_INFO (BUTTON_REC | BUTTON_PLAY) #elif (CONFIG_KEYPAD == GIGABEAT_PAD) #define MINESWP_UP BUTTON_UP #define MINESWP_DOWN BUTTON_DOWN #define MINESWP_QUIT BUTTON_A #define MINESWP_START BUTTON_SELECT #define MINESWP_TOGGLE BUTTON_SELECT #define MINESWP_DISCOVER BUTTON_POWER #define MINESWP_INFO 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 */ (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 Lose :("); break; case MINESWEEPER_USB: return PLUGIN_USB_CONNECTED; case MINESWEEPER_QUIT: exit = true; break; default: break; } } return PLUGIN_OK; } #endif an class="hl opt">= 0; ((t_object *)x)->ob_outlet = 0; } return (x); } void pd_free(t_pd *x) { t_class *c = *x; if (c->c_freemethod) (*(t_gotfn)(c->c_freemethod))(x); if (c->c_patchable) { while (((t_object *)x)->ob_outlet) outlet_free(((t_object *)x)->ob_outlet); while (((t_object *)x)->ob_inlet) inlet_free(((t_object *)x)->ob_inlet); if (((t_object *)x)->ob_binbuf) binbuf_free(((t_object *)x)->ob_binbuf); } if (c->c_size) t_freebytes(x, c->c_size); } void gobj_save(t_gobj *x, t_binbuf *b) { t_class *c = x->g_pd; if (c->c_savefn) (c->c_savefn)(x, b); } /* deal with several objects bound to the same symbol. If more than one, we actually bind a collection object to the symbol, which forwards messages sent to the symbol. */ static t_class *bindlist_class; typedef struct _bindelem { t_pd *e_who; struct _bindelem *e_next; } t_bindelem; typedef struct _bindlist { t_pd b_pd; t_bindelem *b_list; } t_bindlist; static void bindlist_bang(t_bindlist *x) { t_bindelem *e; for (e = x->b_list; e; e = e->e_next) pd_bang(e->e_who); } static void bindlist_float(t_bindlist *x, t_float f) { t_bindelem *e; for (e = x->b_list; e; e = e->e_next) { pd_float(e->e_who, f); } } static void bindlist_symbol(t_bindlist *x, t_symbol *s) { t_bindelem *e; for (e = x->b_list; e; e = e->e_next) pd_symbol(e->e_who, s); } static void bindlist_pointer(t_bindlist *x, t_gpointer *gp) { t_bindelem *e; for (e = x->b_list; e; e = e->e_next) pd_pointer(e->e_who, gp); } static void bindlist_list(t_bindlist *x, t_symbol *s, int argc, t_atom *argv) { t_bindelem *e; for (e = x->b_list; e; e = e->e_next) pd_list(e->e_who, s, argc, argv); } static void bindlist_anything(t_bindlist *x, t_symbol *s, int argc, t_atom *argv) { t_bindelem *e; for (e = x->b_list; e; e = e->e_next) pd_typedmess(e->e_who, s, argc, argv); } void m_pd_setup(void) { bindlist_class = class_new(gensym("bindlist"), 0, 0, sizeof(t_bindlist), CLASS_PD, 0); class_addbang(bindlist_class, bindlist_bang); class_addfloat(bindlist_class, (t_method)bindlist_float); class_addsymbol(bindlist_class, bindlist_symbol); class_addpointer(bindlist_class, bindlist_pointer); class_addlist(bindlist_class, bindlist_list); class_addanything(bindlist_class, bindlist_anything); } void pd_bind(t_pd *x, t_symbol *s) { pd_checkgui(x,s); if (s->s_thing) { if (*s->s_thing == bindlist_class) { t_bindlist *b = (t_bindlist *)s->s_thing; t_bindelem *e = (t_bindelem *)getbytes(sizeof(t_bindelem)); e->e_next = b->b_list; e->e_who = x; b->b_list = e; } else { t_bindlist *b = (t_bindlist *)pd_new(bindlist_class); t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem)); t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem)); b->b_list = e1; e1->e_who = x; e1->e_next = e2; e2->e_who = s->s_thing; e2->e_next = 0; s->s_thing = &b->b_pd; } } else s->s_thing = x; } void pd_unbind(t_pd *x, t_symbol *s) { if (s->s_thing == x) s->s_thing = 0; else if (s->s_thing && *s->s_thing == bindlist_class) { /* bindlists always have at least two elements... if the number goes down to one, get rid of the bindlist and bind the symbol straight to the remaining element. */ t_bindlist *b = (t_bindlist *)s->s_thing; t_bindelem *e, *e2; if ((e = b->b_list)->e_who == x) { b->b_list = e->e_next; freebytes(e, sizeof(t_bindelem)); } else for (e = b->b_list; (e2 = e->e_next); e = e2) if (e2->e_who == x) { e->e_next = e2->e_next; freebytes(e2, sizeof(t_bindelem)); break; } if (!b->b_list->e_next) { s->s_thing = b->b_list->e_who; freebytes(b->b_list, sizeof(t_bindelem)); pd_free(&b->b_pd); } } else pd_error(x, "%s: couldn't unbind", s->s_name); } void zz(void) {} t_pd *pd_findbyclass(t_symbol *s, t_class *c) { t_pd *x = 0; if (!s->s_thing) return (0); if (*s->s_thing == c) return (s->s_thing); if (*s->s_thing == bindlist_class) { t_bindlist *b = (t_bindlist *)s->s_thing; #ifdef ROCKBOX t_bindelem *e; #else /* ROCKBOX */ t_bindelem *e, *e2; #endif /* ROCKBOX */ int warned = 0; for (e = b->b_list; e; e = e->e_next) if (*e->e_who == c) { if (x && !warned) { zz(); post("warning: %s: multiply defined", s->s_name); warned = 1; } x = e->e_who; } } return x; } /* stack for maintaining bindings for the #X symbol during nestable loads. */ typedef struct _gstack { t_pd *g_what; t_symbol *g_loadingabstraction; struct _gstack *g_next; } t_gstack; static t_gstack *gstack_head = 0; static t_pd *lastpopped; static t_symbol *pd_loadingabstraction; int pd_setloadingabstraction(t_symbol *sym) { t_gstack *foo = gstack_head; for (foo = gstack_head; foo; foo = foo->g_next) if (foo->g_loadingabstraction == sym) return (1); pd_loadingabstraction = sym; return (0); } void pd_pushsym(t_pd *x) { t_gstack *y = (t_gstack *)t_getbytes(sizeof(*y)); y->g_what = s__X.s_thing; y->g_next = gstack_head; y->g_loadingabstraction = pd_loadingabstraction; pd_loadingabstraction = 0; gstack_head = y; s__X.s_thing = x; } void pd_popsym(t_pd *x) { if (!gstack_head || s__X.s_thing != x) bug("gstack_pop"); else { t_gstack *headwas = gstack_head; s__X.s_thing = headwas->g_what; gstack_head = headwas->g_next; t_freebytes(headwas, sizeof(*headwas)); lastpopped = x; } } void pd_doloadbang(void) { if (lastpopped) pd_vmess(lastpopped, gensym("loadbang"), ""); lastpopped = 0; } void pd_bang(t_pd *x) { (*(*x)->c_bangmethod)(x); } void pd_float(t_pd *x, t_float f) { (*(*x)->c_floatmethod)(x, f); } void pd_pointer(t_pd *x, t_gpointer *gp) { (*(*x)->c_pointermethod)(x, gp); } void pd_symbol(t_pd *x, t_symbol *s) { (*(*x)->c_symbolmethod)(x, s); } void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv) { #ifdef ROCKBOX (void) s; #endif (*(*x)->c_listmethod)(x, &s_list, argc, argv); } void mess_init(void); void obj_init(void); void conf_init(void); void glob_init(void); void pd_init(void) { mess_init(); obj_init(); conf_init(); glob_init(); }