Skip to content
Browse files

initial commit

git-svn-id: http://svn.php.net/repository/pear/packages/Games_Chess/trunk@142347 c90b9560-bf6c-de11-be94-00142212c4b1
  • Loading branch information...
1 parent 5890638 commit 3b7772e5f6046f34cee42d55d06f48aea326dd23 Greg Beaver committed
Showing with 11,628 additions and 0 deletions.
  1. +2,173 −0 Chess.php
  2. +914 −0 Chess/Standard.php
  3. +69 −0 LICENSE
  4. +381 −0 examples/HTMLChess.php
  5. BIN examples/images/B.gif
  6. BIN examples/images/K.gif
  7. BIN examples/images/N.gif
  8. BIN examples/images/P.gif
  9. BIN examples/images/Q.gif
  10. BIN examples/images/R.gif
  11. BIN examples/images/blank.gif
  12. BIN examples/images/dark/b.gif
  13. BIN examples/images/dark/blank.gif
  14. BIN examples/images/dark/k.gif
  15. BIN examples/images/dark/n.gif
  16. BIN examples/images/dark/p.gif
  17. BIN examples/images/dark/q.gif
  18. BIN examples/images/dark/r.gif
  19. +172 −0 package.xml
  20. +509 −0 tests/Games_Chess_TestCase_addPiece.php
  21. +79 −0 tests/Games_Chess_TestCase_bugEnPassant.php
  22. +97 −0 tests/Games_Chess_TestCase_bugdxc3.php
  23. +181 −0 tests/Games_Chess_TestCase_bugpromotion.php
  24. +572 −0 tests/Games_Chess_TestCase_convertSquareToSAN.php
  25. +118 −0 tests/Games_Chess_TestCase_getAllPieceLocations.php
  26. +206 −0 tests/Games_Chess_TestCase_getAllPieceSquares.php
  27. +138 −0 tests/Games_Chess_TestCase_getDiagonal.php
  28. +87 −0 tests/Games_Chess_TestCase_getDiagonalColor.php
  29. +110 −0 tests/Games_Chess_TestCase_getKingSquares.php
  30. +142 −0 tests/Games_Chess_TestCase_getKnightSquares.php
  31. +331 −0 tests/Games_Chess_TestCase_getPathToKing.php
  32. +92 −0 tests/Games_Chess_TestCase_getPieceTypes.php
  33. +150 −0 tests/Games_Chess_TestCase_getPossibleBishopMoves.php
  34. +176 −0 tests/Games_Chess_TestCase_getPossibleChecks.php
  35. +151 −0 tests/Games_Chess_TestCase_getPossibleKingMoves.php
  36. +147 −0 tests/Games_Chess_TestCase_getPossibleKnightMoves.php
  37. +194 −0 tests/Games_Chess_TestCase_getPossibleMoves.php
  38. +307 −0 tests/Games_Chess_TestCase_getPossiblePawnMoves.php
  39. +155 −0 tests/Games_Chess_TestCase_getPossibleQueenMoves.php
  40. +151 −0 tests/Games_Chess_TestCase_getPossibleRookMoves.php
  41. +143 −0 tests/Games_Chess_TestCase_getRookSquares.php
  42. +237 −0 tests/Games_Chess_TestCase_getSquareFromParsedMove.php
  43. +196 −0 tests/Games_Chess_TestCase_inBasicDraw.php
  44. +123 −0 tests/Games_Chess_TestCase_inCheck.php
  45. +164 −0 tests/Games_Chess_TestCase_inCheckMate.php
  46. +153 −0 tests/Games_Chess_TestCase_inStaleMate.php
  47. +137 −0 tests/Games_Chess_TestCase_interposeOrCapture.php
  48. +104 −0 tests/Games_Chess_TestCase_moveAlgebraic.php
  49. +109 −0 tests/Games_Chess_TestCase_movePiece.php
  50. +484 −0 tests/Games_Chess_TestCase_moveSAN.php
  51. +454 −0 tests/Games_Chess_TestCase_parseFen.php
  52. +427 −0 tests/Games_Chess_TestCase_parseMove.php
  53. +101 −0 tests/Games_Chess_TestCase_squareToPiece.php
  54. +708 −0 tests/Games_Chess_TestCase_validMove.php
  55. +64 −0 tests/HTML_TestListener.php
  56. +55 −0 tests/TestUnit.php
  57. +65 −0 tests/stylesheet.css
  58. +102 −0 tests/testsuite.php
View
2,173 Chess.php
2,173 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
914 Chess/Standard.php
@@ -0,0 +1,914 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 2003 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available through the world-wide-web at |
+// | http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Gregory Beaver <cellog@php.net> |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+/**
+ * A standard chess game representation
+ * @package Games_Chess
+ * @author Gregory Beaver <cellog@php.net>
+ */
+/**
+ * The parent class
+ */
+require_once 'Games/Chess.php';
+
+/**
+ * Standard chess game
+ * @package Games_Chess
+ * @author Gregory Beaver <cellog@php.net>
+ */
+class Games_Chess_Standard extends Games_Chess {
+ /**
+ * The chess pieces
+ * @access private
+ * @var array
+ */
+ var $_pieces;
+
+ /**
+ * Set up a blank chess board
+ */
+ function blankBoard()
+ {
+ parent::blankBoard();
+ $this->_pieces =
+ array(
+ 'WR1' => false,
+ 'WN1' => false,
+ 'WB1' => false,
+ 'WQ' => false,
+ 'WK' => false,
+ 'WB2' => false,
+ 'WN2' => false,
+ 'WR2' => false,
+
+ 'WP1' => false,
+ 'WP2' => false,
+ 'WP3' => false,
+ 'WP4' => false,
+ 'WP5' => false,
+ 'WP6' => false,
+ 'WP7' => false,
+ 'WP8' => false,
+
+ 'BP1' => false,
+ 'BP2' => false,
+ 'BP3' => false,
+ 'BP4' => false,
+ 'BP5' => false,
+ 'BP6' => false,
+ 'BP7' => false,
+ 'BP8' => false,
+
+ 'BR1' => false,
+ 'BN1' => false,
+ 'BB1' => false,
+ 'BQ' => false,
+ 'BK' => false,
+ 'BB2' => false,
+ 'BN2' => false,
+ 'BR2' => false,
+ );
+ }
+
+ /**
+ * Set up a starting position for a new chess game
+ * @access protected
+ */
+ function _setupStartingPosition()
+ {
+ $this->_board = array(
+'a8' => 'BR1', 'b8' => 'BN1', 'c8' => 'BB1', 'd8' => 'BQ', 'e8' => 'BK', 'f8' => 'BB2', 'g8' => 'BN2', 'h8' => 'BR2',
+'a7' => 'BP1', 'b7' => 'BP2', 'c7' => 'BP3', 'd7' => 'BP4', 'e7' => 'BP5', 'f7' => 'BP6', 'g7' => 'BP7', 'h7' => 'BP8',
+'a6' => 'a6', 'b6' => 'b6', 'c6' => 'c6', 'd6' => 'd6', 'e6' => 'e6', 'f6' => 'f6', 'g6' => 'g6', 'h6' => 'h6',
+'a5' => 'a5', 'b5' => 'b5', 'c5' => 'c5', 'd5' => 'd5', 'e5' => 'e5', 'f5' => 'f5', 'g5' => 'g5', 'h5' => 'h5',
+'a4' => 'a4', 'b4' => 'b4', 'c4' => 'c4', 'd4' => 'd4', 'e4' => 'e4', 'f4' => 'f4', 'g4' => 'g4', 'h4' => 'h4',
+'a3' => 'a3', 'b3' => 'b3', 'c3' => 'c3', 'd3' => 'd3', 'e3' => 'e3', 'f3' => 'f3', 'g3' => 'g3', 'h3' => 'h3',
+'a2' => 'WP1', 'b2' => 'WP2', 'c2' => 'WP3', 'd2' => 'WP4', 'e2' => 'WP5', 'f2' => 'WP6', 'g2' => 'WP7', 'h2' => 'WP8',
+'a1' => 'WR1', 'b1' => 'WN1', 'c1' => 'WB1', 'd1' => 'WQ', 'e1' => 'WK', 'f1' => 'WB2', 'g1' => 'WN2', 'h1' => 'WR2',
+ );
+ $this->_halfMoves = 0;
+ $this->_moveNumber = 1;
+ $this->_move = 'W';
+ $this->_WCastleQ = true;
+ $this->_WCastleK = true;
+ $this->_BCastleQ = true;
+ $this->_BCastleK = true;
+ $this->_enPassantSquare = '-';
+ $this->_pieces =
+ array(
+ 'WR1' => 'a1',
+ 'WN1' => 'b1',
+ 'WB1' => 'c1',
+ 'WQ' => 'd1',
+ 'WK' => 'e1',
+ 'WB2' => 'f1',
+ 'WN2' => 'g1',
+ 'WR2' => 'h1',
+
+ 'WP1' => array('a2', 'P'),
+ 'WP2' => array('b2', 'P'),
+ 'WP3' => array('c2', 'P'),
+ 'WP4' => array('d2', 'P'),
+ 'WP5' => array('e2', 'P'),
+ 'WP6' => array('f2', 'P'),
+ 'WP7' => array('g2', 'P'),
+ 'WP8' => array('h2', 'P'),
+
+ 'BP1' => array('a7', 'P'),
+ 'BP2' => array('b7', 'P'),
+ 'BP3' => array('c7', 'P'),
+ 'BP4' => array('d7', 'P'),
+ 'BP5' => array('e7', 'P'),
+ 'BP6' => array('f7', 'P'),
+ 'BP7' => array('g7', 'P'),
+ 'BP8' => array('h7', 'P'),
+
+ 'BR1' => 'a8',
+ 'BN1' => 'b8',
+ 'BB1' => 'c8',
+ 'BQ' => 'd8',
+ 'BK' => 'e8',
+ 'BB2' => 'f8',
+ 'BN2' => 'g8',
+ 'BR2' => 'h8',
+ );
+ }
+
+ /**
+ * Add a piece to the chessboard
+ * @param W|B piece color
+ * @param K|Q|R|N|P|B Piece type
+ * @param string [a-h][1-8] algebraic location of piece
+ * @return true|PEAR_Error
+ * @throws GAMES_CHESS_ERROR_INVALIDSQUARE
+ * @throws GAMES_CHESS_ERROR_DUPESQUARE
+ * @throws GAMES_CHESS_ERROR_MULTIPIECE
+ */
+ function addPiece($color, $type, $square)
+ {
+ if (!isset($this->_board[$square])) {
+ return $this->raiseError(GAMES_CHESS_ERROR_INVALIDSQUARE,
+ array('square' => $square));
+ }
+ if ($this->_board[$square] != $square) {
+ $dpiece = $this->_board[$square];
+ if ($dpiece{1} == 'P') {
+ $dpiece = $this->_pieces[$dpiece][1];
+ } else {
+ $dpiece = $dpiece{1};
+ }
+ return $this->raiseError(GAMES_CHESS_ERROR_DUPESQUARE,
+ array('piece' => $type, 'dpiece' => $dpiece, 'square' => $square));
+ }
+ switch ($type) {
+ case 'B' :
+ case 'N' :
+ case 'R' :
+ $piece_name = $color . $type;
+ if (!$this->_pieces[$piece_name . '1']) {
+ $this->_board[$square] = $piece_name . '1';
+ $this->_pieces[$piece_name . '1'] = $square;
+ } elseif (!$this->_pieces[$piece_name . '2']) {
+ $this->_board[$square] = $piece_name . '2';
+ $this->_pieces[$piece_name . '2'] = $square;
+ } else {
+ // handle promoted pawns
+ for ($col = 1; $col <= 8; $col++) {
+ if (!$this->_pieces[$color . 'P' . $col]) {
+ $this->_pieces[$color . 'P' . $col] =
+ array($square, $type);
+ $this->_board[$square] = $color . 'P' . $col;
+ break 2;
+ }
+ }
+ return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
+ array('color' => $color, 'piece' => $type));
+
+ }
+ break;
+ case 'Q' :
+ $piece_name = $color . 'Q';
+ if (!$this->_pieces[$piece_name]) {
+ $this->_board[$square] = $piece_name;
+ $this->_pieces[$piece_name] = $square;
+ } else {
+ // handle promoted pawns
+ for ($col = 1; $col <= 8; $col++) {
+ if (!$this->_pieces[$color . 'P' . $col]) {
+ $this->_pieces[$color . 'P' . $col] =
+ array($square, 'Q');
+ $this->_board[$square] = $color . 'P' . $col;
+ break 2;
+ }
+ }
+ return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
+ array('color' => $color, 'piece' => $type));
+ }
+ break;
+ case 'P' :
+ // handle regular pawns
+ for ($col = 1; $col <= 8; $col++) {
+ if (!$this->_pieces[$color . 'P' . $col]) {
+ $this->_pieces[$color . 'P' . $col] =
+ array($square, 'P');
+ $this->_board[$square] = $color . 'P' . $col;
+ break 2;
+ }
+ }
+ return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
+ array('color' => $color, 'piece' => $type));
+ break;
+ case 'K' :
+ if (!$this->_pieces[$color . 'K']) {
+ $this->_pieces[$color . 'K'] = $square;
+ $this->_board[$square] = $color . 'K';
+ } else {
+ return $this->raiseError(GAMES_CHESS_ERROR_MULTIPIECE,
+ array('color' => $color, 'piece' => $type));
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Generate a representation of the chess board and pieces for use as a
+ * direct translation to a visual chess board
+ * @return array
+ */
+ function toArray()
+ {
+ $ret = array();
+ foreach ($this->_board as $square => $piece) {
+ if ($piece == $square) {
+ $ret[$square] = false;
+ continue;
+ }
+ $lower = $piece{0};
+ if (is_array($this->_pieces[$piece])) {
+ $piece = $this->_pieces[$piece][1];
+ } else {
+ $piece = $piece{1};
+ }
+ if ($lower == 'B') {
+ $piece = strtolower($piece);
+ }
+ $ret[$square] = $piece;
+ }
+ uksort($ret, array($this, '_sortToArray'));
+ return $ret;
+ }
+
+ /**
+ * Sort two algebraic coordinates for easy display by foreach() iteration
+ * @param string
+ * @param string
+ * @access private
+ */
+ function _sortToArray($a, $b)
+ {
+ if ($a == $b) {
+ return 0;
+ }
+ if ($a{1} == $b{1}) {
+ return strnatcmp($a{0}, $b{0});
+ }
+ if ($a{0} == $b{0}) {
+ return strnatcmp($b{1}, $a{1});
+ }
+ if ($b{1} > $a{1}) {
+ return 1;
+ }
+ if ($a{1} > $b{1}) {
+ return -1;
+ }
+ }
+
+ /**
+ * Render the current board position into Farnsworth-Edwards Notation
+ *
+ * This method only renders the board contents, not the castling and other
+ * information
+ * @return string
+ * @access protected
+ */
+ function _renderFen()
+ {
+ $fen = '';
+ $ws = 0;
+ $saverow = '8';
+ foreach ($this->_board as $square => $piece) {
+ if ($square{1} != $saverow) {
+ // if we have just moved to the next rank,
+ // output any whitespace, and a '/'
+ if ($ws) {
+ $fen .= $ws;
+ }
+ $fen .= '/';
+ $ws = 0;
+ $saverow = $square{1};
+ }
+ if ($square == $piece) {
+ // increment whitespace - no piece on this square
+ $ws++;
+ } else {
+ // add any whitespace and reset
+ if ($ws) {
+ $fen .= $ws;
+ }
+ $ws = 0;
+ if (is_array($this->_pieces[$piece])) {
+ // add pawns/promoted pawns
+ $p = ($piece{0} == 'W') ? $this->_pieces[$piece][1] :
+ strtolower($this->_pieces[$piece][1]);
+ } else {
+ // add pieces
+ $p = ($piece{0} == 'W') ? $piece{1} : strtolower($piece{1});
+ }
+ $fen .= $p;
+ }
+ }
+ // add any trailing whitespace
+ if ($ws) {
+ $fen .= $ws;
+ }
+ return $fen;
+ }
+
+ /**
+ * Get the location of every piece on the board of color $color
+ * @access protected
+ * @param W|B color of pieces to check
+ */
+ function _getAllPieceLocations($color)
+ {
+ $ret = array();
+ foreach ($this->_pieces as $name => $loc) {
+ if ($name{0} == $color) {
+ $where = (is_array($loc) ? $loc[0] : $loc);
+ if ($where) {
+ $ret[] = $where;
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Used to determine check
+ *
+ * Retrieve all of the moves of the pieces matching the color passed in.
+ * @param W|B
+ * @return array
+ * @access protected
+ */
+ function _getPossibleChecks($color)
+ {
+ $ret = array();
+ foreach ($this->_pieces as $name => $loc) {
+ if (!$loc) {
+ continue;
+ }
+ if ($name{0} == $color) {
+ if ($name{1} == 'P') {
+ $ret[$name] = $this->getPossibleMoves($loc[1], $loc[0], $color);
+ } else {
+ $ret[$name] = $this->getPossibleMoves($name{1}, $loc, $color);
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Determine whether one side's king is in check by the other side's pieces
+ * @param W|B color of pieces to determine enemy check
+ * @return string|array|false square of checking piece(s) or false
+ */
+ function inCheck($color)
+ {
+ $ret = array();
+ $king = $this->_pieces[$color . 'K'];
+ $possible = $this->_getPossibleChecks($color == 'W' ? 'B' : 'W');
+ foreach ($possible as $piece => $squares) {
+ if (in_array($king, $squares)) {
+ $loc = $this->_pieces[$piece];
+ $ret[] = is_array($loc) ? $loc[0] : $loc;
+ }
+ }
+ if (!count($ret)) {
+ return false;
+ }
+ if (count($ret) == 1) {
+ return $ret[0];
+ }
+ return $ret;
+ }
+
+ /**
+ * Mark a piece as having been taken. No validation is performed
+ * @param string [a-h][1-8]
+ * @access protected
+ */
+ function _takePiece($piece)
+ {
+ if (isset($this->_pieces[$this->_board[$piece]])) {
+ $this->_pieces[$this->_board[$piece]] = false;
+ }
+ }
+
+ /**
+ * Move a piece from one square to another, disregarding any existing pieces
+ *
+ * {@link _takePiece()} should always be used prior to this method. No
+ * validation is performed
+ * @param string [a-h][1-8] square the piece resides on
+ * @param string [a-h][1-8] square the piece moves to
+ * @param string Piece to promote to if this is a promotion move
+ */
+ function _movePiece($from, $to, $promote = '')
+ {
+ if (isset($this->_pieces[$this->_board[$from]])) {
+ $newto = $this->_pieces[$this->_board[$from]];
+ if (is_array($newto)) {
+ $newto[0] = $to;
+ if ($to{1} == '8' || $to{1} == '1') {
+ $newto[1] = $promote;
+ }
+ } else {
+ $newto = $to;
+ }
+ $this->_pieces[$this->_board[$from]] = $newto;
+ }
+ }
+
+ /**
+ * Translate an algebraic coordinate into the color and name of a piece,
+ * or false if no piece is on that square
+ * @return false|array Format array('color' => B|W, 'piece' => P|R|Q|N|K|B)
+ * @param string [a-h][1-8]
+ * @access protected
+ */
+ function _squareToPiece($square)
+ {
+ if ($this->_board[$square] != $square) {
+ $piece = $this->_board[$square];
+ if ($piece{1} == 'P') {
+ $color = $piece{0};
+ $piece = $this->_pieces[$piece][1];
+ } else {
+ $color = $piece{0};
+ $piece = $piece{1};
+ }
+ return array('color' => $color, 'piece' => $piece);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Retrieve the locations of all pieces of the same type as $piece
+ * @param K|B|N|R|W|P
+ * @param W|B
+ * @param string [a-h][1-8] optional square of piece to exclude from the listing
+ * @access protected
+ * @return array
+ */
+ function _getAllPieceSquares($piece, $color, $exclude = null)
+ {
+ $ret = array();
+ foreach ($this->_pieces as $name => $loc) {
+ if (!$loc) {
+ continue;
+ }
+ if ($name{0} != $color) {
+ continue;
+ }
+ if ($name{1} == 'P') {
+ if ($loc[1] != $piece || $loc[0] == $exclude) {
+ continue;
+ } else {
+ $ret[] = $loc[0];
+ continue;
+ }
+ }
+ if ($loc == $exclude) {
+ continue;
+ }
+ if ($name{1} != $piece) {
+ continue;
+ }
+ $ret[] = $loc;
+ }
+ return $ret;
+ }
+
+ /**
+ * @return string|PEAR_Error
+ * @param array contents returned from {@link parent::_parseMove()}
+ * in other words, not array(GAMES_CHESS_PIECEMOVE =>
+ * array('piece' => 'K', ...)), but array('piece' => 'K', ...)
+ * @param W|B current side moving
+ */
+ function _getSquareFromParsedMove($parsedmove, $color = null)
+ {
+ if (is_null($color)) {
+ $color = $this->_move;
+ }
+ switch ($parsedmove['piece']) {
+ case 'K' :
+ if (in_array($parsedmove['square'],
+ $this->getPossibleKingMoves($this->_pieces[$color . 'K'], $color))) {
+ return $this->_pieces[$color . 'K'];
+ }
+ break;
+ case 'Q' :
+ case 'B' :
+ case 'R' :
+ case 'N' :
+ if ($parsedmove['disambiguate']) {
+ if (strlen($parsedmove['disambiguate']) == 2) {
+ $square = $parsedmove['disambiguate'];
+ } elseif (is_numeric($parsedmove['disambiguate'])) {
+ $row = $parsedmove['disambiguate'];
+ } else {
+ $col = $parsedmove['disambiguate'];
+ }
+ } else {
+ $others = array();
+ $others = $this->_getAllPieceSquares($parsedmove['piece'],
+ $color);
+ $disambiguate = '';
+ $ambiguous = array();
+ if (count($others)) {
+ foreach ($others as $square) {
+ if (in_array($parsedmove['square'],
+ $this->getPossibleMoves($parsedmove['piece'],
+ $square,
+ $color))) {
+ // other pieces can move to this square - need to disambiguate
+ $ambiguous[] = $square;
+ }
+ }
+ }
+ if (count($ambiguous) > 1) {
+ $pieces = implode($ambiguous, ' ');
+ return $this->raiseError(
+ GAMES_CHESS_ERROR_TOO_AMBIGUOUS,
+ array('san' => $parsedmove['piece'] .
+ $parsedmove['disambiguate'] . $parsedmove['takes']
+ . $parsedmove['square'],
+ 'squares' => $pieces,
+ 'piece' => $parsedmove['piece']));
+ }
+ $square = $col = $row = null;
+ }
+ $potentials = array();
+ foreach ($this->_pieces as $name => $value) {
+ if (!$value) {
+ continue;
+ }
+ if ($name{0} != $color) {
+ continue;
+ }
+ if (isset($square)) {
+ if ($name{1} == $parsedmove['piece'] &&
+ $value[0] == $square) {
+ return $square;
+ }
+ if ($name{1} == 'P' && $value[0] == $square &&
+ $value[1] == $parsedmove['piece']) {
+ return $square;
+ }
+ } elseif (isset($col)) {
+ if ($name{1} == $parsedmove['piece'] &&
+ $value{0} == $col) {
+ if (in_array($parsedmove['square'],
+ $this->getPossibleMoves($parsedmove['piece'],
+ $value, $color))) {
+ $potentials[] = $value;
+ }
+ }
+ if ($name{1} == 'P' && $value[0]{0} == $col &&
+ $value[1] == $parsedmove['piece']) {
+ if (in_array($parsedmove['square'],
+ $this->getPossibleMoves($parsedmove['piece'],
+ $value[0], $color))) {
+ $potentials[] = $value[0];
+ }
+ }
+ } elseif (isset($row)) {
+ if ($name{1} == $parsedmove['piece'] &&
+ $value{1} == $row) {
+ if (in_array($parsedmove['square'],
+ $this->getPossibleMoves($parsedmove['piece'],
+ $value, $color))) {
+ $potentials[] = $value;
+ }
+ }
+ if ($name{1} == 'P' && $value[0]{1} == $row &&
+ $value[1] == $parsedmove['piece']) {
+ if (in_array($parsedmove['square'],
+ $this->getPossibleMoves($parsedmove['piece'],
+ $value[0], $color))) {
+ $potentials[] = $value[0];
+ }
+ }
+ } else {
+ if ($name{1} == $parsedmove['piece']) {
+ if (in_array($parsedmove['square'],
+ $this->getPossibleMoves($parsedmove['piece'],
+ $value, $color))) {
+ $potentials[] = $value;
+ }
+ } elseif ($name{1} == 'P' &&
+ $value[1] == $parsedmove['piece']) {
+ if (in_array($parsedmove['square'],
+ $this->getPossibleMoves($parsedmove['piece'],
+ $value[0], $color))) {
+ $potentials[] = $value[0];
+ }
+ }
+ }
+ }
+ if (count($potentials) == 1) {
+ return $potentials[0];
+ }
+ break;
+ case 'P' :
+ if ($parsedmove['disambiguate']) {
+ $square = $parsedmove['disambiguate'] . $parsedmove['takesfrom'];
+ } else {
+ $square = null;
+ }
+ if ($parsedmove['takesfrom']) {
+ $col = $parsedmove['takesfrom'];
+ } else {
+ $col = null;
+ }
+ $potentials = array();
+ foreach ($this->_pieces as $name => $value) {
+ if ($name{0} != $color) {
+ continue;
+ }
+ if (isset($square)) {
+ if ($name{1} == 'P' && $value[0] == $square && $value[1] == 'P') {
+ return $square;
+ }
+ } elseif (isset($col)) {
+ if ($name{1} == 'P' && $value[0]{0} == $col && $value[1] == 'P') {
+ if (in_array($parsedmove['square'],
+ $this->getPossiblePawnMoves($value[0], $color))) {
+ $potentials[] = $value[0];
+ }
+ }
+ } else {
+ if ($name{1} == 'P' && $value[1] == 'P') {
+ if (in_array($parsedmove['square'],
+ $this->getPossiblePawnMoves($value[0], $color))) {
+ $potentials[] = $value[0];
+ }
+ }
+ }
+ }
+ if (count($potentials) == 1) {
+ return $potentials[0];
+ }
+ break;
+ }
+ if ($parsedmove['piece'] == 'P') {
+ $san = $parsedmove['takesfrom'] . $parsedmove['takes'] . $parsedmove['square'];
+ } else {
+ $san = $parsedmove['piece'] .
+ $parsedmove['disambiguate'] . $parsedmove['takes'] .
+ $parsedmove['square'];
+ }
+ return $this->raiseError(GAMES_CHESS_ERROR_NOPIECE_CANDOTHAT,
+ array('san' => $san,
+ 'color' => $color));
+ }
+
+ /**
+ * Get the location of the king
+ *
+ * assumes valid color input
+ * @return false|string
+ * @access protected
+ */
+ function _getKing($color = null)
+ {
+ if (!is_null($color)) {
+ return $this->_pieces[$color . 'K'];
+ } else {
+ return $this->_pieces[$this->_move . 'K'];
+ }
+ }
+
+ /**
+ * Get the location of a piece
+ *
+ * This does NOT take an algebraic square as the argument, but the contents
+ * of _board[algebraic square]
+ * @param string
+ * @return string|array
+ * @access protected
+ */
+ function _getPiece($piecename)
+ {
+ return is_array($this->_pieces[$piecename]) ?
+ $this->_pieces[$piecename][0] :
+ $this->_pieces[$piecename];
+ }
+
+ /**
+ * Determine whether a piece name is a knight
+ *
+ * This does NOT take an algebraic square as the argument, but the contents
+ * of _board[algebraic square]
+ * @param string
+ * @return boolean
+ * @access protected
+ */
+ function _isKnight($piecename)
+ {
+ return $piecename{1} == 'N' ||
+ ($piecename{1} == 'P' &&
+ $this->_pieces[$piecename][1] == 'N');
+ }
+
+ /**
+ * Determine whether a piece name is a queen
+ *
+ * This does NOT take an algebraic square as the argument, but the contents
+ * of _board[algebraic square]
+ * @param string
+ * @return boolean
+ * @access protected
+ */
+ function _isQueen($piecename)
+ {
+ return $piecename{1} == 'Q' ||
+ ($piecename{1} == 'P' &&
+ $this->_pieces[$piecename][1] == 'Q');
+ }
+
+ /**
+ * Determine whether a piece name is a bishop
+ *
+ * This does NOT take an algebraic square as the argument, but the contents
+ * of _board[algebraic square]
+ * @param string
+ * @return boolean
+ * @access protected
+ */
+ function isBishop($piecename)
+ {
+ return $piecename{1} == 'B' ||
+ ($piecename{1} == 'P' &&
+ $this->_pieces[$piecename][1] == 'B');
+ }
+
+ /**
+ * Determine whether a piece name is a rook
+ *
+ * This does NOT take an algebraic square as the argument, but the contents
+ * of _board[algebraic square]
+ * @param string
+ * @return boolean
+ * @access protected
+ */
+ function isRook($piecename)
+ {
+ return $piecename{1} == 'R' ||
+ ($piecename{1} == 'P' &&
+ $this->_pieces[$piecename][1] == 'R');
+ }
+
+ /**
+ * Determine whether a piece name is a pawn
+ *
+ * This does NOT take an algebraic square as the argument, but the contents
+ * of _board[algebraic square]
+ * @param string
+ * @return boolean
+ * @access protected
+ */
+ function isPawn($piecename)
+ {
+ return $piecename{1} == 'P' &&
+ $this->_pieces[$piecename][1] == 'P';
+ }
+
+ /**
+ * Determine whether a piece name is a king
+ *
+ * This does NOT take an algebraic square as the argument, but the contents
+ * of _board[algebraic square]
+ * @param string
+ * @return boolean
+ * @access protected
+ */
+ function isKing($piecename)
+ {
+ return $piecename{1} == 'K';
+ }
+
+ /**
+ * Determine whether it is possible to capture the piece delivering check,
+ * or to interpose a piece in between the checking piece and the king
+ * @param array squares that will block a checkmate
+ * @param W|B color of the side attempting to prevent checkmate
+ * @return boolean true if it is possible to remove check
+ */
+ function _interposeOrCapture($squares, $color)
+ {
+ foreach ($this->_pieces as $name => $value) {
+ if (!$value) {
+ continue;
+ }
+ if ($name{0} != $color) {
+ continue;
+ }
+ if ($name{1} == 'K') {
+ continue;
+ }
+ if (is_array($value)) {
+ $name = $value[1];
+ $value = $value[0];
+ } else {
+ $name = $name{1};
+ }
+ $allmoves = $this->getPossibleMoves($name, $value, $color);
+ foreach($squares as $square) {
+ if (in_array($square, $allmoves)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the color of a piece from its name
+ *
+ * Game-specific method of retrieving the color of a piece
+ * @access protected
+ */
+ function _getColor($name)
+ {
+ return $name{0};
+ }
+
+ /**
+ * Get a list of all pieces on the board organized by the type of piece,
+ * and the color of the square the piece is on.
+ *
+ * Used to determine basic draw conditions
+ * @return array Format:
+ *
+ * <pre>
+ * array(
+ * // white pieces
+ * 'W' => array('B' => array('W', 'B'), // all bishops
+ * 'K' => array('W'),...
+ * ),
+ * // black pieces
+ * 'B' => array('Q' => array('B'), // all queens
+ * 'K' => array('W'),... // king is on white square
+ * </pre>
+ * @access protected
+ */
+ function _getPieceTypes()
+ {
+ $ret = array('W' => array(), 'B' => array());
+ foreach($this->_pieces as $name => $loc) {
+ if (!$loc) {
+ continue;
+ }
+ $type = $name{1};
+ if (is_array($loc)) {
+ $type = $loc[1];
+ $loc = $loc[0];
+ }
+ $ret[$name{0}][$type][] = $this->_getDiagonalColor($loc);
+ }
+ return $ret;
+ }
+}
+?>
View
69 LICENSE
@@ -0,0 +1,69 @@
+--------------------------------------------------------------------
+ The PHP License, version 3.0
+Copyright (c) 1999 - 2003 The PHP Group. All rights reserved.
+--------------------------------------------------------------------
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ 3. The name "PHP" must not be used to endorse or promote products
+ derived from this software without prior written permission. For
+ written permission, please contact group@php.net.
+
+ 4. Products derived from this software may not be called "PHP", nor
+ may "PHP" appear in their name, without prior written permission
+ from group@php.net. You may indicate that your software works in
+ conjunction with PHP by saying "Foo for PHP" instead of calling
+ it "PHP Foo" or "phpfoo"
+
+ 5. The PHP Group may publish revised and/or new versions of the
+ license from time to time. Each version will be given a
+ distinguishing version number.
+ Once covered code has been published under a particular version
+ of the license, you may always continue to use it under the terms
+ of that version. You may also choose to use such covered code
+ under the terms of any subsequent version of the license
+ published by the PHP Group. No one other than the PHP Group has
+ the right to modify the terms applicable to covered code created
+ under this License.
+
+ 6. Redistributions of any form whatsoever must retain the following
+ acknowledgment:
+ "This product includes PHP, freely available from
+ <http://www.php.net/>".
+
+THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
+ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
+DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------
+
+This software consists of voluntary contributions made by many
+individuals on behalf of the PHP Group.
+
+The PHP Group can be contacted via Email at group@php.net.
+
+For more information on the PHP Group and the PHP project,
+please see <http://www.php.net>.
+
+This product includes the Zend Engine, freely available at
+<http://www.zend.com>.
+
View
381 examples/HTMLChess.php
@@ -0,0 +1,381 @@
+<?php
+require_once 'Games/Chess/Standard.php';
+
+// hack control
+if (!isset($_GET['start']) || !is_string($_GET['start'])) {
+ $_GET['start'] = '';
+}
+if (strlen($_GET['start']) != 2) {
+ $_GET['start'] = '';
+} elseif ($_GET['start'] != '' && !preg_match('/[a-h][1-8]/', $_GET['start'])) {
+ $_GET['start'] = '';
+}
+
+if (!isset($_GET['goto']) || !is_string($_GET['goto'])) {
+ $_GET['goto'] = '';
+} elseif (strlen($_GET['goto']) != 2) {
+ $_GET['goto'] = '';
+} elseif (!preg_match('/[a-h][1-8]/', $_GET['goto'])) {
+ $_GET['goto'] = '';
+}
+
+if (!empty($_GET['promote']) && !in_array($_GET['promote'], array('Q', 'R',
+ 'N', 'B'))) {
+ $_GET['promote'] = 'Q';
+}
+/**
+* Creates the game and maintains persistence through sessions
+* Call this at the top of the webpage
+* @param string name of the session containing the current game
+* @param string name of the game variable (a {@link visualboard} class)
+*/
+function setup_game($session_id, $gamename)
+{
+ session_name($session_id);
+ session_start();
+ if (isset($_GET['newgame'])) {
+ session_destroy();
+ }
+ session_name($session_id);
+ session_start();
+ session_register($gamename);
+}
+
+/**
+ * The primary class - declare one of these at the top of the file
+ *
+ * Do it like this:
+ *
+ * <code>
+ * setup_game('mygame','x');
+ * $x = $_SESSION['x'];
+ * if (!isset($x)) $x = new visualboard;
+ * </code>
+ * @author Greg Beaver <cellog@users.sourceforge.net>
+ * @copyright Copyright 2002, Greg Beaver
+ * @version 1.0
+ */
+class visualboard
+{
+ /**
+ * The logical board
+ * @var Games_Chess
+ */
+ var $_board;
+ /**
+ * Promotion contents
+ * @var false|array
+ */
+ var $promote = false;
+
+ /**
+ * Initializes {@link $moves, $board}
+ */
+ function visualboard($fen = false)
+ {
+ $this->_board = new Games_Chess_Standard;
+ $this->_board->resetGame($fen);
+ }
+
+ /**
+ * Prints javascript for the function addmove:
+ * {@source}
+ */
+ function javascript()
+ {?>
+<script language="JavaScript" type="text/javascript">
+<!--
+function addMove(move)
+{
+ if (document.forms[0].start.value == '')
+ document.forms[0].start.value = move;
+ else
+ {
+ if (document.forms[0]["goto"].value == '')
+ {
+ document.forms[0]["goto"].value = move;
+ if (confirm("Do this move?"))
+ {
+ document.forms[0].submit();
+ }
+ }
+ }
+}
+//-->
+</script>
+<?php
+ }
+
+ /**
+ * Grabs the next move from form variables start, goto, kingcastle and queencastle
+ *
+ * If $_GET['start'] is not used, it checks for $_GET['kingcastle'] and tries
+ * to castle kingside if found. Otherwise, it looks for $_GET['queencastle']
+ * and tries to castle queenside
+ */
+ function domove()
+ {
+ if (!empty($_GET['from']) && !empty($_GET['to']) && !empty($_GET['promote'])) {
+ $err = $this->_board->moveSquare($_GET['from'], $_GET['to'],
+ $_GET['promote']);
+ if ($this->_board->isError($err)) {
+ echo '<b>' .$err->getMessage() . '</b><br />';
+ }
+ $this->promote = false;
+ return;
+ }
+ if (!empty($_GET['SAN'])) {
+ $err = $this->_board->moveSAN($_GET['SAN']);
+ if ($this->_board->isError($err)) {
+ echo '<b>' .$err->getMessage() . '</b><br />';
+ }
+ return;
+ }
+ if (!empty($_GET['start']) && !empty($_GET['goto'])) {
+ if ($this->_board->isPromoteMove($_GET['start'], $_GET['goto'])) {
+ $this->promote = array($_GET['start'], $_GET['goto']);
+ return;
+ } else {
+ $this->promote = false;
+ }
+ $err = $this->_board->moveSquare($_GET['start'], $_GET['goto']);
+ if ($this->_board->isError($err)) {
+ echo '<b>' .$err->getMessage() . '</b><br />';
+ }
+ } elseif (isset($_GET['kingcastle'])) {
+ $err = $this->_board->moveSAN('O-O');
+ if ($this->_board->isError($err)) {
+ echo '<b>' .$err->getMessage() . '</b><br />';
+ }
+ } elseif (isset($_GET['queencastle'])) {
+ $err = $this->_board->moveSAN('O-O-O');
+ if ($this->_board->isError($err)) {
+ echo '<b>' .$err->getMessage() . '</b><br />';
+ }
+ }
+ }
+
+ /**
+ * This function prints the javascript that will ask the user what to promote the pawn to
+ *
+ * Using the alert() function, this method asks the user if they want a queen.
+ * If they click Cancel, it asks if they want a rook, then knight, then
+ * bishop. If they cancel on bishop, it promotes to queen
+ * to avoid any illogical possibilities
+ */
+ function dopromote()
+ {
+ ?>
+<form action="<?php echo $_SERVER['PHP_SELF'].'?'.session_name().'='.session_id() ?>" name="chess" id="chess">
+<input type="hidden" name="promote" value=""><input type="hidden" name="from" value="">
+<input type="hidden" name="to" value="">
+<input type="submit" name="newmove" value="New move"></form>
+<script language="JavaScript" type="text/javascript">
+<!--
+
+function promote(from, to)
+{
+ document.forms[0].from.value = from;
+ document.forms[0].to.value = to;
+ if (confirm("promote to Queen?"))
+ {
+ document.forms[0].promote.value = 'Q';
+ document.forms[0].submit();
+ } else
+ {
+ if (confirm("promote to Rook?"))
+ {
+ document.forms[0].promote.value = 'R';
+ document.forms[0].submit();
+ } else
+ {
+ if (confirm("promote to Knight?"))
+ {
+ document.forms[0].promote.value = 'N';
+ document.forms[0].submit();
+ } else
+ {
+ if (confirm("promote to Bishop?"))
+ {
+ document.forms[0].promote.value = 'B';
+ document.forms[0].submit();
+ } else
+ {
+ document.forms[0].promote.value = 'Q';
+ document.forms[0].submit();
+ }
+ }
+ }
+ }
+}
+promote('<?php print $this->promote[0] . "', '" . $this->promote[1]; ?>');
+//-->
+</script>
+<?php
+ }
+
+ /**
+ * Print out the chess game in its entirety: the board, move list and control buttons
+ *
+ * first, it checks for a pawn promotion and adds the promote move to {@link $moves} using
+ * {@link game::addpromote()}. Then it moves the next piece by calling {@link domove()}.
+ * Then it checks for stalemate and checkmate, and stops the gameplay if either condition is met.
+ * It creates a visual representation of the board using {@link abstractboard::createrows()}, and
+ * displays the chessboard by linking together the display of each row on the chessboard using
+ * {@link row::draw()}, and finally the movelist using {@link game::draw()}
+ */
+ function draw()
+ {
+ $this->domove();
+ if ($this->promote)
+ {
+ return $this->dopromote();
+ }
+ $board = $this->_board->toArray();
+ $checkmate = $this->_board->inCheckmate();
+ $fen = $this->_board->renderFen();
+ $colors = array('#999933', '#FFFFFF');
+ $textcolors = array('#FFFFFF', '#000000');
+ $cycle = 0;
+ if (!$checkmate) $this->javascript();
+ echo '<table border="1">';
+ $imagepath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'images';
+ foreach($board as $square => $piece) {
+ if ($square{0} == 'a') {
+ echo '<tr>';
+ $cycle = ($cycle + 1) % 2;
+ }
+ echo '<td width="30" bgcolor="' .$colors[$cycle]. '"><font color="' .$textcolors[$cycle]. '">';
+ echo "<a href=\"#\" onClick=\"addMove('$square');return false;" .
+ "\" id=\"$square\">";
+
+
+ if ($piece) {
+ if (file_exists($imagepath . '/' . strtoupper($piece) . '.gif')) {
+ if ($piece != strtoupper($piece)) {
+ $image = 'dark/' . $piece . '.gif';
+ } else {
+ $image = $piece . '.gif';
+ }
+ $imgsize = GetImageSize($imagepath . DIRECTORY_SEPARATOR . $image);
+ echo '<img src="images/' . $image . '" border="0" width="' . $imgsize[0] .
+ '" height="' . $imgsize[1] . '" alt="'. $piece . '">';
+ } else {
+ echo $piece;
+ }
+ } else {
+ if (file_exists($imagepath . '/blank.gif')) {
+ if ($this->_board->getDiagonalColor($square) == 'W') {
+ $image = 'blank.gif';
+ } else {
+ $image = 'dark/blank.gif';
+ }
+ $imgsize = GetImageSize($imagepath . DIRECTORY_SEPARATOR . $image);
+ echo '<img src="images/' . $image . '" border="0" width="' . $imgsize[0] .
+ '" height="' . $imgsize[1] . '" alt="'. $piece . '">';
+ } else {
+ echo '&nbsp;';
+ }
+ }
+ echo '</a>';
+ echo '</font></td>';
+ if ($square{0} == 'h') {
+ echo '</tr>';
+ }
+ $cycle = ($cycle + 1) % 2;
+ }
+ echo '</table>';
+
+ if ($stalemate = $this->_board->inStalemate())
+ {
+ print "<h1>STALEMATE</h1>";
+ } elseif ($draw = $this->_board->inDraw())
+ {
+ print "<h1>DRAW</h1>";
+ }
+ if ($this->_board->inCheckmate())
+ {
+ print "<h1>CHECKMATE!</h1>";
+ }
+
+ $side = ($this->_board->toMove() == 'W') ? 'White' : 'Black';
+?><form action="<?php echo $_SERVER['PHP_SELF'].'?'.session_name().'='.session_id() ?>" name="chess" id="chess">
+<?php if (!$checkmate && !$stalemate && !$draw) { echo "<b>{$side} to move</b><br>";
+ ?>
+from <input type="text" name="start" size="2" maxlength="2"> to <input type="text" name="goto" size="2" maxlength="2">
+<input type="submit" name="newmove" value="New move"><br>
+(alternate) SAN move: <input type="text" name="SAN" size="5"><br>
+Reset with new FEN: <input type="text" name="FEN" size="70"><br>
+<br><input type="reset"><br>
+<?php $this->castlebutton(); } ?><br><br>
+
+<input type="submit" name="newgame" value="New Game"></form><?php if (!$checkmate && !$stalemate && !$draw) { ?>
+for a friend to join, click here <a href="mailto:example@example.com?Subject=Join my chess game!&Body=<?php
+echo htmlentities("go to <a href=\"http://" . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] .
+"?mygame=".session_id()."\">Here</a> to play me in chess! http://$_SERVER[SERVER_NAME]$_SERVER[PHP_SELF]?mygame=" .
+session_id()); ?>">Email my friend</a>
+
+<form action="<?php echo $_SERVER['PHP_SELF'].'?'.session_name().'='.session_id() ?>">
+<input type="submit" value="Check to see if opponent has moved"></form>
+<?php }
+
+ echo "<blockquote>Current position FEN: <strong>$fen</strong></blockquote>";
+ $moves = $this->_board->getMoveList();
+ echo '<table border="1"><th colspan="3" align="center">Moves</th><tr>' .
+ '<td>#</td><td>White</td><td>Black</td></tr>';
+ foreach($moves as $num => $moveset) {
+ echo '<tr>';
+ echo "<td>$num</td>";
+ if (isset($moveset[0])) {
+ echo "<td>$moveset[0]</td>";
+ } else {
+ echo "<td>&nbsp;</td>";
+ }
+
+ if (isset($moveset[1])) {
+ echo "<td>$moveset[1]</td>";
+ }
+ echo '</tr>';
+ }
+ echo '</table>';
+ }
+
+ /**
+ * Prints the castling buttons after checking castling rights
+ *
+ * If castling rights have been taken away by a king or rook move, the button is not displayed. This function
+ * uses {@link Games_Chess::canCastleKingside(), Games_Chess::canCastleQueenside()} to find out.
+ */
+ function castlebutton()
+ {
+ if ($this->_board->canCastleKingside())
+ echo '<input type="submit" name="kingcastle" value="Castle Your King Kingside">';
+ if ($this->_board->canCastleQueenside())
+ echo '<input type="submit" name="queencastle" value="Castle Your King Queenside">';
+ }
+}
+
+setup_game('mygame','x');
+$x = $_SESSION['x'];
+$fen = isset($_GET['FEN']) ? $_GET['FEN'] : false;
+if (!isset($x) || isset($_GET['newgame']) || $fen) $x = new visualboard($fen);
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+<head>
+ <title>PHP Chess!</title>
+</head>
+
+<body>
+<h1>Welcome to <a href="http://www.chiaraquartet.net">The Chiara Quartet's</a> PHP Chess</h1>
+<?php
+$x->draw();
+$_SESSION['x'] = $x;
+?>
+
+
+</body>
+</html>
+
+
View
BIN examples/images/B.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/K.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/N.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/P.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/Q.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/R.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/blank.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/dark/b.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/dark/blank.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/dark/k.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/dark/n.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/dark/p.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/dark/q.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN examples/images/dark/r.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
172 package.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
+<package version="1.0">
+ <name>Games_Chess</name>
+ <summary>Construct and validate a logical chess game, does not display</summary>
+ <description>The logic of handling a chessboard and parsing standard
+FEN (Farnsworth-Edwards Notation) for describing a position as well as SAN
+(Standard Algebraic Notation) for describing individual moves is handled. This
+class can be used as a backend driver for playing chess, or for validating
+and/or creating PGN files using the File_ChessPGN package.
+
+Although this package is alpha, it is fully unit-tested. The code works, but
+the API is fluid, and may change dramatically as it is put into use and better
+ways are found to use it. When the API stabilizes, the stability will increase.</description>
+ <maintainers>
+ <maintainer>
+ <user>cellog</user>
+ <name>Greg Beaver</name>
+ <email>cellog@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ </maintainers>
+ <release>
+ <version>0.3</version>
+ <date>2003-10-09</date>
+ <license>PHP License</license>
+ <state>alpha</state>
+ <notes>Fixed a few bugs:
+
+- example works in Mozilla now
+- promotion was endless loop in example
+- promotion didn't change the pawn to the promoted piece</notes>
+ <deps>
+ <dep type="php" rel="ge" version="4.2.0" optional="no"/>
+ </deps>
+ <provides type="class" name="Games_Chess_Standard" extends="Games_Chess" />
+ <provides type="function" name="Games_Chess_Standard::blankBoard" />
+ <provides type="function" name="Games_Chess_Standard::addPiece" />
+ <provides type="function" name="Games_Chess_Standard::toArray" />
+ <provides type="function" name="Games_Chess_Standard::inCheck" />
+ <provides type="function" name="Games_Chess_Standard::isBishop" />
+ <provides type="function" name="Games_Chess_Standard::isRook" />
+ <provides type="function" name="Games_Chess_Standard::isPawn" />
+ <provides type="function" name="Games_Chess_Standard::isKing" />
+ <provides type="class" name="Games_Chess" />
+ <provides type="function" name="Games_Chess::blankBoard" />
+ <provides type="function" name="Games_Chess::resetGame" />
+ <provides type="function" name="Games_Chess::moveSAN" />
+ <provides type="function" name="Games_Chess::moveSquare" />
+ <provides type="function" name="Games_Chess::getMoveList" />
+ <provides type="function" name="Games_Chess::inCheckMate" />
+ <provides type="function" name="Games_Chess::inStaleMate" />
+ <provides type="function" name="Games_Chess::inDraw" />
+ <provides type="function" name="Games_Chess::inRepetitionDraw" />
+ <provides type="function" name="Games_Chess::in50MoveDraw" />
+ <provides type="function" name="Games_Chess::inBasicDraw" />
+ <provides type="function" name="Games_Chess::renderFen" />
+ <provides type="function" name="Games_Chess::addPiece" />
+ <provides type="function" name="Games_Chess::toArray" />
+ <provides type="function" name="Games_Chess::isPromoteMove" />
+ <provides type="function" name="Games_Chess::toMove" />
+ <provides type="function" name="Games_Chess::canCastleKingside" />
+ <provides type="function" name="Games_Chess::canCastleQueenside" />
+ <provides type="function" name="Games_Chess::getPossibleMoves" />
+ <provides type="function" name="Games_Chess::getPieceLocations" />
+ <provides type="function" name="Games_Chess::getPossibleKnightMoves" />
+ <provides type="function" name="Games_Chess::getPossibleBishopMoves" />
+ <provides type="function" name="Games_Chess::getPossibleRookMoves" />
+ <provides type="function" name="Games_Chess::getPossibleQueenMoves" />
+ <provides type="function" name="Games_Chess::getPossiblePawnMoves" />
+ <provides type="function" name="Games_Chess::getPossibleKingMoves" />
+ <provides type="function" name="Games_Chess::getDiagonalColor" />
+ <provides type="function" name="Games_Chess::raiseError" />
+ <provides type="function" name="Games_Chess::getMessage" />
+ <provides type="function" name="Games_Chess::isError" />
+ <provides type="function" name="Games_Chess::startTransaction" />
+ <provides type="function" name="Games_Chess::commitTransaction" />
+ <provides type="function" name="Games_Chess::rollbackTransaction" />
+ <filelist>
+ <file role="php" baseinstalldir="Games" md5sum="b0f33976a66ffe3ce56b13d676120bdb" name="Chess/Standard.php"/>
+ <file role="data" baseinstalldir="Games" md5sum="b61133218ad94b329fe2bae6bbc1dfd0" name="examples/HTMLChess.php"/>
+ <file role="data" baseinstalldir="Games" md5sum="a847ef7d029f5f9c608fa5166268437d" name="examples/images/B.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="c9ee061f36289f8faca053b5d9064562" name="examples/images/blank.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="41b6871dd5591a3ecb235fc6720a1818" name="examples/images/K.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="1713880fd9cbc1b5c28ebfc049c47c1f" name="examples/images/N.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="e8dde345f489a7d3c5a76f018a94ba00" name="examples/images/P.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="3334b0e912084403dcf79fee727e62ca" name="examples/images/Q.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="f63487caff4a223b13fdab4384270b53" name="examples/images/R.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="8f9dd9b5e11b0d99673c3a08b26cab17" name="examples/images/dark/b.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="c9ee061f36289f8faca053b5d9064562" name="examples/images/dark/blank.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="ab32ae187ffe55910de5adaf895bcba4" name="examples/images/dark/k.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="e3dd0206913f96a83771b5c40bdfe0fd" name="examples/images/dark/n.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="f43c43879224759e27d4283c0eb9c5ff" name="examples/images/dark/p.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="a5ab27171a3346b17ff59e05876234b4" name="examples/images/dark/q.gif"/>
+ <file role="data" baseinstalldir="Games" md5sum="ab04b1a7cbdbf94a25d2f1e778963225" name="examples/images/dark/r.gif"/>
+ <file role="test" baseinstalldir="Games" md5sum="dbe2b883686266a921ed5aa95fca4fb7" name="tests/Games_Chess_TestCase_addPiece.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="30231b4d643f818e5f0ead01371b7d8f" name="tests/Games_Chess_TestCase_bugdxc3.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="a9bcaa43e5ba76decb4261e28cc50bd0" name="tests/Games_Chess_TestCase_bugEnPassant.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="90e03398c85fa6ffb4c261ebb0053d82" name="tests/Games_Chess_TestCase_bugpromotion.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="fe04c3bf4ba73de3ab3e26ed0ad72399" name="tests/Games_Chess_TestCase_convertSquareToSAN.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="446933f068d59ee06211ca03d5ee17fd" name="tests/Games_Chess_TestCase_getAllPieceLocations.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="da6198dd89ad23323699ad754ce2f21e" name="tests/Games_Chess_TestCase_getAllPieceSquares.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="b48ca050375a6da62047f1bfde9bb178" name="tests/Games_Chess_TestCase_getDiagonal.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="2f7334000c8300a398fba346f66870fa" name="tests/Games_Chess_TestCase_getDiagonalColor.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="a283ed506f61ee73e1accb534a6dfdfe" name="tests/Games_Chess_TestCase_getKingSquares.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="bbdc2a5bb2112fbb66efb9ec7438ee37" name="tests/Games_Chess_TestCase_getKnightSquares.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="57b4550d312be4f791284b03d45dc1c1" name="tests/Games_Chess_TestCase_getPathToKing.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="9b7700cd2d996c1e7bcfd40d99f87f46" name="tests/Games_Chess_TestCase_getPieceTypes.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="02e355d9c8401238bf13c50d01bda2a5" name="tests/Games_Chess_TestCase_getPossibleBishopMoves.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="737aad18a9d45e90d713d428ecb67f1a" name="tests/Games_Chess_TestCase_getPossibleChecks.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="a5819f518f040b2ef4b38aec55109d66" name="tests/Games_Chess_TestCase_getPossibleKingMoves.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="d4e9786c481d828047c63a2c96ab92cd" name="tests/Games_Chess_TestCase_getPossibleKnightMoves.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="c57cb42129dc3f1a6c64ef15940cbfb9" name="tests/Games_Chess_TestCase_getPossibleMoves.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="16514f8d85e2f25d94f0cde2a43b1f6c" name="tests/Games_Chess_TestCase_getPossiblePawnMoves.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="980598768a2c1d558e059ff5c1071638" name="tests/Games_Chess_TestCase_getPossibleQueenMoves.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="bf4f5667b11ec902580f3a39c7cf7d4e" name="tests/Games_Chess_TestCase_getPossibleRookMoves.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="e99c2d964b6f746691fb093d75e896be" name="tests/Games_Chess_TestCase_getRookSquares.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="8d139f32b795b37b685264f7389a9a30" name="tests/Games_Chess_TestCase_getSquareFromParsedMove.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="ac10c2c951e7a195dcefc712b90fe4c0" name="tests/Games_Chess_TestCase_inBasicDraw.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="df060933b0debed2dcb475dd751b663d" name="tests/Games_Chess_TestCase_inCheck.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="9748a36097fef330ba10a2e58797dac5" name="tests/Games_Chess_TestCase_inCheckMate.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="f8db06b8283cbe867d096b6ba68ab02f" name="tests/Games_Chess_TestCase_inStaleMate.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="0ba061b10dfd7d0e7e37cb3efc43bdf3" name="tests/Games_Chess_TestCase_interposeOrCapture.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="fae3fc256b54af980467a847680f6b29" name="tests/Games_Chess_TestCase_moveAlgebraic.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="99d8684b534f2fafd72a2adae7894a30" name="tests/Games_Chess_TestCase_movePiece.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="fb37cc2e8f48e1dd1d4a80b42dab5ab5" name="tests/Games_Chess_TestCase_moveSAN.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="4c07b576b45aa67d42f403ded7540427" name="tests/Games_Chess_TestCase_parseFen.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="96a8c3869dabc58c55c8d11d72677f5f" name="tests/Games_Chess_TestCase_parseMove.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="56f365eca6f284141b46cab5bff38006" name="tests/Games_Chess_TestCase_squareToPiece.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="d78339f1379b6494757b35d23d448495" name="tests/Games_Chess_TestCase_validMove.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="8bbdae3a8342f16df5ac4b77b8ad585c" name="tests/HTML_TestListener.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="4ffb9e95c0e9ee80b1ca71f1a833ba95" name="tests/stylesheet.css"/>
+ <file role="test" baseinstalldir="Games" md5sum="1359793fd6b7a178b3aec92ce5824f51" name="tests/testsuite.php"/>
+ <file role="test" baseinstalldir="Games" md5sum="5dc8e2fdd74c593e87e60c7dcba3b251" name="tests/TestUnit.php"/>
+ <file role="php" baseinstalldir="Games" md5sum="91f6118591d50db7de9a06d576605cfd" name="Chess.php">
+ <replace type="package-info" from="@VER@" to="version"/>
+ </file>
+ <file role="doc" baseinstalldir="Games" md5sum="d471bf1c3b38de5e83f8c0bda73e7e8a" name="LICENSE"/>
+ </filelist>
+ </release>
+ <changelog>
+ <release>
+ <version>0.1</version>
+ <date>2003-10-08</date>
+ <license>PHP License</license>
+ <state>alpha</state>
+ <notes>Initial test release</notes>
+ </release>
+ <release>
+ <version>0.2</version>
+ <date>2003-10-08</date>
+ <license>PHP License</license>
+ <state>alpha</state>
+ <notes>Fixed a few bugs:
+
+- 1. e4 e5 2. Nf3 Nc6 3. Bc4 Nf6 4. Nc3 Bb4 5.
+a3 Bxc3 6. dxc3 was fine through moveSAN(), but not through moveSquare('d2', 'c3')
+- en passant didn't actually delete the captured pawn</notes>
+ </release>
+ <release>
+ <version>0.3</version>
+ <date>2003-10-09</date>
+ <license>PHP License</license>
+ <state>alpha</state>
+ <notes>Fixed a few bugs:
+
+- example works in Mozilla now
+- promotion was endless loop in example
+- promotion didn't change the pawn to the promoted piece</notes>
+ </release>
+ </changelog>
+</package>
View
509 tests/Games_Chess_TestCase_addPiece.php
@@ -0,0 +1,509 @@
+<?php
+
+/**
+ * API Unit tests for Games_Chess package.
+ *
+ * @version $Id$
+ * @author Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
+ * @author Greg Beaver
+ * @package Games_Chess
+ */
+
+class Games_Chess_TestCase_addPiece extends PHPUnit_TestCase
+{
+ /**
+ * A Games_Chess_Standard object
+ * @var object
+ */
+ var $board;
+
+ function Games_Chess_TestCase_addPiece($name)
+ {
+ $this->PHPUnit_TestCase($name);
+ }
+
+ function setUp()
+ {
+ error_reporting(E_ALL);
+ $this->errorOccured = false;
+ set_error_handler(array(&$this, 'errorHandler'));
+
+ $this->board = new Games_Chess_Standard();
+ $this->board->blankBoard();
+ }
+
+ function tearDown()
+ {
+ unset($this->board);
+ }
+
+ function _stripWhitespace($str)
+ {
+ return preg_replace('/\\s+/', '', $str);
+ }
+
+ function _methodExists($name)
+ {
+ if (in_array(strtolower($name), get_class_methods($this->board))) {
+ return true;
+ }
+ $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->board));
+ return false;
+ }
+
+ function errorHandler($errno, $errstr, $errfile, $errline) {
+ //die("$errstr in $errfile at line $errline: $errstr");
+ $this->errorOccured = true;
+ $this->assertTrue(false, "$errstr at line $errline");
+ }
+
+ function test_addbishopw()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('W', 'B', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['WB1'],
+ 'incorrect bishop setup');
+ $this->board->addPiece('W', 'B', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['WB1'],
+ 'first bishop changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['WB2'],
+ 'incorrect bishop setup');
+ $this->board->addPiece('W', 'B', 'h1');
+ $this->assertEquals('a1', $this->board->_pieces['WB1'],
+ 'first bishop changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['WB2'],
+ 'second bishop changed, should not change');
+ $this->assertEquals(array('h1', 'B'), $this->board->_pieces['WP1']);
+ }
+
+ function test_addbishopb()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('B', 'B', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['BB1'],
+ 'incorrect bishop setup');
+ $this->board->addPiece('B', 'B', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['BB1'],
+ 'first bishop changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['BB2'],
+ 'incorrect bishop setup');
+ $this->board->addPiece('B', 'B', 'h1');
+ $this->assertEquals('a1', $this->board->_pieces['BB1'],
+ 'first bishop changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['BB2'],
+ 'second bishop changed, should not change');
+ $this->assertEquals(array('h1', 'B'), $this->board->_pieces['BP1']);
+ }
+
+ function test_addknightw()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('W', 'N', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['WN1'],
+ 'incorrect knight setup');
+ $this->board->addPiece('W', 'N', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['WN1'],
+ 'first knight changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['WN2'],
+ 'incorrect knight setup');
+ $this->board->addPiece('W', 'N', 'h1');
+ $this->assertEquals('a1', $this->board->_pieces['WN1'],
+ 'first knight changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['WN2'],
+ 'second knight changed, should not change');
+ $this->assertEquals(array('h1', 'N'), $this->board->_pieces['WP1']);
+ }
+
+ function test_addknightb()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('B', 'N', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['BN1'],
+ 'incorrect knight setup');
+ $this->board->addPiece('B', 'N', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['BN1'],
+ 'first knight changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['BN2'],
+ 'incorrect knight setup');
+ $this->board->addPiece('B', 'N', 'h1');
+ $this->assertEquals('a1', $this->board->_pieces['BN1'],
+ 'first knight changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['BN2'],
+ 'second knight changed, should not change');
+ $this->assertEquals(array('h1', 'N'), $this->board->_pieces['BP1']);
+ }
+
+ function test_addrookw()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('W', 'R', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['WR1'],
+ 'incorrect rook setup');
+ $this->board->addPiece('W', 'R', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['WR1'],
+ 'first rook changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['WR2'],
+ 'incorrect rook setup');
+ $this->board->addPiece('W', 'R', 'h1');
+ $this->assertEquals('a1', $this->board->_pieces['WR1'],
+ 'first rook changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['WR2'],
+ 'second rook changed, should not change');
+ $this->assertEquals(array('h1', 'R'), $this->board->_pieces['WP1']);
+ }
+
+ function test_addrookb()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('B', 'R', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['BR1'],
+ 'incorrect rook setup');
+ $this->board->addPiece('B', 'R', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['BR1'],
+ 'first rook changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['BR2'],
+ 'incorrect rook setup');
+ $this->board->addPiece('B', 'R', 'h1');
+ $this->assertEquals('a1', $this->board->_pieces['BR1'],
+ 'first rook changed, should not change');
+ $this->assertEquals('g1', $this->board->_pieces['BR2'],
+ 'second rook changed, should not change');
+ $this->assertEquals(array('h1', 'R'), $this->board->_pieces['BP1']);
+ }
+
+ function test_addqueenw()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('W', 'Q', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['WQ'],
+ 'incorrect queen setup');
+ $this->board->addPiece('W', 'Q', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['WQ'],
+ 'first queen changed, should not change');
+ $this->assertEquals(array('g1', 'Q'), $this->board->_pieces['WP1']);
+ }
+
+ function test_addqueenb()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('B', 'Q', 'a1');
+ $this->assertEquals('a1', $this->board->_pieces['BQ'],
+ 'incorrect queen setup');
+ $this->board->addPiece('B', 'Q', 'g1');
+ $this->assertEquals('a1', $this->board->_pieces['BQ'],
+ 'first queen changed, should not change');
+ $this->assertEquals(array('g1', 'Q'), $this->board->_pieces['BP1']);
+ }
+
+ function test_addpawnsw()
+ {
+ if (!$this->_methodExists('addPiece')) {
+ return;
+ }
+ $this->board->addPiece('W', 'P', 'a2');
+ $this->assertEquals(array('a2', 'P'), $this->board->_pieces['WP1'],
+ 'incorrect pawn setup');
+ $this->board->addPiece('W', 'P', 'a3');
+ $this->assertEquals(array('a2', 'P'), $this->board->_pieces['WP1'],
+ '1 pawn not the same');
+ $this->assertEquals(array('a3', 'P'), $this->board->_pieces['WP2'],
+ 'incorrect pawn setup');
+ $this->board->addPiece('W', 'P', 'b2');
+ $this->assertEquals(array('a2', 'P'), $this->board->_pieces['WP1'],
+ '1 pawn not the same');
+ $this->assertEquals(array('a3', 'P'), $this->board->_pieces['WP2'],
+ '2 pawn not the same');
+ $this->assertEquals(array('b2', 'P'), $this->board->_pieces['WP3'],
+ 'incorrect pawn setup');
+ $this->board->addPiece('W', 'P', 'c2');
+ $this->assertEquals(array('a2', 'P'), $this->board->_pieces['WP1'],
+ '1 pawn not the same');
+ $this->assertEquals(array('a3', 'P'), $this->board->_pieces['WP2'],
+ '2 pawn not the same');
+ $this->assertEquals(array('b2', 'P'), $this->board->_pieces['WP3'],
+ '3 pawn not the same');
+ $this->assertEquals(array('c2', 'P'), $this->board->_pieces['WP4'],
+ 'incorrect pawn setup');
+ $this->board->addPiece('W', 'P', 'd2');
+ $this->asser