diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/othelo.c | 1546 |
1 files changed, 1546 insertions, 0 deletions
diff --git a/apps/plugins/othelo.c b/apps/plugins/othelo.c new file mode 100644 index 0000000000..8298b1d0c7 --- /dev/null +++ b/apps/plugins/othelo.c | |||
@@ -0,0 +1,1546 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2003 Blue Chip | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | /* | ||
20 | Designed, Written, AI Bots, the lot ...BlueChip =8ĒD# | ||
21 | |||
22 | Thanks espcially to | ||
23 | Hardeep, DevZer0, LinusN | ||
24 | for their help with understanding Rockbox & the SDK | ||
25 | */ | ||
26 | |||
27 | #include "plugin.h" | ||
28 | #ifdef HAVE_LCD_BITMAP | ||
29 | |||
30 | /* the following #define had to be taken from Button.c | ||
31 | 'cos it is not defined in the header!! */ | ||
32 | /* how long until repeat kicks in */ | ||
33 | #define REPEAT_START 6 | ||
34 | |||
35 | /* player types */ | ||
36 | #define HUMAN false | ||
37 | #define AIBOT true | ||
38 | |||
39 | /* for domove() */ | ||
40 | #define CHECK false | ||
41 | #define MAKE true | ||
42 | |||
43 | /* screen coords - top left x&y */ | ||
44 | /* game over */ | ||
45 | #define go_tlx 71 | ||
46 | #define go_tly 17 | ||
47 | /* WiNS */ | ||
48 | #define win_tlx 63 | ||
49 | #define win_tly 1 | ||
50 | /* DRaW */ | ||
51 | #define draw_tlx 59 | ||
52 | #define draw_tly 1 | ||
53 | /* scores */ | ||
54 | #define sc_tlx 65 | ||
55 | #define sc_tly 39 | ||
56 | /* logo */ | ||
57 | #define logo_tlx 65 | ||
58 | #define logo_tly 2 | ||
59 | |||
60 | /* board sqaures - | ||
61 | * there are a number of routines that expect these values asis | ||
62 | * do not try to play with these, you will likely kill the program | ||
63 | */ | ||
64 | #define PLAYERX 0 | ||
65 | #define PLAYERO 1 | ||
66 | #define POSS 2 | ||
67 | #define CHOICE 3 | ||
68 | #define EMPTY 4 | ||
69 | #define BORDER 5 | ||
70 | |||
71 | /* Who gets first turn */ | ||
72 | #define FIRST PLAYERX | ||
73 | #define DF_PLX HUMAN | ||
74 | #define DF_AIX NONE | ||
75 | #define DF_PLO AIBOT | ||
76 | #define DF_AIO WEAK | ||
77 | |||
78 | /* Oponent skill level / help level | ||
79 | * -------- --------------------------------------------------- | ||
80 | * NONE no ai / no help | ||
81 | * WEAK random valid move / show all possible | ||
82 | * AVERAGE most pieces (random) / all + most pieces | ||
83 | * SMART most pieces (weighted/random) / all + weighted | ||
84 | * EXPERT | ||
85 | * GURU | ||
86 | */ | ||
87 | #define NONE 0 | ||
88 | #define WEAK 1 | ||
89 | #define AVERAGE 2 | ||
90 | #define SMART 3 | ||
91 | #define EXPERT 4 | ||
92 | #define GURU 5 | ||
93 | #define BEST 3 /* the best ai alogrithm currently available */ | ||
94 | |||
95 | /* these are for code clarity, do not change them! */ | ||
96 | #define LEFT 0x08 | ||
97 | #define RIGHT 0x04 | ||
98 | #define UP 0x02 | ||
99 | #define DOWN 0x01 | ||
100 | |||
101 | /* This represents the maximum number of possible moves | ||
102 | * I have no idea what the real maximum is, buts tests | ||
103 | * suggest about 10 | ||
104 | */ | ||
105 | #define MAXPOSS 20 | ||
106 | |||
107 | struct move | ||
108 | { | ||
109 | int x; | ||
110 | int y; | ||
111 | int taken; | ||
112 | int rank; | ||
113 | bool player; | ||
114 | }; | ||
115 | |||
116 | |||
117 | /*=================================================================== | ||
118 | * Procedure prototypes | ||
119 | *==================================================================*/ | ||
120 | static void changeplayer(bool pl); | ||
121 | |||
122 | static int othstrlen(char* s); | ||
123 | static void othprint(unsigned char x, unsigned char y, char ch, bool upd); | ||
124 | static void othprints(unsigned char x, unsigned char y, char* s, bool upd); | ||
125 | |||
126 | static void initscreen(void); | ||
127 | static void show_board(void); | ||
128 | static void flashboard(void); | ||
129 | static void show_grid(void); | ||
130 | static void show_score(bool turn); | ||
131 | static void show_players(void); | ||
132 | static void show_f3(bool playing); | ||
133 | static void hilite(struct move* move, bool on); | ||
134 | static void show_endgame(unsigned char scx, unsigned char sco); | ||
135 | |||
136 | static void initboard(void); | ||
137 | static int getmove(struct move* move, struct move* plist, | ||
138 | unsigned char* pcnt, bool turn); | ||
139 | static int checkmove(unsigned char x, unsigned char y, bool pl, | ||
140 | unsigned char dir, bool type); | ||
141 | static void domove(struct move* move, bool type); | ||
142 | |||
143 | static bool calcposs(struct move* plist, unsigned char* pcnt, bool turn); | ||
144 | static int getplist(struct move* plist, unsigned char pl); | ||
145 | static unsigned char reduceplist(struct move* plist, unsigned char pcnt, | ||
146 | unsigned char ai_help); | ||
147 | static void smartranking(struct move* plist, unsigned char pcnt); | ||
148 | static int plist_bytaken(const void* m1, const void* m2); | ||
149 | static int plist_byrank(const void* m1, const void* m2); | ||
150 | static void clearposs(void); | ||
151 | |||
152 | |||
153 | /*=================================================================== | ||
154 | * *static* local global variables | ||
155 | *==================================================================*/ | ||
156 | |||
157 | static struct plugin_api* rb; | ||
158 | |||
159 | /* score */ | ||
160 | static struct | ||
161 | { | ||
162 | int x; | ||
163 | int o; | ||
164 | } score; | ||
165 | |||
166 | /* 8x8 with borders */ | ||
167 | static unsigned char board[10][10]; | ||
168 | |||
169 | /* player=HUMAN|AIBOT */ | ||
170 | static bool player[2] = {DF_PLX, DF_PLO}; | ||
171 | |||
172 | /* AI = WEAK|AVERAGE|SMART|EXPERT|GURU | ||
173 | Help=NONE|WEAK|AVERAGE|SMART|EXPERT|GURU */ | ||
174 | static unsigned char ai_help[2] = {DF_AIX, DF_AIO}; | ||
175 | |||
176 | /* is a game under way */ | ||
177 | static bool playing = false; | ||
178 | |||
179 | /* who's turn is it? */ | ||
180 | static bool turn = FIRST; | ||
181 | |||
182 | /* Don't reorder this array - you have been warned! */ | ||
183 | enum othfontc { | ||
184 | of_plx, | ||
185 | of_plo, | ||
186 | of_poss, | ||
187 | of_choice, | ||
188 | of_sp, | ||
189 | of_h, | ||
190 | of_c, | ||
191 | of_0, | ||
192 | of_1, | ||
193 | of_2, | ||
194 | of_3, | ||
195 | of_4, | ||
196 | of_5, | ||
197 | of_6, | ||
198 | of_7, | ||
199 | of_8, | ||
200 | of_9, | ||
201 | of_colon, | ||
202 | of_dash, | ||
203 | of_ptr, | ||
204 | of_p, | ||
205 | of_l, | ||
206 | of_a, | ||
207 | of_y, | ||
208 | of_q, | ||
209 | of_u, | ||
210 | of_i, | ||
211 | of_t, | ||
212 | of_eos | ||
213 | }; | ||
214 | |||
215 | static unsigned char othfont[of_eos][6] = { | ||
216 | /* +------+ | ||
217 | * | ## | | ||
218 | * | #### | | ||
219 | * |######| | ||
220 | * |######| | ||
221 | * | #### | | ||
222 | * | ## | | ||
223 | * +------+ | ||
224 | */ | ||
225 | {0x0C, 0x1E, 0x3F, 0x3F, 0x1E, 0x0C}, | ||
226 | /* +------+ | ||
227 | * | ## | | ||
228 | * | #### | | ||
229 | * |## ##| | ||
230 | * |## ##| | ||
231 | * | #### | | ||
232 | * | ## | | ||
233 | * +------+ | ||
234 | */ | ||
235 | {0x0C, 0x1E, 0x33, 0x33, 0x1E, 0x0C}, | ||
236 | /* +------+ | ||
237 | * | | | ||
238 | * | | | ||
239 | * | ## | | ||
240 | * | ## | | ||
241 | * | | | ||
242 | * | | | ||
243 | * +------+ | ||
244 | */ | ||
245 | {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00}, | ||
246 | /* +------+ | ||
247 | * | | | ||
248 | * | # # | | ||
249 | * | ## | | ||
250 | * | ## | | ||
251 | * | # # | | ||
252 | * | | | ||
253 | * +------+ | ||
254 | */ | ||
255 | {0x00, 0x12, 0x0C, 0x0C, 0x12, 0x00}, | ||
256 | /* +------+ | ||
257 | * | | | ||
258 | * | | | ||
259 | * | | | ||
260 | * | | | ||
261 | * | | | ||
262 | * | | | ||
263 | * +------+ | ||
264 | */ | ||
265 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, | ||
266 | /* +------+ | ||
267 | * | # # | 0001 0010 12 | ||
268 | * | # # | 0001 0010 12 | ||
269 | * | #### | 0001 1110 1E | ||
270 | * | # # | 0001 0010 12 | ||
271 | * | # # | 0001 0010 12 | ||
272 | * | # # | 0001 0010 12 | ||
273 | * +------+ | ||
274 | */ | ||
275 | {0x12,0x12,0x1E,0x12,0x12,0x12}, | ||
276 | /* +------+ | ||
277 | * | ## | 0000 1100 0C | ||
278 | * | # # | 0001 0010 12 | ||
279 | * |# | 0010 0000 20 | ||
280 | * |# | 0010 0000 20 | ||
281 | * | # # | 0001 0010 12 | ||
282 | * | ## | 0000 1100 0C | ||
283 | * +------+ | ||
284 | */ | ||
285 | {0x0C,0x12,0x20,0x20,0x12,0x0C}, | ||
286 | /* +------+ | ||
287 | * | ## | 0000 1100 0C | ||
288 | * | # # | 0001 0010 12 | ||
289 | * | # ## | 0001 0110 16 | ||
290 | * | ## # | 0001 1010 1A | ||
291 | * | # # | 0001 0010 12 | ||
292 | * | ## | 0000 1100 0C | ||
293 | * +------+ | ||
294 | */ | ||
295 | {0x0C,0x12,0x16,0x1A,0x12,0x0C}, | ||
296 | /* +------+ | ||
297 | * | # | 0000 0100 04 | ||
298 | * | ## | 0000 1100 0C | ||
299 | * | # | 0000 0100 04 | ||
300 | * | # | 0000 0100 04 | ||
301 | * | # | 0000 0100 04 | ||
302 | * | ### | 0000 1110 0E | ||
303 | * +------+ | ||
304 | */ | ||
305 | {0x04,0x0C,0x04,0x04,0x04,0x0E}, | ||
306 | /* +------+ | ||
307 | * | ## | 0000 1100 0C | ||
308 | * | # # | 0001 0010 12 | ||
309 | * | # | 0000 0010 02 | ||
310 | * | ## | 0000 1100 0C | ||
311 | * | # | 0001 0000 10 | ||
312 | * | #### | 0001 1110 1E | ||
313 | * +------+ | ||
314 | */ | ||
315 | {0x0C,0x12,0x02,0x0C,0x10,0x1E}, | ||
316 | /* +------+ | ||
317 | * | ### | 0001 1100 1C | ||
318 | * | # | 0000 0010 02 | ||
319 | * | ## | 0000 1100 0C | ||
320 | * | # | 0000 0010 02 | ||
321 | * | # | 0000 0010 02 | ||
322 | * | ### | 0001 1100 1C | ||
323 | * +------+ | ||
324 | */ | ||
325 | {0x1C,0x02,0x0C,0x02,0x02,0x1C}, | ||
326 | /* +------+ | ||
327 | * | # | 0001 0000 10 | ||
328 | * | # | 0001 0000 10 | ||
329 | * | # # | 0001 0100 14 | ||
330 | * | # # | 0001 0100 14 | ||
331 | * | #### | 0001 1110 1E | ||
332 | * | # | 0000 0100 04 | ||
333 | * +------+ | ||
334 | */ | ||
335 | {0x10,0x10,0x14,0x14,0x1E,0x04}, | ||
336 | /* +------+ | ||
337 | * | #### | 0001 1110 1E | ||
338 | * | # | 0001 0000 10 | ||
339 | * | ### | 0001 1100 1C | ||
340 | * | # | 0000 0010 02 | ||
341 | * | # # | 0001 0010 12 | ||
342 | * | ## | 0000 1100 0C | ||
343 | * +------+ | ||
344 | */ | ||
345 | {0x1E,0x10,0x1C,0x02,0x12,0x0C}, | ||
346 | /* +------+ | ||
347 | * | ### | 0000 1110 0E | ||
348 | * | # | 0001 0000 10 | ||
349 | * | ### | 0001 1100 1C | ||
350 | * | # # | 0001 0010 12 | ||
351 | * | # # | 0001 0010 12 | ||
352 | * | ## | 0000 1100 0C | ||
353 | * +------+ | ||
354 | */ | ||
355 | {0x0E,0x10,0x1C,0x12,0x12,0x0C}, | ||
356 | /* +------+ | ||
357 | * | #### | 0001 1110 1E | ||
358 | * | # | 0000 0010 02 | ||
359 | * | # | 0000 0100 04 | ||
360 | * | # | 0000 0100 04 | ||
361 | * | # | 0000 1000 08 | ||
362 | * | # | 0000 1000 08 | ||
363 | * +------+ | ||
364 | */ | ||
365 | {0x1E,0x02,0x04,0x04,0x08,0x08}, | ||
366 | /* +------+ | ||
367 | * | ## | 0000 1100 0C | ||
368 | * | # # | 0001 0010 12 | ||
369 | * | ## | 0000 1100 0C | ||
370 | * | # # | 0001 0010 12 | ||
371 | * | # # | 0001 0010 12 | ||
372 | * | ## | 0000 1100 0C | ||
373 | * +------+ | ||
374 | */ | ||
375 | {0x0C,0x12,0x0C,0x12,0x12,0x0C}, | ||
376 | /* +------+ | ||
377 | * | ## | 0000 1100 0C | ||
378 | * | # # | 0001 0010 12 | ||
379 | * | # # | 0001 0010 12 | ||
380 | * | ### | 0000 1110 0E | ||
381 | * | # | 0000 0010 02 | ||
382 | * | ## | 0000 1100 0C | ||
383 | * +------+ | ||
384 | */ | ||
385 | {0x0C,0x12,0x12,0x0E,0x02,0x0C}, | ||
386 | /* +------+ | ||
387 | * | | 0000 0000 00 | ||
388 | * | ## | 0000 1100 0C | ||
389 | * | ## | 0000 1100 0C | ||
390 | * | | 0000 0000 00 | ||
391 | * | ## | 0000 1100 0C | ||
392 | * | ## | 0000 1100 0C | ||
393 | * +------+ | ||
394 | */ | ||
395 | {0x00,0x0C,0x0C,0x00,0x0C,0x0C}, | ||
396 | /* +------+ | ||
397 | * | | 0000 0000 00 | ||
398 | * | | 0000 0000 00 | ||
399 | * | #### | 0001 1110 1E | ||
400 | * | #### | 0001 1110 1E | ||
401 | * | | 0000 0000 00 | ||
402 | * | | 0000 0000 00 | ||
403 | * +------+ | ||
404 | */ | ||
405 | {0x00,0x00,0x1E,0x1E,0x00,0x00}, | ||
406 | /* +------+ | ||
407 | * | | 0000 0000 00 | ||
408 | * | # | 0000 0100 04 | ||
409 | * | ## | 0000 0110 06 | ||
410 | * |######| 0011 1111 3F | ||
411 | * | ## | 0000 0110 06 | ||
412 | * | # | 0000 0100 04 | ||
413 | * +------+ | ||
414 | */ | ||
415 | {0x00,0x04,0x06,0x3F,0x06,0x04}, | ||
416 | /* | ||
417 | * ÚÄÄÄÄÄÄŋ ÚÄÄÄÄÄÄŋ ÚÄÄÄÄÄÄŋ ÚÄÄÄÄÄÄŋ | ||
418 | * ŗ.###..ŗ.ŗ#.....ŗ.ŗ.###..ŗ.ŗ#...#.ŗ xx01 1100 | xx10 0000 | xx01 1100 | xx10 0010 | 1C 20 1C 22 | ||
419 | * ŗ#...#.ŗ.ŗ#.....ŗ.ŗ#...#.ŗ.ŗ#...#.ŗ xx10 0010 | xx10 0000 | xx10 0010 | xx10 0010 | 22 20 22 22 | ||
420 | * ŗ#...#.ŗ.ŗ#.....ŗ.ŗ#...#.ŗ.ŗ.###..ŗ xx10 0010 | xx10 0000 | xx10 0010 | xx01 1100 | 22 20 22 1C | ||
421 | * ŗ####..ŗ.ŗ#.....ŗ.ŗ#####.ŗ.ŗ..#...ŗ xx11 1100 | xx10 0000 | xx11 1110 | xx00 1000 | 3C 20 3E 08 | ||
422 | * ŗ#.....ŗ.ŗ#...#.ŗ.ŗ#...#.ŗ.ŗ..#...ŗ xx10 0000 | xx10 0010 | xx10 0010 | xx00 1000 | 20 22 22 08 | ||
423 | * ŗ#.....ŗ.ŗ.###..ŗ.ŗ#...#.ŗ.ŗ..#...ŗ xx10 0000 | xx01 1100 | xx10 0010 | xx00 1000 | 20 1C 22 08 | ||
424 | * ĀÄÄÄÄÄÄŲ ĀÄÄÄÄÄÄŲ ĀÄÄÄÄÄÄŲ ĀÄÄÄÄÄÄŲ | ||
425 | */ | ||
426 | {0x1C,0x22,0x22,0x3C,0x20,0x20}, | ||
427 | {0x20,0x20,0x20,0x20,0x22,0x1C}, | ||
428 | {0x1C,0x22,0x22,0x3E,0x22,0x22}, | ||
429 | {0x22,0x22,0x1C,0x08,0x08,0x08}, | ||
430 | /* ÚÄÄÄÄÄÄŋ ÚÄÄÄÄÄÄŋ ÚÄÄÄÄÄÄŋ ÚÄÄÄÄÄÄŋ | ||
431 | * ŗ.###..ŗ.ŗ#...#.ŗ.ŗ#####.ŗ.ŗ#####.ŗ xx01 1100 | xx10 0010 | xx11 1110 | xx11 1110 | 1C 22 3E 3E | ||
432 | * ŗ#...#.ŗ.ŗ#...#.ŗ.ŗ..#...ŗ.ŗ..#...ŗ xx10 0010 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08 | ||
433 | * ŗ#...#.ŗ.ŗ#...#.ŗ.ŗ..#...ŗ.ŗ..#...ŗ xx10 0010 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08 | ||
434 | * ŗ#...#.ŗ.ŗ#...#.ŗ.ŗ..#...ŗ.ŗ..#...ŗ xx10 0010 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08 | ||
435 | * ŗ#..##.ŗ.ŗ#...#.ŗ.ŗ..#...ŗ.ŗ..#...ŗ xx10 0110 | xx10 0010 | xx00 1000 | xx00 1000 | 22 22 08 08 | ||
436 | * ŗ.#####ŗ.ŗ.###..ŗ.ŗ#####.ŗ.ŗ..#...ŗ xx01 1111 | xx01 1100 | xx11 1110 | xx00 1000 | 1F 1C 3E 08 | ||
437 | * ĀÄÄÄÄÄÄŲ ĀÄÄÄÄÄÄŲ ĀÄÄÄÄÄÄŲ ĀÄÄÄÄÄÄŲ | ||
438 | */ | ||
439 | {0x1C,0x22,0x22,0x22,0x22,0x1F}, | ||
440 | {0x22,0x22,0x22,0x22,0x22,0x1C}, | ||
441 | {0x3E,0x08,0x08,0x08,0x08,0x3E}, | ||
442 | {0x3E,0x08,0x08,0x08,0x08,0x08} | ||
443 | |||
444 | }; | ||
445 | |||
446 | /* | ||
447 | |||
448 | ######### # # ### ## ## ### | ||
449 | #### # # # # # # # # # # | ||
450 | ## # ### ### # # # # # | ||
451 | ## # # # # # ### # ## | ||
452 | ## # # # # # # # # # | ||
453 | # # ### ## # # ### | ||
454 | # | ||
455 | # ### # # ### ##### ### # # ### | ||
456 | # # # # # # # # # # # | ||
457 | # ## ### ## # ### # # # ## | ||
458 | # # # # # # # # # # | ||
459 | # # # # # # # # # # | ||
460 | #### ### # ### # ### # # ### | ||
461 | |||
462 | |||
463 | |||
464 | ##################################### | ||
465 | ##################################### | ||
466 | |||
467 | |||
468 | ## ##### # # #### # ## | ||
469 | #### # # # # # #### | ||
470 | ###### # #### ### # ## ## | ||
471 | ###### # # # # # ## ## | ||
472 | #### # # # # # #### | ||
473 | ## # # # #### #### ## | ||
474 | |||
475 | |||
476 | ##################################### | ||
477 | ##################################### | ||
478 | |||
479 | X=42, Y=30 | ||
480 | ####|####|# # | # |### | ##| #|# |### | | | FF A2 E3 18 E0 00 | ||
481 | ####| |# # | # |# #| # |# # | # #| | | | F0 A2 94 A5 00 00 | ||
482 | ## | |# #|## |### | # |# # | # #| | | | C0 9C E4 A5 00 00 | ||
483 | ## | | |# |# #| # |# ##|# #| ##| | | C0 08 94 B9 30 00 | ||
484 | ## | | |# |# #| # |# # |# #| #| | | C0 08 94 A9 10 00 | ||
485 | # | | |# |### | ##| # | # |### | | | 80 08 E3 24 E0 00 | ||
486 | # | | | | | | | | | | | 80 00 00 00 00 00 | ||
487 | # | ##|# # | # | ###| ###|## |### | # #| #|## | 83 A2 77 CE 51 C0 | ||
488 | # | # | # | # |# | #| #| |# # |# # | | 84 22 81 10 AA 00 | ||
489 | # | ##| #|## | ## | #| #|## |# # |# #|# | 83 1C 61 1C A9 80 | ||
490 | # | |# |# | #| #| #| |# # |# | # | 80 88 11 10 A8 40 | ||
491 | # #| |# |# | #| #| #| |# |# | # | 90 88 11 10 88 40 | ||
492 | ####| ###| |# |### | #| |### |# |# ##|# | F7 08 E1 0E 8B 80 | ||
493 | | | | | | | | | | | | 00 00 00 00 00 00 | ||
494 | | | | | | | | | | | | 00 00 00 00 00 00 | ||
495 | | | | | | | | | | | | 00 00 00 00 00 00 | ||
496 | ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00 | ||
497 | ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00 | ||
498 | | | | | | | | | | | | 00 00 00 00 00 00 | ||
499 | | | | | | | | | | | | 00 00 00 00 00 00 | ||
500 | | ##| #|####| # |# ##|## #| | ## | | | 03 1F 4B D0 60 00 | ||
501 | | ###|# | # | # |# # | #| |####| | | 07 84 4A 10 F0 00 | ||
502 | |####|## | # | ###|# ##|# #| #|# #|# | | 0F C4 7B 91 98 00 | ||
503 | |####|## | # | # |# # | #| #|# #|# | | 0F C4 4A 11 98 00 | ||
504 | | ###|# | # | # |# # | #| |####| | | 07 84 4A 10 F0 00 | ||
505 | | ##| | # | # |# ##|## #|### | ## | | | 03 04 4B DE 60 00 | ||
506 | | | | | | | | | | | | 00 00 00 00 00 00 | ||
507 | | | | | | | | | | | | 00 00 00 00 00 00 | ||
508 | ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00 | ||
509 | ##|####|####|####|####|####|####|####|####|### | | 3F FF FF FF FE 00 | ||
510 | */ | ||
511 | |||
512 | /* | ||
513 | * bpl = BYTES per line | ||
514 | * ppl = PIXELS per line | ||
515 | * l = total lines | ||
516 | */ | ||
517 | #define logo_bpl 6 | ||
518 | #define logo_ppl 42 | ||
519 | #define logo_l 32 | ||
520 | |||
521 | static unsigned char logo[] = { | ||
522 | 0xFF,0xA2,0xE3,0x18,0xE0,0x00, | ||
523 | 0xF0,0xA2,0x94,0xA5,0x00,0x00, | ||
524 | 0xC0,0x9C,0xE4,0xA5,0x00,0x00, | ||
525 | 0xC0,0x08,0x94,0xB9,0x30,0x00, | ||
526 | 0xC0,0x08,0x94,0xA9,0x10,0x00, | ||
527 | 0x80,0x08,0xE3,0x24,0xE0,0x00, | ||
528 | 0x80,0x00,0x00,0x00,0x00,0x00, | ||
529 | 0x83,0xA2,0x77,0xCE,0x51,0xC0, | ||
530 | 0x84,0x22,0x81,0x10,0xAA,0x00, | ||
531 | 0x83,0x1C,0x61,0x1C,0xA9,0x80, | ||
532 | 0x80,0x88,0x11,0x10,0xA8,0x40, | ||
533 | 0x90,0x88,0x11,0x10,0x88,0x40, | ||
534 | 0xF7,0x08,0xE1,0x0E,0x8B,0x80, | ||
535 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
536 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
537 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
538 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
539 | 0x3F,0xFF,0xFF,0xFF,0xFE,0x00, | ||
540 | 0x3F,0xFF,0xFF,0xFF,0xFE,0x00, | ||
541 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
542 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
543 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
544 | 0x03,0x1F,0x4B,0xD0,0x60,0x00, | ||
545 | 0x07,0x84,0x4A,0x10,0xF0,0x00, | ||
546 | 0x0F,0xC4,0x7B,0x91,0x98,0x00, | ||
547 | 0x0F,0xC4,0x4A,0x11,0x98,0x00, | ||
548 | 0x07,0x84,0x4A,0x10,0xF0,0x00, | ||
549 | 0x03,0x04,0x4B,0xDE,0x60,0x00, | ||
550 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
551 | 0x00,0x00,0x00,0x00,0x00,0x00, | ||
552 | 0x3F,0xFF,0xFF,0xFF,0xFE,0x00, | ||
553 | 0x3F,0xFF,0xFF,0xFF,0xFE,0x00 | ||
554 | }; | ||
555 | |||
556 | static void showlogo(int x, int y, bool on) | ||
557 | { | ||
558 | int px,py; /* pixel x & y */ | ||
559 | |||
560 | if (on) | ||
561 | { | ||
562 | for (py=0; py<logo_l; py++) | ||
563 | for (px=0; px<logo_ppl; px++) | ||
564 | if ( ((logo[(py*logo_bpl)+(px/8)] >>(7-(px%8))) &1) ) | ||
565 | rb->lcd_drawpixel(x+px, y+py); | ||
566 | else | ||
567 | rb->lcd_clearpixel(x+px, y+py); | ||
568 | rb->lcd_update_rect(x,y, logo_ppl, logo_l); | ||
569 | } | ||
570 | else | ||
571 | rb->lcd_clearrect(x,y, logo_ppl, logo_l); | ||
572 | |||
573 | return; | ||
574 | |||
575 | } | ||
576 | |||
577 | |||
578 | /******************************************************************** | ||
579 | * strlen ofr use with othello print system | ||
580 | ********************************************************************/ | ||
581 | static int othstrlen(char* s) | ||
582 | { | ||
583 | |||
584 | int i; | ||
585 | |||
586 | for(i=0; s[i]!=of_eos; i++); | ||
587 | |||
588 | return(i); | ||
589 | |||
590 | } | ||
591 | |||
592 | /******************************************************************** | ||
593 | * print othello char upd=true will issue update_lcd() | ||
594 | ********************************************************************/ | ||
595 | static void othprint(unsigned char x, unsigned char y, char ch, bool upd) | ||
596 | { | ||
597 | int px,py; /* pixel coords 1..6 */ | ||
598 | |||
599 | for (py=0; py<6; py++) | ||
600 | for (px=0; px<6; px++) | ||
601 | if ((othfont[(unsigned char)ch][py] >>(5-px)) &1) | ||
602 | rb->lcd_drawpixel(x+px, y+py); | ||
603 | else | ||
604 | rb->lcd_clearpixel(x+px, y+py); | ||
605 | |||
606 | if (upd) | ||
607 | rb->lcd_update_rect(x,y, 6,6); | ||
608 | |||
609 | return; | ||
610 | |||
611 | } | ||
612 | |||
613 | |||
614 | /******************************************************************** | ||
615 | * print othello string upd=true will issue update_lcd() | ||
616 | ********************************************************************/ | ||
617 | static void othprints(unsigned char x, unsigned char y, char* s, bool upd) | ||
618 | { | ||
619 | int i; | ||
620 | int l; /* length of string */ | ||
621 | |||
622 | l = othstrlen(s); | ||
623 | |||
624 | for (i=0; i<l; i++) | ||
625 | othprint(x+i*6,y, s[i], false); | ||
626 | |||
627 | if (upd) | ||
628 | rb->lcd_update_rect(x,y, l*6,6); | ||
629 | |||
630 | return; | ||
631 | |||
632 | } | ||
633 | |||
634 | |||
635 | /******************************************************************** | ||
636 | * display game over visuals | ||
637 | ********************************************************************/ | ||
638 | static void show_endgame(unsigned char scx, unsigned char sco) | ||
639 | { | ||
640 | /* end of game messages */ | ||
641 | showlogo(logo_tlx,logo_tly, false); | ||
642 | |||
643 | /* game over */ | ||
644 | rb->lcd_putsxy(go_tlx+1,go_tly+1, "Game"); | ||
645 | rb->lcd_putsxy(go_tlx+1,go_tly+11, "oveR"); | ||
646 | rb->lcd_invertrect(go_tlx,go_tly, 27,20); | ||
647 | |||
648 | if (scx==sco) | ||
649 | { | ||
650 | /* draw */ | ||
651 | rb->lcd_putsxy(draw_tlx+13,draw_tly+4, "DraW"); | ||
652 | othprint(draw_tlx+5,draw_tly+5, of_plx, true); | ||
653 | othprint(draw_tlx+40,draw_tly+5, of_plo, true); | ||
654 | rb->lcd_drawrect(draw_tlx+2,draw_tly+2, 47,11); | ||
655 | rb->lcd_drawrect(draw_tlx,draw_tly, 51,15); | ||
656 | } | ||
657 | else | ||
658 | { | ||
659 | /* win */ | ||
660 | rb->lcd_putsxy(win_tlx+14,win_tly+4, "WiNS"); | ||
661 | if (sco>scx) | ||
662 | othprint(win_tlx+5,win_tly+5, of_plo, true); | ||
663 | else | ||
664 | othprint(win_tlx+5,win_tly+5, of_plx, true); | ||
665 | rb->lcd_drawrect(win_tlx+2,win_tly+2, 39,11); | ||
666 | rb->lcd_drawrect(win_tlx,win_tly, 43,15); | ||
667 | } | ||
668 | |||
669 | rb->lcd_update(); | ||
670 | |||
671 | return; | ||
672 | |||
673 | } | ||
674 | |||
675 | |||
676 | /******************************************************************** | ||
677 | * display othello grid | ||
678 | * currenly hard coded to the top left corner of the screen | ||
679 | ********************************************************************/ | ||
680 | static void show_grid(void) | ||
681 | { | ||
682 | int x,y; | ||
683 | |||
684 | rb->lcd_clearrect(0,0, (8*7)+1,(8*7)+1); | ||
685 | rb->lcd_drawrect(0,0, (8*7)+1,(8*7)+1); | ||
686 | for (x=7; x<((7*7)+1); x+=7) | ||
687 | { | ||
688 | rb->lcd_drawline(1,x, 2,x); | ||
689 | rb->lcd_drawline(x,1, x,2); | ||
690 | rb->lcd_drawline(x,(8*7)-1, x,(8*7)-2); | ||
691 | rb->lcd_drawline((8*7)-1,x, (8*7)-2,x); | ||
692 | for (y=7; y<((7*7)+1); y+=7) | ||
693 | { | ||
694 | rb->lcd_drawline(x-2,y, x+2,y); | ||
695 | rb->lcd_drawline(x,y-2, x,y+2); | ||
696 | } | ||
697 | } | ||
698 | rb->lcd_update_rect(0,0, (8*7)+1,(8*7)+1); | ||
699 | |||
700 | return; | ||
701 | |||
702 | } | ||
703 | |||
704 | |||
705 | /******************************************************************** | ||
706 | * flash the board - used for invalid move! | ||
707 | ********************************************************************/ | ||
708 | static void flashboard() | ||
709 | { | ||
710 | rb->lcd_invertrect(0,0, (8*7)+1,(8*7)+1); | ||
711 | rb->lcd_update_rect(0,0, (8*7)+1,(8*7)+1); | ||
712 | rb->sleep(HZ/10); | ||
713 | rb->lcd_invertrect(0,0, (8*7)+1,(8*7)+1); | ||
714 | rb->lcd_update_rect(0,0, (8*7)+1,(8*7)+1); | ||
715 | |||
716 | return; | ||
717 | |||
718 | } | ||
719 | |||
720 | |||
721 | /******************************************************************** | ||
722 | * show player skill levels | ||
723 | ********************************************************************/ | ||
724 | static void show_players(void) | ||
725 | { | ||
726 | static char scs[] = { | ||
727 | of_plx, of_colon, of_h, of_dash, of_0, of_eos, /* 0 */ | ||
728 | of_plo, of_colon, of_h, of_dash, of_0, of_eos /* 6 */ | ||
729 | }; | ||
730 | |||
731 | if (player[PLAYERX]==AIBOT) | ||
732 | scs[2] = of_c; | ||
733 | scs[4] = ai_help[PLAYERX] +of_0; | ||
734 | |||
735 | if (player[PLAYERO]==AIBOT) | ||
736 | scs[8] = of_c; | ||
737 | scs[10] = ai_help[PLAYERO] +of_0; | ||
738 | |||
739 | othprints( 2,58, &scs[0], true); | ||
740 | othprints(40,58, &scs[6], true); | ||
741 | |||
742 | return; | ||
743 | |||
744 | } | ||
745 | |||
746 | |||
747 | /******************************************************************** | ||
748 | * show f3 function | ||
749 | ********************************************************************/ | ||
750 | static void show_f3(bool playing) | ||
751 | { | ||
752 | static char scs[10] = {of_p, of_l, of_a, of_y, of_eos, | ||
753 | of_q, of_u, of_i, of_t, of_eos }; | ||
754 | |||
755 | if (playing) | ||
756 | othprints(80,58, &scs[5], true); | ||
757 | else | ||
758 | othprints(80,58, &scs[0], true); | ||
759 | |||
760 | return; | ||
761 | |||
762 | } | ||
763 | |||
764 | |||
765 | /******************************************************************** | ||
766 | * update board tiles | ||
767 | ********************************************************************/ | ||
768 | static void show_board(void) | ||
769 | { | ||
770 | unsigned char x,y; | ||
771 | |||
772 | for (y=1; y<=8; y++) | ||
773 | for (x=1; x<=8; x++) | ||
774 | othprint(((x-1)*7)+1, ((y-1)*7)+1, board[y][x], false); | ||
775 | rb->lcd_update_rect(0,0, (8*7)+1,(8*7)+1); | ||
776 | |||
777 | return; | ||
778 | |||
779 | } | ||
780 | |||
781 | |||
782 | /******************************************************************** | ||
783 | * display scores player "turn" will get the arrow | ||
784 | ********************************************************************/ | ||
785 | static void show_score(bool turn) | ||
786 | { | ||
787 | static char scs[] = {of_ptr, of_eos, /* 0 */ | ||
788 | of_sp, of_eos, /* 2 */ | ||
789 | of_plx, of_colon, of_eos, /* 4 */ | ||
790 | of_plo, of_colon, of_eos, /* 7 */ | ||
791 | of_sp, of_sp, of_eos, /* 10 score.x */ | ||
792 | of_sp, of_sp, of_eos, /* 13 score.o */ | ||
793 | }; | ||
794 | |||
795 | rb->snprintf(&scs[10], 3, "%d", score.x); | ||
796 | scs[10] = scs[10] -'0' +of_0; | ||
797 | if (scs[11]=='\0') | ||
798 | scs[11] = of_sp; | ||
799 | else | ||
800 | scs[11] = scs[11] -'0' +of_0; | ||
801 | scs[12] = of_eos; | ||
802 | |||
803 | rb->snprintf(&scs[13], 3, "%d", score.o); | ||
804 | scs[13] = scs[13] -'0' +of_0; | ||
805 | if (scs[14]=='\0') | ||
806 | scs[14] = of_sp; | ||
807 | else | ||
808 | scs[14] = scs[14] -'0' +of_0; | ||
809 | scs[15] = of_eos; | ||
810 | |||
811 | /* turn arrow */ | ||
812 | if (turn==PLAYERX) | ||
813 | { | ||
814 | othprints(sc_tlx,sc_tly, &scs[0], false); | ||
815 | othprints(sc_tlx,sc_tly+8, &scs[2], false); | ||
816 | } | ||
817 | else | ||
818 | { | ||
819 | othprints(sc_tlx,sc_tly, &scs[2], false); | ||
820 | othprints(sc_tlx,sc_tly+8, &scs[0], false); | ||
821 | } | ||
822 | |||
823 | /* names */ | ||
824 | othprints(sc_tlx+10,sc_tly, &scs[4], false); | ||
825 | othprints(sc_tlx+10,sc_tly+8, &scs[7], false); | ||
826 | |||
827 | /* scores */ | ||
828 | othprints(sc_tlx+26,sc_tly, &scs[10], false); | ||
829 | othprints(sc_tlx+26,sc_tly+8, &scs[13], false); | ||
830 | |||
831 | rb->lcd_update_rect(sc_tlx,sc_tly, 40,14); | ||
832 | |||
833 | return; | ||
834 | } | ||
835 | |||
836 | |||
837 | /******************************************************************** | ||
838 | * cls() | ||
839 | ********************************************************************/ | ||
840 | static void initscreen(void) | ||
841 | { | ||
842 | rb->lcd_setfont(FONT_SYSFIXED); | ||
843 | rb->lcd_clear_display(); | ||
844 | rb->lcd_update(); | ||
845 | |||
846 | return; | ||
847 | } | ||
848 | |||
849 | |||
850 | /******************************************************************** | ||
851 | * Check is the specified move is valid | ||
852 | * if type=MOVE - the board will be updated. | ||
853 | * this is the recursive bit - it is called by domove() | ||
854 | * checkmove only checks the move in ONE direction | ||
855 | ********************************************************************/ | ||
856 | static int checkmove(unsigned char x, unsigned char y, bool pl, | ||
857 | unsigned char dir, bool type) | ||
858 | { | ||
859 | int i; | ||
860 | unsigned char t; | ||
861 | |||
862 | x -= ( ((dir&LEFT )==LEFT ) ?1:0); | ||
863 | x += ( ((dir&RIGHT)==RIGHT) ?1:0); | ||
864 | y -= ( ((dir&UP )==UP ) ?1:0); | ||
865 | y += ( ((dir&DOWN )==DOWN ) ?1:0); | ||
866 | |||
867 | t = board[y][x]; | ||
868 | |||
869 | /* found your piece */ | ||
870 | if ( t == ((pl==PLAYERX)?PLAYERX:PLAYERO) ) | ||
871 | return(1); | ||
872 | |||
873 | /* found an empty sqaure or board edge */ | ||
874 | if (t>PLAYERO) | ||
875 | return(0); | ||
876 | |||
877 | /* must have found opponent piece */ | ||
878 | if ((i = checkmove(x,y, pl, dir, type))) | ||
879 | { | ||
880 | if (type==MAKE) | ||
881 | board[y][x] = pl; | ||
882 | return(i+1); | ||
883 | } | ||
884 | else | ||
885 | return(0); | ||
886 | } | ||
887 | |||
888 | |||
889 | /******************************************************************** | ||
890 | * this is the control loop for checkmove() | ||
891 | * checkmove()it is called with all eight possible directoins | ||
892 | * the move.taken is defined before it returns | ||
893 | * 0 taken is an invalid move | ||
894 | ********************************************************************/ | ||
895 | static void domove(struct move* move, bool type) | ||
896 | { | ||
897 | int i; | ||
898 | unsigned char dir; | ||
899 | |||
900 | move->taken = 0; | ||
901 | for (dir=DOWN; dir<=(LEFT|UP); dir++) | ||
902 | { | ||
903 | if ( (dir&(UP|DOWN)) ==(UP|DOWN) ) | ||
904 | continue; | ||
905 | if ((i = checkmove(move->x, move->y, move->player, dir, type))) | ||
906 | move->taken += i-1; | ||
907 | } | ||
908 | |||
909 | return; | ||
910 | } | ||
911 | |||
912 | |||
913 | /******************************************************************** | ||
914 | * initialise a new game board and draw it on the screen | ||
915 | ********************************************************************/ | ||
916 | static void initboard(void) | ||
917 | { | ||
918 | unsigned char x,y; | ||
919 | |||
920 | for (y=0; y<10; y++) | ||
921 | for (x=0; x<10; x++) | ||
922 | if ( (y%9)==0 || (x%9)==0) | ||
923 | board[y][x] = BORDER; | ||
924 | else | ||
925 | board[y][x] = EMPTY; | ||
926 | |||
927 | board[4][4] = PLAYERX; | ||
928 | board[5][5] = PLAYERX; | ||
929 | board[4][5] = PLAYERO; | ||
930 | board[5][4] = PLAYERO; | ||
931 | |||
932 | score.x = 2; | ||
933 | score.o = 2; | ||
934 | |||
935 | show_grid(); | ||
936 | show_board(); | ||
937 | show_score(FIRST); | ||
938 | |||
939 | return; | ||
940 | } | ||
941 | |||
942 | |||
943 | /******************************************************************** | ||
944 | * remove "possible" markers from the board | ||
945 | ********************************************************************/ | ||
946 | static void clearposs(void) | ||
947 | { | ||
948 | int x, y; | ||
949 | |||
950 | for (y=1; y<=8; y++) | ||
951 | for (x=1; x<=8; x++) | ||
952 | if (board[y][x]>=POSS) | ||
953 | board[y][x]=EMPTY; | ||
954 | |||
955 | return; | ||
956 | } | ||
957 | |||
958 | |||
959 | /******************************************************************** | ||
960 | * build a list of all possible moves | ||
961 | ********************************************************************/ | ||
962 | static int getplist(struct move* plist, unsigned char pl) | ||
963 | { | ||
964 | int x, y; | ||
965 | unsigned char pcnt = 0; | ||
966 | |||
967 | /* this significantly reduces the amount of pointer maths */ | ||
968 | struct move pmove; | ||
969 | |||
970 | /* clear previous possibilities */ | ||
971 | clearposs(); | ||
972 | |||
973 | for (y=1; y<=8; y++) | ||
974 | for (x=1; x<=8; x++) | ||
975 | { | ||
976 | /* only empty sqaures */ | ||
977 | if (board[y][x]!=EMPTY) | ||
978 | continue; | ||
979 | /* try move */ | ||
980 | pmove.x = x; | ||
981 | pmove.y = y; | ||
982 | pmove.player = pl; | ||
983 | domove(&pmove, CHECK); | ||
984 | /* if valid - add to list */ | ||
985 | if (pmove.taken) | ||
986 | rb->memcpy(&plist[pcnt++], &pmove, sizeof(struct move)); | ||
987 | } | ||
988 | |||
989 | return(pcnt); | ||
990 | |||
991 | } | ||
992 | |||
993 | |||
994 | /******************************************************************** | ||
995 | * qsort | ||
996 | ********************************************************************/ | ||
997 | static int plist_bytaken(const void* m1, const void* m2) | ||
998 | { | ||
999 | /* highest is best */ | ||
1000 | return( ((struct move*)m2)->taken - ((struct move*)m1)->taken ); | ||
1001 | } | ||
1002 | |||
1003 | |||
1004 | /******************************************************************** | ||
1005 | * qsort | ||
1006 | ********************************************************************/ | ||
1007 | static int plist_byrank(const void* m1, const void* m2) | ||
1008 | { | ||
1009 | /* lowest is best */ | ||
1010 | return( ((struct move*)m1)->rank - ((struct move*)m2)->rank ); | ||
1011 | } | ||
1012 | |||
1013 | |||
1014 | /******************************************************************** | ||
1015 | * | ||
1016 | CORNERS (1) | ||
1017 | x......x 1,1(01) 1,8(08) | ||
1018 | ........ | ||
1019 | ........ | ||
1020 | ........ | ||
1021 | ........ | ||
1022 | ........ | ||
1023 | ........ | ||
1024 | x......x 8,1(08) 8,8(64) | ||
1025 | |||
1026 | |||
1027 | BLUFF (2) | ||
1028 | ..x..x.. 1,3(03) 1,6(06) | ||
1029 | ........ | ||
1030 | x.x..x.x 3,1(03) 3,3(09) 3,6(18) 3,8(24) | ||
1031 | ........ | ||
1032 | ........ | ||
1033 | x.x..x.x 6,1(06) 6,3(18) 6,6(36) 6,8(48) | ||
1034 | ........ | ||
1035 | ..x..x.. 8,3(24) 8,6(48) 8,8(64) | ||
1036 | |||
1037 | |||
1038 | EDGE (3) | ||
1039 | ...xx... 1,4(00) 1,5(00) | ||
1040 | ........ | ||
1041 | ........ | ||
1042 | x......x 4,1(00) 4,8(00) | ||
1043 | x......x 5,1(00) 5,8(00) | ||
1044 | ........ | ||
1045 | ........ | ||
1046 | ...xx... 8,4(00) 8,5(00) | ||
1047 | |||
1048 | |||
1049 | BAD (5) - some of these are edge pieces | ||
1050 | .x....x. 1,2(02) 1,7(07) | ||
1051 | xx....xx 2,1(02) 2,2(04) 2,7(14) 2,8(16) | ||
1052 | ........ | ||
1053 | ........ | ||
1054 | ........ | ||
1055 | ........ | ||
1056 | xx....xx 7,1(07) 7,2(14) 7,7(49) 7,8(56) | ||
1057 | .x....x. 8,2(16) 8,7(56) | ||
1058 | |||
1059 | |||
1060 | OTHER (4) | ||
1061 | |||
1062 | * this is called my reduceplist, if the "smart" AIBOT is playing | ||
1063 | * board sqaures are weighted as above | ||
1064 | * | ||
1065 | ********************************************************************/ | ||
1066 | static void smartranking(struct move* plist, unsigned char pcnt) | ||
1067 | { | ||
1068 | |||
1069 | #define corner \ | ||
1070 | ( ((y==1)||(y==8)) && ((x==1)||(x==8)) ) | ||
1071 | |||
1072 | #define bluff \ | ||
1073 | ( ((y==1)||(y==3)||(y==6)||(y==8)) && \ | ||
1074 | ((x==1)||(x==3)||(x==6)||(x==8)) ) | ||
1075 | |||
1076 | #define edge \ | ||
1077 | ( ( ((y==1)||(y==8)) && ((x==4)||(x==5)) ) || \ | ||
1078 | ( ((y==4)||(y==5)) && ((x==1)||(x==8)) ) ) | ||
1079 | |||
1080 | int i; | ||
1081 | register unsigned char mul; | ||
1082 | register unsigned char x, y; | ||
1083 | |||
1084 | for (i=0; i<pcnt; i++) | ||
1085 | { | ||
1086 | x = plist[i].x; | ||
1087 | y = plist[i].y; | ||
1088 | mul = x *y; | ||
1089 | |||
1090 | /* preferred squares */ | ||
1091 | if (corner) { plist[i].rank = 1; continue; } | ||
1092 | else if (bluff) { plist[i].rank = 2; continue; } | ||
1093 | else if (edge) { plist[i].rank = 3; continue; } | ||
1094 | |||
1095 | /* uninteresting square */ | ||
1096 | plist[i].rank = 4; | ||
1097 | |||
1098 | /* avoid "bad" sqaures */ | ||
1099 | if ( (mul==02)||(mul==04)|| | ||
1100 | (mul==07)||(mul==14)||(mul==16)|| | ||
1101 | (mul==49)||(mul==56) ) | ||
1102 | plist[i].rank = 5; | ||
1103 | } | ||
1104 | |||
1105 | return; | ||
1106 | |||
1107 | #undef corner | ||
1108 | #undef bluff | ||
1109 | #undef edge | ||
1110 | |||
1111 | } | ||
1112 | |||
1113 | |||
1114 | /******************************************************************** | ||
1115 | * called by pressing f1 or f2 to change player modes | ||
1116 | ********************************************************************/ | ||
1117 | static void changeplayer(bool pl) | ||
1118 | { | ||
1119 | ai_help[pl]++; | ||
1120 | if (ai_help[pl]>BEST) | ||
1121 | { | ||
1122 | player[pl] = (player[pl]==HUMAN)?AIBOT:HUMAN; | ||
1123 | if (player[pl]==HUMAN) | ||
1124 | ai_help[pl] = NONE; | ||
1125 | else | ||
1126 | ai_help[pl] = WEAK; | ||
1127 | } | ||
1128 | show_players(); | ||
1129 | |||
1130 | return; | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | /******************************************************************** | ||
1135 | * this proc reduces the list of possible moves to a short list of | ||
1136 | * preferred moves, dependand on the player AI | ||
1137 | ********************************************************************/ | ||
1138 | static unsigned char reduceplist(struct move* plist, unsigned char pcnt, unsigned char ai_help) | ||
1139 | { | ||
1140 | |||
1141 | int i; | ||
1142 | |||
1143 | switch(ai_help) | ||
1144 | { | ||
1145 | /* ------------------------------------------------- */ | ||
1146 | /* weak does not modify the possible's list */ | ||
1147 | /* | ||
1148 | case WEAK: | ||
1149 | break; | ||
1150 | */ | ||
1151 | /* ------------------------------------------------- */ | ||
1152 | case GURU: | ||
1153 | break; | ||
1154 | /* ------------------------------------------------- */ | ||
1155 | case EXPERT: | ||
1156 | break; | ||
1157 | /* ------------------------------------------------- */ | ||
1158 | /* this player will favour certain known moves */ | ||
1159 | case SMART: | ||
1160 | if (pcnt>1) | ||
1161 | { | ||
1162 | smartranking(plist, pcnt); | ||
1163 | rb->qsort(plist, pcnt, sizeof(struct move), plist_byrank); | ||
1164 | for (i=1; i<pcnt; i++) | ||
1165 | if (plist[i].rank!=plist[i-1].rank) | ||
1166 | break; | ||
1167 | pcnt = i; | ||
1168 | } | ||
1169 | /* FALL THROUGH */ | ||
1170 | /* ------------------------------------------------- */ | ||
1171 | /* reduce possibilites to "most pieces taken" */ | ||
1172 | case AVERAGE: | ||
1173 | if (pcnt>1) | ||
1174 | { | ||
1175 | rb->qsort(plist, pcnt, sizeof(struct move), plist_bytaken); | ||
1176 | for (i=1; i<pcnt; i++) | ||
1177 | if (plist[i].taken!=plist[i-1].taken) | ||
1178 | break; | ||
1179 | pcnt = i; | ||
1180 | } | ||
1181 | break; | ||
1182 | /* ------------------------------------------------- */ | ||
1183 | default: | ||
1184 | // you should never get here! | ||
1185 | break; | ||
1186 | } | ||
1187 | |||
1188 | return(pcnt); | ||
1189 | |||
1190 | } | ||
1191 | |||
1192 | |||
1193 | /******************************************************************** | ||
1194 | * calc all moves with wieghting and report back to the user/aibot | ||
1195 | ********************************************************************/ | ||
1196 | static bool calcposs(struct move* plist, unsigned char* pcnt, bool turn) | ||
1197 | { | ||
1198 | int i; | ||
1199 | |||
1200 | /* only evaluate moves for AIBOTs or HUMAN+HELP */ | ||
1201 | if ( (player[turn]==AIBOT) || (ai_help[turn]) ) | ||
1202 | { | ||
1203 | /* get list of all possible moves */ | ||
1204 | (*pcnt) = getplist(plist, turn); | ||
1205 | |||
1206 | /* no moves? trigger Game Over */ | ||
1207 | if (!(*pcnt)) | ||
1208 | return(true); | ||
1209 | |||
1210 | /* mark all possible moves on board */ | ||
1211 | for (i=0; i<(*pcnt); i++) | ||
1212 | board[plist[i].y][plist[i].x] = POSS; | ||
1213 | |||
1214 | /* use ai to reduce list */ | ||
1215 | (*pcnt) = reduceplist(plist, (*pcnt), ai_help[turn]); | ||
1216 | |||
1217 | /* higlight preferred moves */ | ||
1218 | if (ai_help[turn]>WEAK) | ||
1219 | for (i=0; i<(*pcnt); i++) | ||
1220 | board[plist[i].y][plist[i].x] = CHOICE; | ||
1221 | } | ||
1222 | else /* no ai/help required */ | ||
1223 | { | ||
1224 | /* create dummy plist entry for default cursor position */ | ||
1225 | plist[0].x = 4; | ||
1226 | plist[0].y = 4; | ||
1227 | } | ||
1228 | |||
1229 | return(false); /* do not cause Game Over */ | ||
1230 | } | ||
1231 | |||
1232 | |||
1233 | /******************************************************************** | ||
1234 | * cursor highlight | ||
1235 | ********************************************************************/ | ||
1236 | static void hilite(struct move* move, bool on) | ||
1237 | { | ||
1238 | int x = (move->x-1)*7; | ||
1239 | int y = (move->y-1)*7; | ||
1240 | |||
1241 | rb->lcd_invertrect(x+1,y+1, 6,6); | ||
1242 | if (on) | ||
1243 | rb->lcd_drawrect(x,y, 8,8); | ||
1244 | else | ||
1245 | { | ||
1246 | if (x) | ||
1247 | rb->lcd_clearline(x,y+3, x,y+4); | ||
1248 | if (y) | ||
1249 | rb->lcd_clearline(x+3,y, x+4,y); | ||
1250 | if (x!=7*7) | ||
1251 | rb->lcd_clearline(x+7,y+3, x+7,y+4); | ||
1252 | if (y!=7*7) | ||
1253 | rb->lcd_clearline(x+3,y+7, x+4,y+7); | ||
1254 | } | ||
1255 | rb->lcd_update_rect(x,y, 8,8); | ||
1256 | } | ||
1257 | |||
1258 | |||
1259 | /******************************************************************** | ||
1260 | * main othelo keyboard handler | ||
1261 | * returns the key that it terminated with | ||
1262 | ********************************************************************/ | ||
1263 | static int getmove(struct move* move, struct move* plist, unsigned char* pcnt, bool turn) | ||
1264 | { | ||
1265 | int key; | ||
1266 | bool waiting = true; | ||
1267 | |||
1268 | /* get next move */ | ||
1269 | do | ||
1270 | { | ||
1271 | hilite(move, true); | ||
1272 | key = rb->button_get(true); | ||
1273 | hilite(move, false); | ||
1274 | |||
1275 | switch(key) | ||
1276 | { | ||
1277 | case BUTTON_ON: | ||
1278 | case BUTTON_OFF: | ||
1279 | case BUTTON_F3: | ||
1280 | waiting = false; | ||
1281 | break; | ||
1282 | case BUTTON_UP: | ||
1283 | case BUTTON_UP | BUTTON_REPEAT: | ||
1284 | if (move->y>1) move->y--; | ||
1285 | break; | ||
1286 | case BUTTON_DOWN: | ||
1287 | case BUTTON_DOWN | BUTTON_REPEAT: | ||
1288 | if (move->y<8) move->y++; | ||
1289 | break; | ||
1290 | case BUTTON_LEFT: | ||
1291 | case BUTTON_LEFT | BUTTON_REPEAT: | ||
1292 | if (move->x>1) move->x--; | ||
1293 | break; | ||
1294 | case BUTTON_RIGHT: | ||
1295 | case BUTTON_RIGHT | BUTTON_REPEAT: | ||
1296 | if (move->x<8) move->x++; | ||
1297 | break; | ||
1298 | case BUTTON_PLAY: | ||
1299 | if (board[move->y][move->x]>=POSS) | ||
1300 | waiting = false; | ||
1301 | else | ||
1302 | flashboard(); | ||
1303 | break; | ||
1304 | case BUTTON_F1: | ||
1305 | case BUTTON_F2: | ||
1306 | { | ||
1307 | bool pl; | ||
1308 | |||
1309 | pl = (key==BUTTON_F1)?PLAYERX:PLAYERO; | ||
1310 | |||
1311 | changeplayer(pl); | ||
1312 | /* update board if *current* player options changed */ | ||
1313 | if (move->player==pl) | ||
1314 | { | ||
1315 | clearposs(); | ||
1316 | calcposs(plist, pcnt, turn); | ||
1317 | show_board(); | ||
1318 | } | ||
1319 | break; | ||
1320 | } | ||
1321 | default: | ||
1322 | break; | ||
1323 | } | ||
1324 | } while (waiting); | ||
1325 | |||
1326 | return(key); | ||
1327 | } | ||
1328 | |||
1329 | |||
1330 | /******************************************************************** | ||
1331 | * main control loop | ||
1332 | ********************************************************************/ | ||
1333 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
1334 | { | ||
1335 | #define STILL_PLAYING (!gameover && !quit) | ||
1336 | |||
1337 | #define default_players \ | ||
1338 | player[PLAYERX] = DF_PLX; \ | ||
1339 | ai_help[PLAYERX] = DF_AIX; \ | ||
1340 | player[PLAYERO] = DF_PLO; \ | ||
1341 | ai_help[PLAYERO] = DF_AIO; | ||
1342 | |||
1343 | int key; | ||
1344 | |||
1345 | unsigned char pcnt; | ||
1346 | struct move plist[MAXPOSS]; | ||
1347 | |||
1348 | bool gameover; | ||
1349 | bool quit; | ||
1350 | |||
1351 | struct move move; | ||
1352 | |||
1353 | TEST_PLUGIN_API(api); | ||
1354 | (void)parameter; | ||
1355 | rb = api; | ||
1356 | |||
1357 | quit = false; | ||
1358 | |||
1359 | do /* while !quit */ | ||
1360 | { | ||
1361 | initscreen(); | ||
1362 | showlogo(logo_tlx,logo_tly, true); | ||
1363 | show_players(); | ||
1364 | show_f3(true); | ||
1365 | |||
1366 | if (!playing) | ||
1367 | { | ||
1368 | initboard(); | ||
1369 | playing = true; | ||
1370 | turn = FIRST; | ||
1371 | } | ||
1372 | else | ||
1373 | { | ||
1374 | show_grid(); | ||
1375 | show_board(); | ||
1376 | show_score(turn); | ||
1377 | } | ||
1378 | |||
1379 | gameover = false; | ||
1380 | |||
1381 | do /* while !gameover && !quit */ | ||
1382 | { | ||
1383 | /* who's move is it? */ | ||
1384 | move.player = turn; | ||
1385 | |||
1386 | /* perform ai/help routine */ | ||
1387 | if ((gameover = calcposs(plist, &pcnt, turn))) continue; | ||
1388 | |||
1389 | /* player now gets to take a turn */ | ||
1390 | if (player[turn]==AIBOT) | ||
1391 | { | ||
1392 | int timeout; | ||
1393 | bool held = false; | ||
1394 | |||
1395 | unsigned char t; | ||
1396 | /* select a random move from the possibles list */ | ||
1397 | /* this block of code corrupts pcnt */ | ||
1398 | if (pcnt>1) | ||
1399 | t = rb->rand() % pcnt; | ||
1400 | else | ||
1401 | t = 0; | ||
1402 | move.x = plist[t].x; | ||
1403 | move.y = plist[t].y; | ||
1404 | /* move selected will always be valid! */ | ||
1405 | domove(&move, CHECK); | ||
1406 | |||
1407 | /* bots run faster when no humans are playing */ | ||
1408 | if ((player[PLAYERX]==AIBOT) && (player[PLAYERO]==AIBOT)) | ||
1409 | timeout = *rb->current_tick +((HZ*6)/10); | ||
1410 | else | ||
1411 | timeout = *rb->current_tick +((HZ*(REPEAT_START+1))/10); | ||
1412 | while (TIME_BEFORE(*rb->current_tick, timeout)) | ||
1413 | { | ||
1414 | key = rb->button_get(false); | ||
1415 | switch (key) | ||
1416 | { | ||
1417 | case SYS_USB_CONNECTED: | ||
1418 | rb->usb_screen(); | ||
1419 | return PLUGIN_USB_CONNECTED; | ||
1420 | /* hold play to freeze board */ | ||
1421 | case BUTTON_PLAY: | ||
1422 | case BUTTON_PLAY|BUTTON_REPEAT: | ||
1423 | timeout = *rb->current_tick +HZ; | ||
1424 | held = true; | ||
1425 | break; | ||
1426 | case BUTTON_PLAY|BUTTON_REL: | ||
1427 | if (held) | ||
1428 | timeout = *rb->current_tick-1; | ||
1429 | continue; | ||
1430 | case BUTTON_F3: | ||
1431 | gameover = true; | ||
1432 | break; | ||
1433 | case BUTTON_OFF: | ||
1434 | default_players; | ||
1435 | playing = false; | ||
1436 | /* Fall through to BUTTON_ON */ | ||
1437 | case BUTTON_ON: | ||
1438 | return PLUGIN_OK; | ||
1439 | default: | ||
1440 | break; | ||
1441 | } | ||
1442 | } /*endwhile*/; | ||
1443 | } | ||
1444 | else /* player is human */ | ||
1445 | { | ||
1446 | /* only display poss on screen if help is enabled */ | ||
1447 | if (ai_help[turn]) show_board(); | ||
1448 | move.x = plist[0].x; | ||
1449 | move.y = plist[0].y; | ||
1450 | while(true) | ||
1451 | { | ||
1452 | key = getmove(&move, plist, &pcnt, turn); | ||
1453 | switch(key) | ||
1454 | { | ||
1455 | case SYS_USB_CONNECTED: | ||
1456 | rb->usb_screen(); | ||
1457 | return PLUGIN_USB_CONNECTED; | ||
1458 | case BUTTON_OFF: | ||
1459 | playing = false; | ||
1460 | default_players; | ||
1461 | case BUTTON_ON: | ||
1462 | rb->lcd_setfont(FONT_UI); | ||
1463 | return PLUGIN_OK; | ||
1464 | case BUTTON_F3: | ||
1465 | gameover = true; | ||
1466 | default: | ||
1467 | break; | ||
1468 | } | ||
1469 | if (key==BUTTON_F3) | ||
1470 | break; | ||
1471 | |||
1472 | /* check move is valid & retrieve "pieces taken" */ | ||
1473 | domove(&move, CHECK); | ||
1474 | if (move.taken==0) | ||
1475 | flashboard(); | ||
1476 | else | ||
1477 | break; | ||
1478 | } | ||
1479 | } | ||
1480 | |||
1481 | /* player may have hit restart instead of moving */ | ||
1482 | if (STILL_PLAYING) | ||
1483 | { | ||
1484 | /* MAKE MOVE */ | ||
1485 | /* add new piece */ | ||
1486 | board[move.y][move.x] = move.player; | ||
1487 | /* flip opponent pieces */ | ||
1488 | domove(&move, MAKE); | ||
1489 | /* update board */ | ||
1490 | clearposs(); | ||
1491 | show_board(); | ||
1492 | /* update score */ | ||
1493 | if (turn==PLAYERX) | ||
1494 | { | ||
1495 | score.x += move.taken+1; | ||
1496 | score.o -= move.taken; | ||
1497 | } | ||
1498 | if (turn==PLAYERO) | ||
1499 | { | ||
1500 | score.o += move.taken+1; | ||
1501 | score.x -= move.taken; | ||
1502 | } | ||
1503 | /* next player please */ | ||
1504 | turn = (turn==PLAYERX)?PLAYERO:PLAYERX; | ||
1505 | show_score(turn); | ||
1506 | } | ||
1507 | |||
1508 | } while(STILL_PLAYING); | ||
1509 | |||
1510 | clearposs(); | ||
1511 | show_board(); | ||
1512 | show_f3(false); | ||
1513 | show_endgame(score.x, score.o); | ||
1514 | playing = false; | ||
1515 | |||
1516 | do | ||
1517 | { | ||
1518 | if ((key = rb->button_get(true)) ==BUTTON_F3) | ||
1519 | break; | ||
1520 | switch(key) | ||
1521 | { | ||
1522 | case SYS_USB_CONNECTED: | ||
1523 | rb->usb_screen(); | ||
1524 | return PLUGIN_USB_CONNECTED; | ||
1525 | case BUTTON_OFF: | ||
1526 | default_players; | ||
1527 | case BUTTON_ON: | ||
1528 | quit = true; | ||
1529 | break; | ||
1530 | case BUTTON_F1: | ||
1531 | changeplayer(PLAYERX); | ||
1532 | break; | ||
1533 | case BUTTON_F2: | ||
1534 | changeplayer(PLAYERO); | ||
1535 | break; | ||
1536 | default: | ||
1537 | break; | ||
1538 | } | ||
1539 | } while(!quit); | ||
1540 | |||
1541 | }while(!quit); | ||
1542 | |||
1543 | return PLUGIN_OK; | ||
1544 | |||
1545 | } | ||
1546 | #endif | ||