* Fix plugin keymaps for VX777
[kugel-rb.git] / apps / plugins / sliding_puzzle.c
blob2f1d366960d6196696adb2eb322c740f8b57c186
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Vicentini Martin
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 ****************************************************************************/
21 #include "plugin.h"
23 #ifdef HAVE_LCD_BITMAP
24 PLUGIN_HEADER
26 /* variable button definitions */
27 #if CONFIG_KEYPAD == RECORDER_PAD
28 #define PUZZLE_QUIT BUTTON_OFF
29 #define PUZZLE_LEFT BUTTON_LEFT
30 #define PUZZLE_RIGHT BUTTON_RIGHT
31 #define PUZZLE_UP BUTTON_UP
32 #define PUZZLE_DOWN BUTTON_DOWN
33 #define PUZZLE_SHUFFLE BUTTON_F1
34 #define PUZZLE_PICTURE BUTTON_F2
36 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
37 #define PUZZLE_QUIT BUTTON_OFF
38 #define PUZZLE_LEFT BUTTON_LEFT
39 #define PUZZLE_RIGHT BUTTON_RIGHT
40 #define PUZZLE_UP BUTTON_UP
41 #define PUZZLE_DOWN BUTTON_DOWN
42 #define PUZZLE_SHUFFLE BUTTON_F1
43 #define PUZZLE_PICTURE BUTTON_F2
45 #elif CONFIG_KEYPAD == ONDIO_PAD
46 #define PUZZLE_QUIT BUTTON_OFF
47 #define PUZZLE_LEFT BUTTON_LEFT
48 #define PUZZLE_RIGHT BUTTON_RIGHT
49 #define PUZZLE_UP BUTTON_UP
50 #define PUZZLE_DOWN BUTTON_DOWN
51 #define PUZZLE_SHUFFLE_PICTURE_PRE BUTTON_MENU
52 #define PUZZLE_SHUFFLE (BUTTON_MENU | BUTTON_REPEAT)
53 #define PUZZLE_PICTURE (BUTTON_MENU | BUTTON_REL)
55 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
56 (CONFIG_KEYPAD == IRIVER_H300_PAD)
57 #define PUZZLE_QUIT BUTTON_OFF
58 #define PUZZLE_LEFT BUTTON_LEFT
59 #define PUZZLE_RIGHT BUTTON_RIGHT
60 #define PUZZLE_UP BUTTON_UP
61 #define PUZZLE_DOWN BUTTON_DOWN
62 #define PUZZLE_SHUFFLE BUTTON_SELECT
63 #define PUZZLE_PICTURE BUTTON_ON
65 #define PUZZLE_RC_QUIT BUTTON_RC_STOP
67 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
68 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
69 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
70 #define PUZZLE_QUIT (BUTTON_SELECT | BUTTON_MENU)
71 #define PUZZLE_LEFT BUTTON_LEFT
72 #define PUZZLE_RIGHT BUTTON_RIGHT
73 #define PUZZLE_UP BUTTON_MENU
74 #define PUZZLE_DOWN BUTTON_PLAY
75 #define PUZZLE_SHUFFLE (BUTTON_SELECT | BUTTON_LEFT)
76 #define PUZZLE_PICTURE (BUTTON_SELECT | BUTTON_RIGHT)
78 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
79 #define PUZZLE_QUIT BUTTON_POWER
80 #define PUZZLE_LEFT BUTTON_LEFT
81 #define PUZZLE_RIGHT BUTTON_RIGHT
82 #define PUZZLE_UP BUTTON_UP
83 #define PUZZLE_DOWN BUTTON_DOWN
84 #define PUZZLE_SHUFFLE BUTTON_REC
85 #define PUZZLE_PICTURE BUTTON_PLAY
87 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
88 #define PUZZLE_QUIT BUTTON_POWER
89 #define PUZZLE_LEFT BUTTON_LEFT
90 #define PUZZLE_RIGHT BUTTON_RIGHT
91 #define PUZZLE_UP BUTTON_UP
92 #define PUZZLE_DOWN BUTTON_DOWN
93 #define PUZZLE_SHUFFLE BUTTON_SELECT
94 #define PUZZLE_PICTURE BUTTON_A
96 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
97 (CONFIG_KEYPAD == SANSA_C200_PAD)
98 #define PUZZLE_QUIT BUTTON_POWER
99 #define PUZZLE_LEFT BUTTON_LEFT
100 #define PUZZLE_RIGHT BUTTON_RIGHT
101 #define PUZZLE_UP BUTTON_UP
102 #define PUZZLE_DOWN BUTTON_DOWN
103 #define PUZZLE_SHUFFLE BUTTON_REC
104 #define PUZZLE_PICTURE BUTTON_SELECT
106 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
107 #define PUZZLE_QUIT (BUTTON_HOME|BUTTON_REPEAT)
108 #define PUZZLE_LEFT BUTTON_LEFT
109 #define PUZZLE_RIGHT BUTTON_RIGHT
110 #define PUZZLE_UP BUTTON_UP
111 #define PUZZLE_DOWN BUTTON_DOWN
112 #define PUZZLE_SHUFFLE BUTTON_SELECT|BUTTON_DOWN
113 #define PUZZLE_PICTURE BUTTON_SELECT
115 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
116 #define PUZZLE_QUIT BUTTON_POWER
117 #define PUZZLE_LEFT BUTTON_LEFT
118 #define PUZZLE_RIGHT BUTTON_RIGHT
119 #define PUZZLE_UP BUTTON_UP
120 #define PUZZLE_DOWN BUTTON_DOWN
121 #define PUZZLE_SHUFFLE BUTTON_HOME
122 #define PUZZLE_PICTURE BUTTON_SELECT
124 #elif (CONFIG_KEYPAD == SANSA_M200_PAD)
125 #define PUZZLE_QUIT BUTTON_POWER
126 #define PUZZLE_LEFT BUTTON_LEFT
127 #define PUZZLE_RIGHT BUTTON_RIGHT
128 #define PUZZLE_UP BUTTON_UP
129 #define PUZZLE_DOWN BUTTON_DOWN
130 #define PUZZLE_SHUFFLE (BUTTON_SELECT | BUTTON_UP)
131 #define PUZZLE_PICTURE (BUTTON_SELECT | BUTTON_REL)
133 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
134 #define PUZZLE_QUIT BUTTON_POWER
135 #define PUZZLE_LEFT BUTTON_LEFT
136 #define PUZZLE_RIGHT BUTTON_RIGHT
137 #define PUZZLE_UP BUTTON_SCROLL_UP
138 #define PUZZLE_DOWN BUTTON_SCROLL_DOWN
139 #define PUZZLE_SHUFFLE BUTTON_REW
140 #define PUZZLE_PICTURE BUTTON_PLAY
142 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
143 #define PUZZLE_QUIT BUTTON_BACK
144 #define PUZZLE_LEFT BUTTON_LEFT
145 #define PUZZLE_RIGHT BUTTON_RIGHT
146 #define PUZZLE_UP BUTTON_UP
147 #define PUZZLE_DOWN BUTTON_DOWN
148 #define PUZZLE_SHUFFLE BUTTON_SELECT
149 #define PUZZLE_PICTURE BUTTON_MENU
151 #elif (CONFIG_KEYPAD == MROBE100_PAD)
152 #define PUZZLE_QUIT BUTTON_POWER
153 #define PUZZLE_LEFT BUTTON_LEFT
154 #define PUZZLE_RIGHT BUTTON_RIGHT
155 #define PUZZLE_UP BUTTON_UP
156 #define PUZZLE_DOWN BUTTON_DOWN
157 #define PUZZLE_SHUFFLE BUTTON_SELECT
158 #define PUZZLE_PICTURE BUTTON_DISPLAY
160 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
161 #define PUZZLE_QUIT BUTTON_RC_REC
162 #define PUZZLE_LEFT BUTTON_RC_REW
163 #define PUZZLE_RIGHT BUTTON_RC_FF
164 #define PUZZLE_UP BUTTON_RC_VOL_UP
165 #define PUZZLE_DOWN BUTTON_RC_VOL_DOWN
166 #define PUZZLE_SHUFFLE BUTTON_RC_MODE
167 #define PUZZLE_PICTURE BUTTON_RC_MENU
169 #elif (CONFIG_KEYPAD == COWOND2_PAD)
170 #define PUZZLE_QUIT BUTTON_POWER
171 #define PUZZLE_QUIT_TEXT "[POWER]"
173 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
174 #define PUZZLE_QUIT BUTTON_BACK
175 #define PUZZLE_LEFT BUTTON_LEFT
176 #define PUZZLE_RIGHT BUTTON_RIGHT
177 #define PUZZLE_UP BUTTON_UP
178 #define PUZZLE_DOWN BUTTON_DOWN
179 #define PUZZLE_SHUFFLE BUTTON_PLAY
180 #define PUZZLE_PICTURE BUTTON_MENU
182 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
183 #define PUZZLE_QUIT BUTTON_POWER
184 #define PUZZLE_LEFT BUTTON_LEFT
185 #define PUZZLE_RIGHT BUTTON_RIGHT
186 #define PUZZLE_UP BUTTON_UP
187 #define PUZZLE_DOWN BUTTON_DOWN
188 #define PUZZLE_SHUFFLE BUTTON_VIEW
189 #define PUZZLE_PICTURE BUTTON_MENU
191 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
192 CONFIG_KEYPAD == ONDAVX777_PAD || \
193 CONFIG_KEYPAD == MROBE500_PAD
194 #define PUZZLE_QUIT BUTTON_POWER
195 #define PUZZLE_QUIT_TEXT "[POWER]"
197 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
198 #define PUZZLE_QUIT BUTTON_REC
199 #define PUZZLE_LEFT BUTTON_LEFT
200 #define PUZZLE_RIGHT BUTTON_RIGHT
201 #define PUZZLE_UP BUTTON_UP
202 #define PUZZLE_DOWN BUTTON_DOWN
203 #define PUZZLE_SHUFFLE BUTTON_REW
204 #define PUZZLE_PICTURE BUTTON_PLAY
206 #else
207 #error No keymap defined!
208 #endif
210 #ifdef HAVE_TOUCHSCREEN
211 #ifndef PUZZLE_QUIT
212 #define PUZZLE_QUIT BUTTON_TOPLEFT
213 #endif
214 #ifndef PUZZLE_LEFT
215 #define PUZZLE_LEFT BUTTON_MIDLEFT
216 #endif
217 #ifndef PUZZLE_RIGHT
218 #define PUZZLE_RIGHT BUTTON_MIDRIGHT
219 #endif
220 #ifndef PUZZLE_UP
221 #define PUZZLE_UP BUTTON_TOPMIDDLE
222 #endif
223 #ifndef PUZZLE_DOWN
224 #define PUZZLE_DOWN BUTTON_BOTTOMMIDDLE
225 #endif
226 #ifndef PUZZLE_SHUFFLE
227 #define PUZZLE_SHUFFLE BUTTON_BOTTOMLEFT
228 #endif
229 #ifndef PUZZLE_PICTURE
230 #define PUZZLE_PICTURE BUTTON_CENTER
231 #endif
232 #ifndef PUZZLE_QUIT_TEXT
233 #define PUZZLE_QUIT_TEXT "[TOPLEFT]"
234 #endif
235 #ifndef PUZZLE_SHUFFLE_TEXT
236 #define PUZZLE_SHUFFLE_TEXT "[BOTTOMLEFT]"
237 #endif
238 #ifndef PUZZLE_PICTURE_TEXT
239 #define PUZZLE_PICTURE_TEXT "[CENTER]"
240 #endif
241 #endif
243 #ifdef HAVE_ALBUMART
244 #include "lib/read_image.h"
245 #define READ_IMAGE read_image_file
246 #else
247 #define READ_IMAGE rb->read_bmp_file
248 #endif
250 #include "pluginbitmaps/sliding_puzzle.h"
251 #define IMAGE_WIDTH BMPWIDTH_sliding_puzzle
252 #define IMAGE_HEIGHT BMPHEIGHT_sliding_puzzle
253 #define IMAGE_SIZE IMAGE_WIDTH
255 /* use a square image, (the default Archos bitmap looks square on its display)
256 Puzzle image dimension is min(lcd_height,lcd_width)
257 4x4 is more convenient for square puzzles
258 Note: sliding_puzzle.bmp should be evenly divisible by SPOTS_X
259 and SPOTS_Y, otherwise lcd_bitmap_part stride won't be correct */
260 #define SPOTS_X 4
261 #define SPOTS_Y 4
262 #define SPOTS_WIDTH (IMAGE_WIDTH / SPOTS_X)
263 #define SPOTS_HEIGHT (IMAGE_HEIGHT / SPOTS_Y)
264 #define NUM_SPOTS (SPOTS_X*SPOTS_Y)
265 #define HOLE_ID (NUM_SPOTS)
266 #define INITIAL_HOLE (HOLE_ID-1)
268 enum picmodes
270 PICMODE_NUMERALS = 0,
271 PICMODE_INITIAL_PICTURE,
272 PICMODE_DEFAULT_PICTURE,
273 #ifdef HAVE_ALBUMART
274 PICMODE_ALBUM_ART,
275 #endif
276 // PICMODE_RANDOM,
277 PICMODE_LAST_XXX /* placeholder */
280 static const char* const picmode_descriptions[] = {
281 "Numerals",
282 "Viewer Picture",
283 "Default Picture",
284 #ifdef HAVE_ALBUMART
285 "Album Art",
286 #endif
287 "Shouldn't Get Here",
290 static int spots[NUM_SPOTS];
291 static int hole = INITIAL_HOLE, moves;
292 static unsigned char s[32];
293 static enum picmodes picmode = PICMODE_INITIAL_PICTURE;
294 static int num_font = FONT_UI;
295 static int moves_font = FONT_UI;
296 static int moves_y = 0;
298 static unsigned char *img_buf;
299 static size_t img_buf_len;
300 #ifdef HAVE_ALBUMART
301 static char albumart_path[MAX_PATH+1];
302 #endif
303 static char img_buf_path[MAX_PATH+1];
305 static const fb_data * puzzle_bmp_ptr;
306 /* initial_bmp_path points to selected bitmap if this game is launched
307 as a viewer for a .bmp file, or NULL if game is launched regular way */
308 static const char * initial_bmp_path=NULL;
310 #ifdef HAVE_ALBUMART
311 const char * get_albumart_bmp_path(void)
313 struct mp3entry* track = rb->audio_current_track();
315 if (!track || !track->path || track->path[0] == '\0')
316 return NULL;
318 if (!rb->search_albumart_files(track, "", albumart_path, MAX_PATH ) )
319 return NULL;
321 albumart_path[ MAX_PATH ] = '\0';
322 return albumart_path;
324 #endif
326 const char * get_random_bmp_path(void)
328 return(initial_bmp_path);
331 static bool load_resize_bitmap(void)
333 int rc;
334 const char * filename = NULL;
336 /* initially assume using the built-in default */
337 puzzle_bmp_ptr = sliding_puzzle;
339 switch( picmode ){
340 /* some modes don't even need to touch disk and trivially succeed */
341 case PICMODE_NUMERALS:
342 case PICMODE_DEFAULT_PICTURE:
343 default:
344 return(true);
346 #ifdef HAVE_ALBUMART
347 case PICMODE_ALBUM_ART:
348 filename = get_albumart_bmp_path();
349 break;
350 #endif
352 case PICMODE_RANDOM:
353 if(NULL == (filename=get_random_bmp_path()) )
354 filename = initial_bmp_path;
355 break;
357 case PICMODE_INITIAL_PICTURE:
358 filename = initial_bmp_path;
359 break;
362 if( filename != NULL )
364 /* if we already loaded image before, don't touch disk */
365 if( 0 == rb->strcmp( filename, img_buf_path ) )
367 puzzle_bmp_ptr = (const fb_data *)img_buf;
368 return true;
371 struct bitmap main_bitmap;
372 rb->memset(&main_bitmap,0,sizeof(struct bitmap));
373 main_bitmap.data = img_buf;
375 main_bitmap.width = IMAGE_WIDTH;
376 main_bitmap.height = IMAGE_HEIGHT;
378 rc = READ_IMAGE( filename, &main_bitmap,
379 img_buf_len,
380 FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER,
381 NULL);
382 if( rc > 0 )
384 puzzle_bmp_ptr = (const fb_data *)img_buf;
385 rb->strcpy( img_buf_path, filename );
386 return true;
390 /* something must have failed. get_albumart_bmp_path could return
391 NULL if albumart doesn't exist or couldn't be loaded, or
392 read_bmp_file could have failed. return false and caller should
393 try the next mode (PICMODE_DEFAULT_PICTURE and PICMODE_NUMERALS will
394 always succeed) */
395 return false;
398 /* draws a spot at the coordinates (x,y), range of p is 1-20 */
399 static void draw_spot(int p, int x, int y)
401 int w, h;
403 if (p == HOLE_ID)
405 #if LCD_DEPTH==1
406 /* the bottom-right cell of the default sliding_puzzle image is
407 an appropriate hole graphic */
408 rb->lcd_bitmap_part(sliding_puzzle, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
409 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
410 STRIDE(BMPWIDTH_sliding_puzzle, BMPHEIGHT_sliding_puzzle),
411 x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
412 #else
413 /* just draw a black rectangle */
414 int old_fg = rb->lcd_get_foreground();
415 rb->lcd_set_foreground(LCD_BLACK);
416 rb->lcd_fillrect(x,y,SPOTS_WIDTH,SPOTS_HEIGHT);
417 rb->lcd_set_foreground(old_fg);
418 #endif
420 else if (picmode != PICMODE_NUMERALS)
422 rb->lcd_bitmap_part( puzzle_bmp_ptr, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
423 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
424 STRIDE(BMPWIDTH_sliding_puzzle, BMPHEIGHT_sliding_puzzle),
425 x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
426 } else {
427 rb->lcd_drawrect(x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
428 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
429 rb->lcd_fillrect(x+1, y+1, SPOTS_WIDTH-2, SPOTS_HEIGHT-2);
430 rb->lcd_set_drawmode(DRMODE_SOLID);
431 rb->snprintf(s, sizeof(s), "%d", p);
432 rb->lcd_setfont(num_font);
433 rb->lcd_getstringsize(s, &w, &h);
434 rb->lcd_putsxy(x + (SPOTS_WIDTH/2) - w / 2,
435 y + (SPOTS_HEIGHT/2) - h / 2, s);
439 /* check if the puzzle is solved */
440 static bool puzzle_finished(void)
442 int i;
443 for (i=0; i<NUM_SPOTS; i++)
444 if (spots[i] != (i+1))
445 return false;
446 return true;
449 /* move a piece in any direction */
450 static void move_spot(int x, int y)
452 int i, w;
453 spots[hole] = spots[hole-x-SPOTS_X*y];
454 hole -= (x+SPOTS_X*y);
455 moves++;
456 rb->lcd_setfont(moves_font);
457 #if LCD_WIDTH > LCD_HEIGHT
458 rb->snprintf(s, sizeof(s), "%d", moves);
459 w = rb->lcd_getstringsize(s, NULL, NULL);
460 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
461 moves_y, s);
462 #else
463 (void)w;
464 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
465 rb->lcd_putsxy(3, moves_y, s);
466 #endif
467 for(i=1;i<=4;i++)
469 draw_spot(HOLE_ID,
470 (hole%SPOTS_X)*SPOTS_WIDTH,
471 (hole/SPOTS_X)*SPOTS_HEIGHT);
472 draw_spot(spots[hole],
473 (hole%SPOTS_X)*SPOTS_WIDTH + (i*x*SPOTS_WIDTH)/5,
474 (hole/SPOTS_X)*SPOTS_HEIGHT + (i*y*SPOTS_HEIGHT)/5);
475 rb->lcd_update();
476 rb->sleep(HZ/50);
478 draw_spot(HOLE_ID,
479 (hole%SPOTS_X)*SPOTS_WIDTH,
480 (hole/SPOTS_X)*SPOTS_HEIGHT);
481 draw_spot(spots[hole],
482 ((hole%SPOTS_X)+x)*SPOTS_WIDTH,
483 ((hole/SPOTS_X)+y)*SPOTS_HEIGHT);
484 rb->lcd_update();
486 spots[hole] = HOLE_ID;
489 static void draw_playfield(void)
491 int i, w;
493 rb->lcd_clear_display();
494 rb->lcd_setfont(moves_font);
495 #if LCD_WIDTH > LCD_HEIGHT
496 rb->lcd_vline(IMAGE_WIDTH, 0, LCD_HEIGHT-1);
497 w = rb->lcd_getstringsize("Moves", NULL, NULL);
498 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
499 10, "Moves");
500 rb->snprintf(s, sizeof(s), "%d", moves);
501 w = rb->lcd_getstringsize(s, NULL, NULL);
502 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
503 moves_y, s);
504 #else
505 (void)w;
506 rb->lcd_hline(0, LCD_WIDTH-1, IMAGE_HEIGHT);
507 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
508 rb->lcd_putsxy(3, moves_y, s);
509 #endif
511 /* draw spots to the lcd */
512 for (i=0; i<NUM_SPOTS; i++)
513 draw_spot(spots[i], (i%SPOTS_X)*SPOTS_WIDTH, (i/SPOTS_X)*SPOTS_HEIGHT);
515 rb->lcd_update();
518 /* initializes the puzzle */
519 static void puzzle_init(void)
521 int i, r, temp, tsp[NUM_SPOTS];
523 moves = 0;
525 /* shuffle spots */
526 for (i=NUM_SPOTS-1; i>=0; i--) {
527 r = (rb->rand() % (i+1));
529 temp = spots[r];
530 spots[r] = spots[i];
531 spots[i] = temp;
533 if (spots[i]==HOLE_ID)
534 hole = i;
537 /* test if the puzzle is solvable */
538 for (i=0; i<NUM_SPOTS; i++)
539 tsp[i] = spots[i];
540 r=0;
542 /* First, check if the problem has even or odd parity,
543 depending on where the empty square is */
544 if ((((SPOTS_X-1)-hole%SPOTS_X) + ((SPOTS_Y-1)-hole/SPOTS_X))%2 == 1)
545 ++r;
547 /* Now check how many swaps we need to solve it */
548 for (i=0; i<NUM_SPOTS-1; i++) {
549 while (tsp[i] != (i+1)) {
550 temp = tsp[i];
551 tsp[i] = tsp[temp-1];
552 tsp[temp-1] = temp;
553 ++r;
557 /* if the random puzzle isn't solvable just change two spots */
558 if (r%2 == 1) {
559 if (spots[0]!=HOLE_ID && spots[1]!=HOLE_ID) {
560 temp = spots[0];
561 spots[0] = spots[1];
562 spots[1] = temp;
563 } else {
564 temp = spots[2];
565 spots[2] = spots[3];
566 spots[3] = temp;
570 draw_playfield();
573 /* the main game loop */
574 static int puzzle_loop(void)
576 int button;
577 int lastbutton = BUTTON_NONE;
578 bool load_success;
580 puzzle_init();
581 while(true) {
582 button = rb->button_get(true);
583 switch (button) {
584 #ifdef PUZZLE_RC_QUIT
585 case PUZZLE_RC_QUIT:
586 #endif
587 case PUZZLE_QUIT:
588 /* get out of here */
589 return PLUGIN_OK;
591 case PUZZLE_SHUFFLE:
592 #ifdef PUZZLE_SHUFFLE_PICTURE_PRE
593 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
594 break;
595 #endif
596 /* mix up the pieces */
597 puzzle_init();
598 break;
600 case PUZZLE_PICTURE:
601 #ifdef PUZZLE_SHUFFLE_PICTURE_PRE
602 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
603 break;
604 #endif
605 /* change picture */
606 picmode = (picmode+1)%PICMODE_LAST_XXX;
608 /* if load_resize_bitmap fails to load bitmap, try next picmode
612 load_success = load_resize_bitmap();
613 if( !load_success )
614 picmode = (picmode+1)%PICMODE_LAST_XXX;
616 while( !load_success );
618 /* tell the user what mode we picked in the end! */
619 rb->splash(HZ,picmode_descriptions[ picmode ] );
620 draw_playfield();
621 break;
623 case PUZZLE_LEFT:
624 if ((hole%SPOTS_X)<(SPOTS_X-1) && !puzzle_finished())
625 move_spot(-1, 0);
626 break;
628 case PUZZLE_RIGHT:
629 if ((hole%SPOTS_X)>0 && !puzzle_finished())
630 move_spot(1, 0);
631 break;
633 case PUZZLE_UP:
634 if ((hole/SPOTS_X)<(SPOTS_Y-1) && !puzzle_finished())
635 move_spot(0, -1);
636 break;
638 case PUZZLE_DOWN:
639 if ((hole/SPOTS_X)>0 && !puzzle_finished())
640 move_spot(0, 1);
641 break;
643 default:
644 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
645 return PLUGIN_USB_CONNECTED;
646 break;
648 if (button != BUTTON_NONE)
649 lastbutton = button;
653 enum plugin_status plugin_start(
654 const void* parameter)
656 int i, w, h;
658 initial_bmp_path=(const char *)parameter;
659 img_buf = rb->plugin_get_buffer(&img_buf_len);
660 picmode = PICMODE_INITIAL_PICTURE;
661 img_buf_path[0] = '\0';
663 /* If launched as a viewer, just go straight to the game without
664 bothering with the splash or instructions page */
665 if(parameter==NULL)
667 /* if not launched as a viewer, use default puzzle, and show help */
668 picmode = PICMODE_DEFAULT_PICTURE;
670 /* print title */
671 rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h);
672 w = (w+1)/2;
673 h = (h+1)/2;
674 rb->lcd_clear_display();
675 rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h,
676 (unsigned char *)"Sliding Puzzle");
677 rb->lcd_update();
678 rb->sleep(HZ);
680 /* print instructions */
681 rb->lcd_clear_display();
682 rb->lcd_setfont(FONT_SYSFIXED);
683 #if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ARCHOS_AV300_PAD
684 rb->lcd_putsxy(3, 18, "[OFF] to stop");
685 rb->lcd_putsxy(3, 28, "[F1] shuffle");
686 rb->lcd_putsxy(3, 38, "[F2] change pic");
687 #elif CONFIG_KEYPAD == ONDIO_PAD
688 rb->lcd_putsxy(0, 18, "[OFF] to stop");
689 rb->lcd_putsxy(0, 28, "[MODE..] shuffle");
690 rb->lcd_putsxy(0, 38, "[MODE] change pic");
691 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
692 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
693 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
694 rb->lcd_putsxy(0, 18, "[S-MENU] to stop");
695 rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle");
696 rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic");
697 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
698 (CONFIG_KEYPAD == IRIVER_H300_PAD)
699 rb->lcd_putsxy(0, 18, "[STOP] to stop");
700 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
701 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
702 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
703 rb->lcd_putsxy(0, 18, "[OFF] to stop");
704 rb->lcd_putsxy(0, 28, "[REC] shuffle");
705 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
706 #elif CONFIG_KEYPAD == GIGABEAT_PAD
707 rb->lcd_putsxy(0, 18, "[POWER] to stop");
708 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
709 rb->lcd_putsxy(0, 38, "[A] change pic");
710 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
711 (CONFIG_KEYPAD == SANSA_C200_PAD)
712 rb->lcd_putsxy(0, 18, "[OFF] to stop");
713 rb->lcd_putsxy(0, 28, "[REC] shuffle");
714 rb->lcd_putsxy(0, 38, "[SELECT] change pic");
715 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
716 rb->lcd_putsxy(0, 18, "[OFF] to stop");
717 rb->lcd_putsxy(0, 28, "[REW] shuffle");
718 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
719 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
720 rb->lcd_putsxy(0, 18, "[BACK] to stop");
721 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
722 rb->lcd_putsxy(0, 38, "[MENU] change pic");
723 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
724 rb->lcd_putsxy(0, 18, "[REC] to stop");
725 rb->lcd_putsxy(0, 28, "[MODE] shuffle");
726 rb->lcd_putsxy(0, 38, "[MENU] change pic");
727 #endif
728 #ifdef HAVE_TOUCHSCREEN
729 rb->lcd_putsxy(0, 18, PUZZLE_QUIT_TEXT " to stop");
730 rb->lcd_putsxy(0, 28, PUZZLE_SHUFFLE_TEXT " shuffle");
731 rb->lcd_putsxy(0, 38, PUZZLE_PICTURE_TEXT " change pic");
732 #endif
733 #ifdef HAVE_ALBUMART
734 rb->lcd_putsxy(0,48," pic->albumart->num");
735 #else
736 rb->lcd_putsxy(0,48," pic<->num");
737 #endif
738 rb->lcd_update();
739 rb->button_get_w_tmo(HZ*2);
742 hole = INITIAL_HOLE;
744 if( !load_resize_bitmap() )
746 rb->lcd_clear_display();
747 rb->splash(HZ*2,"Failed to load bitmap!");
748 return PLUGIN_OK;
751 /* Calculate possible font sizes and text positions */
752 rb->lcd_setfont(FONT_UI);
753 rb->lcd_getstringsize("15", &w, &h);
754 if ((w > (SPOTS_WIDTH-2)) || (h > (SPOTS_HEIGHT-2)))
755 num_font = FONT_SYSFIXED;
757 #if LCD_WIDTH > LCD_HEIGHT
758 rb->lcd_getstringsize("Moves", &w, &h);
759 if (w > (LCD_WIDTH-IMAGE_WIDTH-1))
760 moves_font = FONT_SYSFIXED;
761 rb->lcd_setfont(moves_font);
762 rb->lcd_getstringsize("Moves", &w, &h);
763 moves_y = 10 + h;
764 #else
765 rb->lcd_getstringsize("Moves: 999", &w, &h);
766 if ((w > LCD_WIDTH) || (h > (LCD_HEIGHT-IMAGE_HEIGHT-1)))
767 moves_font = FONT_SYSFIXED;
768 rb->lcd_setfont(moves_font);
769 rb->lcd_getstringsize("Moves: 999", &w, &h);
770 moves_y = (IMAGE_HEIGHT+1+(LCD_HEIGHT-IMAGE_HEIGHT-1)/2) - h / 2;
771 #endif
772 for (i=0; i<NUM_SPOTS; i++)
773 spots[i]=(i+1);
775 #ifdef HAVE_LCD_COLOR
776 rb->lcd_set_background(LCD_BLACK);
777 rb->lcd_set_foreground(LCD_WHITE);
778 rb->lcd_set_backdrop(NULL);
779 #elif LCD_DEPTH > 1
780 rb->lcd_set_background(LCD_WHITE);
781 rb->lcd_set_foreground(LCD_BLACK);
782 rb->lcd_set_backdrop(NULL);
783 #endif
785 draw_playfield();
786 rb->sleep(HZ*2);
788 return puzzle_loop();
791 #endif