Skip to content

Commit

Permalink
♻️ refactors History (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
garak authored Apr 18, 2021
1 parent e88a1ab commit ed2b5f9
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 91 deletions.
8 changes: 4 additions & 4 deletions docs/chess.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ It represents a chess game.

## Main method

### `__construct(?string $fen, ?array $history)`
### `__construct(?string $fen, ?History $history)`

This is the main method. If you invoke it without arguments, you simply get an instance of the class.
If you decide to start a game from a particular position, you can pass it as first argument,
in [FEN](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation) notation.
Also, you can pass an array of [`\Pchess\Chess\History`](history.md) objects (that are supposed to be consistent
Also, you can pass an [`\Pchess\Chess\History`](history.md) object (that is supposed to be consistent
with the first argument, even if no check is performed).

## Move-related
Expand Down Expand Up @@ -85,9 +85,9 @@ Controls if game is over.

Gets the current position in [FEN](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation) notation.

### `getHistory(): array`
### `getHistory(): History`

Gets a list of moves as [`\Pchess\Chess\Board\History`](history.md) objects.
Gets [`\Pchess\Chess\Board\History`](history.md) object.

## Public properties

Expand Down
6 changes: 3 additions & 3 deletions docs/history.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# History

The `\Pchess\Chess\History` class is a simple value object representing an entry of
the history of moves in [`\Pchess\Chess\Chess`](chess.md).
The `\Pchess\Chess\History` class contains instances of `\Pchess\Chess\Entry`.
Each entry is a value object representing a record of a move in [`\Pchess\Chess\Chess`](chess.md).

The object is composed by the following properties:
The `Entry` object is composed by the following properties:

|Property | Type | Description |
|--------------|--------|------------------------|
Expand Down
47 changes: 18 additions & 29 deletions src/Chess.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,22 @@ class Chess
protected $halfMoves = 0;
/** @var int */
protected $moveNumber = 1;
/** @var array<int, History> */
protected $history = [];
/** @var History */
protected $history;
/** @var array<string, array<int, Move>> */
protected $generateMovesCache = [];
/** @var string */
protected $boardHash = '';
/** @var array<string, string> */
protected $sanMoveCache = [];

/**
* @param array<int, History>|null $history
*/
public function __construct(?string $fen = Board::DEFAULT_POSITION, ?array $history = null)
public function __construct(?string $fen = Board::DEFAULT_POSITION, ?History $history = null)
{
$this->board = new Board();
if (null !== $error = $this->load($fen ?? Board::DEFAULT_POSITION)) {
throw new \InvalidArgumentException(\sprintf('Invalid fen: %s. Error: %s', $fen, $error));
}
if (null !== $history) {
$this->history = $history;
}
$this->history = $history ?? new History();
}

protected function clear(): void
Expand All @@ -53,7 +48,6 @@ protected function clear(): void
$this->epSquare = null;
$this->halfMoves = 0;
$this->moveNumber = 1;
$this->history = [];
$this->generateMovesCache = [];
$this->sanMoveCache = [];

Expand Down Expand Up @@ -318,29 +312,27 @@ protected function makeMove(Move $move): void

$boardHash = \json_encode($this->board);
$this->boardHash = false === $boardHash ? '' : $boardHash;
$this->history[$historyKey]->position = $this->boardHash;
$this->history->get($historyKey)->position = $this->boardHash;
}

protected function recordMove(Move $move): int
{
$this->history[] = new History(
$this->history->add(new Entry(
$move,
[Piece::WHITE => $this->kings[Piece::WHITE], Piece::BLACK => $this->kings[Piece::BLACK]],
$this->turn,
[Piece::WHITE => $this->castling[Piece::WHITE], Piece::BLACK => $this->castling[Piece::BLACK]],
$this->boardHash,
$this->kings,
$this->castling,
$this->epSquare,
$this->halfMoves,
$this->moveNumber
);
));

\end($this->history);

return \key($this->history);
return $this->history->key();
}

protected function undoMove(): ?Move
{
$old = \array_pop($this->history);
$old = $this->history->pop();
if ($old === null) {
return null;
}
Expand Down Expand Up @@ -752,14 +744,14 @@ public function insufficientMaterial(): bool
public function inThreefoldRepetition(): bool
{
$hash = [];
foreach ($this->history as $history) {
if (isset($hash[$history->position])) {
++$hash[$history->position];
foreach ($this->history->getEntries() as $entry) {
if (isset($hash[$entry->position])) {
++$hash[$entry->position];
} else {
$hash[$history->position] = 1;
$hash[$entry->position] = 1;
}

if ($hash[$history->position] >= 3) {
if ($hash[$entry->position] >= 3) {
return true;
}
}
Expand Down Expand Up @@ -899,10 +891,7 @@ protected function moveToSAN(Move $move): void
$move->san = $output;
}

/**
* @return array<int, History>
*/
public function getHistory(): array
public function getHistory(): History
{
return $this->history;
}
Expand Down
60 changes: 60 additions & 0 deletions src/Entry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace PChess\Chess;

class Entry
{
/** @var Move */
public $move;

/** @var string|null */
public $position;

/** @var array<string, ?int> */
public $kings;

/** @var string */
public $turn;

/** @var array<string, ?int> */
public $castling;

/** @var int|null */
public $epSquare;

/** @var int */
public $halfMoves;

/** @var int */
public $moveNumber;

/**
* @param array<string, ?int> $kings
* @param array<string, ?int> $castling
*/
public function __construct(
Move $move,
?string $position,
array $kings,
array $castling,
?int $epSquare,
int $halfMoves,
int $moveNumber
) {
$this->move = $move;
$this->position = $position;
$this->kings = $kings;
$this->turn = $move->turn;
$this->castling = $castling;
$this->epSquare = $epSquare;
$this->halfMoves = $halfMoves;
$this->moveNumber = $moveNumber;
}

public function __toString(): string
{
return (string) $this->move;
}
}
82 changes: 35 additions & 47 deletions src/History.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,44 @@

namespace PChess\Chess;

class History
final class History
{
/** @var Move */
public $move;

/** @var string */
public $position;

/** @var array<string, ?int> */
public $kings;

/** @var string */
public $turn;

/** @var array<string, ?int> */
public $castling;

/** @var int|null */
public $epSquare;

/** @var int */
public $halfMoves;

/** @var int */
public $moveNumber;

/**
* @param array<string, ?int> $kings
* @param array<string, ?int> $castling
*/
public function __construct(
Move $move,
array $kings,
string $turn,
array $castling,
?int $epSquare,
int $halfMoves,
int $moveNumber
) {
$this->move = $move;
$this->kings = $kings;
$this->turn = $turn;
$this->castling = $castling;
$this->epSquare = $epSquare;
$this->halfMoves = $halfMoves;
$this->moveNumber = $moveNumber;
/** @var array<int, Entry> */
private $entries;

/** @param array<int, Entry>|null $entries */
public function __construct(array $entries = null)
{
$this->entries = $entries ?? [];
}

public function add(Entry $entry): void
{
$this->entries[] = $entry;
}

public function get(int $key): Entry
{
return $this->entries[$key];
}

public function pop(): ?Entry
{
if (\count($this->entries) < 1) {
return null;
}

return \array_pop($this->entries);
}

/** @return array<int, Entry> */
public function getEntries(): array
{
return $this->entries;
}

public function __toString(): string
public function key(): ?int
{
return (string) $this->move;
return \key($this->entries);
}
}
6 changes: 3 additions & 3 deletions tests/ChessPublicator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use PChess\Chess\Board;
use PChess\Chess\Chess;
use PChess\Chess\History;
use PChess\Chess\Entry;
use PChess\Chess\Move;

// a proxy for testing protected method
Expand All @@ -17,9 +17,9 @@ public function getBoard(): Board
return $this->board;
}

public function getLastHistory(): History
public function getLastHistory(): Entry
{
return $this->history[\count($this->history) - 1];
return $this->history->get(\count($this->history->getEntries()) - 1);
}

public function attackedPublic(string $color, int $square): bool
Expand Down
9 changes: 6 additions & 3 deletions tests/ConstructorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Imagine\Image\AbstractImagine;
use PChess\Chess\Chess;
use PChess\Chess\Entry;
use PChess\Chess\History;
use PChess\Chess\Move;
use PChess\Chess\Output;
Expand All @@ -31,9 +32,11 @@ public function testInvalidFen(): void
public function testBuildWithHistory(): void
{
$move = new Move('w', 0, new Piece('p', 'w'), 100, 68);
$history = new History($move, ['w' => 116, 'b' => 4], 'b', ['w' => 96, 'b' => 96], null, 0, 1);
$chess = new Chess('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1', [$history]);
self::assertCount(1, $chess->getHistory());
$history = new History();
$entry = new Entry($move, null, ['w' => 116, 'b' => 4], ['w' => 96, 'b' => 96], null, 0, 1);
$history->add($entry);
$chess = new Chess('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1', $history);
self::assertCount(1, $chess->getHistory()->getEntries());
}

public function testUnicodeOutput(): void
Expand Down
4 changes: 2 additions & 2 deletions tests/GameTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function testGetHistory(): void
{
$chess = new Chess();
$chess->move('e4');
self::assertEquals('e4', $chess->getHistory()[0]->move->san);
self::assertEquals('e4', $chess->getHistory()[0]);
self::assertEquals('e4', $chess->getHistory()->get(0)->move->san);
self::assertEquals('e4', $chess->getHistory()->get(0));
}
}

0 comments on commit ed2b5f9

Please sign in to comment.