const PAWN = 0;
const KNIGHT = 1;
const BISHOP = 2;
const ROOK = 3;
const QUEEN = 4;
const KING = 5;
const black_rook_image = document.getElementById('black_rook');
const black_knight_image = document.getElementById('black_knight');
const black_bishop_image = document.getElementById('black_bishop');
const black_queen_image = document.getElementById('black_queen');
const black_king_image = document.getElementById('black_king');
const black_pawn_image = document.getElementById('black_pawn');
const white_rook_image = document.getElementById('white_rook');
const white_knight_image = document.getElementById('white_knight');
const white_bishop_image = document.getElementById('white_bishop');
const white_queen_image = document.getElementById('white_queen');
const white_king_image = document.getElementById('white_king');
const white_pawn_image = document.getElementById('white_pawn');
function uuidv4() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
class Piece {
constructor(col, row, type, color) {
this.row = row;
this.col = col;
this.type = type;
this.color = color;
}
}
/**
* @param {String} HTML representing a single element
* @return {Element}
*/
function htmlToElement(html) {
var template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content.firstChild;
}
var td = htmlToElement('
foo | '),
div = htmlToElement('nested stuff
');
/**
* @param {String} HTML representing any number of sibling elements
* @return {NodeList}
*/
function htmlToElements(html) {
var template = document.createElement('template');
template.innerHTML = html;
return template.content.childNodes;
}
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() *
charactersLength));
}
return result;
}
console.log(makeid(5));
function simulateGame(g, outID) {
let canvasID = makeid(9);
console.log("Simulating game " + g + "; canvas " + canvasID + "; out " + outID + ".");
function executeMoves(s) {
let moves = s.split(". ");
function parsePlyToTargetNoCheck(ply) {
if (ply.includes("=")) {
ply = ply.substring(0, ply.length - 2);
}
let l = ply.length;
let row = parseInt(ply.substring(l - 1, l), 10) - 1;
let col = ["a", "b", "c", "d", "e", "f", "g", "h"].reverse().indexOf(ply.substring(l - 2, l - 1));
return [row, col];
}
function parsePlyToTarget(ply) {
let l = ply.length;
let row = parseInt(ply.substring(l - 1, l), 10) - 1;
let col = ["a", "b", "c", "d", "e", "f", "g", "h"].reverse().indexOf(ply.substring(l - 2, l - 1));
for (const piece of gamePieces) {
if (piece.row === row && piece.col === col) {
return [row, col];
}
}
return -69;
}
function parsePlyToTargetP(ply) {
if (parsePlyToTarget(ply) === -69) {
return -69;
}
let [row, col] = parsePlyToTarget(ply);
for (const piece of gamePieces) {
if (piece.row === row && piece.col === col) {
return piece;
}
}
return -69;
}
function parsePlyToPiece(ply, color) {
let l = ply.length;
let pieceType = -1;
// First, determine the piece type.
let firstChar = ply.substring(0, 1);
if (firstChar === "K") {
pieceType = KING;
} else if (firstChar === "Q") {
pieceType = QUEEN;
} else if (firstChar === "B") {
pieceType = BISHOP;
} else if (firstChar === "N") {
pieceType = KNIGHT;
} else if (firstChar === "R") {
pieceType = ROOK;
} else {
pieceType = PAWN;
}
if (pieceType === KING) { // King is the easiest case.
for (const piece of gamePieces) {
if (piece.type === KING && piece.color === color) {
return piece;
}
}
throw 'No king found for ply ' + ply + ' and color ' + color + '.';
}
if (pieceType === QUEEN) { // Also easy
for (const piece of gamePieces) {
if (piece.type === QUEEN && piece.color === color) {
return piece;
}
}
throw 'No queen found for ply ' + ply + ' and color ' + color + '.';
}
if (pieceType === BISHOP || pieceType === KNIGHT || pieceType === ROOK) { // These all say where they were
let past = ply.split("(")[1].split(")")[0];
return parsePlyToTargetP(past);
}
if (pieceType === PAWN) { // Fuck
if (ply.length === 2) { // Normal pawn move
let ePart = ply.substring(0, 1);
let sevenPart = ply.substring(1, 2);
if (color === 0) {
let potentialPawnSource = ePart + (sevenPart - 1);
let attempt = parsePlyToTargetP(potentialPawnSource);
if (attempt !== -69) {
return attempt
} else {
potentialPawnSource = ePart + (sevenPart - 2);
return parsePlyToTargetP(potentialPawnSource);
}
} else {
let potentialPawnSource = ePart + (sevenPart - -1);
let attempt = parsePlyToTargetP(potentialPawnSource);
if (attempt !== -69) {
return attempt
} else {
potentialPawnSource = ePart + (sevenPart - -2);
return parsePlyToTargetP(potentialPawnSource);
}
}
} else if (ply.length === 4) {
if (!ply.includes("=")) { // normal capture
let ePart = ply.substring(0, 1); // exd7
// ^
let sevenPart = ply.substring(3, 4); // exd7
// ^
if (color === 0) {
let potentialPawnSource = ePart + (sevenPart - 1);
let attempt = parsePlyToTargetP(potentialPawnSource);
if (attempt !== -69) {
return attempt
} else {
potentialPawnSource = ePart + (sevenPart - 2);
return parsePlyToTargetP(potentialPawnSource);
}
} else {
let potentialPawnSource = ePart + (sevenPart - -1);
let attempt = parsePlyToTargetP(potentialPawnSource);
if (attempt !== -69) {
return attempt
} else {
potentialPawnSource = ePart + (sevenPart - -2);
return parsePlyToTargetP(potentialPawnSource);
}
}
} else { // Promotion
let ePart = ply.substring(0, 1); // e8=Q
// ^
let sevenPart = ply.substring(1, 2); // e8=Q
// ^
if (color === 0) {
let potentialPawnSource = ePart + (sevenPart - 1);
return parsePlyToTargetP(potentialPawnSource);
} else {
let potentialPawnSource = ePart + (sevenPart - -1);
return parsePlyToTargetP(potentialPawnSource);
}
}
} else if (ply.length === 6) { // Capture and promotion
let ePart = ply.substring(0, 1); // dxc1=Q
// ^
let sevenPart = ply.substring(3, 4); // dxc1=Q
// ^
if (color === 0) {
let potentialPawnSource = ePart + (sevenPart - 1);
return parsePlyToTargetP(potentialPawnSource);
} else {
let potentialPawnSource = ePart + (sevenPart - -1);
return parsePlyToTargetP(potentialPawnSource);
}
} else {
throw "The heck does " + ply + " mean??";
}
}
}
for (const move of moves) {
if (move === "1") {
continue;
}
let plies = move.split(" ");
let ply1 = plies[0];
selectedPiece = parsePlyToPiece(ply1, turn);
state = 1;
let [row, col] = parsePlyToTargetNoCheck(ply1);
console.log(getLegalMoves(selectedPiece, structuredClone(gamePieces)));
if (getLegalMoves(selectedPiece, structuredClone(gamePieces)).some(a => [row, col].every((v, i) => v === a[i]))) {
let what = "";
if (ply1.includes("=")) {
what = ply1.substring(ply1.length - 1, ply1.length);
}
let [capture, oldCol, special, newPieces] = movePiece(selectedPiece, row, col, gamePieces, what);
gamePieces = newPieces;
updateGravity(gamePieces);
recordMove(selectedPiece, row, col, capture, oldCol, special);
turn = 1 - turn;
}
updateBoard();
console.log("Executed " + ply1);
selectedPiece = null;
state = 0;
let ply2 = plies[1];
if (ply2.length === 0) {
continue;
}
selectedPiece = parsePlyToPiece(ply2, turn);
state = 1;
[row, col] = parsePlyToTargetNoCheck(ply2);
console.log(getLegalMoves(selectedPiece, structuredClone(gamePieces)));
if (getLegalMoves(selectedPiece, structuredClone(gamePieces)).some(a => [row, col].every((v, i) => v === a[i]))) {
let what = "";
if (ply2.includes("=")) {
what = ply2.substring(ply2.length - 1, ply2.length);
}
let [capture, oldCol, special, newPieces] = movePiece(selectedPiece, row, col, gamePieces, what);
gamePieces = newPieces;
updateGravity(gamePieces);
recordMove(selectedPiece, row, col, capture, oldCol, special);
turn = 1 - turn;
}
updateBoard();
console.log("Executed " + ply2);
selectedPiece = null;
state = 0;
}
}
let canvas;
let ctx;
let canvas_width;
let canvas_height;
assert(canvas_width === canvas_height, "Weird canvas you got there");
let SIZE;
Promise.all(Array.from(document.images).filter(img => !img.complete).map(img => new Promise(resolve => {
img.onload = img.onerror = resolve;
}))).then(() => {
var rows = htmlToElements("\n" +
" \n" +
" \n" +
"
\n" +
"
h
\n" +
"
g
\n" +
"
f
\n" +
"
e
\n" +
"
d
\n" +
"
c
\n" +
"
b
\n" +
"
a
\n" +
"\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
1
\n" +
"
2
\n" +
"
3
\n" +
"
4
\n" +
"
5
\n" +
"
6
\n" +
"
7
\n" +
"
8
\n" +
"
\n" +
"
\n" +
" \n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
"
\n" +
" ");
document.body.append(...rows);
}).then(() => {
canvas = document.querySelector('#' + canvasID);
ctx = canvas.getContext('2d');
canvas_width = ctx.canvas.clientWidth;
canvas_height = ctx.canvas.clientHeight;
assert(canvas_width === canvas_height, "Weird canvas you got there");
SIZE = canvas_width / 8;
canvas.addEventListener('mousedown', function (e) {
let [x, y] = getCursorPosition(canvas, e);
console.log("You clicked on " + x + ", " + y);
if (state === 0) { // Selecting a piece
// Detect whether this selected a piece
selectedPiece = getSelectedPiece(x, y);
if (selectedPiece == null) {
console.log("you clicked nowhere");
return;
}
if (selectedPiece.color !== turn) {
console.log("you clicked the other player's piece");
return;
}
console.log("You chose the piece " + selectedPiece.type);
state = 1;
} else if (state === 1) { // Selecting a square to move to
let [row, col] = getSelectedSquare(x, y);
console.log(getLegalMoves(selectedPiece, structuredClone(gamePieces)));
if (getLegalMoves(selectedPiece, structuredClone(gamePieces)).some(a => [row, col].every((v, i) => v === a[i]))) {
let [capture, oldCol, special, newPieces] = movePiece(selectedPiece, row, col, gamePieces);
gamePieces = newPieces;
updateGravity(gamePieces);
recordMove(selectedPiece, row, col, capture, oldCol, special);
turn = 1 - turn;
}
selectedPiece = null;
state = 0;
}
updateBoard(selectedPiece);
});
loadBoard();
}).then(() => {
let url = new URL(window.location.href);
let gameRecord = url.searchParams.get('game');
executeMoves(g);
}).then(() => {
updateBoard();
}).then(() => {
updateBoard();
const ccc = document.getElementById(canvasID);
const dataURL = ccc.toDataURL("image/png");
document.getElementById(outID).innerHTML = "";
});
/**
* Creates an array of pieces on a standard chess board.
*
* @returns {Array} the array of 32 Pieces.
*/
function initGamePieces() {
let pieces = [];
pieces.push(new Piece(0, 7, ROOK, 1));
pieces.push(new Piece(1, 7, KNIGHT, 1));
pieces.push(new Piece(2, 7, BISHOP, 1));
pieces.push(new Piece(3, 7, KING, 1));
pieces.push(new Piece(4, 7, QUEEN, 1));
pieces.push(new Piece(5, 7, BISHOP, 1));
pieces.push(new Piece(6, 7, KNIGHT, 1));
pieces.push(new Piece(7, 7, ROOK, 1));
for (let i = 0; i < 8; i++) {
pieces.push(new Piece(i, 6, PAWN, 1));
}
pieces.push(new Piece(0, 0, ROOK, 0));
pieces.push(new Piece(1, 0, KNIGHT, 0));
pieces.push(new Piece(2, 0, BISHOP, 0));
pieces.push(new Piece(3, 0, KING, 0));
pieces.push(new Piece(4, 0, QUEEN, 0));
pieces.push(new Piece(5, 0, BISHOP, 0));
pieces.push(new Piece(6, 0, KNIGHT, 0));
pieces.push(new Piece(7, 0, ROOK, 0));
for (let i = 0; i < 8; i++) {
pieces.push(new Piece(i, 1, PAWN, 0));
}
return pieces;
}
let gamePieces = initGamePieces();
// The actual game code
let player = 1;
function loadBoard() {
updateBoard();
}
function getPieceOn(row, col, pieces) {
for (const piece of pieces) {
if (piece.row === row && piece.col === col) {
return piece;
}
}
return null;
}
function onBoard(row, col) {
return 0 <= row && row <= 7 && 0 <= col && col <= 7;
}
function structuredClone(a) { // polyfill
return JSON.parse(JSON.stringify(a));
}
function getLegalMoves(piece, pieces, simulated = false) {
let legalMoves = [];
let row = piece.row;
let col = piece.col;
if (piece.type === PAWN) {
if (piece.color === 0) {
if (getPieceOn(row + 1, col, pieces) == null) {
legalMoves.push([row + 1, col]);
}
if (row === 1) {
if (getPieceOn(row + 2, col, pieces) == null) {
legalMoves.push([row + 2, col]);
}
}
if (getPieceOn(row + 1, col + 1, pieces) != null) {
if (getPieceOn(row + 1, col + 1, pieces).color === 1) {
legalMoves.push([row + 1, col + 1]);
}
}
if (getPieceOn(row + 1, col - 1, pieces) != null) {
if (getPieceOn(row + 1, col - 1, pieces).color === 1) {
legalMoves.push([row + 1, col - 1]);
}
}
} else {
if (getPieceOn(row - 1, col, pieces) == null) {
legalMoves.push([row - 1, col]);
}
if (row === 6) {
if (getPieceOn(row - 2, col, pieces) == null) {
legalMoves.push([row - 2, col]);
}
}
if (getPieceOn(row - 1, col + 1, pieces) != null) {
if (getPieceOn(row - 1, col + 1, pieces).color === 0) {
legalMoves.push([row - 1, col + 1]);
}
}
if (getPieceOn(row - 1, col - 1, pieces) != null) {
if (getPieceOn(row - 1, col - 1, pieces).color === 0) {
legalMoves.push([row - 1, col - 1]);
}
}
}
}
if (piece.type === ROOK) {
for (let i = row + 1; i < 8; i++) {
if (getPieceOn(i, col, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(i, col, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([i, col]);
break;
} else {
legalMoves.push([i, col]);
}
}
for (let i = row - 1; i > -1; i--) {
if (getPieceOn(i, col, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(i, col, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([i, col]);
break;
} else {
legalMoves.push([i, col]);
}
}
for (let i = col + 1; i < 8; i++) {
if (getPieceOn(row, i, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(row, i, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([row, i]);
break;
} else {
legalMoves.push([row, i]);
}
}
for (let i = col - 1; i > -1; i--) {
if (getPieceOn(row, i, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(row, i, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([row, i]);
break;
} else {
legalMoves.push([row, i]);
}
}
}
if (piece.type === KNIGHT) {
if (getPieceOn(row + 2, col + 1, pieces) != null) {
if (getPieceOn(row + 2, col + 1, pieces).color !== piece.color) {
legalMoves.push([row + 2, col + 1]);
}
} else {
if (onBoard(row + 2, col + 1)) {
legalMoves.push([row + 2, col + 1]);
}
}
if (getPieceOn(row + 2, col - 1, pieces) != null) {
if (getPieceOn(row + 2, col - 1, pieces).color !== piece.color) {
legalMoves.push([row + 2, col - 1]);
}
} else {
if (onBoard(row + 2, col - 1)) {
legalMoves.push([row + 2, col - 1]);
}
}
if (getPieceOn(row - 2, col + 1, pieces) != null) {
if (getPieceOn(row - 2, col + 1, pieces).color !== piece.color) {
legalMoves.push([row - 2, col + 1]);
}
} else {
if (onBoard(row - 2, col + 1)) {
legalMoves.push([row - 2, col + 1]);
}
}
if (getPieceOn(row - 2, col - 1, pieces) != null) {
if (getPieceOn(row - 2, col - 1, pieces).color !== piece.color) {
legalMoves.push([row - 2, col - 1]);
}
} else {
if (onBoard(row - 2, col - 1)) {
legalMoves.push([row - 2, col - 1]);
}
}
if (getPieceOn(row + 1, col + 2, pieces) != null) {
if (getPieceOn(row + 1, col + 2, pieces).color !== piece.color) {
legalMoves.push([row + 1, col + 2]);
}
} else {
if (onBoard(row + 1, col + 2)) {
legalMoves.push([row + 1, col + 2]);
}
}
if (getPieceOn(row + 1, col - 2, pieces) != null) {
if (getPieceOn(row + 1, col - 2, pieces).color !== piece.color) {
legalMoves.push([row + 1, col - 2]);
}
} else {
if (onBoard(row + 1, col - 2)) {
legalMoves.push([row + 1, col - 2]);
}
}
if (getPieceOn(row - 1, col + 2, pieces) != null) {
if (getPieceOn(row - 1, col + 2, pieces).color !== piece.color) {
legalMoves.push([row - 1, col + 2]);
}
} else {
if (onBoard(row - 1, col + 2)) {
legalMoves.push([row - 1, col + 2]);
}
}
if (getPieceOn(row - 1, col - 2, pieces) != null) {
if (getPieceOn(row - 1, col - 2, pieces).color !== piece.color) {
legalMoves.push([row - 1, col - 2]);
}
} else {
if (onBoard(row - 1, col - 2)) {
legalMoves.push([row - 1, col - 2]);
}
}
}
if (piece.type === BISHOP) {
for (let i = 1; i < 10; i++) {
let newRow = row + i;
let newCol = col + i;
if (!onBoard(newRow, newCol)) {
break;
}
if (getPieceOn(newRow, newCol, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(newRow, newCol, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([newRow, newCol]);
break;
} else {
legalMoves.push([newRow, newCol]);
}
}
for (let i = 1; i < 10; i++) {
let newRow = row + i;
let newCol = col - i;
if (!onBoard(newRow, newCol)) {
break;
}
if (getPieceOn(newRow, newCol, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(newRow, newCol, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([newRow, newCol]);
break;
} else {
legalMoves.push([newRow, newCol]);
}
}
for (let i = 1; i < 10; i++) {
let newRow = row - i;
let newCol = col + i;
if (!onBoard(newRow, newCol)) {
break;
}
if (getPieceOn(newRow, newCol, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(newRow, newCol, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([newRow, newCol]);
break;
} else {
legalMoves.push([newRow, newCol]);
}
}
for (let i = 1; i < 10; i++) {
let newRow = row - i;
let newCol = col - i;
if (!onBoard(newRow, newCol)) {
break;
}
if (getPieceOn(newRow, newCol, pieces) != null) { // If there's a piece in the way
// If it's the same color piece, that's it
if (getPieceOn(newRow, newCol, pieces).color === piece.color) {
break;
}
// If it's the other color piece, add it but that's it
legalMoves.push([newRow, newCol]);
break;
} else {
legalMoves.push([newRow, newCol]);
}
}
}
if (piece.type === QUEEN) {
let pieceCopy = JSON.parse(JSON.stringify(piece));
pieceCopy.type = ROOK;
legalMoves = legalMoves.concat(getLegalMoves(pieceCopy, pieces, true));
let pieceCopy2 = JSON.parse(JSON.stringify(piece));
pieceCopy2.type = BISHOP;
legalMoves = legalMoves.concat(getLegalMoves(pieceCopy2, pieces, true));
}
if (piece.type === KING) {
if (getPieceOn(row + 1, col + 1, pieces) != null) {
if (getPieceOn(row + 1, col + 1, pieces).color !== piece.color) {
legalMoves.push([row + 1, col + 1]);
}
} else {
if (onBoard(row + 1, col + 1)) {
legalMoves.push([row + 1, col + 1]);
}
}
if (getPieceOn(row + 1, col - 1, pieces) != null) {
if (getPieceOn(row + 1, col - 1, pieces).color !== piece.color) {
legalMoves.push([row + 1, col - 1]);
}
} else {
if (onBoard(row + 1, col - 1)) {
legalMoves.push([row + 1, col - 1]);
}
}
if (getPieceOn(row - 1, col + 1, pieces) != null) {
if (getPieceOn(row - 1, col + 1, pieces).color !== piece.color) {
legalMoves.push([row - 1, col + 1]);
}
} else {
if (onBoard(row - 1, col + 1)) {
legalMoves.push([row - 1, col + 1]);
}
}
if (getPieceOn(row - 1, col - 1, pieces) != null) {
if (getPieceOn(row - 1, col - 1, pieces).color !== piece.color) {
legalMoves.push([row - 1, col - 1]);
}
} else {
if (onBoard(row - 1, col - 1)) {
legalMoves.push([row - 1, col - 1]);
}
}
if (getPieceOn(row, col + 1, pieces) != null) {
if (getPieceOn(row, col + 1, pieces).color !== piece.color) {
legalMoves.push([row, col + 1]);
}
} else {
if (onBoard(row, col + 1)) {
legalMoves.push([row, col + 1]);
}
}
if (getPieceOn(row, col - 1, pieces) != null) {
if (getPieceOn(row, col - 1, pieces).color !== piece.color) {
legalMoves.push([row, col - 1]);
}
} else {
if (onBoard(row, col - 1)) {
legalMoves.push([row, col - 1]);
}
}
if (getPieceOn(row - 1, col, pieces) != null) {
if (getPieceOn(row - 1, col, pieces).color !== piece.color) {
legalMoves.push([row - 1, col]);
}
} else {
if (onBoard(row - 1, col)) {
legalMoves.push([row - 1, col]);
}
}
if (getPieceOn(row + 1, col, pieces) != null) {
if (getPieceOn(row + 1, col, pieces).color !== piece.color) {
legalMoves.push([row + 1, col]);
}
} else {
if (onBoard(row + 1, col)) {
legalMoves.push([row + 1, col]);
}
}
}
// function testLegality(move, piece, pieces) {
// let [_, __, ___, newPieces] = movePiece(piece, move[0], move[1], pieces);
//
// let kingLocation = getKingLocation(player, pieces);
//
// for (const chPiece of pieces) {
// if (chPiece.color !== player) { // If it's the opposite color
// let opponentPieceLegalMoves = getLegalMoves(chPiece, structuredClone(newPieces), true);
//
// for (const potentialOpponentMove of opponentPieceLegalMoves) {
// if (potentialOpponentMove[0] === kingLocation[0] && potentialOpponentMove[1] === kingLocation[1]) {
// return false;
// }
// }
// }
// }
//
// return true;
// }
return legalMoves;
// If we're in the recursion, return all the moves
// if (simulated) {
// return legalMoves;
// }
//
// // Otherwise, return only the actually legal moves
// let actuallyLegalMoves = [];
//
// for (let i = 0; i < legalMoves.length; i++) {
// let actuallyLegal = testLegality(legalMoves[i], piece, structuredClone(pieces));
//
// if (actuallyLegal) {
// actuallyLegalMoves.push(legalMoves[i]);
// }
// }
//
// return actuallyLegalMoves;
}
function getKingLocation(whichPlayer, pieces) {
for (const piece of pieces) {
if (piece.type === KING && piece.color === whichPlayer) {
return [piece.row, piece.col];
}
}
throw 'No king of this color on the board!';
}
function updateBoard(selectedPiece) {
drawBoard();
function drawPieceDetailed(piece) {
function drawCircle(piece) {
let centerX = (piece.col + 0.5) * SIZE;
let centerY = (piece.row + 0.5) * SIZE;
let radius = SIZE / 2;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
ctx.lineWidth = 5;
ctx.strokeStyle = '#7dcc11';
ctx.stroke();
}
function highlightLegalMoves(piece) {
let legalMoves = getLegalMoves(piece, structuredClone(gamePieces));
function highlightLegalMove(move) {
ctx.fillStyle = '#f7799e';
ctx.fillRect(move[1] * SIZE, move[0] * SIZE, SIZE, SIZE);
}
legalMoves.forEach(highlightLegalMove)
}
if (piece === selectedPiece) {
drawPiece(piece);
drawCircle(piece);
highlightLegalMoves(piece);
} else {
drawPiece(piece);
}
}
gamePieces.forEach(drawPieceDetailed);
gamePieces.forEach(drawPiece);
}
function drawBoard() {
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
if ((i + j) % 2 === 1) {
ctx.fillStyle = '#bd663d';
} else {
ctx.fillStyle = '#f7b596';
}
ctx.fillRect(i * SIZE, j * SIZE, SIZE, SIZE);
}
}
}
function get_image_scale() {
let w = (black_pawn_image.width / 128 * SIZE);
let h = (black_pawn_image.height / 128 * SIZE);
return [w, h]
}
function drawPiece(piece) {
if (piece.type === PAWN) {
let image = white_pawn_image;
if (piece.color === 1) {
image = black_pawn_image;
}
let [w, h] = get_image_scale();
let offsetW = piece.col * SIZE;
let offsetH = piece.row * SIZE;
ctx.drawImage(image, offsetW + 0.2 * w, offsetH + 0.1 * h, 0.8 * w, 0.8 * h);
} else if (piece.type === ROOK) {
let image = white_rook_image;
if (piece.color === 1) {
image = black_rook_image;
}
let [w, h] = get_image_scale();
let offsetW = piece.col * SIZE;
let offsetH = piece.row * SIZE;
ctx.drawImage(image, offsetW + 0.2 * w, offsetH + 0.1 * h, 0.8 * w, 0.8 * h);
} else if (piece.type === KNIGHT) {
let image = white_knight_image;
if (piece.color === 1) {
image = black_knight_image;
}
let [w, h] = get_image_scale();
let offsetW = piece.col * SIZE;
let offsetH = piece.row * SIZE;
ctx.drawImage(image, offsetW + 0.2 * w, offsetH + 0.1 * h, 0.8 * w, 0.8 * h);
} else if (piece.type === BISHOP) {
let image = white_bishop_image;
if (piece.color === 1) {
image = black_bishop_image;
}
let [w, h] = get_image_scale();
let offsetW = piece.col * SIZE;
let offsetH = piece.row * SIZE;
ctx.drawImage(image, offsetW + 0.2 * w, offsetH + 0.1 * h, 0.8 * w, 0.8 * h);
} else if (piece.type === QUEEN) {
let image = white_queen_image;
if (piece.color === 1) {
image = black_queen_image;
}
let [w, h] = get_image_scale();
let offsetW = piece.col * SIZE;
let offsetH = piece.row * SIZE;
ctx.drawImage(image, offsetW + 0.2 * w, offsetH + 0.1 * h, 0.8 * w, 0.8 * h);
} else if (piece.type === KING) {
let image = white_king_image;
if (piece.color === 1) {
image = black_king_image;
}
let [w, h] = get_image_scale();
let offsetW = piece.col * SIZE;
let offsetH = piece.row * SIZE;
ctx.drawImage(image, offsetW + 0.2 * w, offsetH + 0.1 * h, 0.8 * w, 0.8 * h);
}
}
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
return [x, y];
}
function getSelectedPiece(x, y) {
for (const piece of gamePieces) {
// Figure out this piece's square bounds
let lowX = SIZE * piece.col;
let lowY = SIZE * piece.row;
let highX = lowX + SIZE;
let highY = lowY + SIZE;
if (lowX < x && x < highX && lowY < y && y < highY) {
return piece;
}
}
return null;
}
function getSelectedSquare(x, y) {
return [Math.floor(y / SIZE), Math.floor(x / SIZE)];
}
function updateGravity(pieces) {
for (let i = 0; i < 8; i++) { // Max eight gravity updates
for (const piece of pieces) {
if (piece.type === PAWN) {
continue;
}
let belowRow = piece.row + 1;
let col = piece.col;
if (getPieceOn(belowRow, col, pieces) == null) {
if (onBoard(belowRow, col)) {
piece.row = belowRow;
piece.col = col;
}
}
}
}
}
let state = 0;
let turn = 0;
let selectedPiece = null;
// function movePiece(piece, toRow, toCol) {
// let numPieces = gamePieces.length;
// let special = "";
//
// // First, check for immediate captures
// if (getPieceOn(toRow, toCol) != null) {
// gamePieces = gamePieces.filter(piece => !(piece.row === getPieceOn(toRow, toCol).row && piece.col === getPieceOn(toRow, toCol).col))
// }
//
// let oldCol = piece.col;
//
// piece.row = toRow;
// piece.col = toCol;
//
// // Check if the piece is a promoted pawn
// if (piece.color === 0 && piece.row === 7 && piece.type === PAWN || piece.color === 1 && piece.row === 0 && piece.type === PAWN) {
// piece.type = askForPromotion();
// if (numPieces <= gamePieces.length) {
// special = getCoordsName(piece.row, piece.col) + "=" + getPieceName(piece, 0, 0).substring(0, 1);
// } else {
// special = getCoordsName(piece.row, oldCol).substring(0, 1) + "x" + getCoordsName(piece.row, piece.col) + "=" + getPieceName(piece, 0, 0).substring(0, 1);
// }
// }
//
// return [numPieces > gamePieces.length, oldCol, special];
// }
function movePiece(piece, toRow, toCol, pieces, promotion = "") {
let numPieces = pieces.length;
let special = "";
// First, check for immediate captures
if (getPieceOn(toRow, toCol, pieces) != null) {
pieces = pieces.filter(piece => !(piece.row === getPieceOn(toRow, toCol, pieces).row && piece.col === getPieceOn(toRow, toCol, pieces).col))
}
let oldCol = piece.col;
piece.row = toRow;
piece.col = toCol;
// Check if the piece is a promoted pawn
if (piece.color === 0 && piece.row === 7 && piece.type === PAWN || piece.color === 1 && piece.row === 0 && piece.type === PAWN) {
piece.type = askForPromotion(promotion);
if (numPieces <= pieces.length) {
special = getCoordsName(piece.row, piece.col) + "=" + getPieceName(piece, 0, 0).substring(0, 1);
} else {
special = getCoordsName(piece.row, oldCol).substring(0, 1) + "x" + getCoordsName(piece.row, piece.col) + "=" + getPieceName(piece, 0, 0).substring(0, 1);
}
}
return [numPieces > pieces.length, oldCol, special, pieces];
}
let move = 1;
let gameRecord = "";
function recordMove(selectedPiece, row, col, capture, oldCol, special) {
let pieceName = getPieceName(selectedPiece, capture, oldCol), coordsName = getCoordsName(row, col),
captureName = capture ? "x" : "", currentMoveRecord;
if (turn === 0) {
currentMoveRecord = special.length === 0 ? move + ". " + pieceName + "" + captureName + "" + coordsName + " " : special;
} else {
currentMoveRecord = special.length === 0 ? pieceName + "" + captureName + "" + coordsName + " " : special;
move++;
}
let winner = gameOver();
if (winner === 1) {
currentMoveRecord += " 0–1"
} else if (winner === 0) {
currentMoveRecord += " 1–0"
}
gameRecord += currentMoveRecord;
// let div = document.createElement("div");
// div.className = "move-record";
// div.innerHTML = currentMoveRecord;
//
// document.getElementById("game-record-flex").appendChild(div);
}
function gameOver() {
/**
* Returns the loser
* @type {number}
*/
let numKings = 0;
let winner = -1;
for (let piece of gamePieces) {
if (piece.type === KING) {
numKings++;
winner = piece.color;
}
}
return numKings === 2 ? -1 : winner;
}
function getPieceName(piece, capture, oldCol) {
if (piece.type === PAWN) {
if (!capture) {
return "";
} else {
return getCoordsName(piece.row, oldCol)[0];
}
} else if (piece.type === ROOK) {
return "R(" + getCoordsName(piece.row, piece.col) + ")";
} else if (piece.type === KNIGHT) {
return "N(" + getCoordsName(piece.row, piece.col) + ")";
} else if (piece.type === BISHOP) {
return "B(" + getCoordsName(piece.row, piece.col) + ")";
} else if (piece.type === QUEEN) {
return "Q";
} else if (piece.type === KING) {
return "K";
}
}
function getCoordsName(row, col) {
return ["a", "b", "c", "d", "e", "f", "g", "h"].reverse()[col] + "" + (row - (0 - 1));
}
function askForPromotion(what = "") {
console.log("PROMOTING");
let valid = ["queen", "rook", "bishop", "knight"];
let valid2 = ["q", "r", "b", "n"];
let answer = "";
if (what.length > 0) {
answer = what.toLowerCase();
}
do {
if (answer.length === 0) {
answer = window.prompt("Which piece to promote to?", "Queen");
}
} while (!(valid.includes(answer.toLocaleLowerCase()) || valid2.includes(answer.toLocaleLowerCase())));
switch (answer.toLocaleLowerCase()) {
case "queen":
return QUEEN;
case "q":
return QUEEN;
case "rook":
return ROOK;
case "r":
return ROOK;
case "bishop":
return BISHOP;
case "b":
return BISHOP;
case "knight":
return KNIGHT;
case "n":
return KNIGHT;
}
}
}