HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<script src="https://use.fontawesome.com/9a13584896.js"></script>
<div id="main">
<div id="fullGame">
<h2 class="text-center">Chess</h2>
<h3 class="text-center">The Royal Game</h3>
<div class="text-center">
<p class="description"><strong>Play a game against a friend or explore some of your favorite variations.</strong></p>
</div>
<div id="game container">
<canvas id="myCanvas" width="600" height="600"></canvas>
<!-- <div class="text-center row" id="buttonHolder">
<button class="col" id="toEnd">
<i class="fas fa-arrow-left"></i>
</button>
<button class="col" id="oneMoveBack">
<i class="fas fa-caret-left"></i>
</button>
<button class="col" id="oneMoveBack">
<i class="fas fa-caret-right"></i>
</button>
<button class="col" id="toEnd">
<i class="fas fa-arrow-right"></i>
</button>
</div> -->
<div class="text-center">
<p class="description">Chess is a two-player strategy board game played on a chessboard, a checkered gameboard with 64 squares arranged in an 8×8 grid. The game is played by millions of people worldwide. Chess is believed to be derived from the Indian game chaturanga some time before the 7th century. Chaturanga is also the likely ancestor of the Eastern strategy games xiangqi, janggi, and shogi. Chess reached Europe by the 9th century, due to the Umayyad conquest of Hispania. The pieces assumed their current powers in Spain in the late 15th century with the introduction of "Mad Queen Chess"; the modern rules were standardized in the 19th century.</p>
</div>
<p class="description">
<a target="_blank" href="https://en.wikipedia.org/wiki/Chess">
~ wikipedia
</a>
</p>
</div>
</div>
</div>
@import url('https://fonts.googleapis.com/css?family=Quicksand')
@import url('https://fonts.googleapis.com/css?family=Josefin Sans')
body
background-color: whitesmoke
h2
font-size: 50px
margin: 30px auto
font-family: Quicksand
h3, button
font-family: Josefin Sans
margin: 30px
font-size: 20px
canvas
background: whitesmoke
display: block
margin: 15px auto
.description
font-family: Quicksand
font-size: 24px
text-align: left
margin: auto auto
width: 650px
#buttonHolder
margin: 30px auto
width: 400px
font-weight: bolder
button
font-size: 20px
height: 45px
border-radius: 5px
&:hover
background: #212F3C
color: white
&:focus
outline: none
i
font-size: 35px
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var canvasSize = canvas.width;
const board = {};
const whitePawn = 'https://upload.wikimedia.org/wikipedia/commons/0/04/Chess_plt60.png';
const wPawn = new Image();
wPawn.src = whitePawn;
const blackPawn = 'https://upload.wikimedia.org/wikipedia/commons/c/cd/Chess_pdt60.png';
const bPawn = new Image();
bPawn.src = blackPawn;
const whiteKnight = 'https://upload.wikimedia.org/wikipedia/commons/2/28/Chess_nlt60.png';
const wKnight = new Image();
wKnight.src = whiteKnight;
const blackKnight = 'https://upload.wikimedia.org/wikipedia/commons/f/f1/Chess_ndt60.png';
const bKnight = new Image();
bKnight.src = blackKnight;
const whiteKing = 'https://upload.wikimedia.org/wikipedia/commons/3/3b/Chess_klt60.png';
const wKing = new Image();
wKing.src = whiteKing;
const blackKing = 'https://upload.wikimedia.org/wikipedia/commons/e/e3/Chess_kdt60.png';
const bKing = new Image();
bKing.src = blackKing;
const whiteRook = 'https://upload.wikimedia.org/wikipedia/commons/5/5c/Chess_rlt60.png';
const wRook = new Image();
wRook.src = whiteRook;
const blackRook = 'https://upload.wikimedia.org/wikipedia/commons/a/a0/Chess_rdt60.png';
const bRook = new Image();
bRook.src = blackRook;
const whiteQueen = 'https://upload.wikimedia.org/wikipedia/commons/4/49/Chess_qlt60.png';
const wQueen = new Image();
wQueen.src = whiteQueen;
const blackQueen = 'https://upload.wikimedia.org/wikipedia/commons/a/af/Chess_qdt60.png';
const bQueen = new Image();
bQueen.src = blackQueen;
const whiteBishop = 'https://upload.wikimedia.org/wikipedia/commons/9/9b/Chess_blt60.png';
const wBishop = new Image();
wBishop.src = whiteBishop;
const blackBishop = 'https://upload.wikimedia.org/wikipedia/commons/8/81/Chess_bdt60.png';
const bBishop = new Image();
bBishop.src = blackBishop;
const origin = 10;
const boardSize = 9;
const spacer = (canvasSize-origin*2)/(boardSize-1);
board.spacingPoints = [];
for (let i=0; i<(boardSize); i++) {
let thisPoint = origin + spacer*i;
if (thisPoint < canvasSize-50) {
board.spacingPoints.push(Math.floor(thisPoint+spacer*0.5));
}
}
//******************functions to draw board********************
const outlineBoard = () => {
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.rect(origin, origin-1, canvasSize-origin*2, canvasSize-origin*2);
ctx.stroke();
}
const outlineSquare = (x, y, color) => {
//console.log("drawing a square")
let actualX = x - spacer/2;
let actualY = y - spacer/2;
ctx.beginPath();
ctx.strokeStyle = color;
ctx.rect(actualX,actualY,spacer,spacer);
ctx.stroke();
}
const fillSquare = (x, y, color) => {
//console.log("drawing a square")
let actualX = x - spacer/2;
let actualY = y - spacer/2;
ctx.beginPath();
ctx.fillStyle=color;
ctx.rect(actualX,actualY,spacer,spacer);
ctx.fill();
}
const colorSquares = () => {
//console.log("Im running ")
board.currentBoard.map(function (thisRow) {
thisRow.map(function(thisSquare) {
fillSquare(thisSquare.x, thisSquare.y, thisSquare.bgcolor);
});
});
}
//redo this to get rid of blinking
const drawImage = (x, y, image) => {
let actualX = x - 2;
let actualY = y - 2;
let height = spacer*0.93;
let width = spacer*0.93;
ctx.drawImage(image, actualX, actualY, height, width);
}
const placePieces = () => {
//console.log("Im running ")
board.currentBoard.map(function (thisRow) {
thisRow.map(function(thisSquare) {
if (!!thisSquare.img) {
let offset = spacer/2 - 3;
//console.log(thisSquare.img);
drawImage(thisSquare.x-offset, thisSquare.y-offset, thisSquare.img);
}
});
});
}
//*******************************************************
//**************board object array creation functions****************
function square(i, j) {
this.hasMoved = false; //will become true once piece moves
this.selected = false; // for moving pieces - must be true to move
this.row = j; // board coordinates
this.column = i;
this.x = board.spacingPoints[i]; // canvas coordinates
this.y = board.spacingPoints[j];
let colorCondition = (j%2 == 0 && i%2==0) || (j%2 == 1 && i%2==1);
colorCondition ? this.bgcolor = "#F6DDCC" : this.bgcolor = "#D68910";
// assign starting position for all the pieces
if (j == 1) { // row 1
this.img = bPawn;
this.color = "black";
this.piece = "pawn";
}
else if (j == 6) { // row 6
this.img = wPawn;
this.color = "white";
this.piece = "pawn";
}
else if (j == 7) { // etc
this.color = "white";
if (i == 0 || i == 7) {
this.img = wRook
this.piece = "rook";
}
else if (i == 1 || i == 6) {
this.img = wKnight
this.piece = "knight";
}
else if (i == 2 || i == 5) {
this.img = wBishop
this.piece = "bishop";
}
else if (i == 3) {
this.img = wQueen
this.piece = "queen";
}
else {
this.img = wKing
this.piece = "king";
};
}
else if (j == 0) { // etc
this.color = "black";
if (i == 0 || i == 7) {
this.img = bRook
this.piece = "rook";
}
else if (i == 1 || i == 6) {
this.img = bKnight
this.piece = "knight";
}
else if (i == 2 || i == 5) {
this.img = bBishop
this.piece = "bishop";
}
else if (i == 3) {
this.img = bQueen
this.piece = "queen";
}
else {
this.img = bKing
this.piece = "king";
};
}
else {
this.img = null;
this.color = null;
this.piece = null;
}
}
const makeBoardArray = () => {
board.currentBoard = [];
for (let i=0; i<boardSize-1; i++) {
let thisRow = [];
for (let j=0; j<boardSize-1; j++) {
//console.log(i,j)
let thisPoint = new square(i,j);
thisRow.push(thisPoint);
//console.log(thisPoint.column)
}
board.currentBoard.push(thisRow);
}
}
//****************************************
//**********Piece moving fuctions*********
// Math to convert clicked point to closest coordinate pair
function convertCoords(x,y) {
let convertedX = board.spacingPoints[0];
let convertedY = board.spacingPoints[0];
let xDiff = Math.abs(x-board.spacingPoints[0]);
let yDiff = Math.abs(y-board.spacingPoints[0]);
// find the point on the board closest to where the mouse clicked
let coords = {};
board.spacingPoints.map(function(thisPoint) {
let thisXDiff = Math.abs(x-thisPoint);
let thisYDiff = Math.abs(y-thisPoint);
if (thisXDiff < xDiff) {
coords.X = thisPoint;
xDiff = thisXDiff;
}
if (thisYDiff < yDiff) {
coords.Y = thisPoint;
yDiff = thisYDiff;
}
});
if (!coords.Y) {coords.Y = board.spacingPoints[0];}
if (!coords.X) {coords.X = board.spacingPoints[0];}
return coords;
}
// highlight the selected square and tell the board object a piece is selected
const highlightSquare = (square) => {
outlineSquare(square.x, square.y, "black");
//board.currentBoard[square.col][square.row].selected = true;
board.pieceSelected = [square.column, square.row];
}
const lineFrom = (oldSquare, newSquare) => {
let xDiff = oldSquare.x - newSquare.x;
let yDiff = oldSquare.y - newSquare.y;
let yCorrection = 0;
let xCorrection = 0;
if (yDiff < 0) {
yCorrection = -0.06*canvasSize;
}
else if (yDiff > 0) {
yCorrection = 0.06*canvasSize;
}
if (xDiff < 0) {
xCorrection = -0.06*canvasSize;
}
else if (xDiff > 0) {
xCorrection = 0.06*canvasSize;
}
let startX = oldSquare.x;
let startY = oldSquare.y;
let endX = newSquare.x + xCorrection;
let endY = newSquare.y + yCorrection;
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
}
const switchColor = (currentColor) => {
board.color === "white" ? board.color = "black" : board.color = "white";
}
// define boolean logic return for each piece type
const pawnLogic = (coords, xDiff, yDiff, color, isFirstMove, isCapturing) => {
//console.log(coords, xDiff, yDiff, color, isFirstMove, isCapturing)
if ( Math.abs(xDiff) > 1 ) {
return false;
} // add capturing consideration
else if ( Math.abs(xDiff) === 1 ) {
if (!isCapturing || Math.abs(yDiff) > 1) {return false;}
}
else if ( yDiff === 2 || yDiff === -2 ) {
if (!isFirstMove) {return false};
//console.log("can only do that on first move!")
}
else if ( xDiff === 0 ) {
if (isCapturing) {return false};
}
switch(color) {
case "white":
if (yDiff < 3 && yDiff > 0) {return true;}
break;
case "black":
if (yDiff > -3 && yDiff < 0) {return true;}
break;
}
return false;
}
const rookLogic = (xDiff, yDiff) => {
//console.log(xDiff, yDiff);
if (!xDiff || !yDiff) {return true};
return false;
}
const knightLogic = (xDiff, yDiff) => {
let conditionOne = Math.abs(xDiff) === 1 && Math.abs(yDiff) === 2;
let conditionTwo = Math.abs(xDiff) === 2 && Math.abs(yDiff) === 1;
if (conditionOne || conditionTwo) {return true};
return false;
}
const bishopLogic = (xDiff, yDiff) => {
if (Math.abs(xDiff) === Math.abs(yDiff)) {
return true;
};
return false;
}
const queenLogic = (xDiff, yDiff) => {
if (rookLogic(xDiff, yDiff) || bishopLogic(xDiff, yDiff)) {return true};
return false;
}
const kingLogic = (xDiff, yDiff) => {
//console.log(Math.abs(xDiff), Math.abs(yDiff))
let condition = Math.abs(xDiff) < 2 && Math.abs(yDiff) < 2;
if (condition) {return true};
return false;
}
const castleLogic = (coords, xDiff, yDiff) => {
if (Math.abs(xDiff) !== 2) {return false};
let kingX = coords[0];
let kingY = coords[1];
//let color = board.currentBoard[kingX][kingY].color;
let isFirstKingMove = !board.currentBoard[kingX][kingY].hasMoved;
let rookX;
xDiff < 0 ? rookX = 7 : rookX = 0;
let rookY;
kingY == 0 ? rookY = 0 : rookY = 7;
let isFirstRookMove = !board.currentBoard[0][7].hasMoved;
let pathClear = !isPathBlocked(coords, kingX-rookX, kingY-rookY, board.currentBoard);
//console.log(coords, xDiff, [rookX, rookY], kingX-rookX, kingY-rookY);
//console.log(isFirstRookMove, isFirstKingMove, pathClear)
if (isFirstRookMove && isFirstKingMove && pathClear) {return true};
return false;
}
/////////////////////////////
//check if move is legal based on predefined logic for piece types and checking for discovered check
const isLegalMove = (oldSquare, newSquare, board) => {
//console.log(oldSquare.piece);
//define column and row displacement
let prevCol = oldSquare.column;
let prevRow = oldSquare.row;
let newCol = newSquare.column;
let newRow = newSquare.row;
let xDiff = prevCol - newCol;
let yDiff = prevRow - newRow;
// must not be occupied by the same color
if (oldSquare.color === newSquare.color) {return false};
// must be changing something
if (xDiff == 0 && yDiff == 0) {return false};
// which type of piece ?
let piece = oldSquare.piece;
let color = oldSquare.color;
//get col, row coordinates
let coords = [prevCol, prevRow];
// As long as the piece is not a knight, we can elminate any moves where the move is not truly diagonal or perfectly straight, or if the path is blocked, since this applies to all other pieces. We only need to check on moves that have displacement of > 1
let pathClear = true;
if (Math.abs(xDiff) > 1 || Math.abs(yDiff) > 1) {
if (piece !== "knight") {
let isTrueDiagonal = Math.abs(xDiff) === Math.abs(yDiff);
let isPerfectlyStraight = xDiff === 0 || yDiff === 0;
//console.log(!isTrueDiagonal, !isPerfectlyStraight);
// stop here if not diagonal or straight
if (!isTrueDiagonal && !isPerfectlyStraight) {
//console.log("not a real move!")
return false;
}
//path must be clear when piece is not a knight
//console.log('path clear?' + !isPathBlocked(coords, xDiff, yDiff, board))
if (isPathBlocked(coords, xDiff, yDiff, board)) {
return false;
}
}
}
// if (Math.abs(xDiff) > 1 || Math.abs(yDiff) > 1) {
// if (piece !== "knight") {
// pathClear = !isPathBlocked(coords, xDiff, yDiff, board);
// }
// //console.log(`pathClear: ${pathClear}`)
// }
// if (!pathClear) {
// return false;
// };
//is the target square occupied/ move is a capture?
let isCapturing = !!newSquare.piece;
//console.log(xDiff, yDiff, piece, color);
switch(piece) {
case "pawn":
let isFirstMove = false;
if (prevRow == 1 && color == "black") {
isFirstMove = true;
}
else if (prevRow == 6 && color == "white") {
isFirstMove = true;
}
let legalPawnMove = pawnLogic(coords, xDiff, yDiff, color, isFirstMove, isCapturing);
if (legalPawnMove) {
//console.log("legal pawn move");
return true;
}
break;
case "rook":
//console.log("rook")
let legalRookMove = rookLogic(xDiff, yDiff);
//console.log(`legalRookMove? ${legalRookMove}`)
if (legalRookMove) {
//console.log("legal rook move");
return true;
}
break;
case "knight":
//console.log("knight")
let legalKnightMove = knightLogic(xDiff, yDiff);
//console.log(`legalKnightMove? ${legalKnightMove}`)
if (legalKnightMove) {
//console.log("legal knight move");
return true;
}
break;
case "bishop":
//console.log("bishop")
let legalBishopMove = bishopLogic(xDiff, yDiff);
//console.log(`legalBishopMove? ${legalBishopMove}`);
if (legalBishopMove) {
return true;
};
break;
case "queen":
//console.log("queen")
let legalQueenMove = queenLogic(xDiff, yDiff);
//console.log(`legalQueenMove? ${legalQueenMove}`);
if (legalQueenMove) {
return true;
};
break;
case "king":
//console.log("king")
let legalKingMove = kingLogic(xDiff, yDiff);
let legalCastleMove = castleLogic(coords, xDiff, yDiff);
//console.log(`legalKingMove? ${legalKingMove}`);
//console.log(`legalCastleMove? ${legalCastleMove}`);
if (legalKingMove) {
return true;
}
else if (legalCastleMove) {
return true;
}
break;
}
return false;
}
const isPathBlocked = (coords, xDiff, yDiff, board) => { // only run if dislpacement is > 1
let prevCol = coords[0];
let prevRow = coords[1]
let newCol = prevCol - xDiff;
let newRow = prevRow - yDiff;
let pathLength;
let movingPiece = board[prevCol][prevRow].piece;
let isDiagonal;
xDiff !== 0 && yDiff !== 0 ? isDiagonal = true: isDiagonal = false;
let currentCol = prevCol;
let currentRow = prevRow;
let xStep;
let yStep;
xDiff > 0 ? xStep = -1 : xStep = 1; // assign step direction / value for x and y directions
yDiff > 0 ? yStep = -1 : yStep = 1;
if (isDiagonal) {
//console.log("diagonal moving " + board.currentBoard[currentCol][currentRow].piece)
currentCol = currentCol+xStep;
currentRow = currentRow+yStep;
pathLength = Math.abs(xDiff);
for ( let i = 0; i < pathLength-1; i++) { // step from old square to new square along the path(excluding endpoints), and see if any pieces lie in the path
let currentPiece = board[currentCol][currentRow].piece;
//console.log(`Checking if ${movingPiece} @ ${prevCol}, ${prevRow} can move to ${currentCol}, ${currentRow}`);
if (!!currentPiece) {
//console.log(`obstructed by ${currentPiece} at ${currentCol}, ${currentRow}`);
return true;
};
currentCol = currentCol+xStep;
currentRow = currentRow+yStep;
}
}
else {
//console.log("straight line")
let dimension; // assign dimension to be 1 if X move, or 2 if Y move
xDiff === 0 ? dimension = 2 : dimension = 1;
let currentPiece;
switch(dimension) {
case 1: // step from old square to new square along the path(excluding endpoints), and see if any pieces lie in the path
//console.log("x - move")
pathLength = Math.abs(xDiff);
currentCol = currentCol + xStep;
for (let i = 0; i < pathLength-1; i++) {
//console.log(currentCol, newCol)
currentPiece = board[currentCol][currentRow].piece;
console.log("yepper")
if (!!currentPiece) {
//console.log(`col obstructed by ${currentPiece} at ${currentCol}, ${currentRow}`);
return true;
};
currentCol = currentCol + xStep;
}
break;
case 2: // step from old square to new square along the path(excluding endpoints), and see if any pieces lie in the path
//console.log("y - move")
currentRow = currentRow + yStep;
pathLength = Math.abs(yDiff);
for (let i = 0; i < pathLength-1; i++) {
currentPiece = board[currentCol][currentRow].piece;
if (!!currentPiece) {
//console.log(`row obstructed by ${currentPiece} at ${currentCol}, ${currentRow}`)
return true;
};
currentRow = currentRow + yStep;
}
break;
}
}
//console.log("path clear")
//let pathObstructed = !!board.currentBoard[i][j].piece;
return false;
}
const getDefendingPieces = (currentBoard, color) => {
// find the player's pieces
let defendingPieces = [];
currentBoard.forEach( (thisCol) => {
thisCol.forEach ( (thisSquare) => {
//console.log(thisSquare.color, board.color)
if (thisSquare.color === color) {
defendingPieces.push(thisSquare);
}
});
});
return defendingPieces;
}
const getEmptySquares = (board) => {
// find the empty squares
let emptySquares = [];
board.forEach( (thisCol) => {
thisCol.forEach ( (thisSquare) => {
if (thisSquare.color === null) {
emptySquares.push(thisSquare);
}
});
});
return emptySquares;
}
const isCurrentCheck = (currentBoard) => {
let checkFound = false;
let kingSquare;
for (let i=0; i < currentBoard.length; i++) { //find the king
for (let j=0; j < currentBoard[i].length; j++) {
let thisSquare = currentBoard[i][j];
if (thisSquare.piece == "king" && thisSquare.color == board.color) {
kingSquare = thisSquare;
//console.log(`King at ${kingSquare.column}, ${kingSquare.row}`);
break;
}
}
}
let defendingColor = board.color === "white" ? "black" : "white";
let defendingPieces = getDefendingPieces(currentBoard, defendingColor);
for ( let i=0; i < defendingPieces.length; i++) {
//console.log(`Checking if ${defendingPieces[i].piece} @ ${defendingPieces[i].column}, ${defendingPieces[i].row} attacks the king @ ${kingSquare.column}, ${kingSquare.row}`);
if (isLegalMove(defendingPieces[i], kingSquare, currentBoard)) {
//console.log(`${defendingPieces[i].piece} @ ${defendingPieces[i].column}, ${defendingPieces[i].row} attacks the king`)
return true;
}
}
console.log(`Discovered check: ${checkFound}`)
return false;
}
const isDiscoveredCheck = (currentSquare, newSquare) => {
let prevCol = currentSquare.column;
let prevRow = currentSquare.row;
let newCol = newSquare.column;
let newRow = newSquare.row;
let boardCopy = JSON.parse(JSON.stringify(board.currentBoard));
boardCopy[newCol][newRow].piece = boardCopy[prevCol][prevRow].piece; // fill the new square with piece / properties
boardCopy[newCol][newRow].img = boardCopy[prevCol][prevRow].img;
boardCopy[newCol][newRow].color = boardCopy[prevCol][prevRow].color;
boardCopy[newCol][newRow].hasMoved = true;
boardCopy[prevCol][prevRow].piece = null; // empty the old square
boardCopy[prevCol][prevRow].img = null;
boardCopy[prevCol][prevRow].color = null;
boardCopy[prevCol][prevRow].hasMoved = false;
return isCurrentCheck(boardCopy);
}
const isCheckMate = (currentBoard) => {
if (!isCurrentCheck(currentBoard)) {return false};
// find the player's pieces
let defendingPieces = getDefendingPieces(currentBoard, board.color);
//console.log(defendingPieces);
// find the empty squares
let emptySquares = getEmptySquares(currentBoard);
defendingPieces.forEach((thisPiece) => {
emptySquares.forEach((thisSquare) => {
//console.log(`Checking for checkmate escape by ${thisPiece.column}, ${thisPiece.row} ${thisPiece.piece} @ ${thisSquare.column}, ${thisSquare.row}`)
let legalMove = isLegalMove(thisPiece, thisSquare, currentBoard);
let discoveredCheck = isDiscoveredCheck(thisPiece, thisSquare);
if ( legalMove && !discoveredCheck ) {
//console.log("Escaping move found. Not checkmate.")
return false;
}
})
})
return true;
}
const movePiece = (oldSquare, newSquare) => {
newSquare.piece = oldSquare.piece; // fill the new square with piece / properties
newSquare.img = oldSquare.img;
newSquare.color = oldSquare.color;
newSquare.hasMoved = true;
oldSquare.piece = null; // empty the old square
oldSquare.img = null;
oldSquare.color = null;
oldSquare.hasMoved = false;
let prevCol = oldSquare.column;
let prevRow = oldSquare.row;
let newCol = newSquare.column;
let newRow = newSquare.row;
board.currentBoard[prevCol][prevRow] = oldSquare; //replace old squares with new ones, modified
board.currentBoard[newCol][newRow] = newSquare;
drawCurrentBoard();
switchColor();
highlightSquare(newSquare);
lineFrom(oldSquare, newSquare);
board.boardHistory.push(board.currentBoard); // log the board with changes
board.pieceSelected = null; // clear selection
}
const movePieceCastling = (oldSquare, newSquare) => {
//****move the king as in the normal case of movePiece****//
newSquare.piece = oldSquare.piece; // fill the new square with piece / properties
newSquare.img = oldSquare.img;
newSquare.color = oldSquare.color;
newSquare.hasMoved = true;
oldSquare.piece = null; // empty the old square
oldSquare.img = null;
oldSquare.color = null;
oldSquare.hasMoved = false;
let prevCol = oldSquare.column;
let prevRow = oldSquare.row;
let newCol = newSquare.column;
let newRow = newSquare.row;
//replace old squares with new ones, modified
board.currentBoard[prevCol][prevRow] = oldSquare;
board.currentBoard[newCol][newRow] = newSquare;
//********//
//****move the rook****//
let xDiff = prevCol - newCol;
let rookRow = prevRow; // row won't change
let prevRookCol; // but need before and after col, of course
let newRookCol;
if (xDiff > 0) {
prevRookCol = 0;
newRookCol = 3;
}
else {
prevRookCol = 7;
newRookCol = 5;
}
// get the square objects for the rook
let oldRookSquare = Object.assign({}, board.currentBoard[prevRookCol][rookRow]);
let newRookSquare = Object.assign({}, board.currentBoard[newRookCol][rookRow]);
//console.log(board.currentBoard[prevRookCol][rookRow], board.currentBoard[newRookCol][rookRow])
//modify as above with the king
newRookSquare.piece = oldRookSquare.piece; // fill the new square with piece / properties
newRookSquare.img = oldRookSquare.img;
newRookSquare.color = oldRookSquare.color;
newRookSquare.hasMoved = true;
oldRookSquare.piece = null; // empty the old square
oldRookSquare.img = null;
oldRookSquare.color = null;
oldRookSquare.hasMoved = false;
//replace old squares with new ones, modified
board.currentBoard[prevRookCol][rookRow] = oldRookSquare;
board.currentBoard[newRookCol][rookRow] = newRookSquare;
//********//
drawCurrentBoard();
switchColor();
highlightSquare(newSquare);
lineFrom(oldSquare, newSquare);
board.boardHistory.push(board.currentBoard); // log the board with changes
board.pieceSelected = []; // clear selection
}
const handleClick = (x,y) => {
let coords = convertCoords(x,y); // convert raw x, y to the nearest board coordinates
// get the indices of the point object to change in currentBoard array
let boardCol = board.spacingPoints.indexOf(coords.X);
let boardRow = board.spacingPoints.indexOf(coords.Y);
let thisSquare = Object.assign({}, board.currentBoard[boardCol][boardRow]);
let thisColorsTurn = thisSquare.color == board.color;
if (!board.pieceSelected) { // true if nothing selected yet
if (!thisColorsTurn) {
return;
}
else {
highlightSquare(thisSquare);
}
}
else {
if (thisColorsTurn) {
drawCurrentBoard();
highlightSquare(thisSquare);
}
else {
let currentRow = board.pieceSelected[0];
let currentCol = board.pieceSelected[1];
let currentSquare = Object.assign({}, board.currentBoard[currentRow][currentCol]);
if (isLegalMove(currentSquare, thisSquare, board.currentBoard)) {
if (isDiscoveredCheck(currentSquare, thisSquare)) {
return;
};
console.log("making it past discovered check");
let castlingMove;
let conditionOne = Math.abs(currentSquare.column - thisSquare.column) === 2;
let conditionTwo = currentSquare.piece == "king";
if (conditionOne && conditionTwo) {
movePieceCastling(currentSquare, thisSquare);
} else {
movePiece(currentSquare, thisSquare);
}
}
}
// if (isCheckMate(board.currentBoard)) {
// alert('Check Mate Mofo!')
// startGame();
// }
}
}
//****************************************
//********Board Display functions*********
const drawCurrentBoard = () => {
ctx.clearRect(origin, origin, canvasSize, canvasSize)
colorSquares();
outlineBoard();
placePieces();
}
const clearBoard = () => {
board.boardHistory = [];
board.currentBoard = [];
board.turn = 0;
board.color = "white";
board.pieceSelected = null;
}
const startGame = () => {
clearBoard();
makeBoardArray();
drawCurrentBoard();
let newBoard = JSON.parse(JSON.stringify(board.currentBoard));
board.boardHistory.push(newBoard);
}
//****************************************
//*******Click function assignments*******
$("#myCanvas").on('click',function(event) {
let leftPad = $("#myCanvas").offset().left;
let topPad = $("#myCanvas").offset().top;
let xPos = event.clientX-leftPad;
let yPos = event.clientY-topPad + $(window).scrollTop();
//console.log(currentBoard[xPos/(boardSize-1)][yPos/(boardSize-1)]);
//console.log(xPos, yPos);
handleClick(xPos, yPos);
});
window.setTimeout(function() {
startGame();
}, 500)
Also see: Tab Triggers