2 Designed, Written, AI Bots, the lot ...BlueChip =8ªD#
5 DevZer0, LinusN, Zagor, scott666
6 for their help with understanding Rockbox & the SDK
8 Please note that the code formatting is not that which was
9 produced originally, but has been updated by whoever
10 ported it to the plugin system.
11 I am sure it was done with good reason, so I have not
16 * Version Date Who Comment
17 * -------- -------- ---- ------------------------------------------------
18 * 1.4 20030729 BC Ensure game terminates even if dreamer disabled
19 * 1.3 20030729 BC Fixed display bug introduced by port to plugin
20 * Updated documentation
21 * 1.2 2003 Ported to new plugin system
22 * 1.1 20030625 BC Flash board when invalid move to used aquare
23 * Fixed "pause computer" for real harware!
24 * Added USB_CONNECTED support
25 * Ensure correct fonts on the way in and out
26 * 1.0 20030622 BC Release
31 * # Reintroduce suspend feature under plugin system
37 #ifdef HAVE_LCD_BITMAP
39 static struct plugin_api
* rb
;
41 /***************************************************************************/
42 /***************************************************************************/
44 /***************************************************************************/
45 /***************************************************************************/
47 /* Don't reorder this array - you have been warned! */
80 static unsigned char othfont
[of_eos
][6] = {
90 {0x0C, 0x1E, 0x3F, 0x3F, 0x1E, 0x0C},
100 {0x0C, 0x1E, 0x33, 0x33, 0x1E, 0x0C},
110 {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00},
120 {0x00, 0x12, 0x0C, 0x0C, 0x12, 0x00},
130 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
132 * | # # | 0001 0010 12
133 * | # # | 0001 0010 12
134 * | #### | 0001 1110 1E
135 * | # # | 0001 0010 12
136 * | # # | 0001 0010 12
137 * | # # | 0001 0010 12
140 {0x12,0x12,0x1E,0x12,0x12,0x12},
142 * | ## | 0000 1100 0C
143 * | # # | 0001 0010 12
146 * | # # | 0001 0010 12
147 * | ## | 0000 1100 0C
150 {0x0C,0x12,0x20,0x20,0x12,0x0C},
152 * | ## | 0000 1100 0C
153 * | # # | 0001 0010 12
154 * | # ## | 0001 0110 16
155 * | ## # | 0001 1010 1A
156 * | # # | 0001 0010 12
157 * | ## | 0000 1100 0C
160 {0x0C,0x12,0x16,0x1A,0x12,0x0C},
163 * | ## | 0000 1100 0C
167 * | ### | 0000 1110 0E
170 {0x04,0x0C,0x04,0x04,0x04,0x0E},
172 * | ## | 0000 1100 0C
173 * | # # | 0001 0010 12
175 * | ## | 0000 1100 0C
177 * | #### | 0001 1110 1E
180 {0x0C,0x12,0x02,0x0C,0x10,0x1E},
182 * | ### | 0001 1100 1C
184 * | ## | 0000 1100 0C
187 * | ### | 0001 1100 1C
190 {0x1C,0x02,0x0C,0x02,0x02,0x1C},
194 * | # # | 0001 0100 14
195 * | # # | 0001 0100 14
196 * | #### | 0001 1110 1E
200 {0x10,0x10,0x14,0x14,0x1E,0x04},
202 * | #### | 0001 1110 1E
204 * | ### | 0001 1100 1C
206 * | # # | 0001 0010 12
207 * | ## | 0000 1100 0C
210 {0x1E,0x10,0x1C,0x02,0x12,0x0C},
212 * | ### | 0000 1110 0E
214 * | ### | 0001 1100 1C
215 * | # # | 0001 0010 12
216 * | # # | 0001 0010 12
217 * | ## | 0000 1100 0C
220 {0x0E,0x10,0x1C,0x12,0x12,0x0C},
222 * | #### | 0001 1110 1E
230 {0x1E,0x02,0x04,0x04,0x08,0x08},
232 * | ## | 0000 1100 0C
233 * | # # | 0001 0010 12
234 * | ## | 0000 1100 0C
235 * | # # | 0001 0010 12
236 * | # # | 0001 0010 12
237 * | ## | 0000 1100 0C
240 {0x0C,0x12,0x0C,0x12,0x12,0x0C},
242 * | ## | 0000 1100 0C
243 * | # # | 0001 0010 12
244 * | # # | 0001 0010 12
245 * | ### | 0000 1110 0E
247 * | ## | 0000 1100 0C
250 {0x0C,0x12,0x12,0x0E,0x02,0x0C},
253 * | ## | 0000 1100 0C
254 * | ## | 0000 1100 0C
256 * | ## | 0000 1100 0C
257 * | ## | 0000 1100 0C
260 {0x00,0x0C,0x0C,0x00,0x0C,0x0C},
264 * | #### | 0001 1110 1E
265 * | #### | 0001 1110 1E
270 {0x00,0x00,0x1E,0x1E,0x00,0x00},
274 * | ## | 0000 0110 06
275 * |######| 0011 1111 3F
276 * | ## | 0000 0110 06
280 {0x00,0x04,0x06,0x3F,0x06,0x04},
282 * ÚÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄ¿
283 * ³.###..³.³#.....³.³.###..³.³#...#.³ xx01 1100 | xx10 0000 | xx01 1100 | xx10 0010 | 1C 20 1C 22
284 * ³#...#.³.³#.....³.³#...#.³.³#...#.³ xx10 0010 | xx10 0000 | xx10 0010 | xx10 0010 | 22 20 22 22
285 * ³#...#.³.³#.....³.³#...#.³.³.###..³ xx10 0010 | xx10 0000 | xx10 0010 | xx01 1100 | 22 20 22 1C
286 * ³####..³.³#.....³.³#####.³.³..#...³ xx11 1100 | xx10 0000 | xx11 1110 | xx00 1000 | 3C 20 3E 08
287 * ³#.....³.³#...#.³.³#...#.³.³..#...³ xx10 0000 | xx10 0010 | xx10 0010 | xx00 1000 | 20 22 22 08
288 * ³#.....³.³.###..³.³#...#.³.³..#...³ xx10 0000 | xx01 1100 | xx10 0010 | xx00 1000 | 20 1C 22 08
289 * ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ
291 {0x1C,0x22,0x22,0x3C,0x20,0x20},
292 {0x20,0x20,0x20,0x20,0x22,0x1C},
293 {0x1C,0x22,0x22,0x3E,0x22,0x22},
294 {0x22,0x22,0x1C,0x08,0x08,0x08},
295 /* ÚÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄ¿
296 * ³.###..³.³#...#.³.³#####.³.³#####.³ xx01 1100 | xx10 0010 | xx11 1110 | xx11 1110 | 1C 22 3E 3E
297 * ³#...#.³.³#...#.³.³..#...³.³..#...³ xx10 0010 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08
298 * ³#...#.³.³#...#.³.³..#...³.³..#...³ xx10 0010 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08
299 * ³#...#.³.³#...#.³.³..#...³.³..#...³ xx10 0010 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08
300 * ³#..##.³.³#...#.³.³..#...³.³..#...³ xx10 0110 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08
301 * ³.#####³.³.###..³.³#####.³.³..#...³ xx01 1111 | xx01 1100 | xx11 1110 | xx00 1000 | 1F 1C 3E 08
302 * ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ
304 {0x1C,0x22,0x22,0x22,0x22,0x1F},
305 {0x22,0x22,0x22,0x22,0x22,0x1C},
306 {0x3E,0x08,0x08,0x08,0x08,0x3E},
307 {0x3E,0x08,0x08,0x08,0x08,0x08}
312 /***************************************************************************/
313 /***************************************************************************/
315 /***************************************************************************/
316 /***************************************************************************/
320 ######### # # ### ## ## ###
321 #### # # # # # # # # # #
322 ## # ### ### # # # # #
323 ## # # # # # ### # ##
327 # ### # # ### ##### ### # # ###
328 # # # # # # # # # # #
329 # ## ### ## # ### # # # ##
332 #### ### # ### # ### # # ###
336 #####################################
337 #####################################
340 ## ##### # # #### # ##
342 ###### # #### ### # ## ##
343 ###### # # # # # ## ##
345 ## # # # #### #### ##
348 #####################################
349 #####################################
352 ####|####|# # | # |### | ##| #|# |### | | | FF A2 E3 18 E0 00
353 ####| |# # | # |# #| # |# # | # #| | | | F0 A2 94 A5 00 00
354 ## | |# #|## |### | # |# # | # #| | | | C0 9C E4 A5 00 00
355 ## | | |# |# #| # |# ##|# #| ##| | | C0 08 94 B9 30 00
356 ## | | |# |# #| # |# # |# #| #| | | C0 08 94 A9 10 00
357 # | | |# |### | ##| # | # |### | | | 80 08 E3 24 E0 00
358 # | | | | | | | | | | | 80 00 00 00 00 00
359 # | ##|# # | # | ###| ###|## |### | # #| #|## | 83 A2 77 CE 51 C0
360 # | # | # | # |# | #| #| |# # |# # | | 84 22 81 10 AA 00
361 # | ##| #|## | ## | #| #|## |# # |# #|# | 83 1C 61 1C A9 80
362 # | |# |# | #| #| #| |# # |# | # | 80 88 11 10 A8 40
363 # #| |# |# | #| #| #| |# |# | # | 90 88 11 10 88 40
364 ####| ###| |# |### | #| |### |# |# ##|# | F7 08 E1 0E 8B 80
365 | | | | | | | | | | | 00 00 00 00 00 00
366 | | | | | | | | | | | 00 00 00 00 00 00
367 | | | | | | | | | | | 00 00 00 00 00 00
368 ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00
369 ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00
370 | | | | | | | | | | | 00 00 00 00 00 00
371 | | | | | | | | | | | 00 00 00 00 00 00
372 | ##| #|####| # |# ##|## #| | ## | | | 03 1F 4B D0 60 00
373 | ###|# | # | # |# # | #| |####| | | 07 84 4A 10 F0 00
374 |####|## | # | ###|# ##|# #| #|# #|# | | 0F C4 7B 91 98 00
375 |####|## | # | # |# # | #| #|# #|# | | 0F C4 4A 11 98 00
376 | ###|# | # | # |# # | #| |####| | | 07 84 4A 10 F0 00
377 | ##| | # | # |# ##|## #|### | ## | | | 03 04 4B DE 60 00
378 | | | | | | | | | | | 00 00 00 00 00 00
379 | | | | | | | | | | | 00 00 00 00 00 00
380 ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00
381 ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00
385 * bpl = BYTES per line
386 * ppl = PIXELS per line
393 static unsigned char logo
[] = {
394 0xFF,0xA2,0xE3,0x18,0xE0,0x00,
395 0xF0,0xA2,0x94,0xA5,0x00,0x00,
396 0xC0,0x9C,0xE4,0xA5,0x00,0x00,
397 0xC0,0x08,0x94,0xB9,0x30,0x00,
398 0xC0,0x08,0x94,0xA9,0x10,0x00,
399 0x80,0x08,0xE3,0x24,0xE0,0x00,
400 0x80,0x00,0x00,0x00,0x00,0x00,
401 0x83,0xA2,0x77,0xCE,0x51,0xC0,
402 0x84,0x22,0x81,0x10,0xAA,0x00,
403 0x83,0x1C,0x61,0x1C,0xA9,0x80,
404 0x80,0x88,0x11,0x10,0xA8,0x40,
405 0x90,0x88,0x11,0x10,0x88,0x40,
406 0xF7,0x08,0xE1,0x0E,0x8B,0x80,
407 0x00,0x00,0x00,0x00,0x00,0x00,
408 0x00,0x00,0x00,0x00,0x00,0x00,
409 0x00,0x00,0x00,0x00,0x00,0x00,
410 0x00,0x00,0x00,0x00,0x00,0x00,
411 0x3F,0xFF,0xFF,0xFF,0xFE,0x00,
412 0x3F,0xFF,0xFF,0xFF,0xFE,0x00,
413 0x00,0x00,0x00,0x00,0x00,0x00,
414 0x00,0x00,0x00,0x00,0x00,0x00,
415 0x00,0x00,0x00,0x00,0x00,0x00,
416 0x03,0x1F,0x4B,0xD0,0x60,0x00,
417 0x07,0x84,0x4A,0x10,0xF0,0x00,
418 0x0F,0xC4,0x7B,0x91,0x98,0x00,
419 0x0F,0xC4,0x4A,0x11,0x98,0x00,
420 0x07,0x84,0x4A,0x10,0xF0,0x00,
421 0x03,0x04,0x4B,0xDE,0x60,0x00,
422 0x00,0x00,0x00,0x00,0x00,0x00,
423 0x00,0x00,0x00,0x00,0x00,0x00,
424 0x3F,0xFF,0xFF,0xFF,0xFE,0x00,
425 0x3F,0xFF,0xFF,0xFF,0xFE,0x00
428 static void showlogo(int x
, int y
, bool on
)
430 int px
,py
; /* pixel x & y */
434 for (py
=0; py
<logo_l
; py
++)
435 for (px
=0; px
<logo_ppl
; px
++)
436 if ( ((logo
[(py
*logo_bpl
)+(px
/8)] >>(7-(px
%8))) &1) )
437 rb
->lcd_drawpixel(x
+px
, y
+py
);
439 rb
->lcd_clearpixel(x
+px
, y
+py
);
440 rb
->lcd_update_rect(x
,y
, logo_ppl
, logo_l
);
443 rb
->lcd_clearrect(x
,y
, logo_ppl
, logo_l
);
450 /***************************************************************************/
451 /***************************************************************************/
453 /***************************************************************************/
454 /***************************************************************************/
457 /* the following #define had to be taken from Button.c
458 'cos it is not defined in the header!! */
459 /* how long until repeat kicks in */
460 #define REPEAT_START 6
470 /* screen coords - top left x&y */
488 * there are a number of routines that expect these values asis
489 * do not try to play with these, you will likely kill the program
498 /* Who gets first turn */
499 #define FIRST PLAYERX
505 /* Oponent skill level / help level
506 * -------- ---------------------------------------------------
507 * NONE no ai / no help
508 * WEAK random valid move / show all possible
509 * AVERAGE most pieces (random) / all + most pieces
510 * SMART most pieces (weighted/random) / all + weighted
520 #define BEST 3 /* the best ai alogrithm currently available */
522 /* these are for code clarity, do not change them! */
528 /* This represents the maximum number of possible moves
529 * I have no idea what the real maximum is, buts tests
544 /*===================================================================
545 * local global variables
546 * THIS IS THE DATA THAT NEEDS TO BE SAVED TO ALLOW THE GAME
547 * TO CONTINUE ...THE CONTINUE FEATURE DOES NOT WORK UNDER THE
549 *==================================================================*/
558 /* 8x8 with borders */
559 static unsigned char board
[10][10];
561 /* player=HUMAN|AIBOT */
562 static bool player
[2] = {DF_PLX
, DF_PLO
};
564 /* AI = WEAK|AVERAGE|SMART|EXPERT|GURU
565 Help=NONE|WEAK|AVERAGE|SMART|EXPERT|GURU */
566 static unsigned char ai_help
[2] = {DF_AIX
, DF_AIO
};
568 /* is a game under way */
569 static bool playing
= false;
571 /* who's turn is it? */
572 static bool turn
= FIRST
;
574 /********************************************************************
575 * strlen ofr use with othello print system
576 ********************************************************************/
577 static int othstrlen(char* s
)
581 for(i
=0; s
[i
]!=of_eos
; i
++);
587 /********************************************************************
588 * print othello char upd=true will issue update_lcd()
589 ********************************************************************/
590 static void othprint(unsigned char x
, unsigned char y
, char ch
, bool upd
)
592 int px
,py
; /* pixel coords 1..6 */
594 for (py
=0; py
<6; py
++)
595 for (px
=0; px
<6; px
++)
596 if ((othfont
[(unsigned char)ch
][py
] >>(5-px
)) &1)
597 rb
->lcd_drawpixel(x
+px
, y
+py
);
599 rb
->lcd_clearpixel(x
+px
, y
+py
);
602 rb
->lcd_update_rect(x
,y
, 6,6);
609 /********************************************************************
610 * print othello string upd=true will issue update_lcd()
611 ********************************************************************/
612 static void othprints(unsigned char x
, unsigned char y
, char* s
, bool upd
)
615 int l
; /* length of string */
620 othprint(x
+i
*6,y
, s
[i
], false);
623 rb
->lcd_update_rect(x
,y
, l
*6,6);
630 /********************************************************************
631 * display game over visuals
632 ********************************************************************/
633 static void show_endgame(unsigned char scx
, unsigned char sco
)
635 /* end of game messages */
636 showlogo(logo_tlx
,logo_tly
, false);
639 rb
->lcd_putsxy(go_tlx
+1,go_tly
+1, "Game");
640 rb
->lcd_putsxy(go_tlx
+1,go_tly
+11, "oveR");
641 rb
->lcd_invertrect(go_tlx
,go_tly
, 27,20);
646 rb
->lcd_putsxy(draw_tlx
+13,draw_tly
+4, "DraW");
647 othprint(draw_tlx
+5,draw_tly
+5, of_plx
, true);
648 othprint(draw_tlx
+40,draw_tly
+5, of_plo
, true);
649 rb
->lcd_drawrect(draw_tlx
+2,draw_tly
+2, 47,11);
650 rb
->lcd_drawrect(draw_tlx
,draw_tly
, 51,15);
655 rb
->lcd_putsxy(win_tlx
+14,win_tly
+4, "WiNS");
657 othprint(win_tlx
+5,win_tly
+5, of_plo
, true);
659 othprint(win_tlx
+5,win_tly
+5, of_plx
, true);
660 rb
->lcd_drawrect(win_tlx
+2,win_tly
+2, 39,11);
661 rb
->lcd_drawrect(win_tlx
,win_tly
, 43,15);
671 /********************************************************************
672 * display othello grid
673 * currenly hard coded to the top left corner of the screen
674 ********************************************************************/
675 static void show_grid(void)
679 rb
->lcd_clearrect(0,0, (8*7)+1,(8*7)+1);
680 rb
->lcd_drawrect(0,0, (8*7)+1,(8*7)+1);
681 for (x
=7; x
<((7*7)+1); x
+=7)
683 rb
->lcd_drawline(1,x
, 2,x
);
684 rb
->lcd_drawline(x
,1, x
,2);
685 rb
->lcd_drawline(x
,(8*7)-1, x
,(8*7)-2);
686 rb
->lcd_drawline((8*7)-1,x
, (8*7)-2,x
);
687 for (y
=7; y
<((7*7)+1); y
+=7)
689 rb
->lcd_drawline(x
-2,y
, x
+2,y
);
690 rb
->lcd_drawline(x
,y
-2, x
,y
+2);
693 rb
->lcd_update_rect(0,0, (8*7)+1,(8*7)+1);
700 /********************************************************************
701 * flash the board - used for invalid move!
702 ********************************************************************/
703 static void flashboard(void)
705 rb
->lcd_invertrect(0,0, (8*7)+1,(8*7)+1);
706 rb
->lcd_update_rect(0,0, (8*7)+1,(8*7)+1);
708 rb
->lcd_invertrect(0,0, (8*7)+1,(8*7)+1);
709 rb
->lcd_update_rect(0,0, (8*7)+1,(8*7)+1);
716 /********************************************************************
717 * show player skill levels
718 ********************************************************************/
719 static void show_players(void)
721 static char scs
[] = {
722 of_plx
, of_colon
, of_h
, of_dash
, of_0
, of_eos
, /* 0 */
723 of_plo
, of_colon
, of_h
, of_dash
, of_0
, of_eos
/* 6 */
726 if (player
[PLAYERX
]==AIBOT
)
730 scs
[4] = ai_help
[PLAYERX
] +of_0
;
732 if (player
[PLAYERO
]==AIBOT
)
736 scs
[10] = ai_help
[PLAYERO
] +of_0
;
738 othprints( 2,58, &scs
[0], true);
739 othprints(40,58, &scs
[6], true);
746 /********************************************************************
748 ********************************************************************/
749 static void show_f3(bool playing
)
751 static char scs
[10] = {of_p
, of_l
, of_a
, of_y
, of_eos
,
752 of_q
, of_u
, of_i
, of_t
, of_eos
};
755 othprints(80,58, &scs
[5], true);
757 othprints(80,58, &scs
[0], true);
764 /********************************************************************
766 ********************************************************************/
767 static void show_board(void)
773 othprint(((x
-1)*7)+1, ((y
-1)*7)+1, board
[y
][x
], false);
774 rb
->lcd_update_rect(0,0, (8*7)+1,(8*7)+1);
781 /********************************************************************
782 * display scores player "turn" will get the arrow
783 ********************************************************************/
784 static void show_score(bool turn
)
786 static char scs
[] = {of_ptr
, of_eos
, /* 0 */
787 of_sp
, of_eos
, /* 2 */
788 of_plx
, of_colon
, of_eos
, /* 4 */
789 of_plo
, of_colon
, of_eos
, /* 7 */
790 of_sp
, of_sp
, of_eos
, /* 10 score.x */
791 of_sp
, of_sp
, of_eos
, /* 13 score.o */
794 rb
->snprintf(&scs
[10], 3, "%d", score
.x
);
795 scs
[10] = scs
[10] -'0' +of_0
;
799 scs
[11] = scs
[11] -'0' +of_0
;
802 rb
->snprintf(&scs
[13], 3, "%d", score
.o
);
803 scs
[13] = scs
[13] -'0' +of_0
;
807 scs
[14] = scs
[14] -'0' +of_0
;
813 othprints(sc_tlx
,sc_tly
, &scs
[0], false);
814 othprints(sc_tlx
,sc_tly
+8, &scs
[2], false);
818 othprints(sc_tlx
,sc_tly
, &scs
[2], false);
819 othprints(sc_tlx
,sc_tly
+8, &scs
[0], false);
823 othprints(sc_tlx
+10,sc_tly
, &scs
[4], false);
824 othprints(sc_tlx
+10,sc_tly
+8, &scs
[7], false);
827 othprints(sc_tlx
+26,sc_tly
, &scs
[10], false);
828 othprints(sc_tlx
+26,sc_tly
+8, &scs
[13], false);
830 rb
->lcd_update_rect(sc_tlx
,sc_tly
, 40,14);
836 /********************************************************************
838 ********************************************************************/
839 static void initscreen(void)
841 rb
->lcd_setfont(FONT_SYSFIXED
);
842 rb
->lcd_clear_display();
849 /********************************************************************
850 * Check is the specified move is valid
851 * if type=MOVE - the board will be updated.
852 * this is the recursive bit - it is called by domove()
853 * checkmove only checks the move in ONE direction
854 ********************************************************************/
855 static int checkmove(unsigned char x
, unsigned char y
, bool pl
,
856 unsigned char dir
, bool type
)
861 x
-= ( ((dir
&LEFT
)==LEFT
) ?1:0);
862 x
+= ( ((dir
&RIGHT
)==RIGHT
) ?1:0);
863 y
-= ( ((dir
&UP
)==UP
) ?1:0);
864 y
+= ( ((dir
&DOWN
)==DOWN
) ?1:0);
868 /* found your piece */
869 if ( t
== ((pl
==PLAYERX
)?PLAYERX
:PLAYERO
) )
872 /* found an empty sqaure or board edge */
876 /* must have found opponent piece */
877 if ((i
= checkmove(x
,y
, pl
, dir
, type
)))
888 /********************************************************************
889 * this is the control loop for checkmove()
890 * checkmove()it is called with all eight possible directoins
891 * the move.taken is defined before it returns
892 * 0 taken is an invalid move
893 ********************************************************************/
894 static void domove(struct move
* move
, bool type
)
900 for (dir
=DOWN
; dir
<=(LEFT
|UP
); dir
++)
902 if ( (dir
&(UP
|DOWN
)) ==(UP
|DOWN
) )
904 if ((i
= checkmove(move
->x
, move
->y
, move
->player
, dir
, type
)))
912 /********************************************************************
913 * initialise a new game board and draw it on the screen
914 ********************************************************************/
915 static void initboard(void)
921 if ( (y
%9)==0 || (x
%9)==0)
922 board
[y
][x
] = BORDER
;
926 board
[4][4] = PLAYERX
;
927 board
[5][5] = PLAYERX
;
928 board
[4][5] = PLAYERO
;
929 board
[5][4] = PLAYERO
;
942 /********************************************************************
943 * remove "possible" markers from the board
944 ********************************************************************/
945 static void clearposs(void)
951 if (board
[y
][x
]>=POSS
)
958 /********************************************************************
959 * build a list of all possible moves
960 ********************************************************************/
961 static int getplist(struct move
* plist
, unsigned char pl
)
964 unsigned char pcnt
= 0;
966 /* this significantly reduces the amount of pointer maths */
969 /* clear previous possibilities */
975 /* only empty sqaures */
976 if (board
[y
][x
]!=EMPTY
)
982 domove(&pmove
, CHECK
);
983 /* if valid - add to list */
985 rb
->memcpy(&plist
[pcnt
++], &pmove
, sizeof(struct move
));
993 /********************************************************************
995 ********************************************************************/
996 static int plist_bytaken(const void* m1
, const void* m2
)
998 /* highest is best */
999 return( ((struct move
*)m2
)->taken
- ((struct move
*)m1
)->taken
);
1003 /********************************************************************
1005 ********************************************************************/
1006 static int plist_byrank(const void* m1
, const void* m2
)
1008 /* lowest is best */
1009 return( ((struct move
*)m1
)->rank
- ((struct move
*)m2
)->rank
);
1013 /********************************************************************
1016 x......x 1,1(01) 1,8(08)
1023 x......x 8,1(08) 8,8(64)
1027 ..x..x.. 1,3(03) 1,6(06)
1029 x.x..x.x 3,1(03) 3,3(09) 3,6(18) 3,8(24)
1032 x.x..x.x 6,1(06) 6,3(18) 6,6(36) 6,8(48)
1034 ..x..x.. 8,3(24) 8,6(48) 8,8(64)
1038 ...xx... 1,4(00) 1,5(00)
1041 x......x 4,1(00) 4,8(00)
1042 x......x 5,1(00) 5,8(00)
1045 ...xx... 8,4(00) 8,5(00)
1048 BAD (5) - some of these are edge pieces
1049 .x....x. 1,2(02) 1,7(07)
1050 xx....xx 2,1(02) 2,2(04) 2,7(14) 2,8(16)
1055 xx....xx 7,1(07) 7,2(14) 7,7(49) 7,8(56)
1056 .x....x. 8,2(16) 8,7(56)
1061 * this is called my reduceplist, if the "smart" AIBOT is playing
1062 * board sqaures are weighted as above
1064 ********************************************************************/
1065 static void smartranking(struct move
* plist
, unsigned char pcnt
)
1069 ( ((y==1)||(y==8)) && ((x==1)||(x==8)) )
1072 ( ((y==1)||(y==3)||(y==6)||(y==8)) && \
1073 ((x==1)||(x==3)||(x==6)||(x==8)) )
1076 ( ( ((y==1)||(y==8)) && ((x==4)||(x==5)) ) || \
1077 ( ((y==4)||(y==5)) && ((x==1)||(x==8)) ) )
1080 register unsigned char mul
;
1081 register unsigned char x
, y
;
1083 for (i
=0; i
<pcnt
; i
++)
1089 /* preferred squares */
1090 if (corner
) { plist
[i
].rank
= 1; continue; }
1091 else if (bluff
) { plist
[i
].rank
= 2; continue; }
1092 else if (edge
) { plist
[i
].rank
= 3; continue; }
1094 /* uninteresting square */
1097 /* avoid "bad" sqaures */
1098 if ( (mul
==02)||(mul
==04)||
1099 (mul
==07)||(mul
==14)||(mul
==16)||
1100 (mul
==49)||(mul
==56) )
1113 /********************************************************************
1114 * called by pressing f1 or f2 to change player modes
1115 ********************************************************************/
1116 static void changeplayer(bool pl
)
1119 if (ai_help
[pl
]>BEST
)
1121 player
[pl
] = (player
[pl
]==HUMAN
)?AIBOT
:HUMAN
;
1122 if (player
[pl
]==HUMAN
)
1133 /********************************************************************
1134 * this proc reduces the list of possible moves to a short list of
1135 * preferred moves, dependand on the player AI
1136 ********************************************************************/
1137 static unsigned char reduceplist(struct move
* plist
, unsigned char pcnt
, unsigned char ai_help
)
1144 /* ------------------------------------------------- */
1145 /* weak does not modify the possible's list */
1150 /* ------------------------------------------------- */
1153 /* ------------------------------------------------- */
1156 /* ------------------------------------------------- */
1157 /* this player will favour certain known moves */
1161 smartranking(plist
, pcnt
);
1162 rb
->qsort(plist
, pcnt
, sizeof(struct move
), plist_byrank
);
1163 for (i
=1; i
<pcnt
; i
++)
1164 if (plist
[i
].rank
!=plist
[i
-1].rank
)
1169 /* ------------------------------------------------- */
1170 /* reduce possibilites to "most pieces taken" */
1174 rb
->qsort(plist
, pcnt
, sizeof(struct move
), plist_bytaken
);
1175 for (i
=1; i
<pcnt
; i
++)
1176 if (plist
[i
].taken
!=plist
[i
-1].taken
)
1181 /* ------------------------------------------------- */
1183 // you should never get here!
1192 /********************************************************************
1193 * calc all moves with wieghting and report back to the user/aibot
1194 ********************************************************************/
1195 static bool calcposs(struct move
* plist
, unsigned char* pcnt
, bool turn
)
1199 /* get list of all possible moves */
1200 (*pcnt
) = getplist(plist
, turn
);
1202 /* no moves? trigger Game Over */
1206 /* only evaluate moves for AIBOTs or HUMAN+HELP */
1207 if ( (player
[turn
]==AIBOT
) || (ai_help
[turn
]) )
1209 /* mark all possible moves on board */
1210 for (i
=0; i
<(*pcnt
); i
++)
1211 board
[plist
[i
].y
][plist
[i
].x
] = POSS
;
1213 /* use ai to reduce list */
1214 (*pcnt
) = reduceplist(plist
, (*pcnt
), ai_help
[turn
]);
1216 /* higlight preferred moves */
1217 if (ai_help
[turn
]>WEAK
)
1218 for (i
=0; i
<(*pcnt
); i
++)
1219 board
[plist
[i
].y
][plist
[i
].x
] = CHOICE
;
1221 else /* no ai/help required */
1223 /* create dummy plist entry for default cursor position */
1228 return(false); /* do not cause Game Over */
1232 /********************************************************************
1234 ********************************************************************/
1235 static void hilite(struct move
* move
, bool on
)
1237 int x
= (move
->x
-1)*7;
1238 int y
= (move
->y
-1)*7;
1240 rb
->lcd_invertrect(x
+1,y
+1, 6,6);
1242 rb
->lcd_drawrect(x
,y
, 8,8);
1246 rb
->lcd_clearline(x
,y
+3, x
,y
+4);
1248 rb
->lcd_clearline(x
+3,y
, x
+4,y
);
1250 rb
->lcd_clearline(x
+7,y
+3, x
+7,y
+4);
1252 rb
->lcd_clearline(x
+3,y
+7, x
+4,y
+7);
1254 rb
->lcd_update_rect(x
,y
, 8,8);
1258 /********************************************************************
1259 * main othelo keyboard handler
1260 * returns the key that it terminated with
1261 ********************************************************************/
1262 static int getmove(struct move
* move
, struct move
* plist
, unsigned char* pcnt
, bool turn
)
1265 bool waiting
= true;
1271 key
= rb
->button_get(true);
1272 hilite(move
, false);
1282 case BUTTON_UP
| BUTTON_REPEAT
:
1283 if (move
->y
>1) move
->y
--;
1286 case BUTTON_DOWN
| BUTTON_REPEAT
:
1287 if (move
->y
<8) move
->y
++;
1290 case BUTTON_LEFT
| BUTTON_REPEAT
:
1291 if (move
->x
>1) move
->x
--;
1294 case BUTTON_RIGHT
| BUTTON_REPEAT
:
1295 if (move
->x
<8) move
->x
++;
1298 if (board
[move
->y
][move
->x
]>=POSS
)
1308 pl
= (key
==BUTTON_F1
)?PLAYERX
:PLAYERO
;
1311 /* update board if *current* player options changed */
1312 if (move
->player
==pl
)
1315 calcposs(plist
, pcnt
, turn
);
1329 /********************************************************************
1331 ********************************************************************/
1332 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
1334 #define STILL_PLAYING (!gameover && !quit)
1336 #define default_players \
1337 player[PLAYERX] = DF_PLX; \
1338 ai_help[PLAYERX] = DF_AIX; \
1339 player[PLAYERO] = DF_PLO; \
1340 ai_help[PLAYERO] = DF_AIO;
1345 struct move plist
[MAXPOSS
];
1352 TEST_PLUGIN_API(api
);
1358 do /* while !quit */
1361 showlogo(logo_tlx
,logo_tly
, true);
1380 do /* while !gameover && !quit */
1382 /* who's move is it? */
1385 /* perform ai/help routine */
1386 if ((gameover
= calcposs(plist
, &pcnt
, turn
))) continue;
1388 /* player now gets to take a turn */
1389 if (player
[turn
]==AIBOT
)
1395 /* select a random move from the possibles list */
1396 /* this block of code corrupts pcnt */
1398 t
= rb
->rand() % pcnt
;
1401 move
.x
= plist
[t
].x
;
1402 move
.y
= plist
[t
].y
;
1403 /* move selected will always be valid! */
1404 domove(&move
, CHECK
);
1406 /* bots run faster when no humans are playing */
1407 if ((player
[PLAYERX
]==AIBOT
) && (player
[PLAYERO
]==AIBOT
))
1408 timeout
= *rb
->current_tick
+((HZ
*6)/10);
1410 timeout
= *rb
->current_tick
+((HZ
*(REPEAT_START
+1))/10);
1411 while (TIME_BEFORE(*rb
->current_tick
, timeout
))
1413 key
= rb
->button_get(false);
1416 case SYS_USB_CONNECTED
:
1418 return PLUGIN_USB_CONNECTED
;
1419 /* hold play to freeze board */
1421 case BUTTON_PLAY
|BUTTON_REPEAT
:
1422 timeout
= *rb
->current_tick
+HZ
;
1425 case BUTTON_PLAY
|BUTTON_REL
:
1427 timeout
= *rb
->current_tick
-1;
1435 /* Fall through to BUTTON_ON */
1443 else /* player is human */
1445 /* only display poss on screen if help is enabled */
1446 if (ai_help
[turn
]) show_board();
1447 move
.x
= plist
[0].x
;
1448 move
.y
= plist
[0].y
;
1451 key
= getmove(&move
, plist
, &pcnt
, turn
);
1454 case SYS_USB_CONNECTED
:
1456 return PLUGIN_USB_CONNECTED
;
1461 rb
->lcd_setfont(FONT_UI
);
1471 /* check move is valid & retrieve "pieces taken" */
1472 domove(&move
, CHECK
);
1480 /* player may have hit restart instead of moving */
1485 board
[move
.y
][move
.x
] = move
.player
;
1486 /* flip opponent pieces */
1487 domove(&move
, MAKE
);
1494 score
.x
+= move
.taken
+1;
1495 score
.o
-= move
.taken
;
1499 score
.o
+= move
.taken
+1;
1500 score
.x
-= move
.taken
;
1502 /* next player please */
1503 turn
= (turn
==PLAYERX
)?PLAYERO
:PLAYERX
;
1507 } while(STILL_PLAYING
);
1512 show_endgame(score
.x
, score
.o
);
1517 if ((key
= rb
->button_get(true)) ==BUTTON_F3
)
1521 case SYS_USB_CONNECTED
:
1523 return PLUGIN_USB_CONNECTED
;
1530 changeplayer(PLAYERX
);
1533 changeplayer(PLAYERO
);