feat: Show possible moves for pieces in UI

This commit is contained in:
sigmasternchen 2024-10-20 21:55:31 +02:00
parent fa7719141b
commit 8c194f56a3
7 changed files with 117 additions and 12 deletions

View file

@ -7,7 +7,7 @@ use Game\Game;
$game = Game::fromStartPosition();
$content = function() use ($game) {
require '../src/View/fragments/board.php';
require '../src/View/fragments/game.php';
};
require '../src/View/base.php';

View file

@ -14,6 +14,7 @@
.square {
width: 12.5%;
height: 12.5%;
position: relative;
}
.square.black {
@ -24,11 +25,24 @@
background-color: lightgoldenrodyellow;
}
.square.black.hasMoves {
.square.movePossible:after {
content: "";
display: block;
position: absolute;
top: 50%;
left: 50%;
background: green;
width: 25%;
height: 25%;
border-radius: 50%;
transform: translate(-50%, -50%);
}
.board:not(.moveSelection) .square.black.hasMoves, .square.black.source {
background-color: green;
}
.square.white.hasMoves {
.board:not(.moveSelection) .square.white.hasMoves, .square.white.source {
background-color: greenyellow;
}

View file

@ -161,6 +161,16 @@ class Move {
return $result;
}
public function toJS() {
return join(",", [
$this->piece->toJS(),
$this->target,
$this->captures ?? "",
$this->promoteTo?->getShort() ?? "",
$this->castleWith ?? ""
]);
}
public function __toString(): string {
return $this->getLong();
}

View file

@ -47,6 +47,14 @@ abstract class Piece {
return $this->getType()->getShort() . $this->getPosition();
}
public function toJS() {
return join("-", [
$this->getSide()->getShort(),
$this->getType()->getShort(),
$this->getPosition()
]);
}
private static function getClassForType(PieceType $type): string {
switch ($type) {
case PieceType::PAWN:

View file

@ -13,4 +13,12 @@ enum Side {
return Side::WHITE;
}
}
public function getShort(): string {
if ($this == Side::WHITE) {
return "w";
} else {
return "b";
}
}
}

View file

@ -4,11 +4,9 @@ use Game\Game;
use Game\Piece;
use Game\Position;use Game\Side;
$game ??= new Game([], \Game\Side::WHITE);
$game ??= new Game([], Side::WHITE);
$current = Side::WHITE;
if (($current ?? Side::WHITE) == Side::WHITE) {
if (($viewSide ?? Side::WHITE) == Side::WHITE) {
$start = 7;
$end = -1;
$dir = -1;
@ -18,27 +16,36 @@ if (($current ?? Side::WHITE) == Side::WHITE) {
$dir = 1;
}
$interactive ??= false;
global $boardId;
$boardId = ($boardId ?? 0) + 1;
function getImageForPice(Piece $piece): string {
return "/static/pieces/" .
($piece->getSide() == Side::WHITE ? "w" : "b") .
$piece->getSide()->getShort() .
$piece->getType()->getShort() .
".svg";
}
?>
<div class="board">
<div class="board <?= $interactive ? "interactive" : "" ?>" id="board<?= $boardId ?>">
<?php
for($rank = $start; $rank != $end; $rank += $dir) {
for($file = $start; $file != $end; $file += $dir) {
$position = new Position($file, $rank);
$piece = $game->getPiece($position);
$moves = $piece ? $game->getMovesForPiece($piece) : [];
$hasMoves = count($moves) > 0;
?>
<div class="square <?= strtolower($position->getSquareColor()->name) ?> <?= count($moves) > 0 ? "hasMoves" : "" ?>">
<div class="square <?= strtolower($position->getSquareColor()->name) ?> <?= $hasMoves ? "hasMoves" : "" ?> <?= $position ?>">
<?php
if ($piece) {
?>
<div class="piece <?= strtolower($piece->getSide()->name) ?>">
<div
class="piece <?= strtolower($piece->getSide()->name) ?> <?= $hasMoves ? "hasMoves" : "" ?>"
data-moves="<?= join(";", array_map(fn($m) => $m->toJS(), $moves)) ?>"
>
<img
alt="<?= strtolower($piece->getSide()->name) ?> <?= strtolower($piece->getType()->name) ?>"
src="<?= getImageForPice($piece) ?>"
@ -53,3 +60,49 @@ function getImageForPice(Piece $piece): string {
}
?>
</div>
<?php
if ($interactive) {
?>
<script>
window.addEventListener("load", () => {
const board = document.getElementById("board<?= $boardId ?>");
const getSquare = square => board.getElementsByClassName(square)[0];
const clearSelection = () => {
board.classList.remove("moveSelection");
board.querySelectorAll(".source").forEach(element => {
element.classList.remove("source")
});
board.querySelectorAll(".movePossible").forEach(element => {
element.classList.remove("movePossible")
});
};
const enterSelection = (moves) => {
board.classList.add("moveSelection");
for (const move of moves) {
getSquare(move.target).classList.add("movePossible");
getSquare(move.source).classList.add("source");
}
}
const moveSelected = (move) => {
// TODO
};
board.querySelectorAll(".piece.hasMoves").forEach(element => {
element.addEventListener("click", event => {
clearSelection();
const moves = element.getAttribute("data-moves").split(";").map(move => ({
encoded: move,
source: move.split(",")[0].split("-")[2],
target: move.split(",")[1]
}));
enterSelection(moves);
event.stopPropagation();
});
});
board.addEventListener("click", () => {
clearSelection();
});
});
</script>
<?php
}

View file

@ -0,0 +1,12 @@
<?php
use Game\Game;
use Game\Side;
$game ??= new Game([], Side::WHITE);
$viewSide ??= Side::WHITE;
$interactive = true;
require "board.php";