Skip to content

Commit d2ac450

Browse files
authored
Merge pull request #29 from dustywusty/codex/fix-game-state-and-ui-issues
2 parents 7f48565 + 7ffc461 commit d2ac450

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

internal/game/game_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package game
22

33
import (
4+
"strings"
45
"testing"
56
"time"
67

@@ -36,3 +37,22 @@ func TestMakeMoveInvalidUCI(t *testing.T) {
3637
t.Fatalf("expected error for invalid UCI, got nil")
3738
}
3839
}
40+
41+
func TestCheckmateState(t *testing.T) {
42+
g := newTestGame()
43+
moves := []string{"f2f3", "e7e5", "g2g4", "d8h4"}
44+
for _, m := range moves {
45+
if err := g.MakeMove(m); err != nil {
46+
t.Fatalf("move %s failed: %v", m, err)
47+
}
48+
}
49+
g.Mu.Lock()
50+
st := g.StateLocked()
51+
g.Mu.Unlock()
52+
if st.Status == "" {
53+
t.Fatalf("expected status to be set after checkmate")
54+
}
55+
if !strings.Contains(strings.ToLower(st.Status), "checkmate") {
56+
t.Fatalf("expected checkmate in status, got %s", st.Status)
57+
}
58+
}

internal/templates/game.html

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,12 @@
272272
line-height: 1;
273273
}
274274

275+
.caps span.recent {
276+
outline: 2px solid var(--accent);
277+
outline-offset: 2px;
278+
border-radius: 4px;
279+
}
280+
275281
.reactions {
276282
display: flex;
277283
gap: 6px;
@@ -486,6 +492,8 @@
486492
let playerColor = "white";
487493
let playerColorSet = false;
488494
let isSpectator = false;
495+
let gameOver = false;
496+
let prevCaptured = { byWhite: [], byBlack: [] };
489497

490498
function normalizeColor(c) {
491499
if (!c) return "white";
@@ -799,7 +807,7 @@
799807

800808
// Board-level click handler
801809
boardEl.addEventListener("click", (e) => {
802-
if (isSpectator) return;
810+
if (isSpectator || gameOver) return;
803811
const rect = boardEl.getBoundingClientRect();
804812
const x = Math.min(
805813
Math.max(0, e.clientX - rect.left),
@@ -839,6 +847,22 @@
839847
statusEl.style.color = isErr ? "var(--err)" : "inherit";
840848
}
841849

850+
function updateTurn(st) {
851+
if (!turnEl) return;
852+
if (st.status) {
853+
turnEl.textContent = "Game over";
854+
return;
855+
}
856+
const t = normalizeColor(st.turn);
857+
if (isSpectator) {
858+
turnEl.textContent = t || "";
859+
} else if (t === playerColor) {
860+
turnEl.textContent = "Your turn";
861+
} else {
862+
turnEl.textContent = "Their turn";
863+
}
864+
}
865+
842866
// ---- Captured pieces (derived from FEN) + persisted per game ----
843867
var startCounts = {
844868
P: 8,
@@ -947,13 +971,19 @@
947971
for (var i = 0; i < byWhite.length; i++) {
948972
var s1 = document.createElement("span");
949973
s1.textContent = byWhite[i];
974+
s1.classList.add("black-piece");
975+
if (i >= prevCaptured.byWhite.length) s1.classList.add("recent");
950976
capWhiteEl.appendChild(s1);
951977
}
952978
for (var j = 0; j < byBlack.length; j++) {
953979
var s2 = document.createElement("span");
954980
s2.textContent = byBlack[j];
981+
s2.classList.add("white-piece");
982+
if (j >= prevCaptured.byBlack.length) s2.classList.add("recent");
955983
capBlackEl.appendChild(s2);
956984
}
985+
prevCaptured.byWhite = byWhite.slice();
986+
prevCaptured.byBlack = byBlack.slice();
957987
}
958988

959989
function capKey(id) {
@@ -1058,7 +1088,7 @@
10581088

10591089
// Render start position immediately (prevents blank board)
10601090
renderFEN(START_FEN);
1061-
turnEl.textContent = "white";
1091+
turnEl.textContent = "";
10621092
status("");
10631093

10641094
if (gameId) {
@@ -1095,10 +1125,11 @@
10951125
releaseBtn.style.display = isSpectator ? "none" : "";
10961126
lastMoveSquares = deriveLastMoveSquares(st.uci || []);
10971127
renderFEN(st.fen);
1098-
turnEl.textContent = st.turn || "";
1128+
updateTurn(st);
10991129
pgnEl.textContent = formatPGNLines(st.pgn || "");
11001130
lanEl.textContent = formatUCIMoves(st.uci || []);
11011131
status(st.status || "");
1132+
gameOver = !!st.status;
11021133
const caps = capturedFromFEN(st.fen);
11031134
renderCaptured(caps.byWhite, caps.byBlack);
11041135
try {
@@ -1130,6 +1161,9 @@
11301161
});
11311162
}
11321163
};
1164+
es.onopen = () => {
1165+
status("");
1166+
};
11331167
es.onerror = () => {
11341168
status("Disconnected. Reconnecting…", true);
11351169
};

0 commit comments

Comments
 (0)