Source code for /engineering/REVERSEM/BOARD.CPPOriginal file BOARD.CPP
   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    };