Subversion Repositories Games.Chess Giants

Rev

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