Spaces:
Running
Running
const boardSize = 8; | |
let board = [], | |
currentPlayer = 1,û | |
selectedPiece = null, | |
validMoves = [], | |
gameRunning = false, | |
vsCPU = false; | |
const playerColors = { | |
1: "168, 208, 230", | |
2: "246, 171, 182", | |
}; | |
let players = { | |
1: { name: "Spieler 1", color: "168, 208, 230" }, | |
2: { name: "Spieler 2", color: "246, 171, 182" }, | |
}; | |
const captureHighlightColors = { | |
1: "128, 168, 190", | |
2: "206, 131, 142", | |
}; | |
const pieceColors = { | |
1: "77, 129, 199", | |
2: "214, 106, 139", | |
}; | |
const body = document.body; | |
body.style.setProperty("--player1-color", players[1].color); | |
body.style.setProperty("--player2-color", players[2].color); | |
const inputPlayerName1 = document.getElementById("inputPlayerName1"); | |
inputPlayerName1.value = players[1].name; | |
const inputPlayerName2 = document.getElementById("inputPlayerName2"); | |
inputPlayerName2.value = players[2].name; | |
const savePlayerNamesButton = document.getElementById("savePlayerNames"); | |
const boardElement = document.getElementById("board"); | |
const statusElement = document.getElementById("status"); | |
const newGameButton = document.getElementById("new-game"); | |
const winMessageElement = document.getElementById("winMessage"); | |
const cpuToggle = document.getElementById("cpuToggle"); | |
function inBounds(row, col) { | |
return row >= 0 && row < boardSize && col >= 0 && col < boardSize; | |
} | |
function isEmpty(row, col) { | |
return board[row][col] === 0; | |
} | |
function isOpponent(piece, player) { | |
return piece !== 0 && (player === 1 ? piece === 2 || piece === 4 : piece === 1 || piece === 3); | |
} | |
function isPlayerPiece(piece, player) { | |
return player === 1 ? piece === 1 || piece === 3 : player === 2 && (piece === 2 || piece === 4); | |
} | |
function isKing(piece) { | |
return piece === 3 || piece === 4; | |
} | |
function initGame() { | |
board = Array.from({ length: boardSize }, () => Array(boardSize).fill(0)); | |
for (let row = 0; row < 3; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
if ((row + col) % 2 === 1) board[row][col] = 1; | |
} | |
} | |
for (let row = boardSize - 3; row < boardSize; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
if ((row + col) % 2 === 1) board[row][col] = 2; | |
} | |
} | |
currentPlayer = 1; | |
selectedPiece = null; | |
validMoves = []; | |
gameRunning = true; | |
winMessageElement.style.display = "none"; | |
newGameButton.style.display = "inline-block"; | |
vsCPU = cpuToggle.checked; | |
cpuToggle.disabled = false; | |
updateStatus(); | |
updateBackground(); | |
renderBoard(); | |
if (vsCPU && currentPlayer === 2) { | |
setTimeout(cpuMove, 500); | |
} | |
} | |
function updateStatus() { | |
statusElement.textContent = `${players[currentPlayer].name} ist am Zug`; | |
} | |
function updateBackground() { | |
body.style.setProperty("--active-background-color", players[currentPlayer].color); | |
} | |
function getValidMoves(row, col) { | |
const moves = []; | |
const piece = board[row][col]; | |
if (!isPlayerPiece(piece, currentPlayer)) return moves; | |
const directions = isKing(piece) | |
? [[1, 1], [1, -1], [-1, 1], [-1, -1]] | |
: currentPlayer === 1 | |
? [[1, -1], [1, 1]] | |
: [[-1, -1], [-1, 1]]; | |
directions.forEach(([dr, dc]) => { | |
const newRow = row + dr, newCol = col + dc; | |
if (inBounds(newRow, newCol) && isEmpty(newRow, newCol)) { | |
moves.push({ row: newRow, col: newCol, capture: false }); | |
} | |
const captureRow = row + 2 * dr, captureCol = col + 2 * dc; | |
if (inBounds(newRow, newCol) && inBounds(captureRow, captureCol) && isOpponent(board[newRow][newCol], currentPlayer) && isEmpty(captureRow, captureCol)) { | |
moves.push({ row: captureRow, col: captureCol, capture: true, captured: { row: newRow, col: newCol } }); | |
} | |
}); | |
return moves; | |
} | |
function getValidMovesForPlayer(row, col, player) { | |
const moves = []; | |
const piece = board[row][col]; | |
if (!isPlayerPiece(piece, player)) return moves; | |
const directions = isKing(piece) | |
? [[1, 1], [1, -1], [-1, 1], [-1, -1]] | |
: player === 1 | |
? [[1, -1], [1, 1]] | |
: [[-1, -1], [-1, 1]]; | |
directions.forEach(([dr, dc]) => { | |
const newRow = row + dr, newCol = col + dc; | |
if (inBounds(newRow, newCol) && isEmpty(newRow, newCol)) { | |
moves.push({ row: newRow, col: newCol, capture: false }); | |
} | |
const captureRow = row + 2 * dr, captureCol = col + 2 * dc; | |
if (inBounds(newRow, newCol) && inBounds(captureRow, captureCol) && isOpponent(board[newRow][newCol], player) && isEmpty(captureRow, captureCol)) { | |
moves.push({ row: captureRow, col: captureCol, capture: true, captured: { row: newRow, col: newCol } }); | |
} | |
}); | |
return moves; | |
} | |
function hasAnyMoves(player) { | |
for (let row = 0; row < boardSize; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
if (isPlayerPiece(board[row][col], player) && getValidMovesForPlayer(row, col, player).length > 0) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
function hasAnyCapture() { | |
for (let row = 0; row < boardSize; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
if (isPlayerPiece(board[row][col], currentPlayer) && getValidMoves(row, col).some(move => move.capture)) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
function makeMove(fromRow, fromCol, move) { | |
board[move.row][move.col] = board[fromRow][fromCol]; | |
board[fromRow][fromCol] = 0; | |
if (move.capture) { | |
const captured = move.captured; | |
board[captured.row][captured.col] = 0; | |
} | |
if (currentPlayer === 1 && move.row === boardSize - 1 && board[move.row][move.col] === 1) { | |
board[move.row][move.col] = 3; | |
} else if (currentPlayer === 2 && move.row === 0 && board[move.row][move.col] === 2) { | |
board[move.row][move.col] = 4; | |
} | |
} | |
function switchPlayer() { | |
currentPlayer = currentPlayer === 1 ? 2 : 1; | |
selectedPiece = null; | |
renderBoard(); | |
validMoves = []; | |
updateStatus(); | |
updateBackground(); | |
if (hasAnyMoves(currentPlayer)) { | |
if (vsCPU && currentPlayer === 2) { | |
setTimeout(cpuMove, 500); | |
} | |
} else { | |
endGame(currentPlayer === 1 ? 2 : 1); | |
} | |
} | |
function cpuMove() { | |
let possibleMoves = []; | |
const mustCapture = hasAnyCapture(); | |
for (let row = 0; row < boardSize; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
if (isPlayerPiece(board[row][col], currentPlayer)) { | |
let moves = getValidMoves(row, col); | |
if (mustCapture) { | |
moves = moves.filter(move => move.capture); | |
} | |
if (moves.length > 0) { | |
possibleMoves.push({ row, col, moves }); | |
} | |
} | |
} | |
} | |
if (possibleMoves.length === 0) { | |
endGame(currentPlayer === 1 ? 2 : 1); | |
return; | |
} | |
const { row, col, moves } = possibleMoves[Math.floor(Math.random() * possibleMoves.length)]; | |
const move = moves[Math.floor(Math.random() * moves.length)]; | |
setTimeout(() => { | |
makeMove(row, col, move); | |
renderBoard(); | |
if (move.capture) { | |
cpuCaptureChain(move.row, move.col); | |
} else { | |
checkWin() || switchPlayer(); | |
} | |
}, 500); | |
} | |
function cpuCaptureChain(row, col) { | |
let captureMoves = getValidMoves(row, col).filter(move => move.capture); | |
if (captureMoves.length > 0) { | |
const move = captureMoves[Math.floor(Math.random() * captureMoves.length)]; | |
setTimeout(() => { | |
makeMove(row, col, move); | |
renderBoard(); | |
cpuCaptureChain(move.row, move.col); | |
}, 500); | |
} else { | |
checkWin() || switchPlayer(); | |
} | |
} | |
function checkWin() { | |
let player1Pieces = 0, player2Pieces = 0; | |
for (let row = 0; row < boardSize; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
if (board[row][col] === 1 || board[row][col] === 3) { | |
player1Pieces++; | |
} else if (board[row][col] === 2 || board[row][col] === 4) { | |
player2Pieces++; | |
} | |
} | |
} | |
if (player1Pieces === 0) { | |
endGame(2); | |
return true; | |
} else if (player2Pieces === 0) { | |
endGame(1); | |
return true; | |
} else if (!hasAnyMoves(currentPlayer === 1 ? 2 : 1)) { | |
endGame(currentPlayer); | |
return true; | |
} | |
return false; | |
} | |
function endGame(winner) { | |
gameRunning = false; | |
newGameButton.style.display = "none"; | |
winMessageElement.textContent = `Spieler ${winner} hat gewonnen! (Zum Neustart klicken)`; | |
winMessageElement.style.display = "block"; | |
winMessageElement.style.backgroundColor = `rgba(${players[winner].color}, 1.0)`; | |
cpuToggle.disabled = false; | |
winMessageElement.addEventListener("click", initGame, { once: true }); | |
} | |
function renderBoard() { | |
boardElement.innerHTML = ""; | |
for (let row = 0; row < boardSize; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
const cell = document.createElement("div"); | |
cell.classList.add("cell"); | |
cell.classList.add((row + col) % 2 === 0 ? "light" : "dark"); | |
cell.dataset.row = row; | |
cell.dataset.col = col; | |
if (validMoves.some(move => move.row === row && move.col === col)) { | |
cell.classList.add("highlight"); | |
} | |
if (selectedPiece && selectedPiece.row === row && selectedPiece.col === col) { | |
cell.classList.add("selected"); | |
} | |
const piece = board[row][col]; | |
if (piece !== 0) { | |
const pieceElement = document.createElement("div"); | |
pieceElement.classList.add("piece"); | |
pieceElement.style.setProperty("--player-color", players[piece % 2 === 0 ? 2 : 1].color); | |
if (isKing(piece)) { | |
pieceElement.classList.add("king"); | |
} | |
if (getValidMoves(row, col).some(move => move.capture)) { | |
pieceElement.classList.add("must-capture"); | |
} else { | |
pieceElement.classList.remove("must-capture"); | |
} | |
cell.appendChild(pieceElement); | |
} | |
cell.addEventListener("click", handleCellClick); | |
boardElement.appendChild(cell); | |
} | |
} | |
} | |
function handleCellClick(event) { | |
if (!gameRunning || (vsCPU && currentPlayer === 2)) return; | |
const row = parseInt(event.currentTarget.dataset.row); | |
const col = parseInt(event.currentTarget.dataset.col); | |
if (selectedPiece) { | |
const move = validMoves.find(move => move.row === row && move.col === col); | |
if (move) { | |
makeMove(selectedPiece.row, selectedPiece.col, move); | |
renderBoard(); | |
if (move.capture) { | |
const captureMoves = getValidMoves(move.row, move.col).filter(move => move.capture); | |
if (captureMoves.length > 0) { | |
selectedPiece = { row: move.row, col: move.col }; | |
validMoves = captureMoves; | |
return; | |
} | |
} | |
selectedPiece = null; | |
validMoves = []; | |
checkWin() || switchPlayer(); | |
return; | |
} | |
} | |
if (isPlayerPiece(board[row][col], currentPlayer)) { | |
if (hasAnyCapture()) { | |
const captureMoves = getValidMoves(row, col).filter(move => move.capture); | |
if (captureMoves.length === 0) return; | |
selectedPiece = { row, col }; | |
validMoves = captureMoves; | |
} else { | |
selectedPiece = { row, col }; | |
validMoves = getValidMoves(row, col); | |
} | |
renderBoard(); | |
} | |
} | |
function openSavePlayerNamesDialog() { | |
if (!cpuToggle.checked) { | |
inputPlayerName2.value = inputPlayerName2.value === "CPU" ? "Spieler 2" : inputPlayerName2.value; | |
} else { | |
inputPlayerName2.value = "CPU"; | |
} | |
inputPlayerName2.disabled = cpuToggle.checked; | |
document.getElementById("setPlayerNamesWrapperBackdrop").style.display = "block"; | |
} | |
savePlayerNamesButton.addEventListener("click", () => { | |
players[1].name = inputPlayerName1.value.length > 0 ? inputPlayerName1.value : "Spieler 1"; | |
players[2].name = inputPlayerName2.value.length > 0 ? inputPlayerName2.value : "Spieler 2"; | |
document.getElementById("setPlayerNamesWrapperBackdrop").style.display = "none"; | |
cpuToggle.disabled = false; | |
initGame(); | |
}); | |
newGameButton.addEventListener("click", openSavePlayerNamesDialog); | |
cpuToggle.addEventListener("click", openSavePlayerNamesDialog); | |
initGame(); |