* removed some more unused stuff in the simulator makefile
[kugel-rb.git] / apps / plugins / othelo.c
blob7f0502794b18fadda070ccfdd960c69ae12ebece
1 /*
2 Designed, Written, AI Bots, the lot ...BlueChip =8ªD#
4 Thanks espcially to
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
12 redone it!
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
29 * Todo:
30 * # More AI :)
31 * # Reintroduce suspend feature under plugin system
34 /* Plugin header */
35 #include "plugin.h"
37 #ifdef HAVE_LCD_BITMAP
39 static struct plugin_api* rb;
41 /***************************************************************************/
42 /***************************************************************************/
43 /* OTHFONT.H */
44 /***************************************************************************/
45 /***************************************************************************/
47 /* Don't reorder this array - you have been warned! */
48 enum othfontc {
49 of_plx,
50 of_plo,
51 of_poss,
52 of_choice,
53 of_sp,
54 of_h,
55 of_c,
56 of_0,
57 of_1,
58 of_2,
59 of_3,
60 of_4,
61 of_5,
62 of_6,
63 of_7,
64 of_8,
65 of_9,
66 of_colon,
67 of_dash,
68 of_ptr,
69 of_p,
70 of_l,
71 of_a,
72 of_y,
73 of_q,
74 of_u,
75 of_i,
76 of_t,
77 of_eos
80 static unsigned char othfont[of_eos][6] = {
81 /* +------+
82 * | ## |
83 * | #### |
84 * |######|
85 * |######|
86 * | #### |
87 * | ## |
88 * +------+
90 {0x0C, 0x1E, 0x3F, 0x3F, 0x1E, 0x0C},
91 /* +------+
92 * | ## |
93 * | #### |
94 * |## ##|
95 * |## ##|
96 * | #### |
97 * | ## |
98 * +------+
100 {0x0C, 0x1E, 0x33, 0x33, 0x1E, 0x0C},
101 /* +------+
102 * | |
103 * | |
104 * | ## |
105 * | ## |
106 * | |
107 * | |
108 * +------+
110 {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00},
111 /* +------+
112 * | |
113 * | # # |
114 * | ## |
115 * | ## |
116 * | # # |
117 * | |
118 * +------+
120 {0x00, 0x12, 0x0C, 0x0C, 0x12, 0x00},
121 /* +------+
122 * | |
123 * | |
124 * | |
125 * | |
126 * | |
127 * | |
128 * +------+
130 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
131 /* +------+
132 * | # # | 0001 0010 12
133 * | # # | 0001 0010 12
134 * | #### | 0001 1110 1E
135 * | # # | 0001 0010 12
136 * | # # | 0001 0010 12
137 * | # # | 0001 0010 12
138 * +------+
140 {0x12,0x12,0x1E,0x12,0x12,0x12},
141 /* +------+
142 * | ## | 0000 1100 0C
143 * | # # | 0001 0010 12
144 * |# | 0010 0000 20
145 * |# | 0010 0000 20
146 * | # # | 0001 0010 12
147 * | ## | 0000 1100 0C
148 * +------+
150 {0x0C,0x12,0x20,0x20,0x12,0x0C},
151 /* +------+
152 * | ## | 0000 1100 0C
153 * | # # | 0001 0010 12
154 * | # ## | 0001 0110 16
155 * | ## # | 0001 1010 1A
156 * | # # | 0001 0010 12
157 * | ## | 0000 1100 0C
158 * +------+
160 {0x0C,0x12,0x16,0x1A,0x12,0x0C},
161 /* +------+
162 * | # | 0000 0100 04
163 * | ## | 0000 1100 0C
164 * | # | 0000 0100 04
165 * | # | 0000 0100 04
166 * | # | 0000 0100 04
167 * | ### | 0000 1110 0E
168 * +------+
170 {0x04,0x0C,0x04,0x04,0x04,0x0E},
171 /* +------+
172 * | ## | 0000 1100 0C
173 * | # # | 0001 0010 12
174 * | # | 0000 0010 02
175 * | ## | 0000 1100 0C
176 * | # | 0001 0000 10
177 * | #### | 0001 1110 1E
178 * +------+
180 {0x0C,0x12,0x02,0x0C,0x10,0x1E},
181 /* +------+
182 * | ### | 0001 1100 1C
183 * | # | 0000 0010 02
184 * | ## | 0000 1100 0C
185 * | # | 0000 0010 02
186 * | # | 0000 0010 02
187 * | ### | 0001 1100 1C
188 * +------+
190 {0x1C,0x02,0x0C,0x02,0x02,0x1C},
191 /* +------+
192 * | # | 0001 0000 10
193 * | # | 0001 0000 10
194 * | # # | 0001 0100 14
195 * | # # | 0001 0100 14
196 * | #### | 0001 1110 1E
197 * | # | 0000 0100 04
198 * +------+
200 {0x10,0x10,0x14,0x14,0x1E,0x04},
201 /* +------+
202 * | #### | 0001 1110 1E
203 * | # | 0001 0000 10
204 * | ### | 0001 1100 1C
205 * | # | 0000 0010 02
206 * | # # | 0001 0010 12
207 * | ## | 0000 1100 0C
208 * +------+
210 {0x1E,0x10,0x1C,0x02,0x12,0x0C},
211 /* +------+
212 * | ### | 0000 1110 0E
213 * | # | 0001 0000 10
214 * | ### | 0001 1100 1C
215 * | # # | 0001 0010 12
216 * | # # | 0001 0010 12
217 * | ## | 0000 1100 0C
218 * +------+
220 {0x0E,0x10,0x1C,0x12,0x12,0x0C},
221 /* +------+
222 * | #### | 0001 1110 1E
223 * | # | 0000 0010 02
224 * | # | 0000 0100 04
225 * | # | 0000 0100 04
226 * | # | 0000 1000 08
227 * | # | 0000 1000 08
228 * +------+
230 {0x1E,0x02,0x04,0x04,0x08,0x08},
231 /* +------+
232 * | ## | 0000 1100 0C
233 * | # # | 0001 0010 12
234 * | ## | 0000 1100 0C
235 * | # # | 0001 0010 12
236 * | # # | 0001 0010 12
237 * | ## | 0000 1100 0C
238 * +------+
240 {0x0C,0x12,0x0C,0x12,0x12,0x0C},
241 /* +------+
242 * | ## | 0000 1100 0C
243 * | # # | 0001 0010 12
244 * | # # | 0001 0010 12
245 * | ### | 0000 1110 0E
246 * | # | 0000 0010 02
247 * | ## | 0000 1100 0C
248 * +------+
250 {0x0C,0x12,0x12,0x0E,0x02,0x0C},
251 /* +------+
252 * | | 0000 0000 00
253 * | ## | 0000 1100 0C
254 * | ## | 0000 1100 0C
255 * | | 0000 0000 00
256 * | ## | 0000 1100 0C
257 * | ## | 0000 1100 0C
258 * +------+
260 {0x00,0x0C,0x0C,0x00,0x0C,0x0C},
261 /* +------+
262 * | | 0000 0000 00
263 * | | 0000 0000 00
264 * | #### | 0001 1110 1E
265 * | #### | 0001 1110 1E
266 * | | 0000 0000 00
267 * | | 0000 0000 00
268 * +------+
270 {0x00,0x00,0x1E,0x1E,0x00,0x00},
271 /* +------+
272 * | | 0000 0000 00
273 * | # | 0000 0100 04
274 * | ## | 0000 0110 06
275 * |######| 0011 1111 3F
276 * | ## | 0000 0110 06
277 * | # | 0000 0100 04
278 * +------+
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 /***************************************************************************/
314 /* OTHLOGO.H */
315 /***************************************************************************/
316 /***************************************************************************/
320 ######### # # ### ## ## ###
321 #### # # # # # # # # # #
322 ## # ### ### # # # # #
323 ## # # # # # ### # ##
324 ## # # # # # # # # #
325 # # ### ## # # ###
327 # ### # # ### ##### ### # # ###
328 # # # # # # # # # # #
329 # ## ### ## # ### # # # ##
330 # # # # # # # # # #
331 # # # # # # # # # #
332 #### ### # ### # ### # # ###
336 #####################################
337 #####################################
340 ## ##### # # #### # ##
341 #### # # # # # ####
342 ###### # #### ### # ## ##
343 ###### # # # # # ## ##
344 #### # # # # # ####
345 ## # # # #### #### ##
348 #####################################
349 #####################################
351 X=42, Y=30
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
387 * l = total lines
389 #define logo_bpl 6
390 #define logo_ppl 42
391 #define logo_l 32
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 */
432 if (on)
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);
438 else
439 rb->lcd_clearpixel(x+px, y+py);
440 rb->lcd_update_rect(x,y, logo_ppl, logo_l);
442 else
443 rb->lcd_clearrect(x,y, logo_ppl, logo_l);
445 return;
450 /***************************************************************************/
451 /***************************************************************************/
452 /* OTHELO.H */
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
462 /* player types */
463 #define HUMAN false
464 #define AIBOT true
466 /* for domove() */
467 #define CHECK false
468 #define MAKE true
470 /* screen coords - top left x&y */
471 /* game over */
472 #define go_tlx 71
473 #define go_tly 17
474 /* WiNS */
475 #define win_tlx 63
476 #define win_tly 1
477 /* DRaW */
478 #define draw_tlx 59
479 #define draw_tly 1
480 /* scores */
481 #define sc_tlx 65
482 #define sc_tly 39
483 /* logo */
484 #define logo_tlx 65
485 #define logo_tly 2
487 /* board sqaures -
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
491 #define PLAYERX 0
492 #define PLAYERO 1
493 #define POSS 2
494 #define CHOICE 3
495 #define EMPTY 4
496 #define BORDER 5
498 /* Who gets first turn */
499 #define FIRST PLAYERX
500 #define DF_PLX HUMAN
501 #define DF_AIX NONE
502 #define DF_PLO AIBOT
503 #define DF_AIO WEAK
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
511 * EXPERT
512 * GURU
514 #define NONE 0
515 #define WEAK 1
516 #define AVERAGE 2
517 #define SMART 3
518 #define EXPERT 4
519 #define GURU 5
520 #define BEST 3 /* the best ai alogrithm currently available */
522 /* these are for code clarity, do not change them! */
523 #define LEFT 0x08
524 #define RIGHT 0x04
525 #define UP 0x02
526 #define DOWN 0x01
528 /* This represents the maximum number of possible moves
529 * I have no idea what the real maximum is, buts tests
530 * suggest about 10
532 #define MAXPOSS 20
534 struct move
536 int x;
537 int y;
538 int taken;
539 int rank;
540 bool player;
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
548 * NEW PLUGIN SYSTEM!
549 *==================================================================*/
551 /* score */
552 static struct
554 int x;
555 int o;
556 } score;
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)
579 int i;
581 for(i=0; s[i]!=of_eos; i++);
583 return(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);
598 else
599 rb->lcd_clearpixel(x+px, y+py);
601 if (upd)
602 rb->lcd_update_rect(x,y, 6,6);
604 return;
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)
614 int i;
615 int l; /* length of string */
617 l = othstrlen(s);
619 for (i=0; i<l; i++)
620 othprint(x+i*6,y, s[i], false);
622 if (upd)
623 rb->lcd_update_rect(x,y, l*6,6);
625 return;
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);
638 /* game over */
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);
643 if (scx==sco)
645 /* draw */
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);
652 else
654 /* win */
655 rb->lcd_putsxy(win_tlx+14,win_tly+4, "WiNS");
656 if (sco>scx)
657 othprint(win_tlx+5,win_tly+5, of_plo, true);
658 else
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);
664 rb->lcd_update();
666 return;
671 /********************************************************************
672 * display othello grid
673 * currenly hard coded to the top left corner of the screen
674 ********************************************************************/
675 static void show_grid(void)
677 int x,y;
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);
695 return;
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);
707 rb->sleep(HZ/10);
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);
711 return;
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)
727 scs[2] = of_c;
728 else
729 scs[2] = of_h;
730 scs[4] = ai_help[PLAYERX] +of_0;
732 if (player[PLAYERO]==AIBOT)
733 scs[8] = of_c;
734 else
735 scs[8] = of_h;
736 scs[10] = ai_help[PLAYERO] +of_0;
738 othprints( 2,58, &scs[0], true);
739 othprints(40,58, &scs[6], true);
741 return;
746 /********************************************************************
747 * show f3 function
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 };
754 if (playing)
755 othprints(80,58, &scs[5], true);
756 else
757 othprints(80,58, &scs[0], true);
759 return;
764 /********************************************************************
765 * update board tiles
766 ********************************************************************/
767 static void show_board(void)
769 unsigned char x,y;
771 for (y=1; y<=8; y++)
772 for (x=1; x<=8; x++)
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);
776 return;
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;
796 if (scs[11]=='\0')
797 scs[11] = of_sp;
798 else
799 scs[11] = scs[11] -'0' +of_0;
800 scs[12] = of_eos;
802 rb->snprintf(&scs[13], 3, "%d", score.o);
803 scs[13] = scs[13] -'0' +of_0;
804 if (scs[14]=='\0')
805 scs[14] = of_sp;
806 else
807 scs[14] = scs[14] -'0' +of_0;
808 scs[15] = of_eos;
810 /* turn arrow */
811 if (turn==PLAYERX)
813 othprints(sc_tlx,sc_tly, &scs[0], false);
814 othprints(sc_tlx,sc_tly+8, &scs[2], false);
816 else
818 othprints(sc_tlx,sc_tly, &scs[2], false);
819 othprints(sc_tlx,sc_tly+8, &scs[0], false);
822 /* names */
823 othprints(sc_tlx+10,sc_tly, &scs[4], false);
824 othprints(sc_tlx+10,sc_tly+8, &scs[7], false);
826 /* scores */
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);
832 return;
836 /********************************************************************
837 * cls()
838 ********************************************************************/
839 static void initscreen(void)
841 rb->lcd_setfont(FONT_SYSFIXED);
842 rb->lcd_clear_display();
843 rb->lcd_update();
845 return;
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)
858 int i;
859 unsigned char t;
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);
866 t = board[y][x];
868 /* found your piece */
869 if ( t == ((pl==PLAYERX)?PLAYERX:PLAYERO) )
870 return(1);
872 /* found an empty sqaure or board edge */
873 if (t>PLAYERO)
874 return(0);
876 /* must have found opponent piece */
877 if ((i = checkmove(x,y, pl, dir, type)))
879 if (type==MAKE)
880 board[y][x] = pl;
881 return(i+1);
883 else
884 return(0);
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)
896 int i;
897 unsigned char dir;
899 move->taken = 0;
900 for (dir=DOWN; dir<=(LEFT|UP); dir++)
902 if ( (dir&(UP|DOWN)) ==(UP|DOWN) )
903 continue;
904 if ((i = checkmove(move->x, move->y, move->player, dir, type)))
905 move->taken += i-1;
908 return;
912 /********************************************************************
913 * initialise a new game board and draw it on the screen
914 ********************************************************************/
915 static void initboard(void)
917 unsigned char x,y;
919 for (y=0; y<10; y++)
920 for (x=0; x<10; x++)
921 if ( (y%9)==0 || (x%9)==0)
922 board[y][x] = BORDER;
923 else
924 board[y][x] = EMPTY;
926 board[4][4] = PLAYERX;
927 board[5][5] = PLAYERX;
928 board[4][5] = PLAYERO;
929 board[5][4] = PLAYERO;
931 score.x = 2;
932 score.o = 2;
934 show_grid();
935 show_board();
936 show_score(FIRST);
938 return;
942 /********************************************************************
943 * remove "possible" markers from the board
944 ********************************************************************/
945 static void clearposs(void)
947 int x, y;
949 for (y=1; y<=8; y++)
950 for (x=1; x<=8; x++)
951 if (board[y][x]>=POSS)
952 board[y][x]=EMPTY;
954 return;
958 /********************************************************************
959 * build a list of all possible moves
960 ********************************************************************/
961 static int getplist(struct move* plist, unsigned char pl)
963 int x, y;
964 unsigned char pcnt = 0;
966 /* this significantly reduces the amount of pointer maths */
967 struct move pmove;
969 /* clear previous possibilities */
970 clearposs();
972 for (y=1; y<=8; y++)
973 for (x=1; x<=8; x++)
975 /* only empty sqaures */
976 if (board[y][x]!=EMPTY)
977 continue;
978 /* try move */
979 pmove.x = x;
980 pmove.y = y;
981 pmove.player = pl;
982 domove(&pmove, CHECK);
983 /* if valid - add to list */
984 if (pmove.taken)
985 rb->memcpy(&plist[pcnt++], &pmove, sizeof(struct move));
988 return(pcnt);
993 /********************************************************************
994 * qsort
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 /********************************************************************
1004 * qsort
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 /********************************************************************
1015 CORNERS (1)
1016 x......x 1,1(01) 1,8(08)
1017 ........
1018 ........
1019 ........
1020 ........
1021 ........
1022 ........
1023 x......x 8,1(08) 8,8(64)
1026 BLUFF (2)
1027 ..x..x.. 1,3(03) 1,6(06)
1028 ........
1029 x.x..x.x 3,1(03) 3,3(09) 3,6(18) 3,8(24)
1030 ........
1031 ........
1032 x.x..x.x 6,1(06) 6,3(18) 6,6(36) 6,8(48)
1033 ........
1034 ..x..x.. 8,3(24) 8,6(48) 8,8(64)
1037 EDGE (3)
1038 ...xx... 1,4(00) 1,5(00)
1039 ........
1040 ........
1041 x......x 4,1(00) 4,8(00)
1042 x......x 5,1(00) 5,8(00)
1043 ........
1044 ........
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)
1051 ........
1052 ........
1053 ........
1054 ........
1055 xx....xx 7,1(07) 7,2(14) 7,7(49) 7,8(56)
1056 .x....x. 8,2(16) 8,7(56)
1059 OTHER (4)
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)
1068 #define corner \
1069 ( ((y==1)||(y==8)) && ((x==1)||(x==8)) )
1071 #define bluff \
1072 ( ((y==1)||(y==3)||(y==6)||(y==8)) && \
1073 ((x==1)||(x==3)||(x==6)||(x==8)) )
1075 #define edge \
1076 ( ( ((y==1)||(y==8)) && ((x==4)||(x==5)) ) || \
1077 ( ((y==4)||(y==5)) && ((x==1)||(x==8)) ) )
1079 int i;
1080 register unsigned char mul;
1081 register unsigned char x, y;
1083 for (i=0; i<pcnt; i++)
1085 x = plist[i].x;
1086 y = plist[i].y;
1087 mul = x *y;
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 */
1095 plist[i].rank = 4;
1097 /* avoid "bad" sqaures */
1098 if ( (mul==02)||(mul==04)||
1099 (mul==07)||(mul==14)||(mul==16)||
1100 (mul==49)||(mul==56) )
1101 plist[i].rank = 5;
1104 return;
1106 #undef corner
1107 #undef bluff
1108 #undef edge
1113 /********************************************************************
1114 * called by pressing f1 or f2 to change player modes
1115 ********************************************************************/
1116 static void changeplayer(bool pl)
1118 ai_help[pl]++;
1119 if (ai_help[pl]>BEST)
1121 player[pl] = (player[pl]==HUMAN)?AIBOT:HUMAN;
1122 if (player[pl]==HUMAN)
1123 ai_help[pl] = NONE;
1124 else
1125 ai_help[pl] = WEAK;
1127 show_players();
1129 return;
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)
1140 int i;
1142 switch(ai_help)
1144 /* ------------------------------------------------- */
1145 /* weak does not modify the possible's list */
1147 case WEAK:
1148 break;
1150 /* ------------------------------------------------- */
1151 case GURU:
1152 break;
1153 /* ------------------------------------------------- */
1154 case EXPERT:
1155 break;
1156 /* ------------------------------------------------- */
1157 /* this player will favour certain known moves */
1158 case SMART:
1159 if (pcnt>1)
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)
1165 break;
1166 pcnt = i;
1168 /* FALL THROUGH */
1169 /* ------------------------------------------------- */
1170 /* reduce possibilites to "most pieces taken" */
1171 case AVERAGE:
1172 if (pcnt>1)
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)
1177 break;
1178 pcnt = i;
1180 break;
1181 /* ------------------------------------------------- */
1182 default:
1183 // you should never get here!
1184 break;
1187 return(pcnt);
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)
1197 int i;
1199 /* get list of all possible moves */
1200 (*pcnt) = getplist(plist, turn);
1202 /* no moves? trigger Game Over */
1203 if (!(*pcnt))
1204 return(true);
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 */
1224 plist[0].x = 4;
1225 plist[0].y = 4;
1228 return(false); /* do not cause Game Over */
1232 /********************************************************************
1233 * cursor highlight
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);
1241 if (on)
1242 rb->lcd_drawrect(x,y, 8,8);
1243 else
1245 if (x)
1246 rb->lcd_clearline(x,y+3, x,y+4);
1247 if (y)
1248 rb->lcd_clearline(x+3,y, x+4,y);
1249 if (x!=7*7)
1250 rb->lcd_clearline(x+7,y+3, x+7,y+4);
1251 if (y!=7*7)
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)
1264 int key;
1265 bool waiting = true;
1267 /* get next move */
1270 hilite(move, true);
1271 key = rb->button_get(true);
1272 hilite(move, false);
1274 switch(key)
1276 case BUTTON_ON:
1277 case BUTTON_OFF:
1278 case BUTTON_F3:
1279 waiting = false;
1280 break;
1281 case BUTTON_UP:
1282 case BUTTON_UP | BUTTON_REPEAT:
1283 if (move->y>1) move->y--;
1284 break;
1285 case BUTTON_DOWN:
1286 case BUTTON_DOWN | BUTTON_REPEAT:
1287 if (move->y<8) move->y++;
1288 break;
1289 case BUTTON_LEFT:
1290 case BUTTON_LEFT | BUTTON_REPEAT:
1291 if (move->x>1) move->x--;
1292 break;
1293 case BUTTON_RIGHT:
1294 case BUTTON_RIGHT | BUTTON_REPEAT:
1295 if (move->x<8) move->x++;
1296 break;
1297 case BUTTON_PLAY:
1298 if (board[move->y][move->x]>=POSS)
1299 waiting = false;
1300 else
1301 flashboard();
1302 break;
1303 case BUTTON_F1:
1304 case BUTTON_F2:
1306 bool pl;
1308 pl = (key==BUTTON_F1)?PLAYERX:PLAYERO;
1310 changeplayer(pl);
1311 /* update board if *current* player options changed */
1312 if (move->player==pl)
1314 clearposs();
1315 calcposs(plist, pcnt, turn);
1316 show_board();
1318 break;
1320 default:
1321 break;
1323 } while (waiting);
1325 return(key);
1329 /********************************************************************
1330 * main control loop
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;
1342 int key;
1344 unsigned char pcnt;
1345 struct move plist[MAXPOSS];
1347 bool gameover;
1348 bool quit;
1350 struct move move;
1352 TEST_PLUGIN_API(api);
1353 (void)parameter;
1354 rb = api;
1356 quit = false;
1358 do /* while !quit */
1360 initscreen();
1361 showlogo(logo_tlx,logo_tly, true);
1362 show_players();
1363 show_f3(true);
1365 if (!playing)
1367 initboard();
1368 playing = true;
1369 turn = FIRST;
1371 else
1373 show_grid();
1374 show_board();
1375 show_score(turn);
1378 gameover = false;
1380 do /* while !gameover && !quit */
1382 /* who's move is it? */
1383 move.player = turn;
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)
1391 int timeout;
1392 bool held = false;
1394 unsigned char t;
1395 /* select a random move from the possibles list */
1396 /* this block of code corrupts pcnt */
1397 if (pcnt>1)
1398 t = rb->rand() % pcnt;
1399 else
1400 t = 0;
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);
1409 else
1410 timeout = *rb->current_tick +((HZ*(REPEAT_START+1))/10);
1411 while (TIME_BEFORE(*rb->current_tick, timeout))
1413 key = rb->button_get(false);
1414 switch (key)
1416 case SYS_USB_CONNECTED:
1417 rb->usb_screen();
1418 return PLUGIN_USB_CONNECTED;
1419 /* hold play to freeze board */
1420 case BUTTON_PLAY:
1421 case BUTTON_PLAY|BUTTON_REPEAT:
1422 timeout = *rb->current_tick +HZ;
1423 held = true;
1424 break;
1425 case BUTTON_PLAY|BUTTON_REL:
1426 if (held)
1427 timeout = *rb->current_tick-1;
1428 continue;
1429 case BUTTON_F3:
1430 gameover = true;
1431 break;
1432 case BUTTON_OFF:
1433 default_players;
1434 playing = false;
1435 /* Fall through to BUTTON_ON */
1436 case BUTTON_ON:
1437 return PLUGIN_OK;
1438 default:
1439 break;
1441 } /*endwhile*/;
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;
1449 while(true)
1451 key = getmove(&move, plist, &pcnt, turn);
1452 switch(key)
1454 case SYS_USB_CONNECTED:
1455 rb->usb_screen();
1456 return PLUGIN_USB_CONNECTED;
1457 case BUTTON_OFF:
1458 playing = false;
1459 default_players;
1460 case BUTTON_ON:
1461 rb->lcd_setfont(FONT_UI);
1462 return PLUGIN_OK;
1463 case BUTTON_F3:
1464 gameover = true;
1465 default:
1466 break;
1468 if (key==BUTTON_F3)
1469 break;
1471 /* check move is valid & retrieve "pieces taken" */
1472 domove(&move, CHECK);
1473 if (move.taken==0)
1474 flashboard();
1475 else
1476 break;
1480 /* player may have hit restart instead of moving */
1481 if (STILL_PLAYING)
1483 /* MAKE MOVE */
1484 /* add new piece */
1485 board[move.y][move.x] = move.player;
1486 /* flip opponent pieces */
1487 domove(&move, MAKE);
1488 /* update board */
1489 clearposs();
1490 show_board();
1491 /* update score */
1492 if (turn==PLAYERX)
1494 score.x += move.taken+1;
1495 score.o -= move.taken;
1497 if (turn==PLAYERO)
1499 score.o += move.taken+1;
1500 score.x -= move.taken;
1502 /* next player please */
1503 turn = (turn==PLAYERX)?PLAYERO:PLAYERX;
1504 show_score(turn);
1507 } while(STILL_PLAYING);
1509 clearposs();
1510 show_board();
1511 show_f3(false);
1512 show_endgame(score.x, score.o);
1513 playing = false;
1517 if ((key = rb->button_get(true)) ==BUTTON_F3)
1518 break;
1519 switch(key)
1521 case SYS_USB_CONNECTED:
1522 rb->usb_screen();
1523 return PLUGIN_USB_CONNECTED;
1524 case BUTTON_OFF:
1525 default_players;
1526 case BUTTON_ON:
1527 quit = true;
1528 break;
1529 case BUTTON_F1:
1530 changeplayer(PLAYERX);
1531 break;
1532 case BUTTON_F2:
1533 changeplayer(PLAYERO);
1534 break;
1535 default:
1536 break;
1538 } while(!quit);
1540 }while(!quit);
1542 return PLUGIN_OK;
1545 #endif