public function getAttackTargetKeys() { $keys = array(); $mySquare = $this->board->getSquareByKey($this->getSquareKey()); $x = $this->x; $y = $this->y; $dy = 'white' === $this->color ? 1 : -1; $_y = $y + $dy; foreach (array(-1, 1) as $dx) { $_x = $x + $dx; if ($_x < 1 || $_x > 8) { continue; } // eat $key = Board::posToKey($_x, $_y); if ($piece = $this->board->getPieceByKey($key)) { if ($piece->getColor() !== $this->color) { $keys[] = $key; } } // en passant if (5 === $y || 4 === $y) { $opponentKey = Board::posToKey($_x, $y); if (($piece = $this->board->getPieceByKey($opponentKey)) && $piece instanceof Pawn && $piece->getColor() !== $this->color && $piece->getFirstMove() === $this->getPlayer()->getGame()->getTurns() - 1 && !$this->board->hasPieceByKey($key)) { $keys[] = $key; } } } return $keys; }
public function getBasicTargetKeys() { $mySquare = $this->getSquare(); $x = $mySquare->getX(); $y = $mySquare->getY(); $keys = array(); $board = $this->getBoard(); /** * That's ugly and could be done easily in a nicer way. * But I needed performance optimization. */ for ($dx = -1; $dx < 2; $dx++) { $_x = $x + $dx; if ($_x > 0 && $_x < 9) { for ($dy = -1; $dy < 2; $dy++) { if (0 === $dx && 0 === $dy) { continue; } $_y = $y + $dy; if ($_y > 0 && $_y < 9) { $key = Board::posToKey($_x, $_y); if (($piece = $board->getPieceByKey($key)) && $piece->getColor() === $this->color) { continue; } $keys[] = $key; } } } } return $keys; }
public function getBasicTargetKeys() { $mySquare = $this->getSquare(); $x = $mySquare->getX(); $y = $mySquare->getY(); $keys = array(); $board = $this->getBoard(); /** * That's ugly and could be done easily in a nicer way. * But I needed performance optimization. */ static $deltas = array(array(-1, 2), array(1, -2), array(2, -1), array(2, 1), array(1, 2), array(-1, -2), array(-2, 1), array(-2, -1)); foreach ($deltas as $delta) { $_x = $x + $delta[0]; $_y = $y + $delta[1]; if ($_x > 0 && $_x < 9 && $_y > 0 && $_y < 9) { $key = Board::posToKey($_x, $_y); if (($piece = $board->getPieceByKey($key)) && $piece->getPlayer() === $this->player) { continue; } $keys[] = $key; } } return $keys; }
public function getAttackTargetKeys() { $keys = array(); $dy = 'white' === $this->color ? 1 : -1; $_y = $this->y + $dy; foreach (array(-1, 1) as $dx) { $_x = $this->x + $dx; if ($_x < 1 || $_x > 8) { continue; } $key = Board::posToKey($_x, $_y); $piece = $this->board->getPieceByKey($key); if (!$piece || $piece->getColor() !== $this->color) { $keys[] = $key; } } return $keys; }
public function getSquareKey() { return Board::posToKey($this->x, $this->y); }
public static function diffToMove(Game $game, $forsyth) { $moves = array('from' => array(), 'to' => array()); $x = 1; $y = 8; $board = $game->getBoard(); $forsyth = str_replace('/', '', preg_replace('#\\s*([\\w\\d/]+)\\s.+#i', '$1', $forsyth)); for ($itForsyth = 0, $forsythLen = strlen($forsyth); $itForsyth < $forsythLen; $itForsyth++) { $letter = $forsyth[$itForsyth]; $key = Board::posToKey($x, $y); if (is_numeric($letter)) { for ($x = $x, $max = $x + intval($letter); $x < $max; $x++) { $_key = Board::posToKey($x, $y); if (!$board->getSquareByKey($_key)->isEmpty()) { $moves['from'][] = $_key; } } } else { $color = ctype_lower($letter) ? 'black' : 'white'; switch (strtolower($letter)) { case 'p': $class = 'Pawn'; break; case 'r': $class = 'Rook'; break; case 'n': $class = 'Knight'; break; case 'b': $class = 'Bishop'; break; case 'q': $class = 'Queen'; break; case 'k': $class = 'King'; break; } if ($piece = $board->getPieceByKey($key)) { if ($class != $piece->getClass() || $color !== $piece->getColor()) { $moves['to'][] = $key; } } else { $moves['to'][] = $key; } ++$x; } if ($x > 8) { $x = 1; --$y; } } if (empty($moves['from'])) { return null; } elseif (1 === count($moves['from']) && 1 === count($moves['to'])) { $from = $moves['from'][0]; $to = $moves['to'][0]; } elseif (2 === count($moves['from']) && 2 === count($moves['to'])) { if ($board->getPieceByKey($moves['from'][0])->isClass('King')) { $from = $moves['from'][0]; } else { $from = $moves['from'][1]; } if (in_array($board->getSquareByKey($moves['to'][0])->getX(), array(3, 7))) { $to = $moves['to'][0]; } else { $to = $moves['to'][1]; } } elseif (2 === count($moves['from']) && 1 === count($moves['to']) && $board->getPieceByKey($moves['from'][0])->isClass('Pawn') && $board->getPieceByKey($moves['from'][1])->isClass('Pawn') && !$board->hasPieceByKey($moves['to'][0])) { if ($moves['from'][0][0] === $moves['to'][0][0]) { $from = $moves['from'][1]; } else { $from = $moves['from'][0]; } $to = $moves['to'][0]; } else { throw new \RuntimeException(sprintf('Forsyth:diffToMove game:%s, variant:%s, moves: %s, forsyth:%s', $game->getId(), $game->getVariantName(), str_replace("\n", " ", var_export($moves, true)), $forsyth)); } return $from . ' ' . $to; }
/** * @depends testBoardCreation */ public function testPosToKey(Board $board) { $this->assertEquals('a1', $board->posToKey(1, 1)); $this->assertEquals('h8', $board->posToKey(8, 8)); $this->assertEquals('b4', $board->posToKey(2, 4)); }
public function diffToMove(Game $game, $forsythe) { $moves = array('from' => array(), 'to' => array()); $x = 1; $y = 8; $board = $game->getBoard(); $forsythe = str_replace('/', '', preg_replace('#\\s*([\\w\\d/]+)\\s.+#i', '$1', $forsythe)); for ($itForsythe = 0, $forsytheLen = strlen($forsythe); $itForsythe < $forsytheLen; $itForsythe++) { $letter = $forsythe[$itForsythe]; $key = Board::posToKey($x, $y); if (is_numeric($letter)) { for ($x = $x, $max = $x + intval($letter); $x < $max; $x++) { $_key = Board::posToKey($x, $y); if (!$board->getSquareByKey($_key)->isEmpty()) { $moves['from'][] = $_key; } } } else { $color = ctype_lower($letter) ? 'black' : 'white'; switch (strtolower($letter)) { case 'p': $class = 'Pawn'; break; case 'r': $class = 'Rook'; break; case 'n': $class = 'Knight'; break; case 'b': $class = 'Bishop'; break; case 'q': $class = 'Queen'; break; case 'k': $class = 'King'; break; } if ($piece = $board->getPieceByKey($key)) { if ($class != $piece->getClass() || $color !== $piece->getColor()) { $moves['to'][] = $key; } } else { $moves['to'][] = $key; } ++$x; } if ($x > 8) { $x = 1; --$y; } } if (empty($moves['from'])) { return null; } // two pieces moved: it's a castle if (2 === count($moves['from'])) { if ($board->getPieceByKey($moves['from'][0])->isClass('King')) { $from = $moves['from'][0]; } else { $from = $moves['from'][1]; } if (in_array($board->getSquareByKey($moves['to'][0])->getX(), array(3, 7))) { $to = $moves['to'][0]; } else { $to = $moves['to'][1]; } } else { $from = $moves['from'][0]; $to = $moves['to'][0]; } return $from . ' ' . $to; }
/** * Add castling moves if available * * @return array the squares where the king can go **/ protected function addCastlingSquares(King $king, array $squares) { $player = $king->getPlayer(); $rooks = PieceFilter::filterNotMoved(PieceFilter::filterClass(PieceFilter::filterAlive($player->getPieces()), 'Rook')); if (empty($rooks)) { return $squares; } $opponentControlledKeys = $this->getPlayerControlledKeys($player->getOpponent(), true); foreach ($rooks as $rook) { $kingX = $king->getX(); $kingY = $king->getY(); $rookX = $rook->getX(); $dx = $kingX > $rookX ? -1 : 1; $newKingX = 1 === $dx ? 7 : 3; $newRookX = 1 === $dx ? 6 : 4; $possible = true; // Unattacked $rangeMin = min($kingX, $newKingX); $rangeMax = min(8, max($kingX, $newKingX) + 1); for ($_x = $rangeMin; $_x !== $rangeMax; $_x++) { if (in_array(Board::posToKey($_x, $kingY), $opponentControlledKeys)) { $possible = false; break; } } // Unimpeded $rangeMin = min($kingX, $rookX, $newKingX, $newRookX); $rangeMax = min(8, max($kingX, $rookX, $newKingX, $newRookX) + 1); for ($_x = $rangeMin; $_x !== $rangeMax; $_x++) { if ($piece = $this->board->getPieceByKey(Board::posToKey($_x, $kingY))) { if ($piece !== $king && $piece !== $rook) { $possible = false; break; } } } if ($possible) { // If King moves one square or less (Chess variant) if (1 >= abs($kingX - $newKingX)) { $newKingSquare = $rook->getSquare(); } else { $newKingSquare = $this->board->getSquareByPos($newKingX, $kingY); } $squares[] = $newKingSquare; } } return $squares; }