Subversion Repositories Games.Chess Giants

Rev

Rev 44 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // move.cpp
  2.  
  3. #include "common.h"
  4.  
  5.  
  6. // handy macros
  7. #define IS_VALID(li,co) (((li) >= 0) && ((li) < 8) && ((co) >= 0) && ((co) < 8))
  8. #define IS_FREE(li,co) (IS_VALID ((li), (co)) && (move->slots[(li)][(co)].part == PART_NONE))
  9. #define CAN_PLAY(li,co) (IS_VALID ((li), (co)) && ((move->slots[(li)][(co)].part == PART_NONE) || (move->slots[(li)][(co)].color != boardslot->color)))
  10.  
  11.  
  12. // prototypes of local functions
  13. static bool Move_IsWayClearBetween (boardmove_t *move, int source_line, int source_column, int target_line, int target_column);
  14. static void AddPossibleMove (boardmove_t **possiblemoves, int *possiblemove_count, int color, int part, int source_line, int source_column, int target_line, int target_column, int promotion_type, bool has_captured, bool is_enpassant);
  15.  
  16.  
  17. void Move_SetSlot (boardmove_t *move, int line, int column, int color, int part_type)
  18. {
  19.    // this function populates a board's slot at the given line,column coordinates with the
  20.    // given part of the given color
  21.  
  22.    move->slots[line][column].flags = 0; // reset flags
  23.    move->slots[line][column].color = color; // set part color
  24.    move->slots[line][column].part = part_type; // set part type
  25.  
  26.    return; // finished, board slot is set
  27. }
  28.  
  29.  
  30. bool Move_IsKingThreatenedAtLocation (boardmove_t *move, int color, int at_line, int at_column, int *threat_line, int *threat_column)
  31. {
  32.    // this function returns TRUE if the specified color is safe at the specified location.
  33.    // In case it is not, it returns FALSE and sets the threat's line and column parameters.
  34.    // Note the use of the threat_line and threat_column output parameters as iterator
  35.    // variables.
  36.  
  37.    boardslot_t *boardslot;
  38.    int movement_direction;
  39.    int line;
  40.    int column;
  41.    int index_line;
  42.    int index_column;
  43.  
  44.    // cycle through all the board
  45.    for (line = 0; line < 8; line++)
  46.       for (column = 0; column < 8; column++)
  47.       {
  48.          boardslot = &move->slots[line][column]; // quick access to grid slot
  49.  
  50.          if ((boardslot->part == PART_NONE) || (boardslot->color == color))
  51.             continue; // if this location is empty or ours, it doesn't threaten us
  52.  
  53.          // update new possible threat position
  54.          *threat_line = line;
  55.          *threat_column = column;
  56.  
  57.          //////////////////////////////////////////////////////////////////////////////////////////
  58.          ////////////////////////////////////////// PAWN //////////////////////////////////////////
  59.          //////////////////////////////////////////////////////////////////////////////////////////
  60.          // is it a pawn ? (note: pawns can only threaten kings normally, never "en passant")
  61.          if (boardslot->part == PART_PAWN)
  62.          {
  63.             // figure out movement direction
  64.             if (boardslot->color == COLOR_WHITE)
  65.                movement_direction = 1;
  66.             else
  67.                movement_direction = -1;
  68.  
  69.             // see if pawn can take our piece on either of its sides
  70.             if ((column > 0) && (line + movement_direction == at_line) && (column - 1 == at_column))
  71.                return (true); // this part threatens us, it can take our piece on its left
  72.             else if ((column < 7) && (line + movement_direction == at_line) && (column + 1 == at_column))
  73.                return (true); // this part threatens us, it can take our piece on its right
  74.          }
  75.  
  76.          //////////////////////////////////////////////////////////////////////////////////////////
  77.          ////////////////////////////////////////// ROOK //////////////////////////////////////////
  78.          //////////////////////////////////////////////////////////////////////////////////////////
  79.          // else is it a rook ?
  80.          else if (boardslot->part == PART_ROOK)
  81.          {
  82.             // is rook in the same column as our king ?
  83.             if (column == at_column)
  84.             {
  85.                // is our king above ?
  86.                if (at_line > line)
  87.                {
  88.                   // see if rook can threaten our king by moving upwards
  89.                   for (index_line = line + 1; index_line < 8; index_line++)
  90.                      if (index_line == at_line)
  91.                         return (true); // this part threatens us
  92.                      else if (!IS_FREE (index_line, column))
  93.                         break; // if part can no longer move this way, stop searching
  94.                }
  95.  
  96.                // else our king must be below
  97.                else
  98.                {
  99.                   // see if rook can threaten our king by moving downwards
  100.                   for (index_line = line - 1; index_line >= 0; index_line--)
  101.                      if (index_line == at_line)
  102.                         return (true); // this part threatens us
  103.                      else if (!IS_FREE (index_line, column))
  104.                         break; // if part can no longer move this way, stop searching
  105.                }
  106.             }
  107.  
  108.             // else is rook in the same line as our king ?
  109.             else if (line == at_line)
  110.             {
  111.                // is our king on the right ?
  112.                if (at_column > column)
  113.                {
  114.                   // see if rook can threaten our king by moving right
  115.                   for (index_column = column + 1; index_column < 8; index_column++)
  116.                      if (index_column == at_column)
  117.                         return (true); // this part threatens us
  118.                      else if (!IS_FREE (line, index_column))
  119.                         break; // if part can no longer move this way, stop searching
  120.                }
  121.  
  122.                // else our king must be on the left
  123.                else
  124.                {
  125.                   // see if rook can threaten our king by moving left
  126.                   for (index_column = column - 1; index_column >= 0; index_column--)
  127.                      if (index_column == at_column)
  128.                         return (true); // this part threatens us
  129.                      else if (!IS_FREE (line, index_column))
  130.                         break; // if part can no longer move this way, stop searching
  131.                }
  132.             }
  133.          }
  134.  
  135.          //////////////////////////////////////////////////////////////////////////////////////////
  136.          ///////////////////////////////////////// KNIGHT /////////////////////////////////////////
  137.          //////////////////////////////////////////////////////////////////////////////////////////
  138.          // else is it a knight ?
  139.          else if (boardslot->part == PART_KNIGHT)
  140.          {
  141.             if ((column > 0) && (line < 6) && (line + 2 == at_line) && (column - 1 == at_column))
  142.                return (true); // this part threatens us on its NNW move
  143.             else if ((column < 7) && (line < 6) && (line + 2 == at_line) && (column + 1 == at_column))
  144.                return (true); // this part threatens us on its NNE move
  145.             else if ((column < 6) && (line < 7) && (line + 1 == at_line) && (column + 2 == at_column))
  146.                return (true); // this part threatens us on its ENE move
  147.             else if ((column < 6) && (line > 0) && (line - 1 == at_line) && (column + 2 == at_column))
  148.                return (true); // this part threatens us on its ESE move
  149.             else if ((column > 0) && (line > 1) && (line - 2 == at_line) && (column - 1 == at_column))
  150.                return (true); // this part threatens us on its SSW move
  151.             else if ((column < 7) && (line > 1) && (line - 2 == at_line) && (column + 1 == at_column))
  152.                return (true); // this part threatens us on its SSE move
  153.             else if ((column > 1) && (line < 7) && (line + 1 == at_line) && (column - 2 == at_column))
  154.                return (true); // this part threatens us on its WNW move
  155.             else if ((column > 1) && (line > 0) && (line - 1 == at_line) && (column - 2 == at_column))
  156.                return (true); // this part threatens us on its WSW move
  157.          }
  158.  
  159.          //////////////////////////////////////////////////////////////////////////////////////////
  160.          ///////////////////////////////////////// BISHOP /////////////////////////////////////////
  161.          //////////////////////////////////////////////////////////////////////////////////////////
  162.          // else is it a bishop ?
  163.          else if (boardslot->part == PART_BISHOP)
  164.          {
  165.             // is bishop in the same SWNE diagonal as our king ?
  166.             if (line - at_line == column - at_column)
  167.             {
  168.                // is our king NE ?
  169.                if (at_line > line)
  170.                {
  171.                   // see how far bishop can move NE
  172.                   for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  173.                      if ((index_line == at_line) && (index_column == at_column))
  174.                         return (true); // this part threatens us
  175.                      else if (!IS_FREE (index_line, index_column))
  176.                         break; // if part can no longer move this way, stop searching
  177.                }
  178.  
  179.                // else our king must be SW
  180.                else
  181.                {
  182.                   // see how far bishop can move SW
  183.                   for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  184.                      if ((index_line == at_line) && (index_column == at_column))
  185.                         return (true); // this part threatens us
  186.                      else if (!IS_FREE (index_line, index_column))
  187.                         break; // if part can no longer move this way, stop searching
  188.                }
  189.             }
  190.  
  191.             // else is bishop in the same SENW diagonal as our king ?
  192.             else if (line - at_line == -(column - at_column))
  193.             {
  194.                // is our king NW ?
  195.                if (at_line > line)
  196.                {
  197.                   // see how far bishop can move NW
  198.                   for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  199.                      if ((index_line == at_line) && (index_column == at_column))
  200.                         return (true); // this part threatens us
  201.                      else if (!IS_FREE (index_line, index_column))
  202.                         break; // if part can no longer move this way, stop searching
  203.                }
  204.  
  205.                // else our king must be SE
  206.                else
  207.                {
  208.                   // see how far bishop can move SE
  209.                   for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  210.                      if ((index_line == at_line) && (index_column == at_column))
  211.                         return (true); // this part threatens us
  212.                      else if (!IS_FREE (index_line, index_column))
  213.                         break; // if part can no longer move this way, stop searching
  214.                }
  215.             }
  216.          }
  217.  
  218.          //////////////////////////////////////////////////////////////////////////////////////////
  219.          ///////////////////////////////////////// QUEEN //////////////////////////////////////////
  220.          //////////////////////////////////////////////////////////////////////////////////////////
  221.          // else is it a queen ?
  222.          else if (boardslot->part == PART_QUEEN)
  223.          {
  224.             // is queen in the same column as our king ?
  225.             if (column == at_column)
  226.             {
  227.                // is our king above ?
  228.                if (at_line > line)
  229.                {
  230.                   // see if queen can threaten our king by moving upwards
  231.                   for (index_line = line + 1; index_line < 8; index_line++)
  232.                      if (index_line == at_line)
  233.                         return (true); // this part threatens us
  234.                      else if (!IS_FREE (index_line, column))
  235.                         break; // if part can no longer move this way, stop searching
  236.                }
  237.  
  238.                // else our king must be below
  239.                else
  240.                {
  241.                   // see if queen can threaten our king by moving downwards
  242.                   for (index_line = line - 1; index_line >= 0; index_line--)
  243.                      if (index_line == at_line)
  244.                         return (true); // this part threatens us
  245.                      else if (!IS_FREE (index_line, column))
  246.                         break; // if part can no longer move this way, stop searching
  247.                }
  248.             }
  249.  
  250.             // else is queen in the same line as our king ?
  251.             else if (line == at_line)
  252.             {
  253.                // is our king on the right ?
  254.                if (at_column > column)
  255.                {
  256.                   // see if queen can threaten our king by moving right
  257.                   for (index_column = column + 1; index_column < 8; index_column++)
  258.                      if (index_column == at_column)
  259.                         return (true); // this part threatens us
  260.                      else if (!IS_FREE (line, index_column))
  261.                         break; // if part can no longer move this way, stop searching
  262.                }
  263.  
  264.                // else our king must be on the left
  265.                else
  266.                {
  267.                   // see if queen can threaten our king by moving left
  268.                   for (index_column = column - 1; index_column >= 0; index_column--)
  269.                      if (index_column == at_column)
  270.                         return (true); // this part threatens us
  271.                      else if (!IS_FREE (line, index_column))
  272.                         break; // if part can no longer move this way, stop searching
  273.                }
  274.             }
  275.  
  276.             // else is queen in the same SWNE diagonal as our king ?
  277.             else if (line - at_line == column - at_column)
  278.             {
  279.                // is our king NE ?
  280.                if (at_line > line)
  281.                {
  282.                   // see how far queen can move NE
  283.                   for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  284.                      if ((index_line == at_line) && (index_column == at_column))
  285.                         return (true); // this part threatens us
  286.                      else if (!IS_FREE (index_line, index_column))
  287.                         break; // if part can no longer move this way, stop searching
  288.                }
  289.  
  290.                // else our king must be SW
  291.                else
  292.                {
  293.                   // see how far queen can move SW
  294.                   for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  295.                      if ((index_line == at_line) && (index_column == at_column))
  296.                         return (true); // this part threatens us
  297.                      else if (!IS_FREE (index_line, index_column))
  298.                         break; // if part can no longer move this way, stop searching
  299.                }
  300.             }
  301.  
  302.             // else is queen in the same SENW diagonal as our king ?
  303.             else if (line - at_line == -(column - at_column))
  304.             {
  305.                // is our king NW ?
  306.                if (at_line > line)
  307.                {
  308.                   // see how far queen can move NW
  309.                   for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  310.                      if ((index_line == at_line) && (index_column == at_column))
  311.                         return (true); // this part threatens us
  312.                      else if (!IS_FREE (index_line, index_column))
  313.                         break; // if part can no longer move this way, stop searching
  314.                }
  315.  
  316.                // else our king must be SE
  317.                else
  318.                {
  319.                   // see how far queen can move SE
  320.                   for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  321.                      if ((index_line == at_line) && (index_column == at_column))
  322.                         return (true); // this part threatens us
  323.                      else if (!IS_FREE (index_line, index_column))
  324.                         break; // if part can no longer move this way, stop searching
  325.                }
  326.             }
  327.          }
  328.  
  329.          //////////////////////////////////////////////////////////////////////////////////////////
  330.          ////////////////////////////////////////// KING //////////////////////////////////////////
  331.          //////////////////////////////////////////////////////////////////////////////////////////
  332.          // else is it a king ?
  333.          else if (boardslot->part == PART_KING)
  334.          {
  335.             if ((line < 7) && (column < 7) && (line + 1 == at_line) && (column + 1 == at_column))
  336.                return (true); // this part threatens us on its NE move
  337.             else if ((line > 0) && (column < 7) && (line - 1 == at_line) && (column + 1 == at_column))
  338.                return (true); // this part threatens us on its SE move
  339.             else if ((line < 7) && (column > 0) && (line + 1 == at_line) && (column - 1 == at_column))
  340.                return (true); // this part threatens us on its NW move
  341.             else if ((line > 0) && (column > 0) && (line - 1 == at_line) && (column - 1 == at_column))
  342.                return (true); // this part threatens us on its SW move
  343.             else if ((line < 7) && (line + 1 == at_line) && (column == at_column))
  344.                return (true); // this part threatens us on an upwards move
  345.             else if ((line > 0) && (line - 1 == at_line) && (column == at_column))
  346.                return (true); // this part threatens us on a downwards move
  347.             else if ((column < 7) && (line == at_line) && (column + 1 == at_column))
  348.                return (true); // this part threatens us on a right move
  349.             else if ((column > 0) && (line == at_line) && (column - 1 == at_column))
  350.                return (true); // this part threatens us on a left move
  351.          }
  352.       }
  353.  
  354.    return (false); // this king looks safe at this location
  355. }
  356.  
  357.  
  358. bool Move_IsCheck (boardmove_t *move, int color)
  359. {
  360.    // this function returns TRUE if the king of the specified color is under check
  361.  
  362.    boardslot_t *boardslot;
  363.    int line;
  364.    int column;
  365.    int threat_line;
  366.    int threat_column;
  367.  
  368.    // cycle through all the grid again and see if the king we want is in check
  369.    for (line = 0; line < 8; line++)
  370.       for (column = 0; column < 8; column++)
  371.       {
  372.          boardslot = &move->slots[line][column]; // quick access to grid slot
  373.  
  374.          if ((boardslot->color != color) || (boardslot->part != PART_KING))
  375.             continue; // if this slot is not our king, skip it
  376.  
  377.          // is this king currently threatened ?
  378.          if (Move_IsKingThreatenedAtLocation (move, color, line, column, &threat_line, &threat_column))
  379.             return (true); // yes, it is
  380.          else
  381.             return (false); // no, this king is safe
  382.       }
  383.  
  384.    // code should never reach here (it would mean that no king is on the board)
  385.  
  386.    return (false); // no king of such color found on board, no check possible, return FALSE
  387. }
  388.  
  389.  
  390. bool Move_IsStaleMate (boardmove_t *move, int color)
  391. {
  392.    // this function returns TRUE if the specified color is stalemate (no valid move possible)
  393.  
  394.    boardslot_t *boardslot;
  395.    int movement_direction;
  396.    int line;
  397.    int column;
  398.    int index_line;
  399.    int index_column;
  400.  
  401.    // cycle through all the board and find our parts
  402.    for (line = 0; line < 8; line++)
  403.       for (column = 0; column < 8; column++)
  404.       {
  405.          boardslot = &move->slots[line][column]; // quick access to grid slot
  406.  
  407.          if ((boardslot->part == PART_NONE) || (boardslot->color != color))
  408.             continue; // if this location is empty or not ours, we aren't interested in it
  409.  
  410.          //////////////////////////////////////////////////////////////////////////////////////////
  411.          ////////////////////////////////////////// PAWN //////////////////////////////////////////
  412.          //////////////////////////////////////////////////////////////////////////////////////////
  413.          // is it a pawn ?
  414.          if (boardslot->part == PART_PAWN)
  415.          {
  416.             // figure out movement direction
  417.             if (boardslot->color == COLOR_WHITE)
  418.                movement_direction = 1;
  419.             else
  420.                movement_direction = -1;
  421.  
  422.             // see if pawn can move forward
  423.             if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0)))
  424.                 && (move->slots[line + movement_direction][column].part == PART_NONE) // target slot free
  425.                 && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column, color))
  426.                return (false); // this move is possible
  427.  
  428.             // see if pawn can take a piece on its left
  429.             if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0)))
  430.                 && (column > 0) // has room
  431.                 && (move->slots[line + movement_direction][column - 1].color != color) // target slot NOT our color
  432.                 && (move->slots[line + movement_direction][column - 1].part != PART_NONE) // target slot occupied
  433.                 && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column - 1, color))
  434.                return (false); // this move is possible
  435.  
  436.             // see if pawn can take a piece on its right
  437.             if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0)))
  438.                 && (column < 7) // has room
  439.                 && (move->slots[line + movement_direction][column + 1].color != color) // target slot NOT our color
  440.                 && (move->slots[line + movement_direction][column + 1].part != PART_NONE) // target slot occupied
  441.                 && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column + 1, color))
  442.                return (false); // this move is possible
  443.  
  444.             // if previous move was a pawn rush, see if pawn can take "en passant"
  445.             if ((move->part == PART_PAWN) // last move was a pawn
  446.                   && (move->target[1] == move->source[1]) // pawn moved in column
  447.                   && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed
  448.                   && (move->target[0] == line) // pawn is in line with us
  449.                   && (move->target[1] - column == -1) // pawn is left to us
  450.                   && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column - 1, move->target[0], move->target[1], color))
  451.                return (false); // this move is possible
  452.             else if ((move->part == PART_PAWN) // last move was a pawn
  453.                   && (move->target[1] == move->source[1]) // pawn moved in column
  454.                   && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed
  455.                   && (move->target[0] == line) // pawn is in line with us
  456.                   && (move->target[1] - column == 1) // pawn is right to us
  457.                   && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column + 1, move->target[0], move->target[1], color))
  458.                return (false); // this move is possible
  459.          }
  460.  
  461.          //////////////////////////////////////////////////////////////////////////////////////////
  462.          ////////////////////////////////////////// ROOK //////////////////////////////////////////
  463.          //////////////////////////////////////////////////////////////////////////////////////////
  464.          // else is it a rook ?
  465.          else if (boardslot->part == PART_ROOK)
  466.          {
  467.             // see if rook can move upwards
  468.             for (index_line = line + 1; index_line < 8; index_line++)
  469.                if (!CAN_PLAY (index_line, column))
  470.                   break; // if part can no longer move this way, stop searching
  471.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  472.                   return (false); // this move is possible
  473.                else if (move->slots[index_line][column].part != PART_NONE)
  474.                   break; // no further moves are possible in the same direction
  475.  
  476.             // see if rook can move downwards
  477.             for (index_line = line - 1; index_line >= 0; index_line--)
  478.                if (!CAN_PLAY (index_line, column))
  479.                   break; // if part can no longer move this way, stop searching
  480.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  481.                   return (false); // this move is possible
  482.                else if (move->slots[index_line][column].part != PART_NONE)
  483.                   break; // no further moves are possible in the same direction
  484.  
  485.             // see if rook can move right
  486.             for (index_column = column + 1; index_column < 8; index_column++)
  487.                if (!CAN_PLAY (line, index_column))
  488.                   break; // if part can no longer move this way, stop searching
  489.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  490.                   return (false); // this move is possible
  491.                else if (move->slots[line][index_column].part != PART_NONE)
  492.                   break; // no further moves are possible in the same direction
  493.  
  494.             // see if rook can move left
  495.             for (index_column = column - 1; index_column >= 0; index_column--)
  496.                if (!CAN_PLAY (line, index_column))
  497.                   break; // if part can no longer move this way, stop searching
  498.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  499.                   return (false); // this move is possible
  500.                else if (move->slots[line][index_column].part != PART_NONE)
  501.                   break; // no further moves are possible in the same direction
  502.          }
  503.  
  504.          //////////////////////////////////////////////////////////////////////////////////////////
  505.          ///////////////////////////////////////// KNIGHT /////////////////////////////////////////
  506.          //////////////////////////////////////////////////////////////////////////////////////////
  507.          // else is it a knight ?
  508.          else if (boardslot->part == PART_KNIGHT)
  509.          {
  510.             // see if knight can move in either of his allowed directions NNW
  511.             if (CAN_PLAY (line + 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column - 1, color))
  512.                return (false); // knight can move NNW, we are not stalemate
  513.             else if (CAN_PLAY (line + 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column + 1, color))
  514.                return (false); // knight can move NNE, we are not stalemate
  515.             else if (CAN_PLAY (line + 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 2, color))
  516.                return (false); // knight can move ENE, we are not stalemate
  517.             else if (CAN_PLAY (line - 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 2, color))
  518.                return (false); // knight can move ESE, we are not stalemate
  519.             else if (CAN_PLAY (line - 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column - 1, color))
  520.                return (false); // knight can move SSW, we are not stalemate
  521.             else if (CAN_PLAY (line - 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column + 1, color))
  522.                return (false); // knight can move SSE, we are not stalemate
  523.             else if (CAN_PLAY (line + 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 2, color))
  524.                return (false); // knight can move WNW, we are not stalemate
  525.             else if (CAN_PLAY (line - 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 2, color))
  526.                return (false); // knight can move WSW, we are not stalemate
  527.          }
  528.  
  529.          //////////////////////////////////////////////////////////////////////////////////////////
  530.          ///////////////////////////////////////// BISHOP /////////////////////////////////////////
  531.          //////////////////////////////////////////////////////////////////////////////////////////
  532.          // else is it a bishop ?
  533.          else if (boardslot->part == PART_BISHOP)
  534.          {
  535.             // see if bishop can move NE
  536.             for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  537.                if (!CAN_PLAY (index_line, index_column))
  538.                   break; // if part can no longer move this way, stop searching
  539.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  540.                   return (false); // this move is possible
  541.                else if (move->slots[index_line][index_column].part != PART_NONE)
  542.                   break; // no further moves are possible in the same direction
  543.  
  544.             // see if bishop can move SE
  545.             for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  546.                if (!CAN_PLAY (index_line, index_column))
  547.                   break; // if part can no longer move this way, stop searching
  548.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  549.                   return (false); // this move is possible
  550.                else if (move->slots[index_line][index_column].part != PART_NONE)
  551.                   break; // no further moves are possible in the same direction
  552.  
  553.             // see if bishop can move NW
  554.             for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  555.                if (!CAN_PLAY (index_line, index_column))
  556.                   break; // if part can no longer move this way, stop searching
  557.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  558.                   return (false); // this move is possible
  559.                else if (move->slots[index_line][index_column].part != PART_NONE)
  560.                   break; // no further moves are possible in the same direction
  561.  
  562.             // see if bishop can move SW
  563.             for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  564.                if (!CAN_PLAY (index_line, index_column))
  565.                   break; // if part can no longer move this way, stop searching
  566.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  567.                   return (false); // this move is possible
  568.                else if (move->slots[index_line][index_column].part != PART_NONE)
  569.                   break; // no further moves are possible in the same direction
  570.          }
  571.  
  572.          //////////////////////////////////////////////////////////////////////////////////////////
  573.          ///////////////////////////////////////// QUEEN //////////////////////////////////////////
  574.          //////////////////////////////////////////////////////////////////////////////////////////
  575.          // else is it a queen ?
  576.          else if (boardslot->part == PART_QUEEN)
  577.          {
  578.             // see if queen can move upwards
  579.             for (index_line = line + 1; index_line < 8; index_line++)
  580.                if (!CAN_PLAY (index_line, column))
  581.                   break; // if part can no longer move this way, stop searching
  582.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  583.                   return (false); // this move is possible
  584.                else if (move->slots[index_line][column].part != PART_NONE)
  585.                   break; // no further moves are possible in the same direction
  586.  
  587.             // see if queen can move downwards
  588.             for (index_line = line - 1; index_line >= 0; index_line--)
  589.                if (!CAN_PLAY (index_line, column))
  590.                   break; // if part can no longer move this way, stop searching
  591.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  592.                   return (false); // this move is possible
  593.                else if (move->slots[index_line][column].part != PART_NONE)
  594.                   break; // no further moves are possible in the same direction
  595.  
  596.             // see if queen can move right
  597.             for (index_column = column + 1; index_column < 8; index_column++)
  598.                if (!CAN_PLAY (line, index_column))
  599.                   break; // if part can no longer move this way, stop searching
  600.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  601.                   return (false); // this move is possible
  602.                else if (move->slots[line][index_column].part != PART_NONE)
  603.                   break; // no further moves are possible in the same direction
  604.  
  605.             // see if queen can move left
  606.             for (index_column = column - 1; index_column >= 0; index_column--)
  607.                if (!CAN_PLAY (line, index_column))
  608.                   break; // if part can no longer move this way, stop searching
  609.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  610.                   return (false); // this move is possible
  611.                else if (move->slots[line][index_column].part != PART_NONE)
  612.                   break; // no further moves are possible in the same direction
  613.  
  614.             // see if queen can move NE
  615.             for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  616.                if (!CAN_PLAY (index_line, index_column))
  617.                   break; // if part can no longer move this way, stop searching
  618.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  619.                   return (false); // this move is possible
  620.                else if (move->slots[index_line][index_column].part != PART_NONE)
  621.                   break; // no further moves are possible in the same direction
  622.  
  623.             // see if queen can move SE
  624.             for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  625.                if (!CAN_PLAY (index_line, index_column))
  626.                   break; // if part can no longer move this way, stop searching
  627.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  628.                   return (false); // this move is possible
  629.                else if (move->slots[index_line][index_column].part != PART_NONE)
  630.                   break; // no further moves are possible in the same direction
  631.  
  632.             // see if queen can move NW
  633.             for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  634.                if (!CAN_PLAY (index_line, index_column))
  635.                   break; // if part can no longer move this way, stop searching
  636.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  637.                   return (false); // this move is possible
  638.                else if (move->slots[index_line][index_column].part != PART_NONE)
  639.                   break; // no further moves are possible in the same direction
  640.  
  641.             // see if queen can move SW
  642.             for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  643.                if (!CAN_PLAY (index_line, index_column))
  644.                   break; // if part can no longer move this way, stop searching
  645.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  646.                   return (false); // this move is possible
  647.                else if (move->slots[index_line][index_column].part != PART_NONE)
  648.                   break; // no further moves are possible in the same direction
  649.          }
  650.  
  651.          //////////////////////////////////////////////////////////////////////////////////////////
  652.          ////////////////////////////////////////// KING //////////////////////////////////////////
  653.          //////////////////////////////////////////////////////////////////////////////////////////
  654.          // else is it a king ?
  655.          else if (boardslot->part == PART_KING)
  656.          {
  657.             // see if king can move in either of his allowed directions
  658.             if (CAN_PLAY (line + 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column, color))
  659.                return (false); // king can move up, we are not stalemate
  660.             else if (CAN_PLAY (line - 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column, color))
  661.                return (false); // king can move down, we are not stalemate
  662.             else if (CAN_PLAY (line, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column + 1, color))
  663.                return (false); // king can move right, we are not stalemate
  664.             else if (CAN_PLAY (line, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column - 1, color))
  665.                return (false); // king can move left, we are not stalemate
  666.             else if (CAN_PLAY (line + 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 1, color))
  667.                return (false); // king can move NE, we are not stalemate
  668.             else if (CAN_PLAY (line - 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 1, color))
  669.                return (false); // king can move SE, we are not stalemate
  670.             else if (CAN_PLAY (line + 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 1, color))
  671.                return (false); // king can move NW, we are not stalemate
  672.             else if (CAN_PLAY (line - 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 1, color))
  673.                return (false); // king can move SW, we are not stalemate
  674.          }
  675.       }
  676.  
  677.    return (true); // found no legal move, we are indeed stalemate
  678. }
  679.  
  680.  
  681. bool Move_IsMoveValid (boardmove_t *move, int from_line, int from_column, int to_line, int to_column)
  682. {
  683.    // this function returns TRUE if the specified move is valid, FALSE otherwise
  684.  
  685.    // FIXME: doesn't support castling testing so far! (even though it shouldn't be necessary)
  686.  
  687.    boardslot_t *boardslot;
  688.    int movement_direction;
  689.    int index_line;
  690.    int index_column;
  691.  
  692.    boardslot = &move->slots[from_line][from_column]; // quick access to grid slot
  693.  
  694.    // consistency check
  695.    if (!IS_VALID (from_line, from_column) || !IS_VALID (to_line, to_column))
  696.       return (false); // if movement is out of bounds, it's obviously invalid
  697.  
  698.    //////////////////////////////////////////////////////////////////////////////////////////
  699.    ////////////////////////////////////////// PAWN //////////////////////////////////////////
  700.    //////////////////////////////////////////////////////////////////////////////////////////
  701.    // is it a pawn ?
  702.    if (boardslot->part == PART_PAWN)
  703.    {
  704.       // figure out movement direction
  705.       if (boardslot->color == COLOR_WHITE)
  706.          movement_direction = 1;
  707.       else
  708.          movement_direction = -1;
  709.  
  710.       // quick checks
  711.       if (abs (to_line - from_line) > 2)
  712.          return (false); // pawns cannot make moves longer than 2 rows
  713.       else if (abs (to_column - from_column) > 1)
  714.          return (false); // pawns cannot make moves aside more than 1 column
  715.  
  716.       // do we want pawn to rush forward
  717.       // OR do we want pawn to move forward
  718.       // OR do we want pawn to take a piece on its left
  719.       // OR do we want pawn to take a piece on its right ?
  720.       if ((((from_line == 1) || (from_line == 6)) // pawn on its initial slot
  721.            && (from_line + 2 * movement_direction == to_line) && (from_column == to_column) // target position is the position we want
  722.            && (move->slots[from_line + movement_direction][to_column].part == PART_NONE) // intermediate slot free
  723.            && (move->slots[to_line][to_column].part == PART_NONE)) // target slot free
  724.           || ((((movement_direction == 1) && (from_line < 7)) || ((movement_direction == -1) && (from_line > 0))) // has room
  725.               && (from_line + movement_direction == to_line) && (from_column == to_column) // target position is the position we want
  726.               && (move->slots[to_line][to_column].part == PART_NONE)) // target slot free
  727.           || ((((movement_direction == 1) && (from_line < 7)) || ((movement_direction == -1) && (from_line > 0)))
  728.               && (from_column > 0) // has room
  729.               && (from_line + movement_direction == to_line) && (from_column - 1 == to_column) // target position is the position we want
  730.               && (move->slots[to_line][to_column].color != boardslot->color) // target slot NOT our color
  731.               && (move->slots[to_line][to_column].part != PART_NONE)) // target slot occupied
  732.           || ((((movement_direction == 1) && (from_line < 7)) || ((movement_direction == -1) && (from_line > 0)))
  733.               && (from_column < 7) // has room
  734.               && (from_line + movement_direction == to_line) && (from_column + 1 == to_column) // target position is the position we want
  735.               && (move->slots[to_line][to_column].color != boardslot->color) // target slot NOT our color
  736.               && (move->slots[to_line][to_column].part != PART_NONE))) // target slot occupied
  737.       {
  738.          if (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color))
  739.             return (true); // this move is possible
  740.  
  741.          return (false); // else this pawn can't move in the claimed way (his king would be in check)
  742.       }
  743.  
  744.       // if previous move was a pawn rush, see if pawn can take "en passant"
  745.       if (IS_VALID (move->target[0], move->target[1]) // last move is valid
  746.             && (move->part == PART_PAWN) // last move was a pawn
  747.             && (move->target[1] == move->source[1]) // pawn moved in column
  748.             && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed
  749.             && (move->target[0] == from_line) // pawn is in line with us
  750.             && (move->target[1] - from_column == -1) // pawn is left to us
  751.             && (from_line + movement_direction == to_line) && (from_column - 1 == to_column) // target position is the position we want
  752.             && !Move_IsColorInCheckAfterTestMoveEP (move, from_line, from_column, to_line, to_column, move->target[0], move->target[1], boardslot->color))
  753.          return (true); // this move is possible
  754.       else if (IS_VALID (move->target[0], move->target[1]) // last move is valid
  755.                && (move->part == PART_PAWN) // last move was a pawn
  756.                && (move->target[1] == move->source[1]) // pawn moved in column
  757.                && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed
  758.                && (move->target[0] == from_line) // pawn is in line with us
  759.                && (move->target[1] - from_column == 1) // pawn is right to us
  760.                && (from_line + movement_direction == to_line) && (from_column + 1 == to_column) // target position is the position we want
  761.                && !Move_IsColorInCheckAfterTestMoveEP (move, from_line, from_column, to_line, to_column, move->target[0], move->target[1], boardslot->color))
  762.          return (true); // this move is possible
  763.  
  764.       return (false); // this pawn can't move in the claimed way
  765.    }
  766.  
  767.    //////////////////////////////////////////////////////////////////////////////////////////
  768.    ////////////////////////////////////////// ROOK //////////////////////////////////////////
  769.    //////////////////////////////////////////////////////////////////////////////////////////
  770.    // else is it a rook ?
  771.    else if (boardslot->part == PART_ROOK)
  772.    {
  773.       // quick checks
  774.       if ((to_column != from_column) && (to_line != from_line))
  775.          return (false); // rooks can only move horizontally or vertically
  776.       else if (!Move_IsWayClearBetween (move, from_line, from_column, to_line, to_column))
  777.          return (false); // way must be clear between source and target
  778.  
  779.       // do we want the rook to move upwards ?
  780.       if (to_line > from_line)
  781.       {
  782.          // see if rook can move upwards
  783.          for (index_line = from_line + 1; index_line < 8; index_line++)
  784.             if (!CAN_PLAY (index_line, to_column))
  785.                return (false); // if rook can no longer move this way, stop searching
  786.             else if (index_line == to_line)
  787.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  788.       }
  789.  
  790.       // else do we want the rook to move downwards ?
  791.       else if (to_line < from_line)
  792.       {
  793.          // see if rook can move downwards
  794.          for (index_line = from_line - 1; index_line >= 0; index_line--)
  795.             if (!CAN_PLAY (index_line, to_column))
  796.                return (false); // if rook can no longer move this way, stop searching
  797.             else if (index_line == to_line)
  798.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  799.       }
  800.  
  801.       // else do we want the rook to move right ?
  802.       else if (to_column > from_column)
  803.       {
  804.          // see if rook can move right
  805.          for (index_column = from_column + 1; index_column < 8; index_column++)
  806.             if (!CAN_PLAY (to_line, index_column))
  807.                return (false); // if rook can no longer move this way, stop searching
  808.             else if (index_column == to_column)
  809.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  810.       }
  811.  
  812.       // else do we want the rook to move left ?
  813.       else if (to_column < from_column)
  814.       {
  815.          // see if rook can move left
  816.          for (index_column = from_column - 1; index_column >= 0; index_column--)
  817.             if (!CAN_PLAY (to_line, index_column))
  818.                return (false); // if rook can no longer move this way, stop searching
  819.             else if (index_column == to_column)
  820.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  821.       }
  822.  
  823.       return (false); // this rook can't move in the claimed way
  824.    }
  825.  
  826.    //////////////////////////////////////////////////////////////////////////////////////////
  827.    ///////////////////////////////////////// KNIGHT /////////////////////////////////////////
  828.    //////////////////////////////////////////////////////////////////////////////////////////
  829.    // else is it a knight ?
  830.    else if (boardslot->part == PART_KNIGHT)
  831.    {
  832.       // do we want to move that knight in one of the allowed directions ?
  833.       if (   ((from_line + 2 == to_line) && (from_column - 1 == to_column)) // NNW
  834.           || ((from_line + 2 == to_line) && (from_column + 1 == to_column)) // NNE
  835.           || ((from_line + 1 == to_line) && (from_column + 2 == to_column)) // ENE
  836.           || ((from_line - 1 == to_line) && (from_column + 2 == to_column)) // ESE
  837.           || ((from_line - 2 == to_line) && (from_column - 1 == to_column)) // SSW
  838.           || ((from_line - 2 == to_line) && (from_column + 1 == to_column)) // SSE
  839.           || ((from_line + 1 == to_line) && (from_column - 2 == to_column)) // WNW
  840.           || ((from_line - 1 == to_line) && (from_column - 2 == to_column))) // WSW
  841.       {
  842.          if (!CAN_PLAY (to_line, to_column))
  843.             return (false); // if knight can't move there (out of board, or some of our parts there), return false
  844.          else if (Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color))
  845.             return (false); // if knight would leave his king in check there, return false
  846.  
  847.          return (true); // else this move is safe
  848.       }
  849.  
  850.       return (false); // this knight can't move in the claimed way
  851.    }
  852.  
  853.    //////////////////////////////////////////////////////////////////////////////////////////
  854.    ///////////////////////////////////////// BISHOP /////////////////////////////////////////
  855.    //////////////////////////////////////////////////////////////////////////////////////////
  856.    // else is it a bishop ?
  857.    else if (boardslot->part == PART_BISHOP)
  858.    {
  859.       // quick checks
  860.       if (abs (to_column - from_column) != abs (to_line - from_line))
  861.          return (false); // bishops can only move diagonally
  862.       else if (!Move_IsWayClearBetween (move, from_line, from_column, to_line, to_column))
  863.          return (false); // way must be clear between source and target
  864.  
  865.       // do we want to move the bishop NE ?
  866.       if ((to_line > from_line) && (to_column > from_column))
  867.       {
  868.          // see if bishop can move NE
  869.          for (index_line = from_line + 1, index_column = from_column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  870.             if (!CAN_PLAY (index_line, index_column))
  871.                return (false); // if bishop can no longer move this way, stop searching
  872.             else if ((index_line == to_line) && (index_column == to_column))
  873.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  874.       }
  875.  
  876.       // else do we want to move the bishop SE ?
  877.       else if ((to_line < from_line) && (to_column > from_column))
  878.       {
  879.          // see if bishop can move SE
  880.          for (index_line = from_line - 1, index_column = from_column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  881.             if (!CAN_PLAY (index_line, index_column))
  882.                return (false); // if bishop can no longer move this way, stop searching
  883.             else if ((index_line == to_line) && (index_column == to_column))
  884.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  885.       }
  886.  
  887.       // else do we want to move the bishop NW ?
  888.       else if ((to_line > from_line) && (to_column < from_column))
  889.       {
  890.          // see if bishop can move NW
  891.          for (index_line = from_line + 1, index_column = from_column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  892.             if (!CAN_PLAY (index_line, index_column))
  893.                return (false); // if bishop can no longer move this way, stop searching
  894.             else if ((index_line == to_line) && (index_column == to_column))
  895.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  896.       }
  897.  
  898.       // else do we want to move the bishop SW ?
  899.       else if ((to_line < from_line) && (to_column < from_column))
  900.       {
  901.          // see if bishop can move SW
  902.          for (index_line = from_line - 1, index_column = from_column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  903.             if (!CAN_PLAY (index_line, index_column))
  904.                return (false); // if bishop can no longer move this way, stop searching
  905.             else if ((index_line == to_line) && (index_column == to_column))
  906.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  907.       }
  908.  
  909.       return (false); // this bishop can't move in the claimed way
  910.    }
  911.  
  912.    //////////////////////////////////////////////////////////////////////////////////////////
  913.    ///////////////////////////////////////// QUEEN //////////////////////////////////////////
  914.    //////////////////////////////////////////////////////////////////////////////////////////
  915.    // else is it a queen ?
  916.    else if (boardslot->part == PART_QUEEN)
  917.    {
  918.       // quick checks
  919.       if ((to_column != from_column) && (to_line != from_line)
  920.           && (abs (to_column - from_column) != abs (to_line - from_line)))
  921.          return (false); // queens can only move horizontally, vertically or diagonally
  922.       else if (!Move_IsWayClearBetween (move, from_line, from_column, to_line, to_column))
  923.          return (false); // way must be clear between source and target
  924.  
  925.       // do we want to move that queen vertically ?
  926.       if (from_column == to_column)
  927.       {
  928.          // do we want to move her upwards ?
  929.          if (to_line > from_line)
  930.          {
  931.             // see if queen can move upwards
  932.             for (index_line = from_line + 1; index_line < 8; index_line++)
  933.                if (!CAN_PLAY (index_line, to_column))
  934.                   return (false); // if queen can no longer move this way, stop searching
  935.                else if (index_line == to_line)
  936.                   return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  937.          }
  938.  
  939.          // else do we want to move her downwards ?
  940.          else if (to_line < from_line)
  941.          {
  942.             // see if queen can move downwards
  943.             for (index_line = from_line - 1; index_line >= 0; index_line--)
  944.                if (!CAN_PLAY (index_line, to_column))
  945.                   return (false); // if queen can no longer move this way, stop searching
  946.                else if (index_line == to_line)
  947.                   return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  948.          }
  949.  
  950.          return (false); // this queen can't move in the claimed way
  951.       }
  952.  
  953.       // else do we want to move that queen horizontally ?
  954.       else if (from_line == to_line)
  955.       {
  956.          // do we want this queen to move right ?
  957.          if (to_column > from_column)
  958.          {
  959.             // see if queen can move right
  960.             for (index_column = from_column + 1; index_column < 8; index_column++)
  961.                if (!CAN_PLAY (to_line, index_column))
  962.                   return (false); // if queen can no longer move this way, stop searching
  963.                else if (index_column == to_column)
  964.                   return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  965.          }
  966.  
  967.          // else do we want this queen to move left ?
  968.          else if (to_column < from_column)
  969.          {
  970.             // see if queen can move left
  971.             for (index_column = from_column - 1; index_column >= 0; index_column--)
  972.                if (!CAN_PLAY (to_line, index_column))
  973.                   return (false); // if queen can no longer move this way, stop searching
  974.                else if (index_column == to_column)
  975.                   return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible
  976.          }
  977.  
  978.          return (false); // this queen can't move in the claimed way
  979.       }
  980.  
  981.       // else do we want to move the queen NE ?
  982.       else if ((to_line > from_line) && (to_column > from_column))
  983.       {
  984.          // see if queen can move NE
  985.          for (index_line = from_line + 1, index_column = from_column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  986.             if (!CAN_PLAY (index_line, index_column))
  987.                return (false); // if queen can no longer move this way, stop searching
  988.             else if ((index_line == to_line) && (index_column == to_column))
  989.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  990.       }
  991.  
  992.       // else do we want to move the queen SE ?
  993.       else if ((to_line < from_line) && (to_column > from_column))
  994.       {
  995.          // see if queen can move SE
  996.          for (index_line = from_line - 1, index_column = from_column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  997.             if (!CAN_PLAY (index_line, index_column))
  998.                return (false); // if queen can no longer move this way, stop searching
  999.             else if ((index_line == to_line) && (index_column == to_column))
  1000.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  1001.       }
  1002.  
  1003.       // else do we want to move the queen NW ?
  1004.       else if ((to_line > from_line) && (to_column < from_column))
  1005.       {
  1006.          // see if queen can move NW
  1007.          for (index_line = from_line + 1, index_column = from_column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  1008.             if (!CAN_PLAY (index_line, index_column))
  1009.                return (false); // if queen can no longer move this way, stop searching
  1010.             else if ((index_line == to_line) && (index_column == to_column))
  1011.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  1012.       }
  1013.  
  1014.       // else do we want to move the queen SW ?
  1015.       else if ((to_line < from_line) && (to_column < from_column))
  1016.       {
  1017.          // see if queen can move SW
  1018.          for (index_line = from_line - 1, index_column = from_column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  1019.             if (!CAN_PLAY (index_line, index_column))
  1020.                return (false); // if queen can no longer move this way, stop searching
  1021.             else if ((index_line == to_line) && (index_column == to_column))
  1022.                return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible
  1023.       }
  1024.  
  1025.       return (false); // this queen can't move in the claimed way
  1026.    }
  1027.  
  1028.    //////////////////////////////////////////////////////////////////////////////////////////
  1029.    ////////////////////////////////////////// KING //////////////////////////////////////////
  1030.    //////////////////////////////////////////////////////////////////////////////////////////
  1031.    // else is it a king ?
  1032.    else if (boardslot->part == PART_KING)
  1033.    {
  1034.       // do we want to move that king in one of the allowed directions ?
  1035.       if (((from_line + 1 == to_line) && (from_column == to_column)) // up
  1036.           || ((from_line - 1 == to_line) && (from_column == to_column)) // down
  1037.           || ((from_line == to_line) && (from_column + 1 == to_column)) // right
  1038.           || ((from_line == to_line) && (from_column - 1 == to_column)) // left
  1039.           || ((from_line + 1 == to_line) && (from_column + 1 == to_column)) // NE
  1040.           || ((from_line - 1 == to_line) && (from_column + 1 == to_column)) // SE
  1041.           || ((from_line + 1 == to_line) && (from_column - 1 == to_column)) // NW
  1042.           || ((from_line - 1 == to_line) && (from_column - 1 == to_column))) // SW
  1043.       {
  1044.          if (!CAN_PLAY (to_line, to_column))
  1045.             return (false); // if king can't move there, return false
  1046.          else if (Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color))
  1047.             return (false); // if king would be in check there, return false
  1048.  
  1049.          return (true); // else this move is safe
  1050.       }
  1051.  
  1052.       return (false); // if not, this king can't move in the claimed way
  1053.    }
  1054.  
  1055.    return (false); // this move is not possible, else we'd have returned earlier
  1056. }
  1057.  
  1058.  
  1059. bool Move_FindRandomMove (boardmove_t *move, int color, boardmove_t *random_move)
  1060. {
  1061.    // this function returns TRUE if it can find a random move (most of the time blunderous)
  1062.    // and sets its coordinates in the given output parameters
  1063.  
  1064.    boardslot_t *boardslot;
  1065.    int movement_direction;
  1066.    int line;
  1067.    int column;
  1068.    int index_line;
  1069.    int index_column;
  1070.    boardmove_t *possiblemoves; // mallocated
  1071.    int possiblemove_count;
  1072.    int move_index;
  1073.  
  1074.    // assume no possible move until told otherwise
  1075.    possiblemoves = NULL;
  1076.    possiblemove_count = 0;
  1077.  
  1078.    // cycle through all the board and find our parts
  1079.    for (line = 0; line < 8; line++)
  1080.       for (column = 0; column < 8; column++)
  1081.       {
  1082.          boardslot = &move->slots[line][column]; // quick access to grid slot
  1083.  
  1084.          if ((boardslot->part == PART_NONE) || (boardslot->color != color))
  1085.             continue; // if this location is empty or not ours, we aren't interested in it
  1086.  
  1087.          //////////////////////////////////////////////////////////////////////////////////////////
  1088.          ////////////////////////////////////////// PAWN //////////////////////////////////////////
  1089.          //////////////////////////////////////////////////////////////////////////////////////////
  1090.          // is it a pawn ?
  1091.          if (boardslot->part == PART_PAWN)
  1092.          {
  1093.             // figure out movement direction
  1094.             if (boardslot->color == COLOR_WHITE)
  1095.                movement_direction = 1;
  1096.             else
  1097.                movement_direction = -1;
  1098.  
  1099.             // see if pawn can move forward
  1100.             if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0)))
  1101.                 && (move->slots[line + movement_direction][column].part == PART_NONE) // target slot free
  1102.                 && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column, color))
  1103.             {
  1104.                if (((movement_direction == 1) && (line + movement_direction == 7))
  1105.                    || ((movement_direction == -1) && (line + movement_direction == 0)))
  1106.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column, PART_QUEEN, false, false); // save promotional move
  1107.                else
  1108.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column, PART_NONE, false, false); // save possible move
  1109.             }
  1110.  
  1111.             // see if pawn can take a piece on its left
  1112.             if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0)))
  1113.                 && (column > 0) // has room
  1114.                 && (move->slots[line + movement_direction][column - 1].color != color) // target slot NOT our color
  1115.                 && (move->slots[line + movement_direction][column - 1].part != PART_NONE) // target slot occupied
  1116.                 && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column - 1, color))
  1117.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column - 1, PART_NONE, true, false); // save possible move
  1118.  
  1119.             // see if pawn can take a piece on its right
  1120.             if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0)))
  1121.                 && (column < 7) // has room
  1122.                 && (move->slots[line + movement_direction][column + 1].color != color) // target slot NOT our color
  1123.                 && (move->slots[line + movement_direction][column + 1].part != PART_NONE) // target slot occupied
  1124.                 && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column + 1, color))
  1125.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column + 1, PART_NONE, true, false); // save possible move
  1126.  
  1127.             // if previous move was a pawn rush, see if pawn can take "en passant"
  1128.             if ((move->part == PART_PAWN) // last move was a pawn
  1129.                 && (move->target[1] == move->source[1]) // pawn moved in column
  1130.                 && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed
  1131.                 && (move->target[0] == line) // pawn is in line with us
  1132.                 && (move->target[1] - column == -1) // pawn is left to us
  1133.                 && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column - 1, move->target[0], move->target[1], color))
  1134.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column - 1, PART_NONE, true, true); // save possible move
  1135.             if ((move->part == PART_PAWN) // last move was a pawn
  1136.                 && (move->target[1] == move->source[1]) // pawn moved in column
  1137.                 && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed
  1138.                 && (move->target[0] == line) // pawn is in line with us
  1139.                 && (move->target[1] - column == 1) // pawn is right to us
  1140.                 && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column + 1, move->target[0], move->target[1], color))
  1141.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column + 1, PART_NONE, true, true); // save possible move
  1142.          }
  1143.  
  1144.          //////////////////////////////////////////////////////////////////////////////////////////
  1145.          ////////////////////////////////////////// ROOK //////////////////////////////////////////
  1146.          //////////////////////////////////////////////////////////////////////////////////////////
  1147.          // else is it a rook ?
  1148.          else if (boardslot->part == PART_ROOK)
  1149.          {
  1150.             // see if rook can move upwards
  1151.             for (index_line = line + 1; index_line < 8; index_line++)
  1152.                if (!CAN_PLAY (index_line, column))
  1153.                   break; // if part can no longer move this way, stop searching
  1154.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  1155.                {
  1156.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move
  1157.                   if (move->slots[index_line][column].part != PART_NONE)
  1158.                      break; // this move is possible, but no further moves are possible in the same direction
  1159.                }
  1160.  
  1161.             // see if rook can move downwards
  1162.             for (index_line = line - 1; index_line >= 0; index_line--)
  1163.                if (!CAN_PLAY (index_line, column))
  1164.                   break; // if part can no longer move this way, stop searching
  1165.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  1166.                {
  1167.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move
  1168.                   if (move->slots[index_line][column].part != PART_NONE)
  1169.                      break; // this move is possible, but no further moves are possible in the same direction
  1170.                }
  1171.  
  1172.             // see if rook can move right
  1173.             for (index_column = column + 1; index_column < 8; index_column++)
  1174.                if (!CAN_PLAY (line, index_column))
  1175.                   break; // if part can no longer move this way, stop searching
  1176.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  1177.                {
  1178.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move
  1179.                   if (move->slots[line][index_column].part != PART_NONE)
  1180.                      break; // this move is possible, but no further moves are possible in the same direction
  1181.                }
  1182.  
  1183.             // see if rook can move left
  1184.             for (index_column = column - 1; index_column >= 0; index_column--)
  1185.                if (!CAN_PLAY (line, index_column))
  1186.                   break; // if part can no longer move this way, stop searching
  1187.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  1188.                {
  1189.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move
  1190.                   if (move->slots[line][index_column].part != PART_NONE)
  1191.                      break; // this move is possible, but no further moves are possible in the same direction
  1192.                }
  1193.          }
  1194.  
  1195.          //////////////////////////////////////////////////////////////////////////////////////////
  1196.          ///////////////////////////////////////// KNIGHT /////////////////////////////////////////
  1197.          //////////////////////////////////////////////////////////////////////////////////////////
  1198.          // else is it a knight ?
  1199.          else if (boardslot->part == PART_KNIGHT)
  1200.          {
  1201.             // see if knight can move NNW
  1202.             if (CAN_PLAY (line + 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column - 1, color))
  1203.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 2, column - 1, PART_NONE, (move->slots[line + 2][column - 1].part != PART_NONE), false); // save possible move
  1204.  
  1205.             // see if knight can move NNE
  1206.             if (CAN_PLAY (line + 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column + 1, color))
  1207.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 2, column + 1, PART_NONE, (move->slots[line + 2][column + 1].part != PART_NONE), false); // save possible move
  1208.  
  1209.             // see if knight can move ENE
  1210.             if (CAN_PLAY (line + 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 2, color))
  1211.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 1, column + 2, PART_NONE, (move->slots[line + 1][column + 2].part != PART_NONE), false); // save possible move
  1212.  
  1213.             // see if knight can move ESE
  1214.             if (CAN_PLAY (line - 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 2, color))
  1215.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 1, column + 2, PART_NONE, (move->slots[line - 1][column + 2].part != PART_NONE), false); // save possible move
  1216.  
  1217.             // see if knight can move SSW
  1218.             if (CAN_PLAY (line - 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column - 1, color))
  1219.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 2, column - 1, PART_NONE, (move->slots[line - 2][column - 1].part != PART_NONE), false); // save possible move
  1220.  
  1221.             // see if knight can move SSE
  1222.             if (CAN_PLAY (line - 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column + 1, color))
  1223.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 2, column + 1, PART_NONE, (move->slots[line - 2][column + 1].part != PART_NONE), false); // save possible move
  1224.  
  1225.             // see if knight can move WNW
  1226.             if (CAN_PLAY (line + 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 2, color))
  1227.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 1, column - 2, PART_NONE, (move->slots[line + 1][column - 2].part != PART_NONE), false); // save possible move
  1228.  
  1229.             // see if knight can move WSW
  1230.             if (CAN_PLAY (line - 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 2, color))
  1231.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 1, column - 2, PART_NONE, (move->slots[line - 1][column - 2].part != PART_NONE), false); // save possible move
  1232.          }
  1233.  
  1234.          //////////////////////////////////////////////////////////////////////////////////////////
  1235.          ///////////////////////////////////////// BISHOP /////////////////////////////////////////
  1236.          //////////////////////////////////////////////////////////////////////////////////////////
  1237.          // else is it a bishop ?
  1238.          else if (boardslot->part == PART_BISHOP)
  1239.          {
  1240.             // see if bishop can move NE
  1241.             for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  1242.                if (!CAN_PLAY (index_line, index_column))
  1243.                   break; // if part can no longer move this way, stop searching
  1244.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1245.                {
  1246.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1247.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1248.                      break; // this move is possible, but no further moves are possible in the same direction
  1249.                }
  1250.  
  1251.             // see if bishop can move SE
  1252.             for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  1253.                if (!CAN_PLAY (index_line, index_column))
  1254.                   break; // if part can no longer move this way, stop searching
  1255.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1256.                {
  1257.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1258.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1259.                      break; // this move is possible, but no further moves are possible in the same direction
  1260.                }
  1261.  
  1262.             // see if bishop can move NW
  1263.             for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  1264.                if (!CAN_PLAY (index_line, index_column))
  1265.                   break; // if part can no longer move this way, stop searching
  1266.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1267.                {
  1268.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1269.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1270.                      break; // this move is possible, but no further moves are possible in the same direction
  1271.                }
  1272.  
  1273.             // see if bishop can move SW
  1274.             for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  1275.                if (!CAN_PLAY (index_line, index_column))
  1276.                   break; // if part can no longer move this way, stop searching
  1277.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1278.                {
  1279.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1280.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1281.                      break; // this move is possible, but no further moves are possible in the same direction
  1282.                }
  1283.          }
  1284.  
  1285.          //////////////////////////////////////////////////////////////////////////////////////////
  1286.          ///////////////////////////////////////// QUEEN //////////////////////////////////////////
  1287.          //////////////////////////////////////////////////////////////////////////////////////////
  1288.          // else is it a queen ?
  1289.          else if (boardslot->part == PART_QUEEN)
  1290.          {
  1291.             // see if queen can move upwards
  1292.             for (index_line = line + 1; index_line < 8; index_line++)
  1293.                if (!CAN_PLAY (index_line, column))
  1294.                   break; // if part can no longer move this way, stop searching
  1295.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  1296.                {
  1297.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move
  1298.                   if (move->slots[index_line][column].part != PART_NONE)
  1299.                      break; // this move is possible, but no further moves are possible in the same direction
  1300.                }
  1301.  
  1302.             // see if queen can move downwards
  1303.             for (index_line = line - 1; index_line >= 0; index_line--)
  1304.                if (!CAN_PLAY (index_line, column))
  1305.                   break; // if part can no longer move this way, stop searching
  1306.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color))
  1307.                {
  1308.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move
  1309.                   if (move->slots[index_line][column].part != PART_NONE)
  1310.                      break; // this move is possible, but no further moves are possible in the same direction
  1311.                }
  1312.  
  1313.             // see if queen can move right
  1314.             for (index_column = column + 1; index_column < 8; index_column++)
  1315.                if (!CAN_PLAY (line, index_column))
  1316.                   break; // if part can no longer move this way, stop searching
  1317.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  1318.                {
  1319.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move
  1320.                   if (move->slots[line][index_column].part != PART_NONE)
  1321.                      break; // this move is possible, but no further moves are possible in the same direction
  1322.                }
  1323.  
  1324.             // see if queen can move left
  1325.             for (index_column = column - 1; index_column >= 0; index_column--)
  1326.                if (!CAN_PLAY (line, index_column))
  1327.                   break; // if part can no longer move this way, stop searching
  1328.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color))
  1329.                {
  1330.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move
  1331.                   if (move->slots[line][index_column].part != PART_NONE)
  1332.                      break; // this move is possible, but no further moves are possible in the same direction
  1333.                }
  1334.  
  1335.             // see if queen can move NE
  1336.             for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++)
  1337.                if (!CAN_PLAY (index_line, index_column))
  1338.                   break; // if part can no longer move this way, stop searching
  1339.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1340.                {
  1341.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1342.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1343.                      break; // this move is possible, but no further moves are possible in the same direction
  1344.                }
  1345.  
  1346.             // see if queen can move SE
  1347.             for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++)
  1348.                if (!CAN_PLAY (index_line, index_column))
  1349.                   break; // if part can no longer move this way, stop searching
  1350.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1351.                {
  1352.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1353.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1354.                      break; // this move is possible, but no further moves are possible in the same direction
  1355.                }
  1356.  
  1357.             // see if queen can move NW
  1358.             for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--)
  1359.                if (!CAN_PLAY (index_line, index_column))
  1360.                   break; // if part can no longer move this way, stop searching
  1361.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1362.                {
  1363.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1364.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1365.                      break; // this move is possible, but no further moves are possible in the same direction
  1366.                }
  1367.  
  1368.             // see if queen can move SW
  1369.             for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--)
  1370.                if (!CAN_PLAY (index_line, index_column))
  1371.                   break; // if part can no longer move this way, stop searching
  1372.                else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color))
  1373.                {
  1374.                   AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move
  1375.                   if (move->slots[index_line][index_column].part != PART_NONE)
  1376.                      break; // this move is possible, but no further moves are possible in the same direction
  1377.                }
  1378.          }
  1379.  
  1380.          //////////////////////////////////////////////////////////////////////////////////////////
  1381.          ////////////////////////////////////////// KING //////////////////////////////////////////
  1382.          //////////////////////////////////////////////////////////////////////////////////////////
  1383.          // else is it a king ?
  1384.          else if (boardslot->part == PART_KING)
  1385.          {
  1386.             // see if king can move up
  1387.             if (CAN_PLAY (line + 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column, color))
  1388.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line + 1, column, PART_NONE, (move->slots[line + 1][column].part != PART_NONE), false); // save possible move
  1389.  
  1390.             // see if king can move down
  1391.             if (CAN_PLAY (line - 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column, color))
  1392.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line - 1, column, PART_NONE, (move->slots[line - 1][column].part != PART_NONE), false); // save possible move
  1393.  
  1394.             // see if king can move right
  1395.             if (CAN_PLAY (line, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column + 1, color))
  1396.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line, column + 1, PART_NONE, (move->slots[line][column + 1].part != PART_NONE), false); // save possible move
  1397.  
  1398.             // see if king can move left
  1399.             if (CAN_PLAY (line, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column - 1, color))
  1400.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line, column - 1, PART_NONE, (move->slots[line][column - 1].part != PART_NONE), false); // save possible move
  1401.  
  1402.             // see if king can move NE
  1403.             if (CAN_PLAY (line + 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 1, color))
  1404.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line + 1, column + 1, PART_NONE, (move->slots[line + 1][column + 1].part != PART_NONE), false); // save possible move
  1405.  
  1406.             // see if king can move SE
  1407.             if (CAN_PLAY (line - 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 1, color))
  1408.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line - 1, column + 1, PART_NONE, (move->slots[line - 1][column + 1].part != PART_NONE), false); // save possible move
  1409.  
  1410.             // see if king can move NW
  1411.             if (CAN_PLAY (line + 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 1, color))
  1412.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line + 1, column - 1, PART_NONE, (move->slots[line + 1][column - 1].part != PART_NONE), false); // save possible move
  1413.  
  1414.             // see if king can move SW
  1415.             if (CAN_PLAY (line - 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 1, color))
  1416.                AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line - 1, column - 1, PART_NONE, (move->slots[line - 1][column - 1].part != PART_NONE), false); // save possible move
  1417.          }
  1418.       }
  1419.  
  1420.    // now that all the table has been parsed, see if we have some possible moves
  1421.  
  1422.    if (possiblemove_count == 0)
  1423.       return (false); // if none, return FALSE (it means that we are stalemate, but there's a faster function to check that)
  1424.  
  1425.    move_index = rand () % possiblemove_count; // select a possible move at random
  1426.    memcpy (random_move, &possiblemoves[move_index], sizeof (boardmove_t)); // copy it into destination variable
  1427.  
  1428.    SAFE_free ((void **) &possiblemoves); // free the possible moves array, we no longer need them
  1429.    return (true); // we did find some possible moves
  1430. }
  1431.  
  1432.  
  1433. int Move_CountPartsByColorAndType (boardmove_t *move, int color, int part_type)
  1434. {
  1435.    // this function returns the amount of parts of the specified color and type left on board
  1436.  
  1437.    int line;
  1438.    int column;
  1439.    int count;
  1440.  
  1441.    count = 0; // assume none so far
  1442.  
  1443.    // cycle through all the board...
  1444.    for (line = 0; line < 8; line++)
  1445.       for (column = 0; column < 8; column++)
  1446.          if ((move->slots[line][column].color == color) && (move->slots[line][column].part == part_type))
  1447.             count++; // sum up all the parts of the same colour and type we find
  1448.  
  1449.    return (count); // and return their quantity
  1450. }
  1451.  
  1452.  
  1453. bool Move_IsColorInCheckAfterTestMove (boardmove_t *move, int source_line, int source_column, int target_line, int target_column, int color)
  1454. {
  1455.    // helper function to play a test move on a temporary board (which must have been previously allocated)
  1456.  
  1457.    static boardmove_t temp_move; // declare this static so as not to allocate/free it continuously
  1458.  
  1459.    memcpy (temp_move.slots, move->slots, sizeof (move->slots)); // have a copy of the table, then make the move
  1460.    memcpy (&temp_move.slots[target_line][target_column], &temp_move.slots[source_line][source_column], sizeof (boardslot_t));
  1461.    memset (&temp_move.slots[source_line][source_column], 0, sizeof (boardslot_t)); // erase the source slot
  1462.  
  1463.    return (Move_IsCheck (&temp_move, color)); // return whether the final board has the given color in check
  1464. }
  1465.  
  1466.  
  1467. bool Move_IsColorInCheckAfterTestMoveEP (boardmove_t *move, int source_line, int source_column, int target_line, int target_column, int clear_line, int clear_column, int color)
  1468. {
  1469.    // helper function to play a test move on a temporary board (which must have been previously allocated)
  1470.    // En Passant version -- cleans the specified target before testing
  1471.  
  1472.    static boardmove_t temp_move; // declare this static so as not to allocate/free it continuously
  1473.  
  1474.    memcpy (temp_move.slots, move->slots, sizeof (move->slots)); // have a copy of the table, then make the move
  1475.    memcpy (&temp_move.slots[target_line][target_column], &temp_move.slots[source_line][source_column], sizeof (boardslot_t));
  1476.    memset (&temp_move.slots[source_line][source_column], 0, sizeof (boardslot_t)); // erase the source slot
  1477.  
  1478.    memset (&temp_move.slots[clear_line][clear_column], 0, sizeof (boardslot_t)); // erase the "en passant" target
  1479.  
  1480.    return (Move_IsCheck (&temp_move, color)); // return whether the final board has the given color in check
  1481. }
  1482.  
  1483.  
  1484. void Move_DescribeInFEN (boardmove_t *move)
  1485. {
  1486.    // convert a board and its part placements into a Forsyth Edwards notation, writing in the fen_string buffer
  1487.  
  1488.    boardslot_t *slot;
  1489.    int line;
  1490.    int column;
  1491.    int free_slots;
  1492.    int length;
  1493.  
  1494.    // first reset the string
  1495.    move->fen_string[0] = 0;
  1496.  
  1497.    ////////////////////////////////////////////////////////
  1498.    // first part of the FEN notation is the parts placement
  1499.  
  1500.    // cycle through each column, line after line, starting up left and going downwards right
  1501.    for (line = 7; line >= 0; line--)
  1502.    {
  1503.       free_slots = 0; // no free slot in that line yet
  1504.  
  1505.       for (column = 0; column < 8; column++)
  1506.       {
  1507.          slot = &move->slots[line][column]; // quick access to current slot
  1508.  
  1509.          if (slot->part == PART_ROOK)
  1510.          {
  1511.             // if there are free slots to mention, do it
  1512.             if (free_slots > 0)
  1513.             {
  1514.                length = wcslen (move->fen_string); // append the free slots count
  1515.                swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots);
  1516.                free_slots = 0; // reset the free slots count
  1517.             }
  1518.             wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"r" : (slot->color == COLOR_WHITE ? L"R": L"?")));
  1519.          }
  1520.          else if (slot->part == PART_KNIGHT)
  1521.          {
  1522.             // if there are free slots to mention, do it
  1523.             if (free_slots > 0)
  1524.             {
  1525.                length = wcslen (move->fen_string); // append the free slots count
  1526.                swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots);
  1527.                free_slots = 0; // reset the free slots count
  1528.             }
  1529.             wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"n" : (slot->color == COLOR_WHITE ? L"N": L"?")));
  1530.          }
  1531.          else if (slot->part == PART_BISHOP)
  1532.          {
  1533.             // if there are free slots to mention, do it
  1534.             if (free_slots > 0)
  1535.             {
  1536.                length = wcslen (move->fen_string); // append the free slots count
  1537.                swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots);
  1538.                free_slots = 0; // reset the free slots count
  1539.             }
  1540.             wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"b" : (slot->color == COLOR_WHITE ? L"B": L"?")));
  1541.          }
  1542.          else if (slot->part == PART_QUEEN)
  1543.          {
  1544.             // if there are free slots to mention, do it
  1545.             if (free_slots > 0)
  1546.             {
  1547.                length = wcslen (move->fen_string); // append the free slots count
  1548.                swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots);
  1549.                free_slots = 0; // reset the free slots count
  1550.             }
  1551.             wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"q" : (slot->color == COLOR_WHITE ? L"Q": L"?")));
  1552.          }
  1553.          else if (slot->part == PART_KING)
  1554.          {
  1555.             // if there are free slots to mention, do it
  1556.             if (free_slots > 0)
  1557.             {
  1558.                length = wcslen (move->fen_string); // append the free slots count
  1559.                swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots);
  1560.                free_slots = 0; // reset the free slots count
  1561.             }
  1562.             wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"k" : (slot->color == COLOR_WHITE ? L"K": L"?")));
  1563.          }
  1564.          else if (slot->part == PART_PAWN)
  1565.          {
  1566.             // if there are free slots to mention, do it
  1567.             if (free_slots > 0)
  1568.             {
  1569.                length = wcslen (move->fen_string); // append the free slots count
  1570.                swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots);
  1571.                free_slots = 0; // reset the free slots count
  1572.             }
  1573.             wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"p" : (slot->color == COLOR_WHITE ? L"P": L"?")));
  1574.          }
  1575.          else
  1576.             free_slots++; // we found one free slot more
  1577.  
  1578.          // are we at the end of a line ?
  1579.          if (column == 7)
  1580.          {
  1581.             // if there are free slots to mention, do it
  1582.             if (free_slots > 0)
  1583.             {
  1584.                length = wcslen (move->fen_string); // append the free slots count
  1585.                swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots);
  1586.                free_slots = 0; // reset the free slots count
  1587.             }
  1588.             if (line > 0)
  1589.                wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"/"); // at the end of each line, drop a slash (except on the last line)
  1590.          }
  1591.       }
  1592.    }
  1593.  
  1594.    //////////////////////////////////////////////////////
  1595.    // second part of the FEN notation is the side on move
  1596.  
  1597.    // deduce the side to move according to last move's color
  1598.    if (move->color == COLOR_WHITE)
  1599.       wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" b"); // black to move
  1600.    else
  1601.       wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" w"); // white to move (this also catches the beginning of a game)
  1602.  
  1603.    ///////////////////////////////////////////////////////////////
  1604.    // third part of the FEN notation is the castling possibilities
  1605.  
  1606.    wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" ");
  1607.    if (!(move->sides[COLOR_BLACK].longcastle_allowed | move->sides[COLOR_WHITE].longcastle_allowed | move->sides[COLOR_BLACK].shortcastle_allowed | move->sides[COLOR_WHITE].shortcastle_allowed))
  1608.       wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"-"); // neither side can castle
  1609.    else
  1610.    {
  1611.       if (move->sides[COLOR_WHITE].shortcastle_allowed)
  1612.          wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"K"); // white can castle kingside
  1613.       if (move->sides[COLOR_WHITE].longcastle_allowed)
  1614.          wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"Q"); // white can castle queenside
  1615.       if (move->sides[COLOR_BLACK].shortcastle_allowed)
  1616.          wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"k"); // black can castle kingside
  1617.       if (move->sides[COLOR_BLACK].longcastle_allowed)
  1618.          wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"q"); // black can castle queenside
  1619.    }
  1620.  
  1621.    ///////////////////////////////////////////////////////////////////////////////////////////////////
  1622.    // fourth part of the FEN notation is the optional position for a pawn that can be taken en passant
  1623.  
  1624.    wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" "); // spacer
  1625.  
  1626.    if ((move->part == PART_PAWN) // last move was a pawn
  1627.        && (move->target[1] == move->source[1]) // pawn moved in column
  1628.        && (abs (move->target[0] - move->source[0]) == 2)) // pawn rushed
  1629.    {
  1630.       // column
  1631.       if (move->source[1] == 0) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"a");
  1632.       else if (move->source[1] == 1) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"b");
  1633.       else if (move->source[1] == 2) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"c");
  1634.       else if (move->source[1] == 3) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"d");
  1635.       else if (move->source[1] == 4) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"e");
  1636.       else if (move->source[1] == 5) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"f");
  1637.       else if (move->source[1] == 6) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"g");
  1638.       else if (move->source[1] == 7) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"h");
  1639.       else wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"?");
  1640.  
  1641.       // line (it's the line the pawn would be on if it had made a "normal" move)
  1642.       length = wcslen (move->fen_string);
  1643.       swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", 1 + (move->target[0] + move->source[0]) / 2);
  1644.    }
  1645.    else
  1646.       wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"-"); // last move was not a pawn rush
  1647.  
  1648.    return; // finished
  1649. }
  1650.  
  1651.  
  1652. bool Move_SetupFromFEN (boardmove_t *move, wchar_t *fen_string)
  1653. {
  1654.    // this function sets up the given board according to the Forsyth-Edwards description fen_string makes of it
  1655.  
  1656.    // FIXME : load fen, then load PGN, then back arrow.
  1657.  
  1658.    int char_index;
  1659.    int length;
  1660.    int current_line;
  1661.    int current_column;
  1662.    int enpassant_line;
  1663.    int enpassant_column;
  1664.  
  1665.    // reset the chess grid
  1666.    memset (&move->slots, 0, sizeof (move->slots));
  1667.  
  1668.    // reset the taken pieces for both sides
  1669.    SAFE_free ((void **) &move->sides[COLOR_WHITE].takenparts); // release memory space
  1670.    move->sides[COLOR_WHITE].takenpart_count = 0;
  1671.    SAFE_free ((void **) &move->sides[COLOR_BLACK].takenparts); // release memory space
  1672.    move->sides[COLOR_BLACK].takenpart_count = 0;
  1673.  
  1674.    // reset the moves array comments and the moves array itself
  1675.    SAFE_free ((void **) &move->comment);
  1676.  
  1677.    // DISallow both sides to castle, until told otherwise
  1678.    move->sides[COLOR_WHITE].shortcastle_allowed = false;
  1679.    move->sides[COLOR_WHITE].longcastle_allowed = false;
  1680.    move->sides[COLOR_BLACK].shortcastle_allowed = false;
  1681.    move->sides[COLOR_BLACK].longcastle_allowed = false;
  1682.  
  1683.    // get the length of the FEN string
  1684.    length = wcslen (fen_string);
  1685.  
  1686.    // now parse the board from top left to bottom right, placing parts on the fly
  1687.    current_line = 7;
  1688.    current_column = 0;
  1689.    for (char_index = 0; char_index < length; char_index++)
  1690.    {
  1691.       // is it a number ?
  1692.       if (iswdigit (fen_string[char_index]))
  1693.       {
  1694.          current_column += _wtoi (&fen_string[char_index]); // skip as many columns as needed
  1695.          if (current_column > 8)
  1696.             return (false); // consistency check: something's wrong with this notation, return FALSE
  1697.       }
  1698.  
  1699.       // else is it a line skip ?
  1700.       else if (fen_string[char_index] == L'/')
  1701.       {
  1702.          // were we reading the last line ?
  1703.          if (current_line == 0)
  1704.          {
  1705.             char_index++; // skip this character
  1706.             break; // stop reading parts placement
  1707.          }
  1708.  
  1709.          current_line--; // proceed to next line, decrescending
  1710.          current_column = 0; // and begin at the first column on that line
  1711.       }
  1712.  
  1713.       // else is it a blank space ? meaning parts have been read
  1714.       else if (fen_string[char_index] == L' ')
  1715.          break; // stop reading parts placement
  1716.  
  1717.       // else it's a part. Check first if the current line/column is valid
  1718.       else if (IS_VALID (current_line, current_column))
  1719.       {
  1720.          if (fen_string[char_index] == L'r')
  1721.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_ROOK); // black rook
  1722.          else if (fen_string[char_index] == L'R')
  1723.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_ROOK); // white rook
  1724.          else if (fen_string[char_index] == L'n')
  1725.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KNIGHT); // black knight
  1726.          else if (fen_string[char_index] == L'N')
  1727.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KNIGHT); // white knight
  1728.          else if (fen_string[char_index] == L'b')
  1729.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_BISHOP); // black bishop
  1730.          else if (fen_string[char_index] == L'B')
  1731.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_BISHOP); // white bishop
  1732.          else if (fen_string[char_index] == L'q')
  1733.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_QUEEN); // black queen
  1734.          else if (fen_string[char_index] == L'Q')
  1735.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_QUEEN); // white queen
  1736.          else if (fen_string[char_index] == L'k')
  1737.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KING); // black king
  1738.          else if (fen_string[char_index] == L'K')
  1739.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KING); // white king
  1740.          else if (fen_string[char_index] == L'p')
  1741.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_PAWN); // black pawn
  1742.          else if (fen_string[char_index] == L'P')
  1743.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_PAWN); // white pawn
  1744.  
  1745.          current_column++; // proceed to next column
  1746.       }
  1747.       else
  1748.          return (false); // invalid position, something's wrong with this notation, return FALSE
  1749.    }
  1750.  
  1751.    // a space has been reached: next thing to read is the side on move
  1752.    char_index++;
  1753.    if (char_index >= length)
  1754.       return (false); // consistency check: something's wrong with this notation, return FALSE
  1755.  
  1756.    if (towlower (fen_string[char_index]) == L'w')
  1757.       move->color = COLOR_BLACK; // white to move
  1758.    else if (towlower (fen_string[char_index]) == L'b')
  1759.       move->color = COLOR_WHITE; // black to move
  1760.    else
  1761.       return (false); // consistency check: something's wrong with this notation, return FALSE
  1762.  
  1763.    // there should be a space after this
  1764.    char_index++;
  1765.    if ((char_index >= length) || (fen_string[char_index] != L' '))
  1766.       return (false); // consistency check: something's wrong with this notation, return FALSE
  1767.  
  1768.    // a space has been reached: next thing to read is the castling possibilities
  1769.    char_index++;
  1770.    if (char_index >= length)
  1771.       return (false); // consistency check: something's wrong with this notation, return FALSE
  1772.    for (; char_index < length; char_index++)
  1773.    {
  1774.       if (fen_string[char_index] == L'k')
  1775.          move->sides[COLOR_BLACK].shortcastle_allowed = true; // short castling allowed for black
  1776.       else if (fen_string[char_index] == L'K')
  1777.          move->sides[COLOR_WHITE].shortcastle_allowed = true; // short castling allowed for white
  1778.       else if (fen_string[char_index] == L'q')
  1779.          move->sides[COLOR_BLACK].longcastle_allowed = true; // long castling allowed for black
  1780.       else if (fen_string[char_index] == L'Q')
  1781.          move->sides[COLOR_WHITE].longcastle_allowed = true; // long castling allowed for white
  1782.       else if (fen_string[char_index] == L'-')
  1783.          continue; // no side can castle (explicitly)
  1784.       else if (fen_string[char_index] == L' ')
  1785.          break; // if blank space, stop reading castling possibilities
  1786.    }
  1787.  
  1788.    // is there a free space after this ?
  1789.    if (char_index < length)
  1790.    {
  1791.       char_index++; // if so, skip it
  1792.  
  1793.       // is there enough room for an en passant position AND is it specified ?
  1794.       if ((char_index + 2 <= length) && (fen_string[char_index] != L'-'))
  1795.       {
  1796.          // read column
  1797.          if (towlower (fen_string[char_index]) == L'a') enpassant_column = 0;
  1798.          else if (towlower (fen_string[char_index]) == L'b') enpassant_column = 1;
  1799.          else if (towlower (fen_string[char_index]) == L'c') enpassant_column = 2;
  1800.          else if (towlower (fen_string[char_index]) == L'd') enpassant_column = 3;
  1801.          else if (towlower (fen_string[char_index]) == L'e') enpassant_column = 4;
  1802.          else if (towlower (fen_string[char_index]) == L'f') enpassant_column = 5;
  1803.          else if (towlower (fen_string[char_index]) == L'g') enpassant_column = 6;
  1804.          else if (towlower (fen_string[char_index]) == L'h') enpassant_column = 7;
  1805.          else return (false); // consistency check: something's wrong with this notation, return FALSE
  1806.  
  1807.          // read line
  1808.          enpassant_line = _wtoi (&fen_string[char_index + 1]) - 1;
  1809.          if ((enpassant_line != 2) && (enpassant_line != 5))
  1810.             return (false); // consistency check: something's wrong with this notation, return FALSE
  1811.  
  1812.          // setup move data
  1813.          move->part = PART_PAWN;
  1814.          if (enpassant_line == 2)
  1815.          {
  1816.             move->source[0] = 1; // rush from line 1 to line 3
  1817.             move->target[0] = 3;
  1818.             move->color = COLOR_WHITE;
  1819.          }
  1820.          else
  1821.          {
  1822.             move->source[0] = 6; // rush from line 6 to line 4
  1823.             move->target[0] = 4;
  1824.             move->color = COLOR_BLACK;
  1825.          }
  1826.          move->source[1] = enpassant_column;
  1827.          move->target[1] = enpassant_column;
  1828.       }
  1829.    }
  1830.  
  1831.    // table was setup correctly, save FEN string in move structure
  1832.    wcscpy_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), fen_string);
  1833.    return (true); // and return TRUE
  1834. }
  1835.  
  1836.  
  1837. bool Move_SetupFromStyle12 (boardmove_t *move, wchar_t *positions, int move_color, int pawnrush_column,
  1838.                             bool can_white_castle_short, bool can_white_castle_long, bool can_black_castle_short, bool can_black_castle_long, wchar_t *pretty_movestring)
  1839. {
  1840.    // this function sets up the given board according to the Style12 ICC/FICS description style12_string makes of it
  1841.  
  1842.    int pos_index;
  1843.    int current_line;
  1844.    int current_column;
  1845.  
  1846.    // reset the chess grid
  1847.    memset (&move->slots, 0, sizeof (move->slots));
  1848.  
  1849.    // now parse the line from left to right, placing parts on the fly
  1850.    for (current_line = 0; current_line < 8; current_line++)
  1851.       for (current_column = 0; current_column < 8; current_column++)
  1852.       {
  1853.          pos_index = (7 - current_line) * 8 + current_column; // compute position in line
  1854.  
  1855.          if (positions[pos_index] == L'r')
  1856.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_ROOK); // black rook
  1857.          else if (positions[pos_index] == L'R')
  1858.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_ROOK); // white rook
  1859.          else if (positions[pos_index] == L'n')
  1860.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KNIGHT); // black knight
  1861.          else if (positions[pos_index] == L'N')
  1862.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KNIGHT); // white knight
  1863.          else if (positions[pos_index] == L'b')
  1864.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_BISHOP); // black bishop
  1865.          else if (positions[pos_index] == L'B')
  1866.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_BISHOP); // white bishop
  1867.          else if (positions[pos_index] == L'q')
  1868.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_QUEEN); // black queen
  1869.          else if (positions[pos_index] == L'Q')
  1870.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_QUEEN); // white queen
  1871.          else if (positions[pos_index] == L'k')
  1872.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KING); // black king
  1873.          else if (positions[pos_index] == L'K')
  1874.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KING); // white king
  1875.          else if (positions[pos_index] == L'p')
  1876.             Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_PAWN); // black pawn
  1877.          else if (positions[pos_index] == L'P')
  1878.             Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_PAWN); // white pawn
  1879.       }
  1880.  
  1881.    // save move color
  1882.    move->color = move_color;
  1883.  
  1884.    // allow or disallow both sides to castle, as told
  1885.    move->sides[COLOR_WHITE].shortcastle_allowed = can_white_castle_short;
  1886.    move->sides[COLOR_WHITE].longcastle_allowed = can_white_castle_long;
  1887.    move->sides[COLOR_BLACK].shortcastle_allowed = can_black_castle_short;
  1888.    move->sides[COLOR_BLACK].longcastle_allowed = can_black_castle_long;
  1889.  
  1890.    // is the last move a pawn rush ?
  1891.    if (pawnrush_column != -1)
  1892.    {
  1893.       if ((pawnrush_column < 0) || (pawnrush_column > 7))
  1894.          return (false); // consistency check: something's wrong with this notation, return FALSE
  1895.  
  1896.       move->part = PART_PAWN;
  1897.       if (move->color == COLOR_WHITE)
  1898.       {
  1899.          move->source[0] = 1; // rush from line 1 to line 3
  1900.          move->target[0] = 3;
  1901.       }
  1902.       else
  1903.       {
  1904.          move->source[0] = 6; // rush from line 6 to line 4
  1905.          move->target[0] = 4;
  1906.       }
  1907.       move->source[1] = pawnrush_column;
  1908.       move->target[1] = pawnrush_column;
  1909.    }
  1910.  
  1911.    // finally, save the FEN string with which we initialized this board
  1912.    Move_DescribeInFEN (move);
  1913.    return (true); // finished, no error encountered
  1914. }
  1915.  
  1916.  
  1917. static bool Move_IsWayClearBetween (boardmove_t *move, int source_line, int source_column, int target_line, int target_column)
  1918. {
  1919.    // helper function that checks and returns whether the way is clear between source and target.
  1920.  
  1921.    int column_delta_step;
  1922.    int line_delta_step;
  1923.    int column_delta;
  1924.    int line_delta;
  1925.    int column;
  1926.    int line;
  1927.  
  1928.    line_delta = target_line - source_line;
  1929.    line_delta_step = (line_delta != 0 ? line_delta / abs (line_delta) : 0);
  1930.    column_delta = target_column - source_column;
  1931.    column_delta_step = (column_delta != 0 ? column_delta / abs (column_delta) : 0);
  1932.  
  1933.    // for each square that's between source and target...
  1934.    for (line = source_line + line_delta_step, column = source_column + column_delta_step;
  1935.         IS_VALID (line, column) && (line != target_line || column != target_column);
  1936.         line += line_delta_step, column += column_delta_step)
  1937.       if ((line == target_line) && (column == target_column))
  1938.          break; // don't verify the target position's square
  1939.       else if (move->slots[line][column].part != PART_NONE)
  1940.          return (false); // there's something in the way...
  1941.  
  1942.    if (!IS_VALID (line, column))
  1943.       return (false); // we've gotten off board...
  1944.  
  1945.    return (true); // the way looks clear between source and target
  1946. }
  1947.  
  1948.  
  1949. static void AddPossibleMove (boardmove_t **possiblemoves, int *possiblemove_count, int color, int part, int source_line, int source_column, int target_line, int target_column, int promotion_type, bool has_captured, bool is_enpassant)
  1950. {
  1951.    // helper function that resizes the given possiblemoves array and adds a possible move to it
  1952.  
  1953.    // TODO: raise or clear the is_check and is_stalemate move flags in the returned move.
  1954.    // Not crucial as this function is only called by Board_FindRandomMove(), the result is then
  1955.    // translated in SAN and then fed to the chess engine to order a blunderous move. The move
  1956.    // is then played normally using Board_AppendMove() using source and target locations, and this
  1957.    // call does evaluate the actual move and set the flags correctly in the final moves array.
  1958.  
  1959.    *possiblemoves = (boardmove_t *) SAFE_realloc (*possiblemoves, *possiblemove_count, (*possiblemove_count) + 1, sizeof (boardmove_t), true);
  1960.    (*possiblemoves)[*possiblemove_count].color = color;
  1961.    (*possiblemoves)[*possiblemove_count].part = part;
  1962.    (*possiblemoves)[*possiblemove_count].source[0] = source_line;
  1963.    (*possiblemoves)[*possiblemove_count].source[1] = source_column;
  1964.    (*possiblemoves)[*possiblemove_count].target[0] = target_line;
  1965.    (*possiblemoves)[*possiblemove_count].target[1] = target_column;
  1966.    (*possiblemoves)[*possiblemove_count].promotion_type = promotion_type;
  1967.    (*possiblemoves)[*possiblemove_count].has_captured = has_captured;
  1968.    (*possiblemoves)[*possiblemove_count].is_enpassant = is_enpassant;
  1969.    (*possiblemove_count)++; // possible moves array holds now one move more
  1970.  
  1971.    return; // finished
  1972. }
  1973.