From bc979fee2feb11e29f68b30cc0d8bb42c50259e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 10 Jan 2021 20:35:45 +0200 Subject: [PATCH 1/6] Allow promoting to any piece --- takhta.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/takhta.html b/takhta.html index 2e41f80..81f9fab 100644 --- a/takhta.html +++ b/takhta.html @@ -348,13 +348,9 @@ case 'B': case 'N': case 'R': - promotion = move.slice(index, index + 1); - break; case 'K': - return {error: 'Cannot promote a piece to king'}; - break; case 'P': - return {error: 'Cannot promote a piece to pawn'}; + promotion = move.slice(index, index + 1); break; default: return {error: 'Unrecognized piece: ' + move.slice(index, index + 1)}; From f8f0c794cd1e07ec3ac3f7b08bff1d94fbb4b43a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 10 Jan 2021 20:36:43 +0200 Subject: [PATCH 2/6] Use === everywhere --- takhta.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/takhta.html b/takhta.html index 81f9fab..d08b720 100644 --- a/takhta.html +++ b/takhta.html @@ -378,7 +378,7 @@ let whitePieces = {'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙'}; let blackPieces = {'K': '♚', 'Q': '♛', 'R': '♜', 'B': '♝', 'N': '♞', 'P': '♟'}; - let whiteMove = document.getElementById('tomove').childNodes[0].data == 'White'; + let whiteMove = document.getElementById('tomove').childNodes[0].data === 'White'; let renderedPiece = whiteMove ? whitePieces[piece] : blackPieces[piece]; let renderedPromotion = null; @@ -453,7 +453,7 @@ } // Flip whose turn it is - let whiteMove = document.getElementById('tomove').childNodes[0].data == 'White'; + let whiteMove = document.getElementById('tomove').childNodes[0].data === 'White'; document.getElementById('tomove').childNodes[0].data = whiteMove ? 'Black' : 'White'; // Add to list of redoable moves From 54e4621548acebe023077f18a53ff4856e1f0f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 10 Jan 2021 21:12:46 +0200 Subject: [PATCH 3/6] Implement castling --- takhta.html | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/takhta.html b/takhta.html index d08b720..2e494ec 100644 --- a/takhta.html +++ b/takhta.html @@ -306,6 +306,10 @@ case 'h': piece = 'P'; break; + case 'O': + case '0': + // Castling, handled in its own function + return doCastle(move); default: return {error: 'Not a valid piece: ' + piece}; } @@ -435,6 +439,125 @@ return {} } + function doCastle(move) { + let ballChar = move[0]; + + // Figure out distance between king and rook + let emptySquares = 1; + let index = 1; + while (index < move.length) { + if (move.slice(index, index + 2) === '-' + ballChar) { + emptySquares += 1; + index += 2; + } else { + break; + } + } + + // Check(mate) + if (!['', '+', '++', '#'].includes(move.slice(index))) { + // TODO: Implement handling + return {error: 'Unexpected contents at the end of the move: ' + move.slice(index)}; + } + + // Find the king(s) + let whiteMove = document.getElementById('tomove').childNodes[0].data === 'White'; + let renderedKing = whiteMove ? '♔' : '♚'; + let renderedRook = whiteMove ? '♖' : '♜'; + + let kings = []; + for (let kingLetter of 'abcdefgh') { + for (let kingNumber of '12345678') { + let square = document.getElementById(kingLetter + kingNumber); + if (square.childNodes.length !== 0 && square.childNodes[0].data === renderedKing) { + kings.push([kingLetter, kingNumber]); + } + } + } + + // Find the rook(s) + function squareDiff(squareLetter, squareNumber, dLetter, dNumber) { + let x = 'abcdefgh'.indexOf(squareLetter) + dLetter; + let y = '12345678'.indexOf(squareNumber) + dNumber; + if (x < 0 || x > 7 || y < 0 || y > 7) { + // Would be outside of the board + return null; + } + return ['abcdefgh'[x], '12345678'[y]] + } + + let distance = emptySquares + 1; + let possiblePairs = []; + for (let [kingLetter, kingNumber] of kings) { + for (let [dLetter, dNumber] of [[-distance, 0], [distance, 0], [0, -distance], [0, distance]]) { + let rookCoords = squareDiff(kingLetter, kingNumber, dLetter, dNumber); + if (rookCoords === null) { + continue; + } + let [rookLetter, rookNumber] = rookCoords; + + let square = document.getElementById(rookLetter + rookNumber); + if (square.childNodes.length !== 0 && square.childNodes[0].data === renderedRook) { + possiblePairs.push([kingLetter, kingNumber, rookLetter, rookNumber, dLetter, dNumber]); + } + } + } + + if (possiblePairs.length === 0) { + return {error: 'Could not find king and rook matching castling criteria'}; + } else if (possiblePairs.length > 1) { + return {error: 'Found ' + String(possiblePairs.length) + ' possible pairs of king and rook to castle'}; + } + + let [kingLetter, kingNumber, rookLetter, rookNumber, dLetter, dNumber] = possiblePairs[0]; + let kingStartSquare = document.getElementById(kingLetter + kingNumber); + let rookStartSquare = document.getElementById(rookLetter + rookNumber); + + // Make sure there there are no pieces between the king and the rook + let signLetter = Math.sign(dLetter); + let signNumber = Math.sign(dNumber); + let [squareLetter, squareNumber] = squareDiff(kingLetter, kingNumber, signLetter, signNumber); + while (squareLetter !== rookLetter || squareNumber !== rookNumber) { + if (document.getElementById(squareLetter + squareNumber).childNodes.length !== 0) { + return {error: squareLetter + squareNumber + ' is occupied'}; + } + [squareLetter, squareNumber] = squareDiff(squareLetter, squareNumber, signLetter, signNumber); + } + + // King moves two squares towards rook + let [kingEndLetter, kingEndNumber] = squareDiff(kingLetter, kingNumber, 2 * signLetter, 2 * signNumber); + let kingEndSquare = document.getElementById(kingEndLetter + kingEndNumber); + + // Rook moves to the square king crossed + let [rookEndLetter, rookEndNumber] = squareDiff(kingLetter, kingNumber, signLetter, signNumber); + let rookEndSquare = document.getElementById(rookEndLetter + rookEndNumber); + + // Move pieces + kingStartSquare.removeChild(kingStartSquare.childNodes[0]); + rookStartSquare.removeChild(rookStartSquare.childNodes[0]); + kingEndSquare.appendChild(document.createTextNode(renderedKing)); + rookEndSquare.appendChild(document.createTextNode(renderedRook)); + + // Flip whose turn it is + document.getElementById('tomove').childNodes[0].data = whiteMove ? 'Black' : 'White'; + + // Record our alterations to the table + let removedPieces = {}; + let placedPieces = {}; + removedPieces[kingLetter + kingNumber] = renderedKing; + removedPieces[rookLetter + rookNumber] = renderedRook; + placedPieces[kingEndLetter + kingEndNumber] = renderedKing; + placedPieces[rookEndLetter + rookEndNumber] = renderedRook; + let moveRecord = { + removedPieces: removedPieces, + placedPieces: placedPieces, + moveText: move + }; + moveHistory.push(moveRecord); + + return {} + } + function undoMove() { if (moveHistory.length === 0) { alert('No moves to undo'); From f8d47a3b73805f9cf0ad1a19cf82befa3db123f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 10 Jan 2021 21:23:01 +0200 Subject: [PATCH 4/6] When switching king position, don't redo moves player had undone --- takhta.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/takhta.html b/takhta.html index 2e494ec..037453f 100644 --- a/takhta.html +++ b/takhta.html @@ -713,6 +713,7 @@ let blackQueen = blackKing === 'd8' ? 'e8' : 'd8'; // Undo all moves + let historylength = moveHistory.length; while (moveHistory.length > 0) { undoMove(); } @@ -723,8 +724,8 @@ document.getElementById(blackKing).firstChild.data = '♚'; document.getElementById(blackQueen).firstChild.data = '♛'; - // Redo all the moves we can - while (moveFuture.length > 0) { + // Redo until we can or until the point where we were before, whichever is first + while (moveHistory.length < historylength) { if (!redoMove()) { break; } From 3c5c1ff1bc78f7b545a24588b9d9d5e5f650fef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 10 Jan 2021 21:43:42 +0200 Subject: [PATCH 5/6] Support promotions without the = as well --- takhta.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/takhta.html b/takhta.html index 037453f..fae0274 100644 --- a/takhta.html +++ b/takhta.html @@ -348,11 +348,11 @@ if (move.slice(index, index + 1) === '=') { index++; switch (move.slice(index, index + 1)) { + case 'K': case 'Q': case 'B': case 'N': case 'R': - case 'K': case 'P': promotion = move.slice(index, index + 1); break; @@ -360,6 +360,9 @@ return {error: 'Unrecognized piece: ' + move.slice(index, index + 1)}; } index++; + } else if (['K', 'Q', 'B', 'N', 'R', 'P'].includes(move.slice(index, index + 1))) { + promotion = move.slice(index, index + 1); + index++; } // Check(mate) From ca2cb19da7b1040e6d28c433423853e761f03020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 10 Jan 2021 21:59:59 +0200 Subject: [PATCH 6/6] Centering with CSS is my passion --- takhta.html | 1 + 1 file changed, 1 insertion(+) diff --git a/takhta.html b/takhta.html index fae0274..fb2e043 100644 --- a/takhta.html +++ b/takhta.html @@ -15,6 +15,7 @@ display: flex; justify-content: center; align-items: center; + line-height: 1em; } #board tbody :nth-child(odd) :nth-child(even) { background-color: #fff;