home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0040 - 0049 / ibm0040-0049 / ibm0040.tar / ibm0040 / BCPPOWL1.ZIP / CHECKERS.ZIP / BOARD.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-28  |  41.2 KB  |  1,665 lines

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