Games_Chess
[ class tree: Games_Chess ] [ index: Games_Chess ] [ all elements ]

Source for file Standard.php

Documentation is available at Standard.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 2003 The PHP Group                                     |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at                              |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Gregory Beaver <cellog@php.net>                             |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Standard.php,v 1.8 2006/11/18 00:09:20 cellog Exp $
  20. /**
  21.  * A standard chess game representation
  22.  * @package Games_Chess
  23.  * @author Gregory Beaver <cellog@php.net>
  24.  */
  25. /**
  26.  * The parent class
  27.  */
  28. require_once 'Games/Chess.php';
  29.  
  30. /**
  31.  * Standard chess game
  32.  * @package Games_Chess
  33.  * @author Gregory Beaver <cellog@php.net>
  34.  */
  35. class Games_Chess_Standard extends Games_Chess {
  36.     /**
  37.      * The chess pieces
  38.      * @access private
  39.      * @var array 
  40.      */
  41.     var $_pieces;
  42.     
  43.     /**
  44.      * Set up a blank chess board
  45.      */
  46.     function blankBoard()
  47.     {
  48.         parent::blankBoard();
  49.         $this->_pieces =
  50.         array(
  51.             'WR1' => false,
  52.             'WN1' => false,
  53.             'WB1' => false,
  54.             'WQ' => false,
  55.             'WK' => false,
  56.             'WB2' => false,
  57.             'WN2' => false,
  58.             'WR2' => false,
  59.             
  60.             'WP1' => false,
  61.             'WP2' => false,
  62.             'WP3' => false,
  63.             'WP4' => false,
  64.             'WP5' => false,
  65.             'WP6' => false,
  66.             'WP7' => false,
  67.             'WP8' => false,
  68.             
  69.             'BP1' => false,
  70.             'BP2' => false,
  71.             'BP3' => false,
  72.             'BP4' => false,
  73.             'BP5' => false,
  74.             'BP6' => false,
  75.             'BP7' => false,
  76.             'BP8' => false,
  77.             
  78.             'BR1' => false,
  79.             'BN1' => false,
  80.             'BB1' => false,
  81.             'BQ' => false,
  82.             'BK' => false,
  83.             'BB2' => false,
  84.             'BN2' => false,
  85.             'BR2' => false,
  86.         );
  87.     }
  88.  
  89.     /**
  90.      * Set up a starting position for a new chess game
  91.      * @access protected
  92.      */
  93.     function _setupStartingPosition()
  94.     {
  95.         $this->_board = array(
  96. 'a8' => 'BR1''b8' => 'BN1''c8' => 'BB1''d8' => 'BQ''e8' => 'BK''f8' => 'BB2''g8' => 'BN2''h8' => 'BR2',
  97. 'a7' => 'BP1''b7' => 'BP2''c7' => 'BP3''d7' => 'BP4''e7' => 'BP5''f7' => 'BP6''g7' => 'BP7''h7' => 'BP8',
  98. 'a6' => 'a6''b6' => 'b6''c6' => 'c6''d6' => 'd6''e6' => 'e6''f6' => 'f6''g6' => 'g6''h6' => 'h6',
  99. 'a5' => 'a5''b5' => 'b5''c5' => 'c5''d5' => 'd5''e5' => 'e5''f5' => 'f5''g5' => 'g5''h5' => 'h5',
  100. 'a4' => 'a4''b4' => 'b4''c4' => 'c4''d4' => 'd4''e4' => 'e4''f4' => 'f4''g4' => 'g4''h4' => 'h4',
  101. 'a3' => 'a3''b3' => 'b3''c3' => 'c3''d3' => 'd3''e3' => 'e3''f3' => 'f3''g3' => 'g3''h3' => 'h3',
  102. 'a2' => 'WP1''b2' => 'WP2''c2' => 'WP3''d2' => 'WP4''e2' => 'WP5''f2' => 'WP6''g2' => 'WP7''h2' => 'WP8',
  103. 'a1' => 'WR1''b1' => 'WN1''c1' => 'WB1''d1' => 'WQ''e1' => 'WK''f1' => 'WB2''g1' => 'WN2''h1' => 'WR2',
  104.         );
  105.         $this->_halfMoves = 0;
  106.         $this->_moveNumber = 1;
  107.         $this->_move 'W';
  108.         $this->_WCastleQ = true;
  109.         $this->_WCastleK = true;
  110.         $this->_BCastleQ = true;
  111.         $this->_BCastleK = true;
  112.         $this->_enPassantSquare '-';
  113.         $this->_pieces =
  114.         array(
  115.             'WR1' => 'a1',
  116.             'WN1' => 'b1',
  117.             'WB1' => 'c1',
  118.             'WQ' => 'd1',
  119.             'WK' => 'e1',
  120.             'WB2' => 'f1',
  121.             'WN2' => 'g1',
  122.             'WR2' => 'h1',
  123.             
  124.             'WP1' => array('a2''P'),
  125.             'WP2' => array('b2''P'),
  126.             'WP3' => array('c2''P'),
  127.             'WP4' => array('d2''P'),
  128.             'WP5' => array('e2''P'),
  129.             'WP6' => array('f2''P'),
  130.             'WP7' => array('g2''P'),
  131.             'WP8' => array('h2''P'),
  132.             
  133.             'BP1' => array('a7''P'),
  134.             'BP2' => array('b7''P'),
  135.             'BP3' => array('c7''P'),
  136.             'BP4' => array('d7''P'),
  137.             'BP5' => array('e7''P'),
  138.             'BP6' => array('f7''P'),
  139.             'BP7' => array('g7''P'),
  140.             'BP8' => array('h7''P'),
  141.             
  142.             'BR1' => 'a8',
  143.             'BN1' => 'b8',
  144.             'BB1' => 'c8',
  145.             'BQ' => 'd8',
  146.             'BK' => 'e8',
  147.             'BB2' => 'f8',
  148.             'BN2' => 'g8',
  149.             'BR2' => 'h8',
  150.         );
  151.     }
  152.  
  153.     /**
  154.      * Add a piece to the chessboard
  155.      * @param W|Bpiece color
  156.      * @param K|Q|R|N|P|BPiece type
  157.      * @param string [a-h][1-8] algebraic location of piece
  158.      * @return true|PEAR_Error
  159.      * @throws GAMES_CHESS_ERROR_INVALIDSQUARE
  160.      * @throws GAMES_CHESS_ERROR_DUPESQUARE
  161.      * @throws GAMES_CHESS_ERROR_MULTIPIECE
  162.      */
  163.     function addPiece($color$type$square)
  164.     {
  165.         if (!isset($this->_board[$square])) {
  166.             return $this->raiseError(GAMES_CHESS_ERROR_INVALIDSQUARE,
  167.                 array('square' => $square));
  168.         }
  169.         if ($this->_board[$square!= $square{
  170.             $dpiece $this->_board[$square];
  171.             if ($dpiece{1== 'P'{
  172.                 $dpiece $this->_pieces[$dpiece][1];
  173.             else {
  174.                 $dpiece $dpiece{1};
  175.             }
  176.             return $this->raiseError(GAMES_CHESS_ERROR_DUPESQUARE,
  177.                 array('piece' => $type'dpiece' => $dpiece'square' => $square));
  178.         }
  179.         switch ($type{
  180.             case 'B' :
  181.             case 'N' :
  182.             case 'R' :
  183.                 $piece_name $color $type;
  184.                 if (!$this->_pieces[$piece_name '1']{
  185.                     $this->_board[$square$piece_name '1';
  186.                     $this->_pieces[$piece_name '1'$square;
  187.                 elseif (!$this->_pieces[$piece_name '2']{
  188.                     $this->_board[$square$piece_name '2';
  189.                     $this->_pieces[$piece_name '2'$square;
  190.                 else {
  191.                     // handle promoted pawns
  192.                     for ($col = 1; $col <= 8; $col++{
  193.                         if (!$this->_pieces[$color 'P' $col]{
  194.                             $this->_pieces[$color 'P' $col=
  195.                                 array($square$type);
  196.                             $this->_board[$square$color 'P' $col;
  197.                             break 2;
  198.                         }
  199.                     }
  200.                     return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
  201.                         array('color' => $color'piece' => $type));
  202.  
  203.                 }
  204.             break;
  205.             case 'Q' :
  206.                 $piece_name $color 'Q';
  207.                 if (!$this->_pieces[$piece_name]{
  208.                     $this->_board[$square$piece_name;
  209.                     $this->_pieces[$piece_name$square;
  210.                 else {
  211.                     // handle promoted pawns
  212.                     for ($col = 1; $col <= 8; $col++{
  213.                         if (!$this->_pieces[$color 'P' $col]{
  214.                             $this->_pieces[$color 'P' $col=
  215.                                 array($square'Q');
  216.                             $this->_board[$square$color 'P' $col;
  217.                             break 2;
  218.                         }
  219.                     }
  220.                     return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
  221.                         array('color' => $color'piece' => $type));
  222.                 }
  223.             break;
  224.             case 'P' :
  225.                 // handle regular pawns
  226.                 for ($col = 1; $col <= 8; $col++{
  227.                     if (!$this->_pieces[$color 'P' $col]{
  228.                         $this->_pieces[$color 'P' $col=
  229.                             array($square'P');
  230.                         $this->_board[$square$color 'P' $col;
  231.                         break 2;
  232.                     }
  233.                 }
  234.                 return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
  235.                     array('color' => $color'piece' => $type));
  236.             break;
  237.             case 'K' :
  238.                 if (!$this->_pieces[$color 'K']{
  239.                     $this->_pieces[$color 'K'$square;
  240.                     $this->_board[$square$color 'K';
  241.                 else {
  242.                     return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
  243.                         array('color' => $color'piece' => $type));
  244.                 }
  245.             break;
  246.         }
  247.         return true;
  248.     }
  249.     
  250.     /**
  251.      * Generate a representation of the chess board and pieces for use as a
  252.      * direct translation to a visual chess board
  253.      * @return array 
  254.      */
  255.     function toArray()
  256.     {
  257.         $ret = array();
  258.         foreach ($this->_board as $square => $piece{
  259.             if ($piece == $square{
  260.                 $ret[$square= false;
  261.                 continue;
  262.             }
  263.             $lower $piece{0};
  264.             if (is_array($this->_pieces[$piece])) {
  265.                 $piece $this->_pieces[$piece][1];
  266.             else {
  267.                 $piece $piece{1};
  268.             }
  269.             if ($lower == 'B'{
  270.                 $piece strtolower($piece);
  271.             }
  272.             $ret[$square$piece;
  273.         }
  274.         uksort($retarray($this'_sortToArray'));
  275.         return $ret;
  276.     }
  277.     
  278.     /**
  279.      * Sort two algebraic coordinates for easy display by foreach() iteration
  280.      * @param string 
  281.      * @param string 
  282.      * @access private
  283.      */
  284.     function _sortToArray($a$b)
  285.     {
  286.         if ($a == $b{
  287.             return 0;
  288.         }
  289.         if ($a{1== $b{1}{
  290.             return strnatcmp($a{0}$b{0});
  291.         }
  292.         if ($a{0== $b{0}{
  293.             return strnatcmp($b{1}$a{1});
  294.         }
  295.         if ($b{1$a{1}{
  296.             return 1;
  297.         }
  298.         if ($a{1$b{1}{
  299.             return -1;
  300.         }
  301.     }
  302.     
  303.     /**
  304.      * Render the current board position into Forsyth-Edwards Notation
  305.      *
  306.      * This method only renders the board contents, not the castling and other
  307.      * information
  308.      * @return string 
  309.      * @access protected
  310.      */
  311.     function _renderFen()
  312.     {
  313.         $fen '';
  314.         $ws = 0;
  315.         $saverow '8';
  316.         foreach ($this->_board as $square => $piece{
  317.             if ($square{1!= $saverow{
  318.                 // if we have just moved to the next rank,
  319.                 // output any whitespace, and a '/'
  320.                 if ($ws{
  321.                     $fen .= $ws;
  322.                 }
  323.                 $fen .= '/';
  324.                 $ws = 0;
  325.                 $saverow $square{1};
  326.             }
  327.             if ($square == $piece{
  328.                 // increment whitespace - no piece on this square
  329.                 $ws++;
  330.             else {
  331.                 // add any whitespace and reset
  332.                 if ($ws{
  333.                     $fen .= $ws;
  334.                 }
  335.                 $ws = 0;
  336.                 if (is_array($this->_pieces[$piece])) {
  337.                     // add pawns/promoted pawns
  338.                     $p ($piece{0== 'W'$this->_pieces[$piece][1:
  339.                         strtolower($this->_pieces[$piece][1]);
  340.                 else {
  341.                     // add pieces
  342.                     $p ($piece{0== 'W'$piece{1strtolower($piece{1});
  343.                 }
  344.                 $fen .= $p;
  345.             }
  346.         }
  347.         // add any trailing whitespace
  348.         if ($ws{
  349.             $fen .= $ws;
  350.         }
  351.         return $fen;
  352.     }
  353.  
  354.     /**
  355.      * Get the location of every piece on the board of color $color
  356.      * @access protected
  357.      * @param W|Bcolor of pieces to check
  358.      */
  359.     function _getAllPieceLocations($color)
  360.     {
  361.         $ret = array();
  362.         foreach ($this->_pieces as $name => $loc{
  363.             if ($name{0== $color{
  364.                 $where =  (is_array($loc$loc[0$loc);
  365.                 if ($where{
  366.                     $ret[$where;
  367.                 }
  368.             }
  369.         }
  370.         return $ret;
  371.     }
  372.     
  373.     /**
  374.      * Used to determine check
  375.      *
  376.      * Retrieve all of the moves of the pieces matching the color passed in.
  377.      * @param W|B
  378.      * @return array 
  379.      * @access protected
  380.      */
  381.     function _getPossibleChecks($color)
  382.     {
  383.         $ret = array();
  384.         foreach ($this->_pieces as $name => $loc{
  385.             if (!$loc{
  386.                 continue;
  387.             }
  388.             if ($name{0== $color{
  389.                 if ($name{1== 'P'{
  390.                     $ret[$name$this->getPossibleMoves($loc[1]$loc[0]$colorfalse);
  391.                 else {
  392.                     $ret[$name$this->getPossibleMoves($name{1}$loc$colorfalse);
  393.                 }
  394.             }
  395.         }
  396.         return $ret;
  397.     }
  398.     
  399.     /**
  400.      * Determine whether one side's king is in check by the other side's pieces
  401.      * @param W|Bcolor of pieces to determine enemy check
  402.      * @return string|array|falsesquare of checking piece(s) or false
  403.      */
  404.     function inCheck($color)
  405.     {
  406.         $ret = array();
  407.         $king $this->_pieces[$color 'K'];
  408.         $possible $this->_getPossibleChecks($color == 'W' 'B' 'W');
  409.         foreach ($possible as $piece => $squares{
  410.             if (in_array($king$squares)) {
  411.                 $loc $this->_pieces[$piece];
  412.                 $ret[is_array($loc$loc[0$loc;
  413.             }
  414.         }
  415.         if (!count($ret)) {
  416.             return false;
  417.         }
  418.         if (count($ret== 1{
  419.             return $ret[0];
  420.         }
  421.         return $ret;
  422.     }
  423.     
  424.     /**
  425.      * Mark a piece as having been taken.  No validation is performed
  426.      * @param string [a-h][1-8]
  427.      * @access protected
  428.      */
  429.     function _takePiece($piece)
  430.     {
  431.         if (isset($this->_pieces[$this->_board[$piece]])) {
  432.             $this->_pieces[$this->_board[$piece]] = false;
  433.         }
  434.     }
  435.     
  436.     /**
  437.      * Move a piece from one square to another, disregarding any existing pieces
  438.      *
  439.      * {@link _takePiece()} should always be used prior to this method.  No
  440.      * validation is performed
  441.      * @param string [a-h][1-8] square the piece resides on
  442.      * @param string [a-h][1-8] square the piece moves to
  443.      * @param string Piece to promote to if this is a promotion move
  444.      */
  445.     function _movePiece($from$to$promote '')
  446.     {
  447.         if (isset($this->_pieces[$this->_board[$from]])) {
  448.             $newto $this->_pieces[$this->_board[$from]];
  449.             if (is_array($newto)) {
  450.                 $newto[0$to;
  451.                 if ($promote && ($to{1== '8' || $to{1== '1')) {
  452.                     $newto[1$promote;
  453.                 }
  454.             else {
  455.                 $newto $to;
  456.             }
  457.             $this->_pieces[$this->_board[$from]] $newto;
  458.         }
  459.     }
  460.     
  461.     /**
  462.      * Translate an algebraic coordinate into the color and name of a piece,
  463.      * or false if no piece is on that square
  464.      * @return false|arrayFormat array('color' => B|W, 'piece' => P|R|Q|N|K|B)
  465.      * @param string [a-h][1-8]
  466.      * @access protected
  467.      */
  468.     function _squareToPiece($square)
  469.     {
  470.         if ($this->_board[$square!= $square{
  471.             $piece $this->_board[$square];
  472.             if ($piece{1== 'P'{
  473.                 $color $piece{0};
  474.                 $piece $this->_pieces[$piece][1];
  475.             else {
  476.                 $color $piece{0};
  477.                 $piece $piece{1};
  478.             }
  479.             return array('color' => $color'piece' => $piece);
  480.         else {
  481.             return false;
  482.         }
  483.     }
  484.     
  485.     /**
  486.      * Retrieve the locations of all pieces of the same type as $piece
  487.      * @param K|B|N|R|W|P
  488.      * @param W|B
  489.      * @param string [a-h][1-8] optional square of piece to exclude from the listing
  490.      * @access protected
  491.      * @return array 
  492.      */
  493.     function _getAllPieceSquares($piece$color$exclude = null)
  494.     {
  495.         $ret = array();
  496.         foreach ($this->_pieces as $name => $loc{
  497.             if (!$loc{
  498.                 continue;
  499.             }
  500.             if ($name{0!= $color{
  501.                 continue;
  502.             }
  503.             if ($name{1== 'P'{
  504.                 if ($loc[1!= $piece || $loc[0== $exclude{
  505.                     continue;
  506.                 else {
  507.                     $ret[$loc[0];
  508.                     continue;
  509.                 }
  510.             }
  511.             if ($loc == $exclude{
  512.                 continue;
  513.             }
  514.             if ($name{1!= $piece{
  515.                 continue;
  516.             }
  517.             $ret[$loc;
  518.         }
  519.         return $ret;
  520.     }
  521.     
  522.     /**
  523.      * @return string|PEAR_Error
  524.      * @param array contents returned from {@link parent::_parseMove()}
  525.      *               in other words, not array(GAMES_CHESS_PIECEMOVE =>
  526.      *               array('piece' => 'K', ...)), but array('piece' => 'K', ...)
  527.      * @param W|Bcurrent side moving
  528.      */
  529.     function _getSquareFromParsedMove($parsedmove$color = null)
  530.     {
  531.         if (is_null($color)) {
  532.             $color $this->_move;
  533.         }
  534.         switch ($parsedmove['piece']{
  535.             case 'K' :
  536.                 if (in_array($parsedmove['square'],
  537.                     $this->getPossibleKingMoves($this->_pieces[$color 'K']$color))) {
  538.                     return $this->_pieces[$color 'K'];
  539.                 }
  540.             break;
  541.             case 'Q' :
  542.             case 'B' :
  543.             case 'R' :
  544.             case 'N' :
  545.                 if ($parsedmove['disambiguate']{
  546.                     if (strlen($parsedmove['disambiguate']== 2{
  547.                         $square $parsedmove['disambiguate'];
  548.                     elseif (is_numeric($parsedmove['disambiguate'])) {
  549.                         $row $parsedmove['disambiguate'];
  550.                     else {
  551.                         $col $parsedmove['disambiguate'];
  552.                     }
  553.                 else {
  554.                     $others = array();
  555.                     $others $this->_getAllPieceSquares($parsedmove['piece'],
  556.                                                          $color);
  557.                     $disambiguate '';
  558.                     $ambiguous = array();
  559.                     if (count($others)) {
  560.                         foreach ($others as $square{
  561.                             if (in_array($parsedmove['square'],
  562.                                     $this->getPossibleMoves($parsedmove['piece'],
  563.                                                             $square,
  564.                                                             $color))) {
  565.                                 // other pieces can move to this square - need to disambiguate
  566.                                 $ambiguous[$square;
  567.                             }
  568.                         }
  569.                     }
  570.                     if (count($ambiguous> 1{
  571.                         $pieces implode($ambiguous' ');
  572.                         return $this->raiseError(
  573.                             GAMES_CHESS_ERROR_TOO_AMBIGUOUS,
  574.                             array('san' => $parsedmove['piece'.
  575.                                 $parsedmove['disambiguate'$parsedmove['takes']
  576.                                 . $parsedmove['square'],
  577.                                   'squares' => $pieces,
  578.                                   'piece' => $parsedmove['piece']));
  579.                     }
  580.                     $square $col $row = null;
  581.                 }
  582.                 $potentials = array();
  583.                 foreach ($this->_pieces as $name => $value{
  584.                     if (!$value{
  585.                         continue;
  586.                     }
  587.                     if ($name{0!= $color{
  588.                         continue;
  589.                     }
  590.                     if (isset($square)) {
  591.                         if ($name{1== $parsedmove['piece'&&
  592.                               $value[0== $square{
  593.                             return $square;
  594.                         }
  595.                         if ($name{1== 'P' && $value[0== $square &&
  596.                               $value[1== $parsedmove['piece']{
  597.                             return $square;
  598.                         }
  599.                     elseif (isset($col)) {
  600.                         if ($name{1== $parsedmove['piece'&&
  601.                               $value{0== $col{
  602.                             if (in_array($parsedmove['square'],
  603.                                   $this->getPossibleMoves($parsedmove['piece'],
  604.                                                             $value$color))) {
  605.                                 $potentials[$value;
  606.                             }
  607.                         }
  608.                         if ($name{1== 'P' && $value[0]{0== $col &&
  609.                               $value[1== $parsedmove['piece']{
  610.                             if (in_array($parsedmove['square'],
  611.                                   $this->getPossibleMoves($parsedmove['piece'],
  612.                                                             $value[0]$color))) {
  613.                                 $potentials[$value[0];
  614.                             }
  615.                         }
  616.                     elseif (isset($row)) {
  617.                         if ($name{1== $parsedmove['piece'&&
  618.                               $value{1== $row{
  619.                             if (in_array($parsedmove['square'],
  620.                                   $this->getPossibleMoves($parsedmove['piece'],
  621.                                                             $value$color))) {
  622.                                 $potentials[$value;
  623.                             }
  624.                         }
  625.                         if ($name{1== 'P' && $value[0]{1== $row &&
  626.                               $value[1== $parsedmove['piece']{
  627.                             if (in_array($parsedmove['square'],
  628.                                   $this->getPossibleMoves($parsedmove['piece'],
  629.                                                             $value[0]$color))) {
  630.                                 $potentials[$value[0];
  631.                             }
  632.                         }
  633.                     else {
  634.                         if ($name{1== $parsedmove['piece']{
  635.                             if (in_array($parsedmove['square'],
  636.                                   $this->getPossibleMoves($parsedmove['piece'],
  637.                                                             $value$color))) {
  638.                                 $potentials[$value;
  639.                             }
  640.                         elseif ($name{1== 'P' &&
  641.                               $value[1== $parsedmove['piece']{
  642.                             if (in_array($parsedmove['square'],
  643.                                   $this->getPossibleMoves($parsedmove['piece'],
  644.                                                             $value[0]$color))) {
  645.                                 $potentials[$value[0];
  646.                             }
  647.                         }
  648.                     }
  649.                 }
  650.                 if (count($potentials== 1{
  651.                     return $potentials[0];
  652.                 }
  653.             break;
  654.             case 'P' :
  655.                 if ($parsedmove['disambiguate']{
  656.                     $square $parsedmove['disambiguate'$parsedmove['takesfrom'];
  657.                 else {
  658.                     $square = null;
  659.                 }
  660.                 if ($parsedmove['takesfrom']{
  661.                     $col $parsedmove['takesfrom'];
  662.                 else {
  663.                     $col = null;
  664.                 }
  665.                 $potentials = array();
  666.                 foreach ($this->_pieces as $name => $value{
  667.                     if ($name{0!= $color{
  668.                         continue;
  669.                     }
  670.                     if (isset($square)) {
  671.                         if ($name{1== 'P' && $value[0== $square && $value[1== 'P'{
  672.                             return $square;
  673.                         }
  674.                     elseif (isset($col)) {
  675.                         if ($name{1== 'P' && $value[0]{0== $col && $value[1== 'P'{
  676.                             if (in_array($parsedmove['square'],
  677.                                   $this->getPossiblePawnMoves($value[0]$color))) {
  678.                                 $potentials[$value[0];
  679.                             }
  680.                         }
  681.                     else {
  682.                         if ($name{1== 'P' && $value[1== 'P'{
  683.                             if (in_array($parsedmove['square'],
  684.                                   $this->getPossiblePawnMoves($value[0]$color))) {
  685.                                 $potentials[$value[0];
  686.                             }
  687.                         }
  688.                     }
  689.                 }
  690.                 if (count($potentials== 1{
  691.                     return $potentials[0];
  692.                 }
  693.             break;
  694.         }
  695.         if ($parsedmove['piece'== 'P'{
  696.             $san $parsedmove['takesfrom'$parsedmove['takes'$parsedmove['square'];
  697.         else {
  698.             $san $parsedmove['piece'.
  699.                            $parsedmove['disambiguate'$parsedmove['takes'.
  700.                            $parsedmove['square'];
  701.         }
  702.         return $this->raiseError(GAMES_CHESS_ERROR_NOPIECE_CANDOTHAT,
  703.             array('san' => $san,
  704.                   'color' => $color));
  705.     }
  706.  
  707.     /**
  708.      * Get the location of the king
  709.      *
  710.      * assumes valid color input
  711.      * @return false|string
  712.      * @access protected
  713.      */
  714.     function _getKing($color = null)
  715.     {
  716.         if (!is_null($color)) {
  717.             return $this->_pieces[$color 'K'];
  718.         else {
  719.             return $this->_pieces[$this->_move 'K'];
  720.         }
  721.     }
  722.     
  723.     /**
  724.      * Get the location of a piece
  725.      *
  726.      * This does NOT take an algebraic square as the argument, but the contents
  727.      * of _board[algebraic square]
  728.      * @param string 
  729.      * @return string|array
  730.      * @access protected
  731.      */
  732.     function _getPiece($piecename)
  733.     {
  734.         return is_array($this->_pieces[$piecename]?
  735.             $this->_pieces[$piecename][0:
  736.             $this->_pieces[$piecename];
  737.     }
  738.     
  739.     /**
  740.      * Determine whether a piece name is a knight
  741.      *
  742.      * This does NOT take an algebraic square as the argument, but the contents
  743.      * of _board[algebraic square]
  744.      * @param string 
  745.      * @return boolean 
  746.      * @access protected
  747.      */
  748.     function _isKnight($piecename)
  749.     {
  750.         return $piecename{1== 'N' ||
  751.             ($piecename{1== 'P' &&
  752.                 $this->_pieces[$piecename][1== 'N');
  753.     }
  754.     
  755.     /**
  756.      * Determine whether a piece name is a queen
  757.      *
  758.      * This does NOT take an algebraic square as the argument, but the contents
  759.      * of _board[algebraic square]
  760.      * @param string 
  761.      * @return boolean 
  762.      * @access protected
  763.      */
  764.     function _isQueen($piecename)
  765.     {
  766.         return $piecename{1== 'Q' ||
  767.             ($piecename{1== 'P' &&
  768.                 $this->_pieces[$piecename][1== 'Q');
  769.     }
  770.     
  771.     /**
  772.      * Determine whether a piece name is a bishop
  773.      *
  774.      * This does NOT take an algebraic square as the argument, but the contents
  775.      * of _board[algebraic square]
  776.      * @param string 
  777.      * @return boolean 
  778.      * @access protected
  779.      */
  780.     function isBishop($piecename)
  781.     {
  782.         return $piecename{1== 'B' ||
  783.             ($piecename{1== 'P' &&
  784.                 $this->_pieces[$piecename][1== 'B');
  785.     }
  786.     
  787.     /**
  788.      * Determine whether a piece name is a rook
  789.      *
  790.      * This does NOT take an algebraic square as the argument, but the contents
  791.      * of _board[algebraic square]
  792.      * @param string 
  793.      * @return boolean 
  794.      * @access protected
  795.      */
  796.     function isRook($piecename)
  797.     {
  798.         return $piecename{1== 'R' ||
  799.             ($piecename{1== 'P' &&
  800.                 $this->_pieces[$piecename][1== 'R');
  801.     }
  802.     
  803.     /**
  804.      * Determine whether a piece name is a pawn
  805.      *
  806.      * This does NOT take an algebraic square as the argument, but the contents
  807.      * of _board[algebraic square]
  808.      * @param string 
  809.      * @return boolean 
  810.      * @access protected
  811.      */
  812.     function isPawn($piecename)
  813.     {
  814.         return $piecename{1== 'P' &&
  815.                 $this->_pieces[$piecename][1== 'P';
  816.     }
  817.     
  818.     /**
  819.      * Determine whether a piece name is a king
  820.      *
  821.      * This does NOT take an algebraic square as the argument, but the contents
  822.      * of _board[algebraic square]
  823.      * @param string 
  824.      * @return boolean 
  825.      * @access protected
  826.      */
  827.     function isKing($piecename)
  828.     {
  829.         return $piecename{1== 'K';
  830.     }
  831.     
  832.     /**
  833.      * Determine whether it is possible to capture the piece delivering check,
  834.      * or to interpose a piece in between the checking piece and the king
  835.      * @param array squares that will block a checkmate
  836.      * @param W|Bcolor of the side attempting to prevent checkmate
  837.      * @return boolean true if it is possible to remove check
  838.      */
  839.     function _interposeOrCapture($squares$color)
  840.     {
  841.         foreach ($this->_pieces as $name => $value{
  842.             if (!$value{
  843.                 continue;
  844.             }
  845.             if ($name{0!= $color{
  846.                 continue;
  847.             }
  848.             if ($name{1== 'K'{
  849.                 continue;
  850.             }
  851.             if (is_array($value)) {
  852.                 $name $value[1];
  853.                 $value $value[0];
  854.             else {
  855.                 $name $name{1};
  856.             }
  857.             $allmoves $this->getPossibleMoves($name$value$color);
  858.             foreach($squares as $square{
  859.                 if (in_array($square$allmoves)) {
  860.                     // try the move, see if we're still in check
  861.                     // if so, then the piece is pinned and cannot move
  862.                     $this->startTransaction();
  863.                     $this->_move $color;
  864.                     if (!class_exists('PEAR')) {
  865.                         require_once 'PEAR.php';
  866.                     }
  867.                     PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  868.                     $ret $this->moveSquare($value$square);
  869.                     PEAR::popErrorHandling(PEAR_ERROR_RETURN);
  870.                     $this->_move $color;
  871.                     $stillchecked $this->inCheck($color);
  872.                     $this->rollbackTransaction();
  873.                     if (!$stillchecked{
  874.                         return true;
  875.                     }
  876.                 }
  877.             }
  878.         }
  879.         return false;
  880.     }
  881.     
  882.     /**
  883.      * Retrieve the color of a piece from its name
  884.      *
  885.      * Game-specific method of retrieving the color of a piece
  886.      * @access protected
  887.      */
  888.     function _getColor($name)
  889.     {
  890.         return $name{0};
  891.     }
  892.     
  893.     /**
  894.      * Get a list of all pieces on the board organized by the type of piece,
  895.      * and the color of the square the piece is on.
  896.      *
  897.      * Used to determine basic draw conditions
  898.      * @return array Format:
  899.      *
  900.      *  <pre>
  901.      *  array(
  902.      *    // white pieces
  903.      *    'W' => array('B' => array('W', 'B'), // all bishops
  904.      *                 'K' => array('W'),...
  905.      *                ),
  906.      *    // black pieces
  907.      *    'B' => array('Q' => array('B'), // all queens
  908.      *                 'K' => array('W'),... // king is on white square
  909.      *  </pre>
  910.      * @access protected
  911.      */
  912.     function _getPieceTypes()
  913.     {
  914.         $ret = array('W' => array()'B' => array());
  915.         foreach($this->_pieces as $name => $loc{
  916.             if (!$loc{
  917.                 continue;
  918.             }
  919.             $type $name{1};
  920.             if (is_array($loc)) {
  921.                 $type $loc[1];
  922.                 $loc $loc[0];
  923.             }
  924.             $ret[$name{0}][$type][$this->_getDiagonalColor($loc);
  925.         }
  926.         return $ret;
  927.     }
  928. }
  929. ?>

Documentation generated on Sun, 17 Jun 2007 02:01:00 -0400 by phpDocumentor 1.3.2. PEAR Logo Copyright © PHP Group 2004.