home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 5.ddi / CHECKERS.ZIP / BOARD.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  41.2 KB  |  1,670 lines

  1. // ObjectWindows - (C) Copyright 1992 by Borland International
  2.  
  3. #include <static.h>
  4. #include "checkers.h"
  5. #include "info.h"
  6. #include "board.h"
  7.  
  8.  
  9. const MYFRAMESIZE = 3;
  10. static char buf[ 80 ];
  11. const char *LOGFILE = "checkers.log";
  12. extern HBITMAP RedManBmp, BlackManBmp, RedKingBmp, BlackKingBmp;
  13.  
  14.  
  15. static char * CharArray[] = { "A","B", "C", "D", "E", "F", "G", "H" };
  16. static char * NumArray[] = { "1", "2", "3", "4", "5", "6", "7", "8" };
  17.  
  18. static MOVE BestVar[ MAXPLY + 1 ][ MAXPLY + 1 ];      /* the best variation */
  19. static MOVE Killer[ MAXPLY + 1 ][ 2 ];                /* Killer moves       */
  20.  
  21.  
  22. /*
  23.  *  Member function definitions for class Square
  24.  */
  25.  
  26. void Square::ClearSquare(HDC hDC)
  27. {
  28.    int x, y;
  29.    HANDLE hOldBrush;
  30.    x = UpperLeftPos.x;
  31.    y = UpperLeftPos.y;
  32.  
  33.  
  34.    hOldBrush = SelectObject(hDC, hBrush);
  35.    PatBlt(hDC, x, y, SQUARE_SIZE, SQUARE_SIZE, PATCOPY);
  36.    SelectObject(hDC, hOldBrush);
  37. }
  38.  
  39.  
  40. /*
  41.  *  Member function definitions for class Piece
  42.  */
  43.  
  44. void Piece::SetBitmap(HBITMAP hbp)
  45. {
  46.    hBitmap = hbp;
  47.    if (hBitmap != 0)
  48.       GetObject(hBitmap, sizeof(BITMAP), (LPSTR) &Bitmap);
  49. }
  50.  
  51. void Piece::DrawPiece(HDC hDC, POINT& p)
  52. {
  53.    HDC hMemoryDC;
  54.    HBITMAP hOldBmp;
  55.  
  56.    if (hBitmap == 0)
  57.       return;
  58.    hMemoryDC = CreateCompatibleDC(hDC);
  59.    hOldBmp = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
  60.    BitBlt(hDC, p.x+PIECE_OFFSET, p.y+PIECE_OFFSET, Bitmap.bmWidth, Bitmap.bmHeight,
  61.       hMemoryDC, 0, 0, SRCCOPY);
  62.    SelectObject(hMemoryDC, hOldBmp);
  63.    DeleteDC(hMemoryDC);
  64. }
  65.  
  66.  
  67. /*
  68.  *  Member function definitions for struct MOVE
  69.  */
  70.  
  71. BOOL MOVE::CompMoves( MOVE &m2 )
  72. {
  73.    if( org.GetRow() == m2.org.GetRow() && org.GetCol() == m2.org.GetCol() )
  74.       {
  75.       if( dest.GetRow() == m2.dest.GetRow() && dest.GetCol() == m2.dest.GetCol() )
  76.          {
  77.          if( Capture == m2.Capture )
  78.             {
  79.             if( Capture != EMPTY )
  80.                {
  81.                if( capt.GetRow() == m2.capt.GetRow() )
  82.                   {
  83.                   if( capt.GetCol() == m2.capt.GetCol() )
  84.                      {
  85.                      if( Crown == m2.Crown )
  86.                         {
  87.                         return( TRUE );
  88.                         }
  89.                      }
  90.                   }
  91.                }
  92.             else
  93.                {
  94.                if( Crown == m2.Crown )
  95.                   {
  96.                   return( TRUE );
  97.                   }
  98.                }
  99.             }
  100.          }
  101.       }
  102.    // all members of 'this' and 'm2' should be equivalent, except
  103.    // the last member, 'value', which is of size int, so its left out
  104.    // THIS MAY FAIL if MOVEs' data structures are changed
  105. //   if (memcmp(this, &m2, sizeof(MOVE) - sizeof(int)) == 0)
  106. //      return TRUE;
  107.    return( FALSE );
  108. }
  109.  
  110.  
  111.  
  112. /*
  113.  *  Utility Functions
  114.  */
  115.  
  116. #pragma argsused
  117. extern "C" char *getenv(const char *var)
  118. {
  119.    // this effectively shortens the time needed to
  120.    // call the 'time' function.  It happens to call
  121.    // getenv for reasons not important to this app.
  122.    // Thats not the real reason this was originally put
  123.    // here, but its a good enough reason to leave it...
  124.    return NULL;
  125. }
  126.  
  127. void TimeToStr(char *tstr, time_t time)
  128. {
  129.    int hours, min, secs;
  130.    secs = (int)(time % 60L);
  131.    min = (int) ((time / 60L) % 60L);
  132.    hours = (int) (time / 3600L);
  133.    min = (int)((time / 60L) % 60L);
  134.    sprintf(tstr, "%d:%02d:%02d", hours, min, secs);
  135. }
  136.  
  137. void UpdateBestVariation( MOVE *m, int ply )
  138. {
  139.    int t1 = ply + 1;
  140.    memcpy( &BestVar[ ply ][ ply ], m, sizeof( MOVE ) );
  141.    MOVE *mptr1, *mptr2;
  142.    for ( mptr1 = &BestVar[t1][t1], mptr2 = &BestVar[ply][t1];
  143.       mptr1->org.GetRow(); mptr1++, mptr2++)
  144.       memcpy(mptr2, mptr1, sizeof(MOVE));
  145.  
  146.    mptr2->org.SetRow(0);
  147.    BestVar[ t1 ][ t1 ].org.SetRow( 0 );
  148. }
  149.  
  150. void MemSwap( void *a, void *b, int size )
  151. {
  152. #if defined(__SMALL__) || defined(__MEDIUM__)
  153.    asm {
  154.       mov   bx, a
  155.       mov   di, b
  156.       mov   cx, size
  157.  
  158.       or    cx, cx
  159.       jne   BEGIN_LOOP
  160.       jmp   END_MEMSWAP
  161.       }
  162.  
  163. BEGIN_LOOP :
  164.    asm  {
  165.       mov   dl, byte ptr [bx]
  166.       mov   al, byte ptr [di]
  167.       mov   byte ptr [bx], al
  168.       mov   byte ptr [di], dl
  169.       inc   bx
  170.       inc   di
  171.  
  172.       dec   cx
  173.       jne   BEGIN_LOOP
  174.       }
  175.  
  176. END_MEMSWAP:
  177.       return;
  178. #else
  179.  
  180.    asm {
  181.       les   bx, dword ptr a
  182.       push  ds
  183.       lds   di, dword ptr b
  184.       mov   cx, size
  185.       or    cx, cx
  186.       jne   BEGIN_LOOP
  187.       jmp   END_MEMSWAP
  188.       }
  189.  
  190. BEGIN_LOOP :
  191.    asm  {
  192.       mov   dl, byte ptr es:[bx]
  193.       mov   al, byte ptr ds:[di]
  194.       mov   byte ptr es:[bx], al
  195.       mov   byte ptr ds:[di], dl
  196.       inc   bx
  197.       inc   di
  198.  
  199.       dec   cx
  200.       jne   BEGIN_LOOP
  201.       }
  202.  
  203. END_MEMSWAP:
  204.    asm pop ds
  205.       return;
  206. #endif
  207.  
  208. }
  209.  
  210. int IsInList( MOVE *list, int num_moves, MOVE &m )
  211. {
  212.    for( int i = 0; i < num_moves; ++i )
  213.       {
  214.       if( (list++)->CompMoves( m ) )
  215.          return( i );
  216.       }
  217.    return( -1 );
  218. }
  219.  
  220. void UpdateKillerTable( MOVE &m, int ply )
  221. {
  222.    static int i;
  223.  
  224.    m.Value = 1;
  225.  
  226.    if( (i = IsInList( Killer[ ply ], 2, m )) != -1 )
  227.       {
  228.       if( ++Killer[ ply ][ i ].Value > 1000 )
  229.          Killer[ ply ][ i ].Value = 1000;
  230.       }
  231.    else           /* add it to the Killer table */
  232.       {
  233.       if( Killer[ ply ][ 0 ].Value <= Killer[ ply ][ 1 ].Value )
  234.          {
  235.          memcpy( &Killer[ ply ][ 0 ], &m, sizeof( MOVE ) );
  236.          }
  237.       else
  238.          {
  239.          memcpy( &Killer[ ply ][ 1 ], &m, sizeof( MOVE ) );
  240.          }
  241.       }
  242. }
  243.  
  244.  
  245. /**********************************************
  246.  sorts the moves list
  247.  **********************************************/
  248.  
  249. int SortMoves( MOVE list[], int num_moves )
  250. {
  251.  
  252.    for( int i = 0; i < num_moves; ++i )
  253.       {
  254.       if( list[ i ].Capture == EMPTY )
  255.          break;
  256.       }
  257.  
  258.    for( int j = i + 1; j < num_moves; ++j )
  259.       {
  260.       if( list[ j ].Capture != EMPTY )
  261.          {
  262.          MemSwap( &list[ i ], &list[ j ], sizeof( MOVE ) );
  263.          ++i;
  264.          }
  265.       }
  266.  
  267.    /* if there is a jump, trim off all non-jump moves */
  268.    if( list[ 0 ].Capture != EMPTY )
  269.       {
  270.       while( list[ num_moves - 1 ].Capture == EMPTY )
  271.          --num_moves;
  272.       }
  273.  
  274.    return( num_moves );
  275. }
  276.  
  277. int KillerSortMoves( MOVE list[], int num_moves, int ply )
  278. {
  279.    MOVE *mptr, *endptr, *mptr2;
  280.    int j;
  281.   /* evaluate each move */
  282.    for( mptr = list, endptr = mptr + num_moves; mptr < endptr; mptr++ )
  283.       {
  284.       if( mptr->Capture != EMPTY )
  285.          mptr->Value = 5000;
  286.       else
  287.          mptr->Value = 0;
  288.  
  289.       if( (j = IsInList( Killer[ ply ], 2, *mptr )) >= 0 )
  290.          {
  291.          mptr->Value += Killer[ ply ][ j ].Value;
  292.          }
  293.       }
  294.  
  295.   /* sort the list in descending order */
  296.    for( mptr = list, endptr = mptr + num_moves; mptr < endptr - 1; mptr++)
  297.       {
  298.       for( mptr2 = mptr + 1; mptr2 < endptr; mptr2++ )
  299.          {
  300.          if( mptr2->Value > mptr->Value )
  301.             {
  302.             MemSwap( mptr, mptr2, sizeof( MOVE ) );
  303.             }
  304.          }
  305.       }
  306.  
  307.    /* if there is a jump, trim off all non-jump moves */
  308.    mptr = &list[num_moves-1];
  309.    if( list[ 0 ].Capture != EMPTY )
  310.       {
  311.       while( (mptr--)->Capture == EMPTY )
  312.          --num_moves;
  313.       }
  314.  
  315.    return( num_moves );
  316. }
  317.  
  318.  
  319. /*
  320.  *  Member function definitions for class BOARD
  321.  */
  322.  
  323. BOARD::BOARD()
  324. {
  325.    BoardSize = 8;
  326.    IterFlag = TRUE;
  327.    KillerFlag = TRUE;
  328.    Man = new Piece[6];
  329.    hRedBrush = CreateSolidBrush(RED);
  330.    hBlackBrush = CreateSolidBrush(BLACK);
  331.    Redraw = NULL;
  332.    Logging = FALSE;
  333.    LastDest.SetRow(0);
  334.    LastDest.SetCol(0);
  335.  
  336.    Man[REDMAN].SetBitmap(RedManBmp);
  337.    Man[BLACKMAN].SetBitmap(BlackManBmp);
  338.    Man[REDKING].SetBitmap(RedKingBmp);
  339.    Man[BLACKKING].SetBitmap(BlackKingBmp);
  340.    Man[EMPTY].SetBitmap(0);
  341.    Man[OFFBOARD].SetBitmap(0);
  342.  
  343.    Man[REDMAN].SetSide(Red);
  344.    Man[BLACKMAN].SetSide(Black);
  345.    Man[REDKING].SetSide(Red);
  346.    Man[BLACKKING].SetSide(Black);
  347.    Man[EMPTY].SetSide(Unknown);
  348.    Man[OFFBOARD].SetSide(Unknown);
  349. }
  350.  
  351. BOARD::~BOARD()
  352. {
  353.    delete Man;
  354.    if (Logging)
  355.       Logoff();
  356.    DeleteObject(hBlackBrush);
  357.    DeleteObject(hRedBrush);
  358. }
  359.  
  360.  
  361. void BOARD::MessageScan()
  362. {
  363.    MSG msg;
  364.    if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  365.       {
  366.       if (msg.message == WM_SETCURSOR)
  367.          DispatchMessage(&msg);
  368.       else if (msg.message == WM_COMMAND && msg.wParam == CM_STOP)
  369.          StopSearch = TRUE;
  370.       else
  371.         {
  372.             TranslateMessage(&msg);
  373.             DispatchMessage(&msg);
  374.         }
  375.     }
  376. }
  377.  
  378.  
  379. BOOL BOARD::OnlyOneMove( SIDE player, int *row, int *col )
  380. {
  381.    int RetVal = FALSE;
  382.    MOVE *list = new MOVE[ MAXMOVES ];
  383.    int NumMoves = 0;
  384.  
  385.    while ( (NumMoves = Lmg( list, player, *row, *col, 0 )) == 1 )
  386.       {
  387.       MakeActualMove( list[ 0 ] );
  388.       RetVal = TRUE;
  389.       if( list[ 0 ].Capture != EMPTY && !list[ 0 ].Crown && CanJump( player, list[ 0 ].dest.GetRow(), list[ 0 ].dest.GetCol() ) )
  390.         {
  391.         *row = list[ 0 ].dest.GetRow();
  392.         *col = list[ 0 ].dest.GetCol();
  393.         }
  394.       else
  395.          goto END_ONLYONE;
  396.       }
  397.  
  398. END_ONLYONE:
  399.    delete list;
  400.    if (NumMoves > 1) /* In case where there is one required jump, but */
  401.       return FALSE;  /* then two possible jumps after that, return FALSE */
  402.    return   RetVal;
  403. }
  404.  
  405.  
  406. void BOARD::PreEvaluate()
  407. {
  408.    int i, j, xman, inside;
  409.    int tBSizeDiv2 = BoardSize >> 1;  // (BoardSize / 2)
  410.  
  411.    /*********************************************************
  412.    This code gets a rough idea as to who is ahead in Material.
  413.    **********************************************************/
  414.    Material[ Red ]   = 0;
  415.    Material[ Black ] = 0;
  416.  
  417.    Man[ REDMAN ].SetValue( 100 );
  418.    Man[ BLACKMAN ].SetValue( 100 );
  419.    Man[ REDKING ].SetValue ( 140 );
  420.    Man[ BLACKKING ].SetValue( 140 );
  421.    Man[ EMPTY ].SetValue( 0 );
  422.    Man[ OFFBOARD ].SetValue( 0 );
  423.  
  424.    for( i = 1; i <= BoardSize; ++i )
  425.       {
  426.       for( j = 1; j <= BoardSize; ++j )
  427.          {
  428.          xman = Board[ i ][ j ].What;
  429.          Material[ Man[ xman ].GetSide() ] += Man[ xman ].GetValue();
  430.          }
  431.       }
  432.  
  433.    /****************************************************
  434.    Now adjust the Material weights based on who is ahead.
  435.    This is to encourage the fellow who is winning to exchange pieces
  436.    and the fellow who is behind to not exchange pieces.
  437.    If Material is dead even then you shouldn't try to force exchanges
  438.    just on general principles.
  439.    *****************************************************/
  440.    if( Material[ Red ] >= Material[ Black ] )
  441.       {
  442.          --Man[ REDMAN ];
  443.          --Man[ REDKING ];
  444.       }
  445.    else
  446.      {
  447.      --Man[ BLACKMAN ];
  448.      --Man[ BLACKKING ];
  449.      }
  450.  
  451.    /****************************************************
  452.    Examine each and every square and calculate the bonus values.
  453.    *****************************************************/
  454.    for( i = 1; i <= BoardSize; ++i )
  455.       {
  456.       for( j = 1; j <= BoardSize; ++j )
  457.          {
  458.          inside = (j > 1 && j < BoardSize) ? 1 : 0;
  459.  
  460.          SValue[ i ][ j ][ REDMAN ]    = Man[ REDMAN ].GetValue() + inside;
  461.          SValue[ i ][ j ][ REDKING ]   = Man[ REDKING ].GetValue() + inside;
  462.          SValue[ i ][ j ][ BLACKMAN ]  = Man[ BLACKMAN ].GetValue() + inside;
  463.          SValue[ i ][ j ][ BLACKKING ] = Man[ BLACKKING ].GetValue() + inside;
  464.  
  465.          /* bonus points for central squares */
  466.          if( abs( tBSizeDiv2 - i ) < 2 && abs( tBSizeDiv2 - j )  < 3 )
  467.             {
  468.             ++SValue[ i ][ j ][ REDMAN ];
  469.             ++SValue[ i ][ j ][ REDKING ];
  470.             ++SValue[ i ][ j ][ BLACKMAN ];
  471.             ++SValue[ i ][ j ][ BLACKKING ];
  472.             }
  473.  
  474.          /* bonus for non-Crown piece advancement */
  475.          if( i > 2 )
  476.             {
  477.             SValue[ i ][ j ][ REDMAN ] += i - 2;
  478.             }
  479.  
  480.          if( i < BoardSize - 2 )
  481.             {
  482.             SValue[ i ][ j ][ BLACKMAN ] += BoardSize - i - 1;
  483.             }
  484.  
  485.          if( i == 1 )
  486.             ++SValue[ i ][ j ][ REDMAN ];
  487.          if( i == BoardSize )
  488.             ++SValue[ i ][ j ][ BLACKMAN ];
  489.          }
  490.       }
  491.  
  492.    Material[ Red ]   = 0;
  493.    Material[ Black ] = 0;
  494.  
  495.    for( i = 1; i <= BoardSize; ++i )
  496.       {
  497.       for( j = 1; j <= BoardSize; ++j )
  498.          {
  499.          xman = Board[ i ][ j ].What;
  500.          Material[ Man[ xman ].GetSide() ] += SValue[ i ][ j ][ xman ];
  501.          }
  502.       }
  503. }
  504.  
  505.  
  506. int BOARD::Evaluate( int alpha, int beta, SIDE player, int row, int col, int limit, int ply )
  507. {
  508.    MOVE *list = new MOVE[ MAXMOVES ];
  509.  
  510.    MOVE *mptr, *endptr;
  511.    int NumMoves, val;
  512.    int num_back = 0;
  513.    int retval = 0;
  514.  
  515.    int t1 = WIN - 2 - ply;
  516.    int plyp1 = ply + 1;
  517.    if (StopSearch)
  518.       goto END_EVALUATE;
  519.  
  520.    ++Nodes;
  521.    if( (NumMoves = Lmg( list, player, row, col, ply )) == 0 )
  522.       {
  523.       retval = LOSS + ply;
  524.       goto END_EVALUATE;
  525.       }
  526.    MessageScan();
  527.    if (StopSearch)
  528.       {
  529.       retval = 0;
  530.       goto END_EVALUATE;
  531.       }
  532.    if( list->Quiescent( limit, NumMoves, ply ) )
  533.       {
  534.       retval = ( Material[ player ] - Material[ OPLAYER ] + (NumMoves > 3 ? 1 : 0) );
  535.       goto END_EVALUATE;
  536.       }
  537.  
  538.    for( mptr = list, endptr = mptr + NumMoves; mptr < endptr && alpha < t1; mptr++ )
  539.       {
  540.       MakeMove( *mptr );
  541.  
  542.       if( mptr->Capture != EMPTY )
  543.          {
  544.          if( !(mptr->Crown) && CanJump( player, mptr->dest.GetRow(), mptr->dest.GetCol() ) )
  545.             {
  546.             val = Evaluate( alpha, beta, player, mptr->dest.GetRow(), mptr->dest.GetCol(), limit, plyp1 );
  547.             }
  548.          else
  549.             {
  550.             val = Evaluate( -beta, -alpha, OPLAYER, 0, 0, limit, plyp1 ) * -1;
  551.             }
  552.          }
  553.          else
  554.             {
  555.             if( limit == 0 || NumMoves == 1 )
  556.                {
  557.                val = Evaluate( -beta, -alpha, OPLAYER, 0, 0, limit, plyp1 ) * -1;
  558.                }
  559.             else
  560.                {
  561.                val = Evaluate( -beta, -alpha, OPLAYER, 0, 0, limit ? limit - 1 : 0, plyp1 ) * -1;
  562.                }
  563.             }
  564.          UnMakeMove( *mptr );
  565.  
  566.          if( val > alpha )
  567.             {
  568.             if( val >= beta )
  569.                {
  570.                   if( KillerFlag )
  571.                      UpdateKillerTable( *mptr, ply );
  572.                   retval =  beta ;
  573.                   goto END_EVALUATE;
  574.                }
  575.          else
  576.             {
  577.             alpha = val;
  578.             ++num_back;
  579.             UpdateBestVariation( mptr, ply );
  580.             }
  581.          }
  582.          BestVar[ plyp1 ][ plyp1 ].org.SetRow(0);
  583.       }
  584.    retval = alpha;
  585. END_EVALUATE:
  586.  
  587.    delete list;
  588.    return   retval;
  589. }
  590.  
  591. BOOL BOARD::ComputersTurn()
  592. {
  593.    int iter, i, val, row = 0, col = 0;
  594.    double t;
  595.    time_t itime1, itime2;
  596.    long lNodes;
  597.    int alpha = -MAXINT, beta = MAXINT;
  598.    StopSearch = FALSE;
  599.    ClearRedoStack();
  600.  
  601.    memcpy(SavedBoard, Board, sizeof(Board));
  602.  
  603.    if( !OnlyOneMove( Black, &row, &col ) )
  604.       {
  605.       Nodes = 0;
  606.       time( &start_t );
  607.  
  608.       PreEvaluate();
  609.  
  610.       /* clear out the best-variation table */
  611.       for( i = 0; i <= MAXPLY; ++i )
  612.          {
  613.          BestVar[ i ][ i ].org.SetRow(0);
  614.          BestVar[ 0 ][ i ].org.SetRow(0);
  615.          }
  616.  
  617.       /* clear out the Killer table */
  618.       for( i = 0; i <= MAXPLY; ++i )
  619.          {
  620.          Killer[ i ][ 0 ].org.SetRow(0);
  621.          Killer[ i ][ 0 ].Value   = -1;
  622.          }
  623.  
  624.       for( iter = IterFlag ? 1 : SearchDepth; iter <= SearchDepth; ++iter )
  625.          {
  626.          lNodes = Nodes;
  627.          time( &itime1 );
  628.  
  629.          val = Evaluate( alpha, beta, Black, row, col, iter, 0 );
  630.  
  631.          if (StopSearch)
  632.             return FALSE;
  633.  
  634.          if( val >= beta )
  635.             {
  636.             TInfo->SetMessageText("Re-evaluation Necessary");
  637.             val = Evaluate( alpha, MAXINT, Black, row, col, iter, 0 );
  638.             TInfo->SetMessageText("");
  639.             if (StopSearch)
  640.                return FALSE;
  641.             }
  642.          else
  643.             {
  644.             if( val <= alpha )
  645.                {
  646.                TInfo->SetMessageText("Re-evaluation Necessary");
  647.                val = Evaluate( -MAXINT, beta, Black, row, col, iter, 0 );
  648.                TInfo->SetMessageText("");
  649.                if (StopSearch)
  650.                   return FALSE;
  651.                }
  652.             }
  653.          alpha = val - 12;
  654.          beta  = val + 12;
  655.  
  656.          /* seed the killer table with the best variation */
  657.          for( i = 0; BestVar[ 0 ][ i ].org.GetRow(); ++i )
  658.             {
  659.             memcpy( &Killer[ i ][ 0 ], &BestVar[ 0 ][ i ], sizeof( MOVE ) );
  660.             Killer[ i ][ 0 ].Value = 1;
  661.             /* eliminate the other killer move */
  662.             Killer[ i ][ 1 ].Value = -1;
  663.             Killer[ i ][ 1 ].org.SetRow(0);
  664.             }
  665.  
  666.          /* clear the rest of the killer table */
  667.          do
  668.             {
  669.             Killer[ i ][ 0 ].org.SetRow(0);
  670.             Killer[ i ][ 1 ].org.SetRow(0);
  671.             }
  672.          while( i++ < MAXPLY );
  673.  
  674.          time( &itime2 );
  675.          t = difftime( itime2, itime1 );
  676.          DisplaySearchStats( iter, val, Nodes - lNodes, t );
  677.          }
  678.  
  679.       time( &end_t );
  680.       if( (t = difftime( end_t, start_t )) != 0 )
  681.          {
  682.          sprintf(buf, "%.0f", t);
  683.          TInfo->SetSecondsText(buf);
  684.          sprintf(buf, "%ld", Nodes);
  685.          TInfo->SetNodeText(buf);
  686.          ComputerTotalTime += t;
  687.          }
  688.       else
  689.          {
  690.          TInfo->SetSecondsText("0");
  691.          sprintf(buf, "%ld", Nodes);
  692.          TInfo->SetNodeText(buf);
  693.          }
  694.  
  695.       for ( i = 0; Man [ Board[ BestVar[0][i].org.GetRow() ]
  696.          [ BestVar[0][i].org.GetCol() ].What ].GetSide() == Black; ++i)
  697.          {
  698.          MakeActualMove( BestVar[ 0 ][ i ] );
  699.          }
  700.  
  701.       }
  702.       TimeToStr(buf, ComputerTotalTime);
  703.       TInfo->SetBlackInfoText(buf);
  704.    return( TRUE );
  705. }
  706.  
  707. /********************************************
  708.  generates the list of moves for a given player at a row, col
  709.  
  710.  returns the number of legal moves found
  711.  ********************************************/
  712.  
  713. int BOARD::GenMoves( MOVE *list, int row, int col )
  714. {
  715.    int NumMoves;
  716.    int what;
  717.    int trow1 = row + 1,  tcol1 = col + 1, trowm1 = row - 1, tcolm1 = col - 1;
  718.    NumMoves = 0;
  719.    what = Board[ row ][ col ].What;
  720.    if( what == REDKING || what == BLACKKING || what == BLACKMAN )
  721.       {
  722.       if( Board[ trowm1 ][ tcolm1 ].What == EMPTY )
  723.          {
  724.          list->org.SetRow( row );
  725.          list->org.SetCol( col );
  726.          list->dest.SetRow( trowm1 );
  727.          list->dest.SetCol( tcolm1 );
  728.          list->Capture  = EMPTY;
  729.          list->Crown    = ((row == 2) && (what == BLACKMAN));
  730.          ++NumMoves;
  731.          ++list;
  732.          }
  733.       if( Board[ trowm1 ][ tcol1 ].What == EMPTY )
  734.          {
  735.          list->org.SetRow( row );
  736.          list->org.SetCol( col );
  737.          list->dest.SetRow( trowm1 );
  738.          list->dest.SetCol( tcol1 );
  739.          list->Capture  = EMPTY;
  740.          list->Crown    = ((row == 2) && ( what == BLACKMAN ));
  741.          ++NumMoves;
  742.          ++list;
  743.          }
  744.       }
  745.  
  746.    if( what == REDKING || what == BLACKKING || what == REDMAN )
  747.       {
  748.       if( Board[ trow1 ][ tcolm1 ].What == EMPTY )
  749.          {
  750.          list->org.SetRow( row );
  751.          list->org.SetCol( col );
  752.          list->dest.SetRow( trow1 );
  753.          list->dest.SetCol( tcolm1 );
  754.          list->Capture  = EMPTY;
  755.          list->Crown    = ((row == BoardSize - 1) && (what == REDMAN));
  756.          ++NumMoves;
  757.          ++list;
  758.          }
  759.       if( Board[ trow1 ][ tcol1 ].What == EMPTY )
  760.          {
  761.          list->org.SetRow( row );
  762.          list->org.SetCol( col );
  763.          list->dest.SetRow( trow1 );
  764.          list->dest.SetCol( tcol1 );
  765.          list->Capture  = EMPTY;
  766.          list->Crown    = ((row == BoardSize - 1) && (what == REDMAN));
  767.          ++NumMoves;
  768.          ++list;
  769.          }
  770.       }
  771.  
  772.    return( NumMoves );
  773. }
  774.  
  775.  
  776. void BOARD::MakeMove( MOVE &m)
  777. {
  778.   PPOSTYPE osqu, dsqu, csqu;
  779.  
  780.   osqu = &Board[ m.org.GetRow() ][ m.org.GetCol() ];
  781.   dsqu = &Board[ m.dest.GetRow() ][ m.dest.GetCol() ];
  782.   csqu = &Board[ m.capt.GetRow() ][ m.capt.GetCol() ];
  783.  
  784.  
  785.   Material[ Man[ (*osqu).What ].GetSide() ] -= SValue[ m.org.GetRow() ][ m.org.GetCol() ][ (*osqu).What ];
  786.  
  787.   (*dsqu).What = (*osqu).What;
  788.   (*osqu).What = EMPTY;
  789.  
  790.   if( m.Crown )  ++(*dsqu).What;
  791.  
  792.   Material[ Man[ (*dsqu).What ].GetSide() ] += SValue[ m.dest.GetRow() ][ m.dest.GetCol() ][ (*dsqu).What ];
  793.  
  794.   if( m.Capture != EMPTY )
  795.     {
  796.     Material[ Man[ m.Capture ].GetSide() ] -= SValue[ m.capt.GetRow() ][ m.capt.GetCol() ][ (*csqu).What ];
  797.     (*csqu).What = EMPTY;
  798.     }
  799.  
  800. }
  801.  
  802. void BOARD::UnMakeMove( MOVE &m )
  803. {
  804.    PPOSTYPE osqu, dsqu, csqu;
  805.    osqu = &Board[ m.org.GetRow() ][ m.org.GetCol() ];
  806.    dsqu = &Board[ m.dest.GetRow() ][ m.dest.GetCol() ];
  807.    csqu = &Board[ m.capt.GetRow() ][ m.capt.GetCol() ];
  808.  
  809.    Material[ Man[ (*dsqu).What ].GetSide() ] -= SValue[ m.dest.GetRow() ][ m.dest.GetCol() ][ (*dsqu).What ];
  810.  
  811.    (*osqu).What = (*dsqu).What;
  812.    (*dsqu).What = EMPTY;
  813.  
  814.    if( m.Crown )
  815.       --(*osqu).What;
  816.    Material[ Man[ (*osqu).What ].GetSide() ] += SValue[ m.org.GetRow() ][ m.org.GetCol() ][ (*osqu).What ];
  817.    if( m.Capture != EMPTY )
  818.       {
  819.       (*csqu).What = m.Capture;
  820.       Material[ Man[ m.Capture ].GetSide() ] += SValue[ m.capt.GetRow() ][ m.capt.GetCol() ][ (*csqu).What ];
  821.       }
  822. }
  823.  
  824.  
  825. int BOARD::Lmg(MOVE *list, SIDE player, int row, int col, int ply)
  826. {
  827.    int num, NumMoves, HasAJump;
  828.  
  829.    NumMoves = 0;
  830.    HasAJump = FALSE;
  831.  
  832.    if( row )          /* examine jumps from this square */
  833.       {
  834.       NumMoves = GenJumps( &list[ NumMoves ], player, row, col );
  835.       }
  836.    else               /* find all legal moves */
  837.       {
  838.       for( row = 1; row <= BoardSize; ++row )
  839.          {
  840.          for( col = 1; col <= BoardSize; ++col )
  841.             {
  842.             if( Man[ Board[ row ][ col ].What ].GetSide() == player )
  843.                {
  844.                if( (num = GenJumps( &list[ NumMoves ], player, row, col )) != 0 )
  845.                   {
  846.                   HasAJump = TRUE;
  847.                   NumMoves += num;
  848.                   }
  849.                if( !HasAJump )
  850.                   {
  851.                   NumMoves += GenMoves( &list[ NumMoves ], row, col );
  852.                   }
  853.                }
  854.             }
  855.          }
  856.       }
  857.  
  858.    if( KillerFlag )
  859.       {
  860.       NumMoves = KillerSortMoves( list, NumMoves, ply );
  861.       }
  862.    else
  863.       {
  864.       NumMoves = SortMoves( list, NumMoves );
  865.       }
  866.  
  867.    return( NumMoves );
  868. }
  869.  
  870. void BOARD::SetupBoard()
  871. {
  872.    int i, j;
  873.    POINT p;
  874.    int tBSizeP1 = BoardSize + 1;
  875.    TotalMoves = 0;
  876.    SearchDepth = 3;
  877.    NumBlackPieces = NumRedPieces = 12;
  878.    TInfo->SetSearchDepthText("3");
  879.    JumpAgain = FALSE;
  880.    ComputerTotalTime = UserTotalTime = 0;
  881.    time(&start_t);
  882.    if (Logging)
  883.       Logoff();
  884.    Logon();
  885.    ClearRedoStack();
  886.    ClearUndoStack();
  887.  
  888.    for (i = 0; i <= tBSizeP1; ++i)
  889.       {
  890.       p.y = (BoardSize - i) * SQUARE_SIZE;
  891.       for (j = 0; j <= tBSizeP1; ++j)
  892.          {
  893.          Board[i][j].What = OFFBOARD;
  894.          p.x = (j - 1) * SQUARE_SIZE - 1;
  895.          Board[i][j].Sq.SetUpperLeftPos(p);
  896.          }
  897.       }
  898.  
  899.    for( i = 1; i <= BoardSize; ++i )
  900.       {
  901.       for( j = 1; j <= BoardSize; ++j )
  902.          {
  903.          if( (i % 2) == (j % 2 ) )
  904.             {
  905.             Board[ i ][ j ].What = EMPTY;
  906.             Board[ i ][ j ].Sq.SetColor(hBlackBrush);
  907.  
  908.             if( i < BoardSize / 2 )
  909.                {
  910.                Board[ i ][ j ].What = REDMAN;
  911.                }
  912.  
  913.             if( i - 1 > tBSizeP1 / 2 )
  914.                {
  915.                Board[ i ][ j ].What = BLACKMAN;
  916.                }
  917.             }
  918.          else
  919.             Board[ i ][ j ].Sq.SetColor(hRedBrush);
  920.          }
  921.       }
  922.  
  923.  
  924.    BoardRect.top = BoardRect.left = BORDERSIZE - MYFRAMESIZE;
  925.    BoardRect.right = BoardRect.bottom = BORDERSIZE + BoardSize * SQUARE_SIZE + MYFRAMESIZE;
  926. }
  927.  
  928.  
  929.  
  930. void BOARD::DrawBoard(HDC hDC)
  931. {
  932.    int i, j;
  933.    int what;
  934.    POINT Point;
  935.  
  936.    for( i = BoardSize; i; --i )
  937.       {
  938.  
  939.       for( j = 1; j <= BoardSize; ++j )
  940.          {
  941.          Board[ i ][ j ].Sq.ClearSquare(hDC);
  942.          what = Board[ i ][ j ].What;
  943.          if (what < EMPTY)
  944.             {
  945.             Point.x = i; Point.y = j;
  946.             DrawPiece(hDC, what, Point);
  947.             }
  948.          }
  949.    }
  950. }
  951.  
  952. POINT BOARD::GetValidSquare(POINT& p, SIDE s)
  953. {
  954. /*
  955.  *  Returns "i" and "j" values of valid square, not
  956.  *  actual screen coordinates
  957.  */
  958.    int i, j;
  959.    SIDE t;
  960.    POINT RetPoint;
  961.    RetPoint.x = 0;
  962.    int what;
  963. /*
  964.  *  this is a very slow algorithm, since it checks all squares.
  965.  *  A better search would only check to see if the point
  966.  *  is in squares that are known to hold a given sides
  967.  *  pieces.  One possibility is to keep a list around
  968.  *  for each side which contains the "i" and "j" values
  969.  *  for each owned square, and just check those.
  970.  */
  971.  
  972.    for (i = 1; i <= BoardSize; i++)
  973.       for (j = 1; j <= BoardSize; j++)
  974.          {
  975.          what = Board[ i ][ j ].What;
  976.          if (what < EMPTY)
  977.             t = Man[what].GetSide();
  978.          else
  979.             t = Unknown;
  980.  
  981.          if (Board[ i ][ j ].Sq.HasPoint(p) && t == s)
  982.             {
  983.             RetPoint.x = i;
  984.             RetPoint.y = j;
  985.             return RetPoint;
  986.             }
  987.          }
  988.    return RetPoint;
  989. }
  990.  
  991. POINT BOARD::GetEmptySquare(POINT& p)
  992. {
  993.    int i,j;
  994.    POINT RetPoint;
  995.    RetPoint.x = 0;
  996.  
  997.    for (i = 1; i <= BoardSize; i++)
  998.       for (j = 1; j <= BoardSize; j++)
  999.          {
  1000.          if (Board[ i ][ j ].Sq.HasPoint(p) && Board[ i ][ j ].What == EMPTY)
  1001.             {
  1002.             RetPoint.x = i;
  1003.             RetPoint.y = j;
  1004.             return RetPoint;
  1005.             }
  1006.          }
  1007.    return RetPoint;
  1008. }
  1009.  
  1010. void BOARD::DrawAlphaNum(HDC hDC)
  1011. {
  1012.    int i;
  1013.    int XPos, YPos;
  1014.  
  1015.  
  1016.  
  1017.    XPos = BORDERSIZE/2 - 4;
  1018.    YPos = BORDERSIZE + SQUARE_SIZE/2 - 6;
  1019.  
  1020.    SetBkColor(hDC, RGB(192, 192, 192));
  1021.  
  1022.    for (i = BoardSize - 1; i >= 0; i--)
  1023.       {
  1024.       TextOut(hDC, XPos, YPos, NumArray[i], 1);
  1025.       YPos += SQUARE_SIZE;
  1026.       }
  1027.  
  1028.    XPos = BORDERSIZE + SQUARE_SIZE / 2 - 4;
  1029.    YPos = BORDERSIZE + (BoardSize * SQUARE_SIZE) + (BORDERSIZE / 2) - 6;
  1030.  
  1031.    for (i = 0; i < BoardSize; i++)
  1032.       {
  1033.       TextOut(hDC, XPos, YPos, CharArray[i], 1);
  1034.       XPos += SQUARE_SIZE;
  1035.       }
  1036. }
  1037.  
  1038. void BOARD::DrawCheckersFrame(HDC hDC)
  1039. {
  1040.     DrawFrame(hDC, BoardRect);
  1041. }
  1042.  
  1043.  
  1044. int BOARD::GenJumps(MOVE *list, int player, int row, int col)
  1045. {
  1046.    int NumMoves = 0;
  1047.    int what;
  1048.    int trow1 = row + 1, trowm1 = row - 1;
  1049.    int tcol1 = col + 1, tcolm1 = col - 1;
  1050.  
  1051.    if (StopSearch)
  1052.       return 0;
  1053.    what = Board[ row ][ col ].What;
  1054.  
  1055.    if(  what == REDKING   || what == BLACKKING   || what == BLACKMAN )
  1056.       {
  1057.       if( Man[ Board[ trowm1 ][ tcolm1 ].What ].GetSide() == OPLAYER )
  1058.          {
  1059.          if( Board[ trowm1 - 1 ][ tcolm1 - 1 ].What == EMPTY )
  1060.             {
  1061.             list->org.SetRow(row);
  1062.             list->org.SetCol(col);
  1063.             list->dest.SetRow(trowm1 - 1);
  1064.             list->dest.SetCol(tcolm1 - 1);
  1065.             list->capt.SetRow(trowm1);
  1066.             list->capt.SetCol(tcolm1);
  1067.             list->Capture  = Board[ trowm1 ][ tcolm1 ].What;
  1068.             list->Crown    = ((row == 3) && (what == BLACKMAN));
  1069.             ++NumMoves;
  1070.             ++list;
  1071.             }
  1072.          }
  1073.       if( Man[ Board[ trowm1 ][ tcol1 ].What ].GetSide() == OPLAYER )
  1074.          {
  1075.          if( Board[ trowm1 - 1 ][ tcol1 + 1 ].What == EMPTY )
  1076.             {
  1077.             list->org.SetRow( row );
  1078.             list->org.SetCol( col );
  1079.             list->dest.SetRow( trowm1 - 1 );
  1080.             list->dest.SetCol( tcol1 + 1 );
  1081.             list->capt.SetRow( trowm1 );
  1082.             list->capt.SetCol( tcol1 );
  1083.             list->Capture  = Board[ trowm1 ][ tcol1 ].What;
  1084.             list->Crown    = ((row == 3) && (what == BLACKMAN));
  1085.             ++NumMoves;
  1086.             ++list;
  1087.             }
  1088.          }
  1089.       }
  1090.  
  1091.    if( what == REDKING || what == BLACKKING || what == REDMAN )
  1092.       {
  1093.       if( Man[ Board[ trow1 ][ tcol1 ].What ].GetSide() == OPLAYER )
  1094.          {
  1095.          if ( Board[ trow1 + 1 ][ tcol1 + 1 ].What == EMPTY )
  1096.             {
  1097.             list->org.SetRow( row );
  1098.             list->org.SetCol( col );
  1099.             list->dest.SetRow( trow1 + 1 );
  1100.             list->dest.SetCol( tcol1 + 1 );
  1101.             list->capt.SetRow( trow1 );
  1102.             list->capt.SetCol( tcol1 );
  1103.             list->Capture  = Board[ trow1 ][ tcol1 ].What;
  1104.             list->Crown    = ((row == BoardSize - 2) && (what == REDMAN));
  1105.             ++NumMoves;
  1106.             ++list;
  1107.             }
  1108.          }
  1109.       if( Man[ Board[ trow1 ][ tcolm1 ].What ].GetSide() == OPLAYER )
  1110.          {
  1111.          if( Board[ trow1 + 1 ][ tcolm1 - 1 ].What == EMPTY )
  1112.             {
  1113.             list->org.SetRow( row );
  1114.             list->org.SetCol( col );
  1115.             list->dest.SetRow( trow1 + 1 );
  1116.             list->dest.SetCol( tcolm1 - 1 );
  1117.             list->capt.SetRow( trow1 );
  1118.             list->capt.SetCol( tcolm1 );
  1119.             list->Capture  = Board[ trow1 ][ tcolm1 ].What;
  1120.             list->Crown    = ((row == BoardSize - 2) && (what == REDMAN));
  1121.             ++NumMoves;
  1122.             ++list;
  1123.             }
  1124.           }
  1125.       }
  1126.  
  1127.    return( NumMoves );
  1128. }
  1129.  
  1130. BOOL BOARD::CanJump( SIDE player, int row, int col )
  1131. {
  1132.    int what;
  1133.  
  1134.    if (!row || row > BoardSize)
  1135.       return FALSE;
  1136.  
  1137.    int trow1 = row + 1, trowm1 = row - 1;
  1138.    int tcol1 = col + 1, tcolm1 = col - 1;
  1139.  
  1140.    what = Board[ row ][ col ].What;
  1141.  
  1142.    if( what == REDKING || what == BLACKKING || what == BLACKMAN )
  1143.       {
  1144.       if( Man[ Board[ trowm1 ][ tcolm1 ].What ].GetSide() == OPLAYER )
  1145.          {
  1146.          if( Board[ trowm1 - 1 ][ tcolm1 - 1 ].What == EMPTY )
  1147.             return( TRUE );
  1148.          }
  1149.  
  1150.       if( Man[ Board[ trowm1 ][ tcol1 ].What ].GetSide() == OPLAYER )
  1151.          {
  1152.          if( Board[ trowm1 - 1 ][ tcol1 + 1 ].What == EMPTY )
  1153.             return( TRUE );
  1154.          }
  1155.       }
  1156.  
  1157.    if( what == REDKING || what == BLACKKING || what == REDMAN )
  1158.       {
  1159.       if( Man[ Board[ trow1 ][ tcol1 ].What ].GetSide() == OPLAYER )
  1160.          {
  1161.          if( Board[ trow1 + 1 ][ tcol1 + 1 ].What == EMPTY )
  1162.             return( TRUE );
  1163.          }
  1164.  
  1165.       if( Man[ Board[ trow1 ][ tcolm1 ].What ].GetSide() == OPLAYER )
  1166.          {
  1167.          if( Board[ trow1 + 1 ][ tcolm1 - 1 ].What == EMPTY )
  1168.             return( TRUE );
  1169.          }
  1170.       }
  1171.  
  1172.    return( FALSE );
  1173. }
  1174.  
  1175. BOOL BOARD::UserMove(POINT& from, POINT& to)
  1176. {
  1177.    MOVE m;
  1178.    int NumMoves;
  1179.    int retval = FALSE;
  1180.    JumpAgain = FALSE;
  1181.    StopSearch = FALSE;
  1182.  
  1183.    MOVE *list = new MOVE[MAXMOVES];
  1184.  
  1185.    NumMoves = Lmg(list, Red, LastDest.GetRow(), LastDest.GetCol(), 0);
  1186.  
  1187.    m.org.SetRow(from.x);
  1188.    m.org.SetCol(from.y);
  1189.    m.dest.SetRow(to.x);
  1190.    m.dest.SetCol(to.y);
  1191.  
  1192.    if (abs(m.org.GetRow() - m.dest.GetRow()) == 2)
  1193.       {
  1194.       m.capt.SetRow( (m.org.GetRow() + m.dest.GetRow()) /2 );
  1195.       m.capt.SetCol( (m.org.GetCol() + m.dest.GetCol()) /2 );
  1196.       m.Capture = CON( m.capt );
  1197.       }
  1198.    else
  1199.       {
  1200.       m.Capture = EMPTY;
  1201.       }
  1202.  
  1203.    if( CON( m.org) == REDMAN && m.dest.GetRow() == BoardSize )
  1204.       m.Crown = TRUE;
  1205.    else
  1206.       m.Crown = FALSE;
  1207.  
  1208.    if( IsInList( list, NumMoves, m ) >= 0 )
  1209.       {
  1210.       MakeActualMove( m );
  1211.  
  1212.       if( m.Capture != EMPTY && !m.Crown )
  1213.          {
  1214.          if( (JumpAgain = CanJump( Red, m.dest.GetRow(), m.dest.GetCol() )) != 0 )
  1215.             {
  1216.             LastDest.SetRow(m.dest.GetRow());
  1217.             LastDest.SetCol(m.dest.GetCol());
  1218.             }
  1219.          else
  1220.             {
  1221.             LastDest.SetRow( 0 );
  1222.             LastDest.SetCol( 0 );
  1223.             }
  1224.          }
  1225.       retval = TRUE;
  1226.       }
  1227.  
  1228.    delete list;
  1229.    return retval;
  1230. }
  1231.  
  1232.  
  1233. void BOARD::InsertRedrawPoint(POINT& inp)
  1234. {
  1235.    PREDRAWLIST p = new REDRAWLIST;
  1236.    p->p = inp;
  1237.    p->next = NULL;
  1238.  
  1239.    if (Redraw == NULL)
  1240.       Redraw = p;
  1241.    else
  1242.       {
  1243.       p->next = Redraw;
  1244.       Redraw = p;
  1245.       }
  1246. }
  1247.  
  1248. void BOARD::DeleteRedrawPoint(POINT& p)
  1249. {
  1250.    PREDRAWLIST cur = Redraw;
  1251.    PREDRAWLIST last = NULL;
  1252.    BOOL found = 0;
  1253.  
  1254.    while (cur != NULL && !found)
  1255.       {
  1256.       if (memcmp(&(cur->p), &p, sizeof(POINT)) != 0)
  1257.          {
  1258.          last = cur;
  1259.          cur = cur->next;
  1260.          }
  1261.       else
  1262.          found = TRUE;
  1263.       }
  1264.  
  1265.    if (found)
  1266.       {
  1267.       if (last == NULL) /* first element */
  1268.          {
  1269.          last = Redraw->next;
  1270.          delete Redraw;
  1271.          Redraw = last;
  1272.          }
  1273.       else
  1274.          {
  1275.          last->next = cur->next;
  1276.          delete cur;
  1277.          }
  1278.       }
  1279. }
  1280.  
  1281. void BOARD::ReleaseRedraw()
  1282. {
  1283.    PREDRAWLIST Next;
  1284.    while (Redraw != NULL)
  1285.       {
  1286.          Next = Redraw->next;
  1287.          delete Redraw;
  1288.          Redraw = Next;
  1289.       }
  1290. }
  1291.  
  1292. BOOL BOARD::GetNextRedrawPoint(POINT *Pt)
  1293. {
  1294.    /*
  1295.       this removes the next point from the list
  1296.       then returns it.  Returns FALSE if
  1297.       no more points exist;
  1298.     */
  1299.  
  1300.    PREDRAWLIST cur;
  1301.  
  1302.    if (Redraw != NULL)
  1303.       {
  1304.       *Pt = Redraw->p;
  1305.       cur = Redraw;
  1306.       Redraw = Redraw->next;
  1307.       delete cur;
  1308.       return TRUE;
  1309.       }
  1310.    else
  1311.       return FALSE;
  1312. }
  1313.  
  1314.  
  1315. void BOARD::RedrawBoard(HDC hDC)
  1316. {
  1317.    POINT DrawP;
  1318.    int what;
  1319.  
  1320.    while (GetNextRedrawPoint(&DrawP))
  1321.       {
  1322.       ClearSquare(hDC, DrawP);
  1323.       if ((what = Board[DrawP.x][DrawP.y].What) < EMPTY)
  1324.          DrawPiece(hDC, what, DrawP);
  1325.       }
  1326. }
  1327.  
  1328.  
  1329. void BOARD::DisplaySearchStats( int iter, int val, long inodes, double stime )
  1330. {
  1331.    char temp[40];
  1332.    int i;
  1333.  
  1334.    sprintf(   buf, "%d", iter);
  1335.    TInfo->SetIterationText(buf);
  1336.    sprintf(buf, "%d", val);
  1337.    TInfo->SetValueText(buf);
  1338.    sprintf(buf, "%ld", inodes);
  1339.    TInfo->SetNodeText(buf);
  1340.    sprintf(buf,"%.0f", stime);
  1341.    TInfo->SetSecondsText(buf);
  1342.  
  1343.    *buf = 0;
  1344.    for( i = 0; BestVar[ 0 ][ i ].org.GetRow(); ++i )
  1345.       {
  1346.       BestVar[0][i].MoveToStr( temp );
  1347.       strcat(buf, temp);
  1348.       strcat(buf, " ");
  1349.       }
  1350.    TInfo->SetBestLineText(buf);
  1351. }
  1352.  
  1353. void DrawFrame(HDC hDC, RECT& BoardRect)
  1354. {
  1355.     int x1, y1, x2, y2;
  1356.     POINT pArray[3];
  1357.     HPEN hPen, hOldPen;
  1358.     HBRUSH hOldBrush;
  1359.  
  1360.     x1 = BoardRect.left;
  1361.     x2 = BoardRect.right;
  1362.     y1 = BoardRect.top;
  1363.     y2 = BoardRect.bottom;
  1364.  
  1365.     hOldBrush = (HBRUSH)SelectObject(hDC, GetStockObject(NULL_BRUSH));
  1366.     hOldPen = (HPEN)SelectObject(hDC, GetStockObject(WHITE_PEN));
  1367.  
  1368.     Rectangle(hDC, x1, y1, x2, y2);
  1369.  
  1370.     pArray[0].x = x1 + 2;
  1371.     pArray[1].y = pArray[0].y = y2 - 3;
  1372.     pArray[2].x = pArray[1].x = x2 - 3;
  1373.     pArray[2].y = y1 + 2;
  1374.  
  1375.     Polyline(hDC, pArray, 3);
  1376.     hPen = CreatePen(PS_SOLID, 1, RGB(128, 128, 128));
  1377.     SelectObject(hDC, hPen);
  1378.     pArray[0].x = x1;
  1379.     pArray[1].y = pArray[0].y = y2-1;
  1380.     pArray[2].x = pArray[1].x = x2-1;
  1381.     pArray[2].y = y1;
  1382.  
  1383.     Polyline(hDC, pArray, 3);
  1384.     pArray[1].x = pArray[0].x = x1 + 2;
  1385.     pArray[0].y = y2 - 3;
  1386.     pArray[2].y = pArray[1].y = y1 + 2;
  1387.     pArray[2].x = x2 - 3;
  1388.     Polyline(hDC, pArray, 3);
  1389.     SelectObject(hDC, hOldBrush);
  1390.     DeleteObject(SelectObject(hDC, hOldPen));
  1391. }
  1392.  
  1393. void BOARD::StartUsersTime()
  1394. {
  1395.    time(&start_t);
  1396. }
  1397.  
  1398. void BOARD::EndUsersTime()
  1399. {
  1400.    time(&end_t);
  1401.  
  1402.    UserTotalTime += (time_t)difftime( end_t, start_t );
  1403.    TimeToStr(buf, UserTotalTime);
  1404.    TInfo->SetRedInfoText(buf);
  1405. }
  1406.  
  1407. void BOARD::SaveGame( char *name )
  1408. {
  1409.    int i, j;
  1410.  
  1411.    ofstream fout(name);
  1412.  
  1413.    if (!fout)
  1414.       {
  1415.       sprintf(buf, "Cannot open %s", name);
  1416.       MessageBox(0, buf, "Error", MB_OK | MB_ICONHAND);
  1417.       return;
  1418.       }
  1419.    fout << BoardSize << ' ';
  1420.  
  1421.    for( i = 1; i <= BoardSize; ++i )
  1422.       {
  1423.       for( j = 1; j <= BoardSize; ++j )
  1424.          {
  1425.          fout << Board[ i ][ j ].What << ' ';
  1426.          }
  1427.       }
  1428.    fout << Material[Black] << ' ';
  1429.    fout << Material[Red] << ' ';
  1430.    fout << JumpAgain << ' ';
  1431.    fout << ComputerTotalTime << ' ';
  1432.    fout << UserTotalTime << ' ';
  1433.    fout << SearchDepth << ' ';
  1434.    fout << NumBlackPieces << ' ';
  1435.    fout << NumRedPieces;
  1436.    fout.close();
  1437. }
  1438.  
  1439. void BOARD::LoadGame( char *name )
  1440. {
  1441.    int i, j;
  1442.  
  1443.    SetupBoard();
  1444.    ifstream fin(name);
  1445.    if (!fin)
  1446.       {
  1447.       sprintf(buf, "Cannot open %s", name);
  1448.       MessageBox(0, buf, "Error", MB_OK | MB_ICONHAND);
  1449.       return;
  1450.       }
  1451.    fin >> BoardSize;
  1452.    for( i = 1; i <= BoardSize; ++i )
  1453.       {
  1454.       for( j = 1; j <= BoardSize; ++j )
  1455.          {
  1456.          fin >> Board[ i ][ j ].What;
  1457.          }
  1458.       }
  1459.    fin >> Material[Black];
  1460.    fin >> Material[Red];
  1461.    fin >> JumpAgain;
  1462.    fin >> ComputerTotalTime;
  1463.    fin >> UserTotalTime;
  1464.    fin >> SearchDepth;
  1465.    fin >> NumBlackPieces;
  1466.    fin >> NumRedPieces;
  1467.    fin.close();
  1468.    TInfo->Reset();
  1469.    TimeToStr(buf, ComputerTotalTime);
  1470.    TInfo->SetBlackInfoText(buf);
  1471.    TimeToStr(buf, UserTotalTime);
  1472.    TInfo->SetRedInfoText(buf);
  1473.    sprintf(buf, "%d", SearchDepth);
  1474.    TInfo->SetSearchDepthText(buf);
  1475.    TInfo->SetMessageText("Game Loaded");
  1476. }
  1477.  
  1478.  
  1479. void BOARD::SetSearchDepth(int NewDepth)
  1480. {
  1481.    if (NewDepth > 0 && NewDepth < MAXPLY )
  1482.       {
  1483.       SearchDepth = NewDepth;
  1484.       sprintf(buf, "%d", SearchDepth);
  1485.       TInfo->SetSearchDepthText(buf);
  1486.       }
  1487.    else
  1488.       {
  1489.       sprintf(buf, "Search depth must be between 1 and %d", MAXPLY - 1);
  1490.       MessageBox(0, buf, "Error", MB_OK | MB_ICONHAND);
  1491.       }
  1492. }
  1493.  
  1494. void BOARD::DrawLastBoard(HDC hDC)
  1495. {
  1496.    int i, j;
  1497.    int what;
  1498.    POINT Point;
  1499.  
  1500.    for( i = BoardSize; i; --i )
  1501.       {
  1502.       for( j = 1; j <= BoardSize; ++j )
  1503.          {
  1504.          SavedBoard[ i ][ j ].Sq.ClearSquare(hDC);
  1505.          what = SavedBoard[ i ][ j ].What;
  1506.          if (what < EMPTY)
  1507.             {
  1508.             Point.x = i; Point.y = j;
  1509.             DrawPiece(hDC, what, Point);
  1510.             }
  1511.          }
  1512.    }
  1513. }
  1514.  
  1515.  
  1516. void BOARD::Logon()
  1517. {
  1518.    olog = new ofstream(LOGFILE);
  1519.  
  1520.    if (!(*olog))
  1521.       {
  1522.       MessageBox(0, "Could not open log file", "Checkers", MB_OK | MB_ICONHAND);
  1523.       Logging = FALSE;
  1524.       return;
  1525.       }
  1526.    Logging = TRUE;
  1527.    *olog << "Checkers Log File" << endl << endl;
  1528.  
  1529.    time_t curtime;
  1530.    struct tm *tmtime;
  1531.    time(&curtime);
  1532.    tmtime = localtime(&curtime);
  1533.    static char AMPM[2][3] = { "AM", "PM" };
  1534.  
  1535.    sprintf(buf, "DATE: %d-%02d-%02d\t\t", tmtime->tm_mon+1,tmtime->tm_mday,
  1536.       (tmtime->tm_year % 100));
  1537.  
  1538.    *olog << buf;
  1539.  
  1540.    sprintf(buf, "TIME: %d:%02d %s", (tmtime->tm_hour % 12) ? (tmtime->tm_hour % 12)
  1541.         : 12, tmtime->tm_min, AMPM[tmtime->tm_hour / 12]);
  1542.  
  1543.    *olog << buf << endl << endl;
  1544. }
  1545.  
  1546. void BOARD::Logoff()
  1547. {
  1548.    if (olog)
  1549.       {
  1550.       time_t curtime;
  1551.       struct tm *tmtime;
  1552.       time(&curtime);
  1553.       tmtime = localtime(&curtime);
  1554.       static char AMPM[2][3] = { "AM", "PM" };
  1555.       sprintf(buf, "%d:%02d %s", (tmtime->tm_hour % 12) ? (tmtime->tm_hour % 12)
  1556.         : 12, tmtime->tm_min, AMPM[tmtime->tm_hour / 12]);
  1557.       *olog << endl << "Ended logging at " << buf << endl;
  1558.       olog->close();
  1559.       olog = NULL;
  1560.       delete olog;
  1561.       }
  1562.    Logging = FALSE;
  1563. }
  1564.  
  1565. void BOARD::Log(MOVE& m, BOOL Undo)
  1566. {
  1567.    if (olog == NULL)
  1568.       {
  1569.       MessageBox(0, "Internal error: attempting to write to unopened log file",
  1570.          "Checkers", MB_OK | MB_ICONHAND);
  1571.       Logging = FALSE;
  1572.       }
  1573.  
  1574.    m.MoveToStr(buf);
  1575.    char *temp = new char[5];
  1576.    if (Undo == TRUE)
  1577.       strcpy(temp, "UNDO");
  1578.    else
  1579.       strcpy(temp, "");
  1580.  
  1581.    *olog << ++TotalMoves << ". " << buf << temp << endl;
  1582. }
  1583.  
  1584.  
  1585. void BOARD::MakeActualMove( MOVE &m)
  1586. {
  1587.    POINT DP;
  1588.  
  1589.    MakeMove(m);
  1590.    DP.x = m.org.GetRow();
  1591.    DP.y = m.org.GetCol();
  1592.    InsertRedrawPoint(DP);
  1593.    DP.x = m.dest.GetRow();
  1594.    DP.y = m.dest.GetCol();
  1595.    InsertRedrawPoint(DP);
  1596.    if (m.Capture != EMPTY)
  1597.       {
  1598.       DP.x = m.capt.GetRow();
  1599.       DP.y = m.capt.GetCol();
  1600.       InsertRedrawPoint(DP);
  1601.       (Man[ m.Capture ].GetSide() == Black) ? --NumBlackPieces : --NumRedPieces;
  1602.       }
  1603.    if (Logging)
  1604.       Log(m, FALSE);
  1605.    RUndoObject undo = *( new UndoObject(m) );
  1606.    UndoStack.push(undo);
  1607. }
  1608.  
  1609. void BOARD::UnMakeActualMove(MOVE& m)
  1610. {
  1611.    POINT UDP;
  1612.  
  1613.    UnMakeMove(m);
  1614.    UDP.x = m.org.GetRow();
  1615.    UDP.y = m.org.GetCol();
  1616.    InsertRedrawPoint(UDP);
  1617.    UDP.x = m.dest.GetRow();
  1618.    UDP.y = m.dest.GetCol();
  1619.    InsertRedrawPoint(UDP);
  1620.    if (m.Capture != EMPTY)
  1621.    {
  1622.       UDP.x = m.capt.GetRow();
  1623.       UDP.y = m.capt.GetCol();
  1624.       InsertRedrawPoint(UDP);
  1625.       (Man[ m.Capture ].GetSide() == Black) ? ++NumBlackPieces : ++NumRedPieces;
  1626.    }
  1627.    if (Logging)
  1628.        Log(m, TRUE);
  1629.    UndoObject &redo = *(new UndoObject(m));
  1630.    RedoStack.push(redo);
  1631. }
  1632.  
  1633. BOOL BOARD::UndoMove()
  1634. {
  1635.    UndoObject& undo = (UndoObject&)UndoStack.pop();
  1636.    MOVE undoMove = undo.GetMove();
  1637.    UnMakeActualMove(undoMove);
  1638.    delete &undo; // reference does hold the original new'd pointer
  1639.    return UndoStack.isEmpty();
  1640. }
  1641.  
  1642. BOOL BOARD::RedoMove()
  1643. {
  1644.    UndoObject& redo = (UndoObject&)RedoStack.pop();
  1645.    MOVE redoMove = redo.GetMove();
  1646.    MakeActualMove(redoMove);
  1647.    delete &redo;
  1648.    return RedoStack.isEmpty();
  1649. }
  1650.  
  1651.  
  1652. void BOARD::ClearRedoStack()
  1653. {
  1654.    while (!RedoStack.isEmpty())
  1655.       {
  1656.       UndoObject& redo = (UndoObject&)RedoStack.pop();
  1657.       delete &redo;
  1658.       }
  1659. }
  1660.  
  1661. void BOARD::ClearUndoStack()
  1662. {
  1663.    while (!UndoStack.isEmpty())
  1664.       {
  1665.       UndoObject& undo = (UndoObject&)UndoStack.pop();
  1666.       delete &undo;
  1667.       }
  1668. }
  1669. 
  1670.