From 2ec631166b4e82b9c63859887c5a0491780c7ffd Mon Sep 17 00:00:00 2001 From: Dicken Date: Sun, 28 Jun 2026 15:15:33 +0200 Subject: [PATCH] fix: Hex Wars - Kopf nach Mine korrekt, volles Grid bei Spielende --- backend/src/tools/gebietseroberung/routes.js | 22 +++++++++++++------- frontend/src/tools/gebietseroberung.jsx | 16 +++++++++----- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/backend/src/tools/gebietseroberung/routes.js b/backend/src/tools/gebietseroberung/routes.js index 9363966..c094ffe 100644 --- a/backend/src/tools/gebietseroberung/routes.js +++ b/backend/src/tools/gebietseroberung/routes.js @@ -175,10 +175,16 @@ function getGameForUser(id, requesterId) { if (!terrain.length) return { ...game, myScore:0, oppScore:0 }; - // Fog anwenden - const visible = computeFog(grid, requesterId); - const maskedGrid = grid.map((row,r) => row.map((cell,c) => visible[r][c] ? cell : (cell===requesterId ? cell : 0))); - const maskedTerrain = terrain.map((row,r) => row.map((cell,c) => visible[r][c] ? cell : -1)); + // Bei beendetem Spiel: vollständiges Grid ohne Fog + let maskedGrid, maskedTerrain; + if (game.status === 'finished') { + maskedGrid = grid; + maskedTerrain = terrain; + } else { + const visible = computeFog(grid, requesterId); + maskedGrid = grid.map((row,r) => row.map((cell,c) => visible[r][c] ? cell : (cell===requesterId ? cell : 0))); + maskedTerrain = terrain.map((row,r) => row.map((cell,c) => visible[r][c] ? cell : -1)); + } // Kopf des anfragenden Spielers mitliefern (für Frontend-Validierung) const myHead = requesterId === game.owner_id ? game.owner_head : game.opp_head; @@ -356,13 +362,15 @@ router.post('/:id/move', authenticate, (req, res) => { let status = 'active'; let winnerId = null; - // Köpfe nach Zug + // Effektiver Kopf nach Zug (bei Mine: zurückgesetzter Kopf, sonst neue Position) const oppHeadStr = game.owner_id === me ? game.opp_head : game.owner_head; const [oppHR, oppHC] = oppHeadStr ? oppHeadStr.split(',').map(Number) : [null, null]; - const myNewHR = row, myNewHC = col; + const effectiveMyHeadStr = game.owner_id === me ? newOwnerHead : newOppHead; + const [effectiveMyHR, effectiveMyHC] = effectiveMyHeadStr + ? effectiveMyHeadStr.split(',').map(Number) : [row, col]; // Spielende: niemand kann mehr ziehen - if (!canMove(grid, terrain, opponent, oppHR, oppHC) && !canMove(grid, terrain, me, myNewHR, myNewHC)) { + if (!canMove(grid, terrain, opponent, oppHR, oppHC) && !canMove(grid, terrain, me, effectiveMyHR, effectiveMyHC)) { status = 'finished'; } else if (!canMove(grid, terrain, opponent, oppHR, oppHC)) { nextTurn = me; diff --git a/frontend/src/tools/gebietseroberung.jsx b/frontend/src/tools/gebietseroberung.jsx index 7d0f636..6828d9e 100644 --- a/frontend/src/tools/gebietseroberung.jsx +++ b/frontend/src/tools/gebietseroberung.jsx @@ -175,11 +175,15 @@ function GameBoard({ game, myId, onMove, toast }) { } catch {} }, [game.last_event]); - // Schlangen-Kopf aus Server-Response - const myHeadStr = game.myHead; - const myHead = myHeadStr ? myHeadStr.split(',').map(Number) : null; + // Schlangen-Köpfe aus Server-Response + const myHeadStr = game.myHead; + const myHead = myHeadStr ? myHeadStr.split(',').map(Number) : null; const [myHR, myHC] = myHead ?? [null, null]; + const oppHeadStr = game.oppHead; + const oppHead = oppHeadStr ? oppHeadStr.split(',').map(Number) : null; + const [oppHR, oppHC] = oppHead ?? [null, null]; + const isAdjacentToHead = (r, c) => { if (myHR === null) return false; return Math.abs(r - myHR) <= 1 && Math.abs(c - myHC) <= 1 && !(r === myHR && c === myHC); @@ -258,7 +262,8 @@ function GameBoard({ game, myId, onMove, toast }) { const clic = canClick(r, c); const isPend = pending?.row === r && pending?.col === c; const isBlast = blastHighlight.has(`${r}-${c}`); - const isHead = myHR === r && myHC === c; // eigener Kopf + const isHead = myHR === r && myHC === c; // eigener Kopf + const isOppHead = game.status === 'finished' && oppHR === r && oppHC === c; // Gegner-Kopf nur bei Spielende const isFog = t === T_FOG; const isRock = t === T_ROCK; const isGold = t === T_GOLD; @@ -287,7 +292,8 @@ function GameBoard({ game, myId, onMove, toast }) { } if (isBlast) { bg = '#ff440066'; border = '2px solid #ff4400'; } - if (isHead && !isPend) { border = `2px solid ${myColor}`; } // Kopf immer markieren + if (isOppHead) { border = `2px solid ${oppColor}`; } + if (isHead && !isPend) { border = `2px solid ${myColor}`; } // eigener Kopf if (isPend) { bg = myColor; border = `2px solid ${myColor}`; } else if (clic && !isPend && !isBlast && !isHead) border = `1px solid ${myColor}44`;