<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SaFu Chess</title>
<style>
body {
margin: 0;
background: #172334;
color: white;
font-family: Arial, sans-serif;
text-align: center;
}
h1 { color: #8fc46b; }
#board {
display: grid;
grid-template-columns: repeat(8, 1fr);
width: min(90vw, 480px);
margin: 20px auto;
border: 5px solid #34465d;
}
.square {
aspect-ratio: 1;
display: grid;
place-items: center;
font-size: clamp(25px, 8vw, 50px);
border: 0;
padding: 0;
}
.light { background: #f0d9b5; }
.dark { background: #b58863; }
.selected { outline: 4px solid yellow; }
.hint { box-shadow: inset 0 0 0 5px #8fc46b; }
button.control {
padding: 12px 20px;
margin: 5px;
border: 0;
border-radius: 8px;
background: #8fc46b;
font-weight: bold;
cursor: pointer;
}
#status { margin: 15px; font-size: 20px; }
</style>
</head>
<body>
<h1>♟ SaFu Chess</h1>
<p>Шахматы для двух игроков</p>
<div id="status">Белые ходят первыми</div>
<div id="board"></div>
<button class="control" onclick="newGame()">Новая игра</button>
<button class="control" onclick="undoMove()">Отменить ход</button>
<button class="control" onclick="flipBoard()">Перевернуть доску</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
<script>
const game = new Chess();
const symbols = {
wk:"♔", wq:"♕", wr:"♖", wb:"♗",
wn:"♘", wp:"♙",
bk:"♚", bq:"♛", br:"♜",
bb:"♝", bn:"♞", bp:"♟"
};
let selected = null;
let flipped = false;
let targets = [];
function render() {
const board = document.getElementById("board");
board.innerHTML = "";
const position = game.board();
for (let vr = 0; vr < 8; vr++) {
for (let vc = 0; vc < 8; vc++) {
const r = flipped ? 7-vr : vr;
const c = flipped ? 7-vc : vc;
const squareName =
"abcdefgh"[c] + (8-r);
const piece = position[r][c];
const button = document.createElement("button");
button.className =
"square " +
((r+c)%2 ? "dark" : "light");
if (selected === squareName)
button.classList.add("selected");
if (targets.some(m => m.to === squareName))
button.classList.add("hint");
if (piece)
button.textContent =
symbols[piece.color + piece.type];
button.onclick = () => clickSquare(squareName);
board.appendChild(button);
}
}
updateStatus();
}
function clickSquare(sq) {
if (game.game_over()) return;
if (selected) {
const move = targets.find(m => m.to === sq);
if (move) {
let promotion = "q";
if (move.flags.includes("p")) {
const answer = prompt(
"Превращение пешки: q — ферзь, r — ладья, b — слон, n — конь",
"q"
);
if (answer && "qrbn".includes(answer.toLowerCase()))
promotion = answer.toLowerCase();
}
game.move({
from: selected,
to: sq,
promotion
});
selected = null;
targets = [];
render();
return;
}
}
const piece = game.get(sq);
if (piece && piece.color === game.turn()) {
selected = sq;
targets = game.moves({
square: sq,
verbose: true
});
} else {
selected = null;
targets = [];
}
render();
}
function updateStatus() {
const status = document.getElementById("status");
if (game.in_checkmate()) {
status.textContent =
"МАТ! Победили " +
(game.turn() === "w" ? "чёрные!" : "белые!");
} else if (game.in_draw()) {
status.textContent = "Ничья!";
} else if (game.in_check()) {
status.textContent = "ШАХ!";
} else {
status.textContent =
game.turn() === "w"
? "Ход белых"
: "Ход чёрных";
}
}
function newGame() {
game.reset();
selected = null;
targets = [];
render();
}
function undoMove() {
game.undo();
selected = null;
targets = [];
render();
}
function flipBoard() {
flipped = !flipped;
render();
}
render();
</script>
</body>
</html>