diff options
Diffstat (limited to 'apps/plugins/sliding_puzzle.c')
-rw-r--r-- | apps/plugins/sliding_puzzle.c | 573 |
1 files changed, 387 insertions, 186 deletions
diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c index 17a96baf2a..223c107265 100644 --- a/apps/plugins/sliding_puzzle.c +++ b/apps/plugins/sliding_puzzle.c | |||
@@ -17,8 +17,9 @@ | |||
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include "plugin.h" | 19 | #include "plugin.h" |
20 | #ifdef HAVE_LCD_BITMAP | 20 | #include "bmp.h" |
21 | 21 | ||
22 | #ifdef HAVE_LCD_BITMAP | ||
22 | PLUGIN_HEADER | 23 | PLUGIN_HEADER |
23 | 24 | ||
24 | /* variable button definitions */ | 25 | /* variable button definitions */ |
@@ -95,190 +96,304 @@ PLUGIN_HEADER | |||
95 | #endif | 96 | #endif |
96 | 97 | ||
97 | static struct plugin_api* rb; | 98 | static struct plugin_api* rb; |
98 | static int spots[20]; | 99 | #if LCD_DEPTH==1 |
99 | static int hole = 19, moves; | 100 | /* for recorder, use rectangular image, 5x4 puzzle */ |
100 | static char s[5]; | 101 | #define SPOTS_X 5 |
101 | static bool pic = true; | 102 | #define SPOTS_Y 4 |
102 | static unsigned char picture[20][32] = { | 103 | #define SPOTS_WIDTH 16 |
103 | { 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0xf8, 0xd9, | 104 | #define SPOTS_HEIGHT 16 |
104 | 0x10, 0xb0, 0x60, 0xc0, 0x80, 0x00, 0x30, 0x78, | 105 | #define IMAGE_WIDTH 80 |
105 | 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x07, | 106 | #define IMAGE_HEIGHT 64 |
106 | 0xbf, 0xf8, 0x43, 0x1c, 0x61, 0x5e, 0xfc, 0xfc }, | 107 | #define IMAGE_SIZE 80 |
107 | 108 | #else | |
108 | { 0x68, 0xc8, 0x48, 0x08, 0x98, 0x90, 0xb0, 0xa4, | 109 | /* for other targets, use a square image, 4x4 puzzle |
109 | 0xa0, 0xc0, 0xc0, 0x88, 0x14, 0x08, 0x00, 0x00, | 110 | Puzzle image dimension is min(lcd_height,lcd_width) |
110 | 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x03, | 111 | 4x4 is more convenient than 5x4 for square puzzles |
111 | 0x00, 0x00, 0x30, 0x48, 0x79, 0x33, 0x06, 0x1c }, | 112 | Note: sliding_puzzle.bmp should be evenly divisible by SPOTS_X |
112 | 113 | and SPOTS_Y, otherwise lcd_bitmap_part stride won't be correct */ | |
113 | { 0x20, 0x00, 0x06, 0x09, 0x09, 0x06, 0x00, 0x80, | 114 | #define SPOTS_X 4 |
114 | 0x40, 0x80, 0x00, 0x08, 0x14, 0x08, 0x20, 0x00, | 115 | #define SPOTS_Y 4 |
115 | 0x60, 0x30, 0x18, 0xf9, 0x70, 0x00, 0x00, 0x00, | 116 | #define IMAGE_SIZE ( (LCD_WIDTH<LCD_HEIGHT)?LCD_WIDTH:LCD_HEIGHT ) |
116 | 0xf9, 0x18, 0x30, 0x60, 0x30, 0x18, 0x06, 0x32 }, | 117 | #define IMAGE_WIDTH IMAGE_SIZE |
117 | 118 | #define IMAGE_HEIGHT IMAGE_SIZE | |
118 | { 0x00, 0x80, 0x42, 0xa0, 0x50, 0x90, 0x88, 0x88, | 119 | #define SPOTS_WIDTH (IMAGE_WIDTH/SPOTS_X) |
119 | 0x84, 0xa4, 0xa4, 0x64, 0x24, 0x18, 0x00, 0x40, | 120 | #define SPOTS_HEIGHT (IMAGE_HEIGHT/SPOTS_Y) |
120 | 0x79, 0x4a, 0x31, 0x02, 0x05, 0x2a, 0xd5, 0xaa, | 121 | #endif |
121 | 0x55, 0xaa, 0x55, 0xab, 0x56, 0xac, 0x58, 0xb0 }, | 122 | |
122 | 123 | #define NUM_SPOTS (SPOTS_X*SPOTS_Y) | |
123 | { 0x04, 0x0a, 0x04, 0x00, 0x80, 0x80, 0xc0, 0xc8, | 124 | #define HOLE_ID (NUM_SPOTS) |
124 | 0x40, 0xc2, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, | 125 | #define INITIAL_HOLE (HOLE_ID-1) |
125 | 0x60, 0x38, 0x9c, 0xe7, 0x59, 0x0c, 0xc4, 0xfc, | 126 | |
126 | 0x3f, 0x07, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00 }, | 127 | enum picmodes |
127 | 128 | { | |
128 | { 0x00, 0x04, 0x00, 0x00, 0x80, 0xe0, 0x78, 0x1e, | 129 | PICMODE_NUMERALS = 0, |
129 | 0xa7, 0xd9, 0xcc, 0x76, 0x3b, 0x0d, 0x1f, 0xff, | 130 | PICMODE_INITIAL_PICTURE, |
130 | 0x00, 0x00, 0x00, 0x00, 0x03, 0x13, 0x03, 0x03, | 131 | PICMODE_DEFAULT_PICTURE, |
131 | 0x11, 0x29, 0x10, 0x00, 0x04, 0x2a, 0x0b, 0x0b }, | 132 | #ifdef HAVE_ALBUMART |
132 | 133 | PICMODE_ALBUM_ART, | |
133 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, | 134 | #endif |
134 | 0xc0, 0x8e, 0x10, 0x00, 0x80, 0x80, 0x60, 0x38, | 135 | // PICMODE_RANDOM, |
135 | 0x0a, 0x08, 0x05, 0x05, 0x07, 0x03, 0x03, 0x03, | 136 | PICMODE_LAST_XXX /* placeholder */ |
136 | 0x03, 0x03, 0x01, 0x11, 0x01, 0x00, 0x00, 0x80 }, | 137 | }; |
137 | 138 | ||
138 | { 0x0e, 0x18, 0x31, 0x3e, 0x1c, 0x00, 0x00, 0x1c, | 139 | static const char* const picmode_descriptions[] = { |
139 | 0x3e, 0x31, 0x18, 0x0c, 0x0c, 0x18, 0x30, 0x20, | 140 | "Numerals", |
140 | 0x00, 0x00, 0x08, 0x14, 0x08, 0x00, 0x02, 0x80, | 141 | "Viewer Picture", |
141 | 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00 }, | 142 | "Default Picture", |
142 | 143 | #ifdef HAVE_ALBUMART | |
143 | { 0x60, 0xc0, 0x48, 0xc7, 0x60, 0xb8, 0x57, 0xaa, | 144 | "Album Art", |
144 | 0x55, 0xaa, 0x55, 0xaa, 0xd5, 0xaa, 0x75, 0x3a, | 145 | #endif |
145 | 0x00, 0x00, 0x01, 0x23, 0x05, 0x05, 0x09, 0x0a, | 146 | "Shouldn't Get Here", |
146 | 0x0b, 0x0a, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00 }, | ||
147 | |||
148 | { 0xe5, 0x8d, 0x18, 0x30, 0x41, 0xc1, 0x8f, 0xfe, | ||
149 | 0xf0, 0x81, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
150 | 0x00, 0x01, 0x03, 0x02, 0x06, 0x06, 0x04, 0x04, | ||
151 | 0x04, 0x05, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00 }, | ||
152 | |||
153 | { 0x00, 0x00, 0x00, 0x10, 0x28, 0x10, 0x00, 0x04, | ||
154 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
155 | 0xc0, 0xb0, 0x18, 0xcc, 0x24, 0x86, 0x42, 0x22, | ||
156 | 0x31, 0x69, 0xd1, 0xa9, 0x51, 0xa1, 0x41, 0x02 }, | ||
157 | |||
158 | { 0x00, 0x00, 0x00, 0x00, 0x40, 0xa1, 0x40, 0x00, | ||
159 | 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
160 | 0x12, 0x16, 0x5c, 0x58, 0xf0, 0xc0, 0x00, 0x00, | ||
161 | 0x06, 0x09, 0x09, 0x86, 0x60, 0x18, 0xc4, 0xf2 }, | ||
162 | |||
163 | { 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, | ||
164 | 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80, 0x8c, 0x12, | ||
165 | 0x6a, 0xa5, 0x95, 0xd2, 0xca, 0xc9, 0xe9, 0xe9, | ||
166 | 0xe1, 0xe9, 0xe1, 0xe1, 0x62, 0x62, 0xc5, 0xc5 }, | ||
167 | |||
168 | { 0x12, 0x0c, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, | ||
169 | 0x40, 0x40, 0x40, 0x82, 0x85, 0x02, 0x00, 0x00, | ||
170 | 0x8a, 0x32, 0x6f, 0xd6, 0xaa, 0x55, 0x83, 0x01, | ||
171 | 0x81, 0x01, 0x81, 0x82, 0x82, 0x0d, 0xbe, 0xdc }, | ||
172 | |||
173 | { 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, | ||
174 | 0x41, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, | ||
175 | 0x00, 0x00, 0x01, 0x02, 0x01, 0x04, 0x00, 0x60, | ||
176 | 0x90, 0x90, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 }, | ||
177 | |||
178 | { 0x3f, 0x6a, 0xc0, 0x9f, 0x20, 0x27, 0x48, 0x4b, | ||
179 | 0x47, 0x22, 0x50, 0x0f, 0x95, 0x4a, 0x25, 0x90, | ||
180 | 0x07, 0x0f, 0x17, 0x23, 0x43, 0x42, 0x44, 0x40, | ||
181 | 0x44, 0x40, 0x42, 0x40, 0x60, 0x30, 0x3c, 0x1f }, | ||
182 | |||
183 | { 0xd0, 0x50, 0x11, 0xb9, 0xef, 0x07, 0x80, 0x40, | ||
184 | 0x30, 0x98, 0x9c, 0xbf, 0x60, 0xc7, 0x0d, 0x36, | ||
185 | 0x59, 0x11, 0x21, 0x23, 0x22, 0x21, 0x30, 0x10, | ||
186 | 0x0d, 0x42, 0x01, 0x80, 0x00, 0x40, 0x03, 0x0c }, | ||
187 | |||
188 | { 0xc3, 0x81, 0x81, 0x00, 0x00, 0x01, 0x03, 0x03, | ||
189 | 0x03, 0x03, 0x02, 0x01, 0x00, 0x00, 0x80, 0x80, | ||
190 | 0x10, 0x91, 0x23, 0x23, 0x67, 0xe6, 0xe6, 0xa6, | ||
191 | 0xa6, 0xa6, 0xa6, 0xa6, 0xb3, 0x93, 0x59, 0x49 }, | ||
192 | |||
193 | { 0xc1, 0x71, 0xff, 0x54, 0x0a, 0x02, 0x06, 0x0e, | ||
194 | 0x0e, 0x0a, 0x06, 0x02, 0x02, 0xc5, 0x7b, 0x17, | ||
195 | 0x24, 0x10, 0x3b, 0x7f, 0x92, 0xa6, 0xa4, 0xa4, | ||
196 | 0xa4, 0xa4, 0xa4, 0x66, 0x23, 0x11, 0x12, 0x0c }, | ||
197 | |||
198 | { 0x55, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, | ||
199 | 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xaa, | ||
200 | 0x55, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, | ||
201 | 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xaa } | ||
202 | }; | 147 | }; |
203 | 148 | ||
149 | static int spots[NUM_SPOTS]; | ||
150 | static int hole = INITIAL_HOLE, moves; | ||
151 | static char s[5]; | ||
152 | static enum picmodes picmode = PICMODE_INITIAL_PICTURE; | ||
153 | |||
154 | static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)] | ||
155 | __attribute__ ((aligned(16))); | ||
156 | #if LCD_DEPTH>1 | ||
157 | static unsigned char temp_img_buf[LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)] | ||
158 | __attribute__ ((aligned(16))); | ||
159 | #endif | ||
160 | #ifdef HAVE_ALBUMART | ||
161 | static char albumart_path[MAX_PATH+1]; | ||
162 | #endif | ||
163 | static char img_buf_path[MAX_PATH+1]; | ||
164 | |||
165 | static const fb_data * puzzle_bmp_ptr; | ||
166 | extern const fb_data sliding_puzzle[]; | ||
167 | /* initial_bmp_path points to selected bitmap if this game is launched | ||
168 | as a viewer for a .bmp file, or NULL if game is launched regular way */ | ||
169 | static const char * initial_bmp_path=NULL; | ||
170 | |||
171 | #ifdef HAVE_ALBUMART | ||
172 | const char * get_albumart_bmp_path(void) | ||
173 | { | ||
174 | struct mp3entry* track = rb->audio_current_track(); | ||
175 | |||
176 | if (!track || !track->path || track->path[0] == '\0') | ||
177 | return NULL; | ||
178 | |||
179 | if (!rb->search_albumart_files(track, "", albumart_path, MAX_PATH ) ) | ||
180 | return NULL; | ||
181 | |||
182 | albumart_path[ MAX_PATH ] = '\0'; | ||
183 | return albumart_path; | ||
184 | } | ||
185 | #endif | ||
186 | |||
187 | const char * get_random_bmp_path(void) | ||
188 | { | ||
189 | return(initial_bmp_path); | ||
190 | } | ||
191 | |||
192 | static bool load_resize_bitmap(void) | ||
193 | { | ||
194 | int rc; | ||
195 | const char * filename = NULL; | ||
196 | |||
197 | /* initially assume using the built-in default */ | ||
198 | puzzle_bmp_ptr = sliding_puzzle; | ||
199 | |||
200 | switch( picmode ){ | ||
201 | /* some modes don't even need to touch disk and trivially succeed */ | ||
202 | case PICMODE_NUMERALS: | ||
203 | case PICMODE_DEFAULT_PICTURE: | ||
204 | default: | ||
205 | return(true); | ||
206 | |||
207 | #ifdef HAVE_ALBUMART | ||
208 | case PICMODE_ALBUM_ART: | ||
209 | filename = get_albumart_bmp_path(); | ||
210 | break; | ||
211 | #endif | ||
212 | /* | ||
213 | case PICMODE_RANDOM: | ||
214 | if(NULL == (filename=get_random_bmp_path()) ) | ||
215 | filename = initial_bmp_path; | ||
216 | break; | ||
217 | */ | ||
218 | case PICMODE_INITIAL_PICTURE: | ||
219 | filename = initial_bmp_path; | ||
220 | break; | ||
221 | }; | ||
222 | |||
223 | if( filename != NULL ) | ||
224 | { | ||
225 | /* if we already loaded image before, don't touch disk */ | ||
226 | if( 0 == rb->strcmp( filename, img_buf_path ) ) | ||
227 | { | ||
228 | puzzle_bmp_ptr = (const fb_data *)img_buf; | ||
229 | return true; | ||
230 | } | ||
231 | |||
232 | struct bitmap main_bitmap; | ||
233 | rb->memset(&main_bitmap,0,sizeof(struct bitmap)); | ||
234 | main_bitmap.data = img_buf; | ||
235 | |||
236 | #if LCD_DEPTH>1 | ||
237 | struct bitmap temp_bitmap; | ||
238 | rb->memset(&temp_bitmap,0,sizeof(struct bitmap)); | ||
239 | temp_bitmap.data = temp_img_buf; | ||
240 | |||
241 | main_bitmap.width = IMAGE_WIDTH; | ||
242 | main_bitmap.height = IMAGE_HEIGHT; | ||
243 | |||
244 | rc = rb->read_bmp_file( filename, &temp_bitmap, sizeof(temp_img_buf), | ||
245 | FORMAT_NATIVE ); | ||
246 | if( rc > 0 ) | ||
247 | { | ||
248 | simple_resize_bitmap( &temp_bitmap, &main_bitmap ); | ||
249 | puzzle_bmp_ptr = (const fb_data *)img_buf; | ||
250 | rb->strcpy( img_buf_path, filename ); | ||
251 | return true; | ||
252 | } | ||
253 | #else | ||
254 | rc = rb->read_bmp_file( filename, &main_bitmap, sizeof(img_buf), | ||
255 | FORMAT_NATIVE ); | ||
256 | if( rc > 0 ) | ||
257 | { | ||
258 | puzzle_bmp_ptr = (const fb_data *)img_buf; | ||
259 | rb->strcpy( img_buf_path, filename ); | ||
260 | return true; | ||
261 | } | ||
262 | #endif | ||
263 | } | ||
264 | |||
265 | /* something must have failed. get_albumart_bmp_path could return | ||
266 | NULL if albumart doesn't exist or couldn't be loaded, or | ||
267 | read_bmp_file could have failed. return false and caller should | ||
268 | try the next mode (PICMODE_DEFAULT_PICTURE and PICMODE_NUMERALS will | ||
269 | always succeed) */ | ||
270 | return false; | ||
271 | } | ||
272 | |||
204 | /* draws a spot at the coordinates (x,y), range of p is 1-20 */ | 273 | /* draws a spot at the coordinates (x,y), range of p is 1-20 */ |
205 | static void draw_spot(int p, int x, int y) | 274 | static void draw_spot(int p, int x, int y) |
206 | { | 275 | { |
207 | if (pic || p==20) { | 276 | if (p == HOLE_ID) |
208 | rb->lcd_mono_bitmap (picture[p-1], x, y, 16, 16); | 277 | { |
278 | #if LCD_DEPTH==1 | ||
279 | /* the bottom-right cell of the default sliding_puzzle image is | ||
280 | an appropriate hole graphic */ | ||
281 | rb->lcd_bitmap_part(sliding_puzzle, ((p-1)%SPOTS_X)*SPOTS_WIDTH, | ||
282 | ((p-1)/SPOTS_X)*SPOTS_HEIGHT, | ||
283 | IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT); | ||
284 | #else | ||
285 | /* just draw a black rectangle */ | ||
286 | rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | ||
287 | rb->lcd_set_background(LCD_BLACK); | ||
288 | rb->lcd_fillrect(x,y,SPOTS_WIDTH,SPOTS_HEIGHT); | ||
289 | rb->lcd_set_drawmode(DRMODE_SOLID); | ||
290 | #endif | ||
291 | } | ||
292 | else if (picmode != PICMODE_NUMERALS) | ||
293 | { | ||
294 | rb->lcd_bitmap_part( puzzle_bmp_ptr, ((p-1)%SPOTS_X)*SPOTS_WIDTH, | ||
295 | ((p-1)/SPOTS_X)*SPOTS_HEIGHT, | ||
296 | IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT); | ||
209 | } else { | 297 | } else { |
210 | rb->lcd_drawrect(x, y, 16, 16); | 298 | rb->lcd_drawrect(x, y, SPOTS_WIDTH, SPOTS_HEIGHT); |
211 | rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | 299 | rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); |
212 | rb->lcd_fillrect(x+1, y+1, 14, 14); | 300 | rb->lcd_fillrect(x+1, y+1, SPOTS_WIDTH-2, SPOTS_HEIGHT-2); |
213 | rb->lcd_set_drawmode(DRMODE_SOLID); | 301 | rb->lcd_set_drawmode(DRMODE_SOLID); |
214 | rb->snprintf(s, sizeof(s), "%d", p); | 302 | rb->snprintf(s, sizeof(s), "%d", p); |
215 | rb->lcd_putsxy(x+2, y+4, (unsigned char *)s); | 303 | rb->lcd_putsxy(x+2, y+4, (unsigned char *)s); |
216 | } | 304 | } |
217 | } | 305 | } |
218 | 306 | ||
219 | /* check if the puzzle is solved */ | 307 | /* check if the puzzle is solved */ |
220 | static bool puzzle_finished(void) | 308 | static bool puzzle_finished(void) |
221 | { | 309 | { |
222 | int i; | 310 | int i; |
223 | for (i=0; i<20; i++) | 311 | for (i=0; i<NUM_SPOTS; i++) |
224 | if (spots[i] != (i+1)) | 312 | if (spots[i] != (i+1)) |
225 | return false; | 313 | return false; |
226 | return true; | 314 | return true; |
227 | } | 315 | } |
228 | 316 | ||
229 | /* move a piece in any direction */ | 317 | /* move a piece in any direction */ |
230 | static void move_spot(int x, int y) | 318 | static void move_spot(int x, int y) |
231 | { | 319 | { |
232 | int i; | 320 | int i; |
233 | spots[hole] = spots[hole-x-5*y]; | 321 | spots[hole] = spots[hole-x-SPOTS_X*y]; |
234 | hole -= (x+5*y); | 322 | hole -= (x+SPOTS_X*y); |
235 | moves++; | 323 | moves++; |
236 | rb->snprintf(s, sizeof(s), "%d", moves); | 324 | rb->snprintf(s, sizeof(s), "%d", moves); |
237 | rb->lcd_putsxy(85, 20, (unsigned char *)s); | 325 | s[sizeof(s)-1] = '\0'; |
326 | #if (LCD_WIDTH>IMAGE_SIZE) | ||
327 | rb->lcd_putsxy(IMAGE_WIDTH+5, 20, (unsigned char *)s); | ||
328 | #else | ||
329 | rb->lcd_putsxy(5, IMAGE_HEIGHT+20, (unsigned char *)s); | ||
330 | #endif | ||
238 | 331 | ||
239 | for (i=4; i<=16; i+=4) { | 332 | for(i=1;i<=4;i++) |
240 | draw_spot(20, (hole%5)*16, (hole/5)*16); | 333 | { |
241 | draw_spot(spots[hole], (hole%5)*16 + x*i, (hole/5)*16 + y*i); | 334 | draw_spot(HOLE_ID, |
242 | rb->lcd_update(); | 335 | (hole%SPOTS_X)*SPOTS_WIDTH, |
336 | (hole/SPOTS_X)*SPOTS_HEIGHT); | ||
337 | draw_spot(spots[hole], | ||
338 | (hole%SPOTS_X)*SPOTS_WIDTH + (i*x*SPOTS_WIDTH)/5, | ||
339 | (hole/SPOTS_X)*SPOTS_HEIGHT + (i*y*SPOTS_HEIGHT)/5); | ||
340 | rb->lcd_update(); | ||
341 | rb->sleep(HZ/50); | ||
243 | } | 342 | } |
244 | spots[hole] = 20; | 343 | draw_spot(HOLE_ID, |
344 | (hole%SPOTS_X)*SPOTS_WIDTH, | ||
345 | (hole/SPOTS_X)*SPOTS_HEIGHT); | ||
346 | draw_spot(spots[hole], | ||
347 | ((hole%SPOTS_X)+x)*SPOTS_WIDTH, | ||
348 | ((hole/SPOTS_X)+y)*SPOTS_HEIGHT); | ||
349 | rb->lcd_update(); | ||
350 | |||
351 | spots[hole] = HOLE_ID; | ||
245 | } | 352 | } |
246 | 353 | ||
247 | /* initializes the puzzle */ | 354 | /* initializes the puzzle */ |
248 | static void puzzle_init(void) | 355 | static void puzzle_init(void) |
249 | { | 356 | { |
250 | int i, r, temp, tsp[20]; | 357 | int i, r, temp, tsp[NUM_SPOTS]; |
358 | |||
251 | moves = 0; | 359 | moves = 0; |
252 | rb->lcd_clear_display(); | 360 | rb->lcd_clear_display(); |
253 | rb->lcd_drawrect(80, 0, 32, 64); | ||
254 | rb->lcd_putsxy(81, 10, (unsigned char *)"Moves"); | ||
255 | rb->snprintf(s, sizeof(s), "%d", moves); | 361 | rb->snprintf(s, sizeof(s), "%d", moves); |
256 | rb->lcd_putsxy(85, 20, (unsigned char *)s); | 362 | |
257 | 363 | #if (LCD_WIDTH>IMAGE_SIZE) | |
364 | rb->lcd_drawrect(IMAGE_WIDTH, 0, 32, 64); | ||
365 | rb->lcd_putsxy(IMAGE_WIDTH+1, 10, (unsigned char *)"Moves"); | ||
366 | rb->lcd_putsxy(IMAGE_WIDTH+5, 20, (unsigned char *)s); | ||
367 | #else | ||
368 | rb->lcd_drawrect(0, IMAGE_HEIGHT, 32, 64); | ||
369 | rb->lcd_putsxy(1, IMAGE_HEIGHT+10, (unsigned char *)"Moves"); | ||
370 | rb->lcd_putsxy(5, IMAGE_HEIGHT+20, (unsigned char *)s); | ||
371 | #endif | ||
372 | |||
258 | /* shuffle spots */ | 373 | /* shuffle spots */ |
259 | for (i=19; i>=0; i--) { | 374 | for (i=NUM_SPOTS-1; i>=0; i--) { |
260 | r = (rb->rand() % (i+1)); | 375 | r = (rb->rand() % (i+1)); |
261 | 376 | ||
262 | temp = spots[r]; | 377 | temp = spots[r]; |
263 | spots[r] = spots[i]; | 378 | spots[r] = spots[i]; |
264 | spots[i] = temp; | 379 | spots[i] = temp; |
265 | 380 | ||
266 | if (spots[i]==20) | 381 | if (spots[i]==HOLE_ID) |
267 | hole = i; | 382 | hole = i; |
268 | } | 383 | } |
269 | 384 | ||
270 | /* test if the puzzle is solvable */ | 385 | /* test if the puzzle is solvable */ |
271 | for (i=0; i<20; i++) | 386 | for (i=0; i<NUM_SPOTS; i++) |
272 | tsp[i] = spots[i]; | 387 | tsp[i] = spots[i]; |
273 | r=0; | 388 | r=0; |
274 | 389 | ||
275 | /* First, check if the problem has even or odd parity, | 390 | /* First, check if the problem has even or odd parity, |
276 | depending on where the empty square is */ | 391 | depending on where the empty square is */ |
277 | if (((4-hole%5) + (3-hole/5))%2 == 1) | 392 | if ((((SPOTS_X-1)-hole%SPOTS_X) + ((SPOTS_Y-1)-hole/SPOTS_X))%2 == 1) |
278 | ++r; | 393 | ++r; |
279 | 394 | ||
280 | /* Now check how many swaps we need to solve it */ | 395 | /* Now check how many swaps we need to solve it */ |
281 | for (i=0; i<19; i++) { | 396 | for (i=0; i<NUM_SPOTS-1; i++) { |
282 | while (tsp[i] != (i+1)) { | 397 | while (tsp[i] != (i+1)) { |
283 | temp = tsp[i]; | 398 | temp = tsp[i]; |
284 | tsp[i] = tsp[temp-1]; | 399 | tsp[i] = tsp[temp-1]; |
@@ -286,10 +401,10 @@ static void puzzle_init(void) | |||
286 | ++r; | 401 | ++r; |
287 | } | 402 | } |
288 | } | 403 | } |
289 | 404 | ||
290 | /* if the random puzzle isn't solvable just change two spots */ | 405 | /* if the random puzzle isn't solvable just change two spots */ |
291 | if (r%2 == 1) { | 406 | if (r%2 == 1) { |
292 | if (spots[0]!=20 && spots[1]!=20) { | 407 | if (spots[0]!=HOLE_ID && spots[1]!=HOLE_ID) { |
293 | temp = spots[0]; | 408 | temp = spots[0]; |
294 | spots[0] = spots[1]; | 409 | spots[0] = spots[1]; |
295 | spots[1] = temp; | 410 | spots[1] = temp; |
@@ -299,10 +414,11 @@ static void puzzle_init(void) | |||
299 | spots[3] = temp; | 414 | spots[3] = temp; |
300 | } | 415 | } |
301 | } | 416 | } |
302 | 417 | ||
303 | /* draw spots to the lcd */ | 418 | /* draw spots to the lcd */ |
304 | for (i=0; i<20; i++) | 419 | for (i=0; i<NUM_SPOTS; i++) |
305 | draw_spot(spots[i], (i%5)*16, (i/5)*16); | 420 | draw_spot(spots[i], (i%SPOTS_X)*SPOTS_WIDTH, (i/SPOTS_X)*SPOTS_HEIGHT); |
421 | |||
306 | rb->lcd_update(); | 422 | rb->lcd_update(); |
307 | } | 423 | } |
308 | 424 | ||
@@ -312,6 +428,8 @@ static int puzzle_loop(void) | |||
312 | int button; | 428 | int button; |
313 | int lastbutton = BUTTON_NONE; | 429 | int lastbutton = BUTTON_NONE; |
314 | int i; | 430 | int i; |
431 | bool load_success; | ||
432 | |||
315 | puzzle_init(); | 433 | puzzle_init(); |
316 | while(true) { | 434 | while(true) { |
317 | button = rb->button_get(true); | 435 | button = rb->button_get(true); |
@@ -331,39 +449,63 @@ static int puzzle_loop(void) | |||
331 | /* mix up the pieces */ | 449 | /* mix up the pieces */ |
332 | puzzle_init(); | 450 | puzzle_init(); |
333 | break; | 451 | break; |
334 | 452 | ||
335 | case PUZZLE_PICTURE: | 453 | case PUZZLE_PICTURE: |
336 | #ifdef PUZZLE_SHUFFLE_PICTURE_PRE | 454 | #ifdef PUZZLE_SHUFFLE_PICTURE_PRE |
337 | if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE) | 455 | if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE) |
338 | break; | 456 | break; |
339 | #endif | 457 | #endif |
340 | /* change picture */ | 458 | /* change picture */ |
341 | pic = (pic==true?false:true); | 459 | picmode = (picmode+1)%PICMODE_LAST_XXX; |
342 | for (i=0; i<20; i++) | 460 | |
343 | draw_spot(spots[i], (i%5)*16, (i/5)*16); | 461 | /* if load_resize_bitmap fails to load bitmap, try next picmode */ |
462 | do | ||
463 | { | ||
464 | load_success = load_resize_bitmap(); | ||
465 | if( !load_success ) | ||
466 | picmode = (picmode+1)%PICMODE_LAST_XXX; | ||
467 | } | ||
468 | while( !load_success ); | ||
469 | |||
470 | /* tell the user what mode we picked in the end! */ | ||
471 | rb->splash(HZ,picmode_descriptions[ picmode ] ); | ||
472 | rb->lcd_clear_display(); | ||
473 | #if (LCD_WIDTH>IMAGE_SIZE) | ||
474 | rb->lcd_drawrect(IMAGE_WIDTH, 0, 32, 64); | ||
475 | rb->lcd_putsxy(IMAGE_WIDTH+1, 10, (unsigned char *)"Moves"); | ||
476 | #else | ||
477 | rb->lcd_drawrect(0,IMAGE_HEIGHT,32,64); | ||
478 | rb->lcd_putsxy(1,IMAGE_HEIGHT+10, (unsigned char *)"Moves"); | ||
479 | #endif | ||
480 | |||
481 | for (i=0; i<NUM_SPOTS; i++) | ||
482 | draw_spot(spots[i], | ||
483 | (i%SPOTS_X)*SPOTS_WIDTH, | ||
484 | (i/SPOTS_X)*SPOTS_HEIGHT); | ||
344 | rb->lcd_update(); | 485 | rb->lcd_update(); |
486 | |||
345 | break; | 487 | break; |
346 | 488 | ||
347 | case BUTTON_LEFT: | 489 | case BUTTON_LEFT: |
348 | if ((hole%5)<4 && !puzzle_finished()) | 490 | if ((hole%SPOTS_X)<(SPOTS_X-1) && !puzzle_finished()) |
349 | move_spot(-1, 0); | 491 | move_spot(-1, 0); |
350 | break; | 492 | break; |
351 | 493 | ||
352 | case BUTTON_RIGHT: | 494 | case BUTTON_RIGHT: |
353 | if ((hole%5)>0 && !puzzle_finished()) | 495 | if ((hole%SPOTS_X)>0 && !puzzle_finished()) |
354 | move_spot(1, 0); | 496 | move_spot(1, 0); |
355 | break; | 497 | break; |
356 | 498 | ||
357 | case PUZZLE_UP: | 499 | case PUZZLE_UP: |
358 | if ((hole/5)<3 && !puzzle_finished()) | 500 | if ((hole/SPOTS_X)<(SPOTS_Y-1) && !puzzle_finished()) |
359 | move_spot(0, -1); | 501 | move_spot(0, -1); |
360 | break; | 502 | break; |
361 | 503 | ||
362 | case PUZZLE_DOWN: | 504 | case PUZZLE_DOWN: |
363 | if ((hole/5)>0 && !puzzle_finished()) | 505 | if ((hole/SPOTS_X)>0 && !puzzle_finished()) |
364 | move_spot(0, 1); | 506 | move_spot(0, 1); |
365 | break; | 507 | break; |
366 | 508 | ||
367 | default: | 509 | default: |
368 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) | 510 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) |
369 | return PLUGIN_USB_CONNECTED; | 511 | return PLUGIN_USB_CONNECTED; |
@@ -373,56 +515,115 @@ static int puzzle_loop(void) | |||
373 | lastbutton = button; | 515 | lastbutton = button; |
374 | } | 516 | } |
375 | } | 517 | } |
376 | 518 | ||
377 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | 519 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) |
378 | { | 520 | { |
379 | int i, w, h; | 521 | int i, w, h; |
380 | 522 | ||
381 | (void)parameter; | ||
382 | rb = api; | 523 | rb = api; |
383 | |||
384 | /* print title */ | ||
385 | rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h); | ||
386 | w = (w+1)/2; | ||
387 | h = (h+1)/2; | ||
388 | rb->lcd_clear_display(); | ||
389 | rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h, (unsigned char *)"Sliding Puzzle"); | ||
390 | rb->lcd_update(); | ||
391 | rb->sleep(HZ); | ||
392 | 524 | ||
393 | /* print instructions */ | 525 | initial_bmp_path=(const char *)parameter; |
394 | rb->lcd_clear_display(); | 526 | picmode = PICMODE_INITIAL_PICTURE; |
395 | rb->lcd_setfont(FONT_SYSFIXED); | 527 | img_buf_path[0] = '\0'; |
396 | #if CONFIG_KEYPAD == RECORDER_PAD | 528 | |
397 | rb->lcd_putsxy(3, 18, "[OFF] to stop"); | 529 | /* If launched as a viewer, just go straight to the game without |
398 | rb->lcd_putsxy(3, 28, "[F1] shuffle"); | 530 | bothering with the splash or instructions page */ |
399 | rb->lcd_putsxy(3, 38, "[F2] change pic"); | 531 | if(parameter==NULL) |
532 | { | ||
533 | /* if not launched as a viewer, use default puzzle, and show help */ | ||
534 | picmode = PICMODE_DEFAULT_PICTURE; | ||
535 | |||
536 | /* print title */ | ||
537 | rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h); | ||
538 | w = (w+1)/2; | ||
539 | h = (h+1)/2; | ||
540 | rb->lcd_clear_display(); | ||
541 | rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h, | ||
542 | (unsigned char *)"Sliding Puzzle"); | ||
543 | rb->lcd_update(); | ||
544 | rb->sleep(HZ); | ||
545 | |||
546 | /* print instructions */ | ||
547 | rb->lcd_clear_display(); | ||
548 | rb->lcd_setfont(FONT_SYSFIXED); | ||
549 | #if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ARCHOS_AV300_PAD | ||
550 | rb->lcd_putsxy(3, 18, "[OFF] to stop"); | ||
551 | rb->lcd_putsxy(3, 28, "[F1] shuffle"); | ||
552 | rb->lcd_putsxy(3, 38, "[F2] change pic"); | ||
400 | #elif CONFIG_KEYPAD == ONDIO_PAD | 553 | #elif CONFIG_KEYPAD == ONDIO_PAD |
401 | rb->lcd_putsxy(0, 18, "[OFF] to stop"); | 554 | rb->lcd_putsxy(0, 18, "[OFF] to stop"); |
402 | rb->lcd_putsxy(0, 28, "[MODE..] shuffle"); | 555 | rb->lcd_putsxy(0, 28, "[MODE..] shuffle"); |
403 | rb->lcd_putsxy(0, 38, "[MODE] change pic"); | 556 | rb->lcd_putsxy(0, 38, "[MODE] change pic"); |
404 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ | 557 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ |
405 | (CONFIG_KEYPAD == IPOD_3G_PAD) || \ | 558 | (CONFIG_KEYPAD == IPOD_3G_PAD) || \ |
406 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) | 559 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) |
407 | rb->lcd_putsxy(0, 18, "[S-MENU] to stop"); | 560 | rb->lcd_putsxy(0, 18, "[S-MENU] to stop"); |
408 | rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle"); | 561 | rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle"); |
409 | rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic"); | 562 | rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic"); |
563 | #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ | ||
564 | (CONFIG_KEYPAD == IRIVER_H300_PAD) | ||
565 | rb->lcd_putsxy(0, 18, "[STOP] to stop"); | ||
566 | rb->lcd_putsxy(0, 28, "[SELECT] shuffle"); | ||
567 | rb->lcd_putsxy(0, 38, "[PLAY] change pic"); | ||
568 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD | ||
569 | rb->lcd_putsxy(0, 18, "[OFF] to stop"); | ||
570 | rb->lcd_putsxy(0, 28, "[REC] shuffle"); | ||
571 | rb->lcd_putsxy(0, 38, "[PLAY] change pic"); | ||
572 | #elif CONFIG_KEYPAD == GIGABEAT_PAD | ||
573 | rb->lcd_putsxy(0, 18, "[OFF] to stop"); | ||
574 | rb->lcd_putsxy(0, 28, "[SELECT] shuffle"); | ||
575 | rb->lcd_putsxy(0, 38, "[A] change pic"); | ||
576 | #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ | ||
577 | (CONFIG_KEYPAD == SANSE_C200_PAD) | ||
578 | rb->lcd_putsxy(0, 18, "[OFF] to stop"); | ||
579 | rb->lcd_putsxy(0, 28, "[REC] shuffle"); | ||
580 | rb->lcd_putsxy(0, 38, "[SELECT] change pic"); | ||
581 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | ||
582 | rb->lcd_putsxy(0, 18, "[OFF] to stop"); | ||
583 | rb->lcd_putsxy(0, 28, "[REW] shuffle"); | ||
584 | rb->lcd_putsxy(0, 38, "[PLAY] change pic"); | ||
410 | #endif | 585 | #endif |
411 | rb->lcd_update(); | 586 | #ifdef HAVE_ALBUMART |
412 | rb->button_get_w_tmo(HZ*2); | 587 | rb->lcd_putsxy(0,48," pic->albumart->num"); |
413 | 588 | #else | |
589 | rb->lcd_putsxy(0,48," pic<->num"); | ||
590 | #endif | ||
591 | rb->lcd_update(); | ||
592 | rb->button_get_w_tmo(HZ*2); | ||
593 | } | ||
594 | |||
595 | hole = INITIAL_HOLE; | ||
596 | |||
597 | if( !load_resize_bitmap() ) | ||
598 | { | ||
599 | rb->lcd_clear_display(); | ||
600 | rb->splash(HZ*2,"Failed to load bitmap!"); | ||
601 | return PLUGIN_OK; | ||
602 | } | ||
603 | |||
604 | #if LCD_DEPTH>1 | ||
605 | rb->lcd_set_background(LCD_BLACK); | ||
606 | rb->lcd_set_foreground(LCD_WHITE); | ||
607 | rb->lcd_set_backdrop(NULL); | ||
608 | #endif | ||
609 | |||
414 | rb->lcd_clear_display(); | 610 | rb->lcd_clear_display(); |
415 | rb->lcd_drawrect(80, 0, 32, 64); | 611 | #if (LCD_WIDTH>IMAGE_SIZE) |
416 | rb->lcd_putsxy(81, 10, (unsigned char *)"Moves"); | 612 | rb->lcd_drawrect(IMAGE_WIDTH, 0, 32, 64); |
417 | for (i=0; i<20; i++) { | 613 | rb->lcd_putsxy(IMAGE_WIDTH+1, 10, (unsigned char *)"Moves"); |
614 | #else | ||
615 | rb->lcd_drawrect(0,IMAGE_HEIGHT,32,64); | ||
616 | rb->lcd_putsxy(1,IMAGE_HEIGHT+10, (unsigned char *)"Moves"); | ||
617 | #endif | ||
618 | |||
619 | for (i=0; i<NUM_SPOTS; i++) { | ||
418 | spots[i]=(i+1); | 620 | spots[i]=(i+1); |
419 | draw_spot(spots[i], (i%5)*16, (i/5)*16); | 621 | draw_spot(spots[i], (i%SPOTS_X)*SPOTS_WIDTH, (i/SPOTS_X)*SPOTS_HEIGHT); |
420 | } | 622 | } |
421 | hole = 19; | 623 | |
422 | pic = true; | ||
423 | rb->lcd_update(); | 624 | rb->lcd_update(); |
424 | rb->sleep(HZ*2); | 625 | rb->sleep(HZ*2); |
425 | 626 | ||
426 | return puzzle_loop(); | 627 | return puzzle_loop(); |
427 | } | 628 | } |
428 | 629 | ||