1 /*--------------------------------------------------------------------------
2
3 REVERSEM :
4
5 UNIT : PLAYING BOARD CLASS
6
7 COPYRIGHT (C) 1994 Erich P. Gatejen ALL RIGHTS RESERVED
8 This is Freeware. You may distribute it as you wish. However, you may not
9 distribute a modified version without my consent.
10
11 Feel free to cut and paste any algorthm.
12
13 NOTE: XTILE is (C) 1992, 1994 by myself. It is NOT freeware. You may use
14 it for personal projects, but otherwise, it is not to be distributed
15 outside this REVERSEM package. (Contact me if you wish to do
16 otherwise)
17
18 ---------------------------------------------------------------------------*/
19
20
21 // ------------------------------------------------------------------------
22 // --- INCLUDES
23 // ------------------------------------------------------------------------
24 #include<stdlib.h>
25 #include<stdio.h>
26 extern "C" {
27 #include "xtile21!.h"
28 };
29 #include"string.h"
30 #include"reversem.hpp"
31 #include"spots.hpp"
32 #include"board.hpp"
33 #include"eval.hpp"
34
35 // ------------------------------------------------------------------------
36 // --- PRIVATE MEMBERS
37 // ------------------------------------------------------------------------
38
39 // -- Members : Board -----------------------------------------------------
40
41 BOOLEAN Board::ValidNorth( void ) {
42 // The valid checks are brute force.
43 register signed int X = TheGo.XIs();
44 register signed int Y = TheGo.YIs();
45
46 // Run north to see if it is a valid move
47 Y--;
48 // Is is not off the board and is the other player
49 if ( Y < TOPY ) return( FALSE );
50 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
51
52 Y--;
53 while( Y >= TOPY ) {
54 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
55 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
56 Y--;
57 };
58 return( FALSE );
59 };
60
61 void Board::FlipNorth( void ) {
62 // The valid checks are brute force.
63 register signed int X = TheGo.XIs();
64 register signed int Y = TheGo.YIs();
65
66 // Run north and flip until it is the same player
67 Y--;
68 while( !Spots[X][Y].IsSpot(Player) ) {
69 Spots[X][Y].FlipSpot();
70 Y--;
71 };
72 };
73
74 BOOLEAN Board::ValidSouth( void ) {
75 // The valid checks are brute force.
76 register signed int X = TheGo.XIs();
77 register signed int Y = TheGo.YIs();
78
79 // Run south to see if it is a valid move
80 Y++;
81 // Is is not off the board and is the other player
82 if ( Y > BOTTOMY ) return( FALSE );
83 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
84
85 Y++;
86 while( Y <= BOTTOMY ) {
87 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
88 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
89 Y++;
90 };
91 return( FALSE );
92 };
93
94 void Board::FlipSouth( void ) {
95 // The valid checks are brute force.
96 register signed int X = TheGo.XIs();
97 register signed int Y = TheGo.YIs();
98
99 // Run south to see if it is a valid move
100 Y++;
101 while( !Spots[X][Y].IsSpot(Player) ) {
102 Spots[X][Y].FlipSpot();
103 Y++;
104 };
105 };
106
107 BOOLEAN Board::ValidWest( void ) {
108 // The valid checks are brute force.
109 register signed int X = TheGo.XIs();
110 register signed int Y = TheGo.YIs();
111
112 // Run north to see if it is a valid move
113 X--;
114 // Is is not off the board and is the other player
115 if ( X < TOPX ) return( FALSE );
116 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
117
118 X--;
119 while ( X >= TOPX ) {
120 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
121 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
122 X--;
123 };
124 return( FALSE );
125 };
126
127 void Board::FlipWest( void ) {
128 // The valid checks are brute force.
129 register signed int X = TheGo.XIs();
130 register signed int Y = TheGo.YIs();
131
132 // Run north to see if it is a valid move
133 X--;
134 while ( !Spots[X][Y].IsSpot(Player) ) {
135 Spots[X][Y].FlipSpot();
136 X--;
137 };
138 };
139
140 BOOLEAN Board::ValidEast( void ) {
141 // The valid checks are brute force.
142 register signed int X = TheGo.XIs();
143 register signed int Y = TheGo.YIs();
144
145 // Run south to see if it is a valid move
146 X++;
147 // Is is not off the board and is the other player
148 if ( X > BOTTOMX ) return( FALSE );
149 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
150
151 X++;
152 while( X <= BOTTOMX ) {
153 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
154 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
155 X++;
156 };
157 return( FALSE );
158 };
159
160 void Board::FlipEast( void ) {
161 // The valid checks are brute force.
162 register signed int X = TheGo.XIs();
163 register signed int Y = TheGo.YIs();
164
165 // Run south to see if it is a valid move
166 X++;
167 while( !Spots[X][Y].IsSpot(Player) ) {
168 Spots[X][Y].FlipSpot();
169 X++;
170 };
171 };
172
173 BOOLEAN Board::ValidNorthEast( void ) {
174 // The valid checks are brute force.
175 register signed int X = TheGo.XIs();
176 register signed int Y = TheGo.YIs();
177
178 // Run north to see if it is a valid move
179 Y--;
180 X++;
181 // Is is not off the board and is the other player
182 if ( X > BOTTOMX ) return( FALSE );
183 if ( Y < TOPY ) return( FALSE );
184 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
185
186 Y--;
187 X++;
188 while(( Y >= TOPY )&&( X <= BOTTOMX )) {
189 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
190 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
191 Y--;
192 X++;
193 };
194 return( FALSE );
195 };
196
197 void Board::FlipNorthEast( void ) {
198 // The valid checks are brute force.
199 register signed int X = TheGo.XIs();
200 register signed int Y = TheGo.YIs();
201
202 // Run north to see if it is a valid move
203 Y--;
204 X++;
205 while( !Spots[X][Y].IsSpot(Player) ) {
206 Spots[X][Y].FlipSpot();
207 Y--;
208 X++;
209 };
210 };
211
212 BOOLEAN Board::ValidNorthWest( void ) {
213 // The valid checks are brute force.
214 register signed int X = TheGo.XIs();
215 register signed int Y = TheGo.YIs();
216
217 // Run north to see if it is a valid move
218 X--;
219 Y--;
220 // Is is not off the board and is the other player
221 if ( Y < TOPY ) return( FALSE );
222 if ( X < TOPX ) return( FALSE );
223 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
224
225 X--;
226 Y--;
227 while( (Y >= TOPY)&&( X >= TOPX ) ) {
228 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
229 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
230 X--;
231 Y--;
232 };
233 return( FALSE );
234 };
235
236 void Board::FlipNorthWest( void ) {
237 // The valid checks are brute force.
238 register signed int X = TheGo.XIs();
239 register signed int Y = TheGo.YIs();
240
241 // Run north to see if it is a valid move
242 X--;
243 Y--;
244 while( !Spots[X][Y].IsSpot(Player) ) {
245 Spots[X][Y].FlipSpot();
246 X--;
247 Y--;
248 };
249 };
250
251 BOOLEAN Board::ValidSouthEast( void ) {
252 // The valid checks are brute force.
253 register signed int X = TheGo.XIs();
254 register signed int Y = TheGo.YIs();
255
256 // Run south to see if it is a valid move
257 Y++;
258 X++;
259 // Is is not off the board and is the other player
260 if ( X > BOTTOMX ) return( FALSE );
261 if ( Y > BOTTOMY ) return( FALSE );
262 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
263
264 Y++;
265 X++;
266 while( (Y <= BOTTOMY)&&( X <= BOTTOMX ) ) {
267 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
268 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
269 Y++;
270 X++;
271 };
272 return( FALSE );
273 };
274
275 void Board::FlipSouthEast( void ) {
276 // The valid checks are brute force.
277 register signed int X = TheGo.XIs();
278 register signed int Y = TheGo.YIs();
279
280 // Run south to see if it is a valid move
281 Y++;
282 X++;
283 while( !Spots[X][Y].IsSpot(Player) ) {
284 Spots[X][Y].FlipSpot();
285 Y++;
286 X++;
287 };
288 };
289
290 BOOLEAN Board::ValidSouthWest( void ) {
291 // The valid checks are brute force.
292 register signed int X = TheGo.XIs();
293 register signed int Y = TheGo.YIs();
294
295 // Run south to see if it is a valid move
296 Y++;
297 X--;
298 // Is is not off the board and is the other player
299 if ( Y > BOTTOMY ) return( FALSE );
300 if ( X < TOPX ) return( FALSE );
301 if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
302
303 Y++;
304 X--;
305 while( (Y <= BOTTOMY)&&(X >= TOPX ) ) {
306 if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
307 if ( Spots[X][Y].IsSpotBlank() ) return( FALSE );
308 Y++;
309 X--;
310 };
311 return( FALSE );
312 };
313
314 void Board::FlipSouthWest( void ) {
315 // The valid checks are brute force.
316 register signed int X = TheGo.XIs();
317 register signed int Y = TheGo.YIs();
318
319 // Run south to see if it is a valid move
320 Y++;
321 X--;
322 while( !Spots[X][Y].IsSpot(Player) ) {
323 Spots[X][Y].FlipSpot();
324 Y++;
325 X--;
326 };
327 };
328
329 // ------------------------------------------------------------------------
330 // --- PUBLIC MEMBERS
331 // ------------------------------------------------------------------------
332
333 Board::Board( Board *OldBoard ) {
334
335 memcpy( Spots, OldBoard->Spots, sizeof( Spots ) );
336
337 };
338
339 Board::Board( Spot TheSpots[BOARDXSIZE][BOARDYSIZE] ) {
340
341 memcpy( Spots, TheSpots, sizeof( Spots ) );
342
343 };
344
345 void Board::InitBoard2Start( void ) {
346
347 register int X, Y;
348
349 for ( X = 0; X < BOARDXSIZE; X++ ) {
350 for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
351
352 Spots[X][Y].Is( SPOT_BLANK );
353 }
354 }
355
356 Spots[3][3].Is( SPOT_WHITE );
357 Spots[3][4].Is( SPOT_BLACK );
358 Spots[4][3].Is( SPOT_BLACK );
359 Spots[4][4].Is( SPOT_WHITE );
360
361
362 };
363
364
365 BOOLEAN Board::ValidGo( Go GoTo, SpotStates ThePlayer ) {
366
367 // If a piece is already there, it is not valid.
368 if ( !Spots[GoTo.XIs()][GoTo.YIs()].IsSpotBlank() ) return FALSE;
369
370 // Copy to local
371 TheGo = GoTo;
372 Player = ThePlayer;
373
374 // Walk in compass directions; if any are valid, the go is valid
375 if (ValidNorth()) return (TRUE);
376 if (ValidSouth()) return (TRUE);
377 if (ValidEast ()) return (TRUE);
378 if (ValidWest ()) return (TRUE);
379 if (ValidNorthEast()) return (TRUE);
380 if (ValidNorthWest()) return (TRUE);
381 if (ValidSouthEast()) return (TRUE);
382 if (ValidSouthWest()) return (TRUE);
383 return( FALSE );
384
385 };
386
387
388 void Board::DoGo ( Go GoTo, SpotStates ThePlayer ) {
389
390 // Copy the go local
391 TheGo = GoTo;
392 Player = ThePlayer;
393
394 // Do the go, flip as appropriate, for each compass direction
395 Spots[TheGo.XIs()][TheGo.YIs()].Is( Player );
396
397 if (ValidNorth()) FlipNorth();
398 if (ValidSouth()) FlipSouth();
399 if (ValidEast ()) FlipEast ();
400 if (ValidWest ()) FlipWest ();
401 if (ValidNorthEast()) FlipNorthEast ();
402 if (ValidNorthWest()) FlipNorthWest ();
403 if (ValidSouthEast()) FlipSouthEast ();
404 if (ValidSouthWest()) FlipSouthWest ();
405
406 };
407
408
409 heuristic Board::Evaluate( SpotStates ThePlayer ) {
410
411 heuristic Value = 0;
412 int X;
413 int Y;
414
415 // Copy the go local
416 Player = ThePlayer;
417
418 // We need to evaluate the heuristic merit of this board for Player
419 // This is where playing with this code will give you the biggest
420 // pay off
421
422 // OK, do the evals that require a visit to every spot
423 for ( X = 0; X < BOARDXSIZE; X++ ) {
424
425 for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
426
427 // Use a case to do some of the evals for some of the levels
428 switch( BrainLevel ) {
429
430 case EXPERIMENTAL:
431 // Through in a random modifier.
432 Value += (random( 5000 ) - 2500);
433
434 case GENIUS:
435 case SWIFT:
436 // Apply the opponate value
437 if ( Spots[X][Y].IsOther( Player ) )
438 Value += OpponantVal[X][Y];
439
440 case AVERAGE:
441 // Apply the player value
442 if ( Spots[X][Y].IsSpot( Player ) )
443 Value += PlayerVal[X][Y];
444
445 case DULLARD:
446
447 // Count bad guys spots
448 if ( Spots[X][Y].IsOther( Player ) )
449 Value -= SPOT_VALUE;
450
451 case SIMPLETON:
452
453 // Count good guys spots
454 if ( Spots[X][Y].IsSpot( Player ) )
455 Value += SPOT_VALUE;
456 break;
457
458
459 } // end case
460
461 } // end inner for
462 }
463
464 // Do multipliers for brain level. This will spread out the H
465 switch( BrainLevel ) {
466
467 case AVERAGE: Value = Value * 2;
468 break;
469
470 case DULLARD: Value = Value * 3;
471 break;
472
473 case SIMPLETON: Value = Value * 4;
474 break;
475
476 }
477
478 return Value;
479 };
480
481 heuristic Board::WinOrLose( SpotStates ThePlayer ) {
482
483 int X;
484 int Y;
485 int GoodGuys = 0;
486 int BadGuys = 0;
487
488 // Copy the go local
489 Player = ThePlayer;
490
491 // Count up the spots.
492 for ( X = 0; X < BOARDXSIZE; X++ ) {
493 for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
494
495 if ( Spots[X][Y].IsSpot( Player ) )
496 GoodGuys++;
497
498 else if ( Spots[X][Y].IsOther( Player ) )
499 BadGuys++;
500
501 } // end inner for
502 }
503
504 // Is it a tie, win, or loss.
505 if ( GoodGuys == BadGuys )
506 return( 0 );
507
508 else if ( GoodGuys > BadGuys )
509 return( VERY_GOOD_THING );
510
511 else
512 return( VERY_BAD_THING );
513
514 };
515
516 int Board::Count( SpotStates ThePlayer ) {
517
518 int X;
519 int Y;
520 int Count = 0;
521
522 // Copy the go local
523 Player = ThePlayer;
524
525 // Count up the spots.
526 for ( X = 0; X < BOARDXSIZE; X++ ) {
527 for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
528
529 if ( Spots[X][Y].IsSpot( Player ) )
530 Count++;
531
532 else if ( Spots[X][Y].IsOther( Player ) )
533 Count--;
534
535 } // end inner for
536 }
537
538 return( Count );
539
540 };
541
542
543 BOOLEAN Board::MoveExists( SpotStates ThePlayer ) {
544
545 register int X;
546 register int Y;
547 Go AGo;
548
549 // OK, do the evals that require a visit to every spot
550 for ( X = 0; X < BOARDXSIZE; X++ ) {
551
552 for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
553
554 AGo.XIs(X);
555 AGo.YIs(Y);
556
557 if ( ValidGo( AGo, ThePlayer ) ) return TRUE;
558
559 } // end inner for
560 }
561
562 return FALSE;
563
564 };
565
566
567 // OK!! Board has a couple of static members. Lets define them.
568 SpotStates Board::Player;
569 BRAIN Board::BrainLevel;
570 Go Board::TheGo;
571
572
573 // The following are the evaluation boards. They are col major (sorry)
574 int Board::PlayerVal[BOARDXSIZE][BOARDYSIZE] = {
575
576 { 900, -220, 90, 70, 70, 90, -220, 900 },
577 { -220, -200, -20, 0, 0, -20, -200, -220 },
578 { 90, -30, 30, 40, 20, 40, -30, 90 },
579 { 78, 0, 40, 0, 0, 20, 0, 78 },
580 { 78, 0, 20, 0, 0, 40, 0, 78 },
581 { 90, -30, 40, 20, 40, 30, -30, 90 },
582 { -220, -200, -20, 0, 0, -20, -200, -220 },
583 { 900, -220, 90, 70, 70, 90, -220, 900 }
584 };
585
586 int Board::OpponantVal[BOARDXSIZE][BOARDYSIZE] = {
587
588 { -2000, 90, -20, -15, -15, -20, 90, -2000 },
589 { 80, 200, 10, 30, 30, 10, 100, 90 },
590 { -20, 10, 0, 0, 0, 0, 10, -20 },
591 { -15, 30, 0, 0, 0, 0, 30, -15 },
592 { -15, 30, 0, 0, 0, 0, 30, -15 },
593 { -20, 10, 0, 0, 0, 0, 10, -20 },
594 { 80, 200, 10, 30, 30, 10, 100, 90 },
595 { -2000, 90, -20, -15, -15, -20, 90, -2000 },
596
597 };
|