mirror of
https://github.com/sigmasternchen/php-chess
synced 2025-03-16 00:18:55 +00:00
feat: Add deserialization for JS move notation
This commit is contained in:
parent
7c17ff94b6
commit
9f5b9c83e1
6 changed files with 112 additions and 2 deletions
|
@ -165,12 +165,27 @@ class Move {
|
|||
return join(",", [
|
||||
$this->piece->toJS(),
|
||||
$this->target,
|
||||
$this->captures ?? "",
|
||||
$this->captures?->toJS() ?? "",
|
||||
$this->promoteTo?->getShort() ?? "",
|
||||
$this->castleWith ?? ""
|
||||
$this->castleWith?->toJS() ?? ""
|
||||
]);
|
||||
}
|
||||
|
||||
static public function fromJS(string $jsStr): Move {
|
||||
$components = explode(",", $jsStr);
|
||||
if (count($components) != 5) {
|
||||
throw new \InvalidArgumentException("unable to deserialize move string: " . $jsStr);
|
||||
}
|
||||
|
||||
return new Move(
|
||||
Piece::fromJS($components[0]),
|
||||
Position::fromString($components[1]),
|
||||
$components[2] != "" ? Piece::fromJS($components[2]) : null,
|
||||
$components[3] != "" ? PieceType::fromShort($components[3]) : null,
|
||||
$components[4] != "" ? Piece::fromJS($components[4]) : null,
|
||||
);
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return $this->getLong();
|
||||
}
|
||||
|
|
|
@ -55,6 +55,19 @@ abstract class Piece {
|
|||
]);
|
||||
}
|
||||
|
||||
public static function fromJS(string $jsStr): Piece {
|
||||
$components = explode("-", $jsStr);
|
||||
if (count($components) != 3) {
|
||||
throw new \InvalidArgumentException("unable to deserialize piece string: " . $jsStr);
|
||||
}
|
||||
|
||||
return self::ofType(
|
||||
PieceType::fromShort($components[1]),
|
||||
Position::fromString($components[2]),
|
||||
Side::fromShort($components[0]),
|
||||
);
|
||||
}
|
||||
|
||||
private static function getClassForType(PieceType $type): string {
|
||||
switch ($type) {
|
||||
case PieceType::PAWN:
|
||||
|
|
|
@ -25,6 +25,18 @@ enum PieceType {
|
|||
};
|
||||
}
|
||||
|
||||
public static function fromShort(string $short): PieceType {
|
||||
return match (strtoupper($short)) {
|
||||
"" => self::PAWN,
|
||||
"B" => self::BISHOP,
|
||||
"N" => self::KNIGHT,
|
||||
"R" => self::ROOK,
|
||||
"Q" => self::QUEEN,
|
||||
"K" => self::KING,
|
||||
default => throw new \InvalidArgumentException("unknown piece type: " . $short)
|
||||
};
|
||||
}
|
||||
|
||||
public function getLong(): string {
|
||||
return match ($this) {
|
||||
self::PAWN => "Pawn",
|
||||
|
|
|
@ -33,6 +33,18 @@ class Position {
|
|||
return $this->getFileString() . $this->getRankString();
|
||||
}
|
||||
|
||||
public static function fromString(string $str): Position {
|
||||
$str = strtolower($str);
|
||||
$file = ord($str[0]) - ord("a");
|
||||
$rank = ord($str[1]) - ord("1");
|
||||
|
||||
$position = new Position($file, $rank);
|
||||
if (!$position->isValid()) {
|
||||
throw new \InvalidArgumentException("position is not valid: " . $str);
|
||||
}
|
||||
return $position;
|
||||
}
|
||||
|
||||
public function equals(Position $position): bool {
|
||||
return $this->file == $position->file && $this->rank == $position->rank;
|
||||
}
|
||||
|
|
|
@ -21,4 +21,12 @@ enum Side {
|
|||
return "b";
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromShort(string $short): Side {
|
||||
return match ($short) {
|
||||
"w" => self::WHITE,
|
||||
"b" => self::BLACK,
|
||||
default => throw new \InvalidArgumentException("unknown side: " . $short),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -97,4 +97,54 @@ final class MoveTest extends TestCase {
|
|||
$this->assertEquals("Nc2xd4++", $subject->getShort($game));
|
||||
}
|
||||
|
||||
public function testToJS_capturesAndPromotes() {
|
||||
$move = new Move(
|
||||
new Pawn(new Position(1, 6), Side::WHITE),
|
||||
new Position(2, 7),
|
||||
new Queen(new Position(2, 7), Side::BLACK),
|
||||
PieceType::QUEEN,
|
||||
);
|
||||
|
||||
$this->assertEquals("w--b7,c8,b-Q-c8,Q,", $move->toJS());
|
||||
}
|
||||
|
||||
public function testToJS_minimal() {
|
||||
$move = new Move(
|
||||
new Queen(new Position(1, 6), Side::WHITE),
|
||||
new Position(3, 4)
|
||||
);
|
||||
|
||||
$this->assertEquals("w-Q-b7,d5,,,", $move->toJS());
|
||||
}
|
||||
|
||||
public function testToJS_castle() {
|
||||
$move = new Move(
|
||||
new King(new Position(4, 0), Side::WHITE),
|
||||
new Position(2, 0),
|
||||
null,
|
||||
null,
|
||||
new Rook(new Position(0, 0), Side::WHITE)
|
||||
);
|
||||
|
||||
$this->assertEquals("w-K-e1,c1,,,w-R-a1", $move->toJS());
|
||||
}
|
||||
|
||||
public function testFromJS_capturesAndPromotes() {
|
||||
$move = Move::fromJS("w--b7,c8,b-Q-c8,Q,");
|
||||
|
||||
$this->assertEquals("b7xc8Q", $move->getLong());
|
||||
}
|
||||
|
||||
public function testFromJS_minimal() {
|
||||
$move = Move::fromJS("w-Q-b7,d5,,,");
|
||||
|
||||
$this->assertEquals("Qb7d5", $move->getLong());
|
||||
}
|
||||
|
||||
public function testFromJS_castle() {
|
||||
$move = Move::fromJS("w-K-e1,c1,,,w-R-a1");
|
||||
|
||||
$this->assertEquals("O-O-O", $move->getLong());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue