Add basic networking capabilities.
Include package-lock.json in git. Add server file. Start moving Board backend into its own file (currently a lot of duplicate code between board.js and backend.js).
This commit is contained in:
parent
365d8b3cea
commit
5fee691c08
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,57 @@
|
|||
const {Board, Piece} = require('./src/backend');
|
||||
|
||||
const express = require("express");
|
||||
const http = require("http");
|
||||
const socketIo = require("socket.io");
|
||||
|
||||
const port = process.env.PORT || 4001;
|
||||
|
||||
const app = express();
|
||||
|
||||
const server = http.createServer(app);
|
||||
|
||||
const io = socketIo(server, {
|
||||
cors: {
|
||||
cors: true,
|
||||
origins: ["http://192.168.1.7:3000"],
|
||||
}
|
||||
});
|
||||
|
||||
let interval;
|
||||
|
||||
let board = new Board();
|
||||
|
||||
let sockets = [];
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
sockets.push(socket);
|
||||
console.log("New client connected");
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
getApiAndEmit(socket);
|
||||
//interval = setInterval(() => getApiAndEmit(socket), 5000);
|
||||
socket.on("disconnect", () => {
|
||||
// TODO sockets.remove(socket)
|
||||
console.log("Client disconnected");
|
||||
clearInterval(interval);
|
||||
});
|
||||
|
||||
socket.on("move", (move) => {
|
||||
console.log("Received move");
|
||||
if(move && board.makeMove(move.from, move.to) == 0) {
|
||||
for (s of sockets) {
|
||||
getApiAndEmit(s);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const getApiAndEmit = socket => {
|
||||
const response = board.textFromState();
|
||||
console.log(response);
|
||||
// Emitting a new message. Will be consumed by the client
|
||||
socket.emit("FromAPI", response);
|
||||
};
|
||||
|
||||
server.listen(port, () => console.log(`Listening on port ${port}`));
|
|
@ -0,0 +1,578 @@
|
|||
const BLACK = 0; const WHITE = 1;
|
||||
|
||||
const PAWN = 0;
|
||||
const ROOK = 1;
|
||||
const KNIGHT = 2;
|
||||
const BISHOP = 3;
|
||||
const QUEEN = 4;
|
||||
const KING = 5;
|
||||
|
||||
const EMPTY = -1;
|
||||
|
||||
const SHUFFLING_ENABLED = 0;
|
||||
|
||||
function getAllSettings() {
|
||||
return [SHUFFLING_ENABLED];
|
||||
}
|
||||
|
||||
function settingText(setting) {
|
||||
switch(setting) {
|
||||
case SHUFFLING_ENABLED:
|
||||
return "Shuffle Back Row";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function range(n) {
|
||||
return Array.from(Array(n).keys());
|
||||
}
|
||||
|
||||
function imageFromPiece(piece) {
|
||||
if (piece && piece.type >= 0) {
|
||||
const image = piece.color === WHITE ? piece.type : piece.type + 6;
|
||||
return Images[image];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class Piece {
|
||||
constructor(color, type) {
|
||||
this.color = color;
|
||||
this.type = type;
|
||||
this.passantable = false;
|
||||
this.moves = 0;
|
||||
}
|
||||
|
||||
setType(type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
getInfoText() {
|
||||
if(this.moves === 1) {
|
||||
return "Has made 1 move"
|
||||
} else {
|
||||
return "Has made " + this.moves + " moves"
|
||||
}
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.type === EMPTY;
|
||||
}
|
||||
|
||||
isFull() {
|
||||
return !this.isEmpty();
|
||||
}
|
||||
|
||||
isBlack() {
|
||||
return this.color === BLACK;
|
||||
}
|
||||
|
||||
isWhite() {
|
||||
return this.color === WHITE;
|
||||
}
|
||||
|
||||
isEnemyOf(piece) {
|
||||
if (this.color === EMPTY || piece.color === EMPTY) {
|
||||
return false;
|
||||
} else {
|
||||
return this.color !== piece.color;
|
||||
}
|
||||
}
|
||||
|
||||
isFriendOf(piece) {
|
||||
if (this.color === EMPTY || piece.color === EMPTY) {
|
||||
return false;
|
||||
} else {
|
||||
return this.color === piece.color;
|
||||
}
|
||||
}
|
||||
|
||||
is(type) {
|
||||
return this.type === type;
|
||||
}
|
||||
|
||||
hasMoved() {
|
||||
return this.moves !== 0;
|
||||
}
|
||||
|
||||
hasntMoved() {
|
||||
return !this.hasMoved();
|
||||
}
|
||||
}
|
||||
|
||||
class Board {
|
||||
constructor(props) {
|
||||
this.state = (props && props.text) ?
|
||||
this.stateFromText(props.text) : this.originalState();
|
||||
}
|
||||
|
||||
setHand(hand) {
|
||||
// setState
|
||||
this.state.hand = hand;
|
||||
}
|
||||
|
||||
clone() {
|
||||
let board = new Board();
|
||||
board.state.squares = this.state.squares.slice();
|
||||
board.state.blackIsNext = this.state.blackIsNext;
|
||||
board.state.hand = {
|
||||
heldPiece: this.state.hand.heldPiece,
|
||||
};
|
||||
return board;
|
||||
}
|
||||
|
||||
stateFromText(text) {
|
||||
text = text.replace(/[\n]+/g, '');
|
||||
const squares = text.substring(1);
|
||||
return {
|
||||
hand: {
|
||||
heldPiece: null,
|
||||
},
|
||||
blackIsNext: text[0].toUpperCase() === 'B',
|
||||
squares: squares.split('').map(c => {
|
||||
const type = c.toLowerCase();
|
||||
const color = c === type ? WHITE : BLACK;
|
||||
switch (type) {
|
||||
case 'r':
|
||||
return new Piece(color, ROOK);
|
||||
case 'n':
|
||||
return new Piece(color, KNIGHT);
|
||||
case 'b':
|
||||
return new Piece(color, BISHOP);
|
||||
case 'q':
|
||||
return new Piece(color, QUEEN);
|
||||
case 'k':
|
||||
return new Piece(color, KING);
|
||||
case 'p':
|
||||
return new Piece(color, PAWN);
|
||||
default:
|
||||
return new Piece(EMPTY, EMPTY);
|
||||
}
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
shuffledBackRow() {
|
||||
return "rnbqkbnr".split('').sort(() => Math.random() - 0.5).join('');
|
||||
}
|
||||
|
||||
shuffledBackRowState() {
|
||||
const backRow = this.shuffledBackRow();
|
||||
const text = ["B", backRow, "pppppppp",
|
||||
"________", "________", "________", "________",
|
||||
"PPPPPPPP", backRow.toUpperCase()].join('');
|
||||
return this.stateFromText(text);
|
||||
}
|
||||
|
||||
textFromState() {
|
||||
const turn = (this.state.blackIsNext? 'B' : 'W');
|
||||
return turn + this.state.squares.map(square => {
|
||||
if (!square) {
|
||||
return '_';
|
||||
}
|
||||
let color = (c) => {
|
||||
return square.color === BLACK ? c.toUpperCase() : c;
|
||||
};
|
||||
switch (square.type) {
|
||||
case ROOK:
|
||||
return color('r');
|
||||
case KNIGHT:
|
||||
return color('n');
|
||||
case BISHOP:
|
||||
return color('b');
|
||||
case QUEEN:
|
||||
return color('q');
|
||||
case KING:
|
||||
return color('k');
|
||||
case PAWN:
|
||||
return color('p');
|
||||
default:
|
||||
return '_';
|
||||
}
|
||||
}).join('');;
|
||||
}
|
||||
|
||||
doReset() {
|
||||
// setState
|
||||
this.state = this.getSetting(SHUFFLING_ENABLED) ?
|
||||
this.shuffledBackRowState() : this.originalState();
|
||||
this.state.showPopup = false;
|
||||
}
|
||||
|
||||
originalState() {
|
||||
let squares = [];
|
||||
const mainRow = [ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK];
|
||||
function add(num, color, type) {
|
||||
for(let i = 0; i < num; i++) {
|
||||
squares.push(new Piece(color, type));
|
||||
}
|
||||
}
|
||||
|
||||
mainRow.forEach(type => add(1, WHITE, type));
|
||||
add(8, WHITE, PAWN);
|
||||
add(32, EMPTY, EMPTY);
|
||||
add(8, BLACK, PAWN);
|
||||
mainRow.forEach(type => add(1, BLACK, type));
|
||||
|
||||
return ({
|
||||
squares,
|
||||
blackIsNext: true,
|
||||
hand: {
|
||||
heldPiece: null,
|
||||
},
|
||||
showPopup: false,
|
||||
settings: {},
|
||||
});
|
||||
}
|
||||
|
||||
getXandY(i) {
|
||||
const x = i % 8;
|
||||
const y = Math.floor(i / 8);
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
getIndex(x, y) {
|
||||
return x + (y * 8);
|
||||
}
|
||||
|
||||
isValidXY(x, y) {
|
||||
return x < 8 && x >=0 && y < 8 && y >= 0;
|
||||
}
|
||||
|
||||
squareCount() {
|
||||
return this.state.squares.length;
|
||||
}
|
||||
|
||||
pieceAtIndex(i) {
|
||||
return i >= 0 && i < 64 ? this.state.squares[i] : null;
|
||||
}
|
||||
|
||||
pieceAt(x, y) {
|
||||
if (this.isValidXY(x, y)) {
|
||||
return this.state.squares[this.getIndex(x, y)];
|
||||
} else {
|
||||
return new Piece(EMPTY, EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
getValidMovesAt(piece, x, y) {
|
||||
let moves = [];
|
||||
const tryAddMove = (x, y) => {
|
||||
if (this.isValidXY(x, y)) {
|
||||
if(this.pieceAt(x, y).isEmpty()) {
|
||||
moves.push({x, y});
|
||||
// Keep searching
|
||||
return 0;
|
||||
} else if (piece.isEnemyOf(this.pieceAt(x, y))) {
|
||||
moves.push({x, y});
|
||||
}
|
||||
// Stop searching
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
const addBunch = (xFunc, yFunc, isUp) => {
|
||||
for (let i = 1; i < 8; i++) {
|
||||
if(tryAddMove(xFunc(i), yFunc(i)) !== 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (piece.is(PAWN)) {
|
||||
const pieceIsBlack = piece.isBlack();
|
||||
const shift = pieceIsBlack ? -1 : 1;
|
||||
const startLine = pieceIsBlack ? 6 : 1;
|
||||
|
||||
// Check for en passant
|
||||
const left = this.pieceAt(x - 1, y);
|
||||
const right = this.pieceAt(x + 1, y);
|
||||
if (left && left.passantable && left.isEnemyOf(piece)) {
|
||||
moves.push({x: x - 1, y: y + shift, passant: {x: x - 1, y}})
|
||||
}
|
||||
if (right && right.passantable && right.isEnemyOf(piece)) {
|
||||
moves.push({x: x + 1, y: y + shift, passant: {x: x + 1, y}})
|
||||
}
|
||||
|
||||
if (this.pieceAt(x, y + shift).isEmpty()) {
|
||||
moves.push({x, y: y + shift});
|
||||
// Pawn moving two spaces becomes en-passantable
|
||||
if (y === startLine && this.pieceAt(x, y + (shift * 2)).isEmpty()) {
|
||||
moves.push({x, y: y + (shift * 2), passantable: true});
|
||||
}
|
||||
}
|
||||
[x + 1, x - 1].forEach(x => {
|
||||
const y2 = y + shift;
|
||||
if (this.isValidXY(x, y2) && piece.isEnemyOf(this.pieceAt(x, y2))) {
|
||||
moves.push({x, y: y2});
|
||||
}
|
||||
});
|
||||
} else if (piece.is(ROOK)) {
|
||||
addBunch(n => {return x;}, n => {return y + n;});
|
||||
addBunch(n => {return x;}, n => {return y - n;});
|
||||
addBunch(n => {return x + n;}, n => {return y;});
|
||||
addBunch(n => {return x - n;}, n => {return y;});
|
||||
} else if (piece.is(BISHOP)) {
|
||||
addBunch(n => {return x + n;}, n => {return y + n;});
|
||||
addBunch(n => {return x - n;}, n => {return y + n;});
|
||||
addBunch(n => {return x + n;}, n => {return y - n;});
|
||||
addBunch(n => {return x - n;}, n => {return y - n;});
|
||||
} else if (piece.is(QUEEN)) {
|
||||
const [rook, bishop] =
|
||||
[new Piece(piece.color, ROOK), new Piece(piece.color, BISHOP)];
|
||||
moves = moves.concat(this.getValidMovesAt(rook, x, y));
|
||||
moves = moves.concat(this.getValidMovesAt(bishop, x, y));
|
||||
} else if (piece.is(KNIGHT)) {
|
||||
[
|
||||
[2, 1], [2, -1], [-2, 1], [-2, -1],
|
||||
[1, 2], [1, -2], [-1, 2], [-1, -2],
|
||||
].forEach(delta => tryAddMove(x + delta[0], y + delta[1]));
|
||||
} else if (piece.is(KING)) {
|
||||
[[1, 1], [1, -1], [-1, 1], [-1, -1], [0, 1], [0, -1], [1, 0], [-1, 0]]
|
||||
.forEach(delta => tryAddMove(x + delta[0], y + delta[1]));
|
||||
if (piece.hasntMoved()) {
|
||||
const kingIndex = this.findIndex(piece);
|
||||
const [x, y] = this.getXandY(kingIndex);
|
||||
|
||||
let leftRook = this.pieceAt(0, y);
|
||||
if(leftRook.is(ROOK) && leftRook.hasntMoved()) {
|
||||
// Check if spaces between rook and king are empty
|
||||
if(this.pieceAt(1, y).isEmpty() &&
|
||||
this.pieceAt(2, y).isEmpty() &&
|
||||
this.pieceAt(3, y).isEmpty()) {
|
||||
// Check if between space puts king in check
|
||||
let board = this.clone();
|
||||
board.state.squares[board.getIndex(x - 1, y)] = piece;
|
||||
board.state.squares[kingIndex].isEmpty();
|
||||
if(board.inCheck(piece) == null) {
|
||||
moves.push({x: x - 2, y, castle: [x - 1, y]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let rightRook = this.pieceAt(7, y);
|
||||
if(rightRook.is(ROOK) && rightRook.hasntMoved()) {
|
||||
// Check if spaces between rook and king are empty
|
||||
if(this.pieceAt(5, y).isEmpty() &&
|
||||
this.pieceAt(6, y).isEmpty()) {
|
||||
// Check if between space puts king in check
|
||||
let board = this.clone();
|
||||
board.state.squares[board.getIndex(x + 1, y)] = piece;
|
||||
board.state.squares[kingIndex].isEmpty();
|
||||
if(board.inCheck(piece) == null) {
|
||||
moves.push({x: x + 2, y, castle: [x + 1, y]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return moves;
|
||||
}
|
||||
|
||||
findIndex(piece) {
|
||||
for(let i = 0; i < this.squareCount(); i++) {
|
||||
const check = this.state.squares[i];
|
||||
if(check.type === piece.type && check.color === piece.color) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
distanceBetween(i1, i2) {
|
||||
const [pos1X, pos1Y] = this.getXandY(i1);
|
||||
const [pos2X, pos2Y] = this.getXandY(i2);
|
||||
|
||||
let a = pos1X - pos2X;
|
||||
a = a * a;
|
||||
|
||||
let b = pos1Y - pos2Y;
|
||||
b = b * b;
|
||||
|
||||
return Math.sqrt(a + b);
|
||||
}
|
||||
|
||||
inCheck(piece) {
|
||||
const kingPos = this.getXandY(this.findIndex(piece));
|
||||
|
||||
for(let i = 0; i < this.squareCount(); i++) {
|
||||
if(piece.isEnemyOf(this.pieceAtIndex(i))) {
|
||||
const moves = this.getValidMoves(i);
|
||||
for(let j = 0; j < moves.length; j++) {
|
||||
if(moves[j].x === kingPos[0] && moves[j].y === kingPos[1]) {
|
||||
return piece;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
whoInCheck() {
|
||||
const blackKing = this.inCheck(new Piece(BLACK, KING));
|
||||
return blackKing ? blackKing : this.inCheck(new Piece(WHITE, KING));
|
||||
}
|
||||
|
||||
checkmate() {
|
||||
const checkedKing = this.whoInCheck();
|
||||
if (checkedKing != null) {
|
||||
// For each square
|
||||
for(let i = 0; i < this.squareCount(); i++) {
|
||||
const piece = this.pieceAtIndex(i);
|
||||
// If that piece is on the checked team
|
||||
if (piece != null && piece.isFriendOf(checkedKing)) {
|
||||
// For each move of the above piece
|
||||
const moves = this.getValidMoves(i)
|
||||
for(const move of moves) {
|
||||
// Copy the board
|
||||
const board = this.clone();
|
||||
const moveIndex = board.getIndex(move.x, move.y);
|
||||
board.state.squares[moveIndex] = board.state.squares[i];
|
||||
const check = board.inCheck(checkedKing);
|
||||
if (check == null || check.color !== checkedKing.color) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getValidMoves(source) {
|
||||
const [x, y] = this.getXandY(source);
|
||||
|
||||
const piece = this.pieceAtIndex(source);
|
||||
return this.getValidMovesAt(piece, x, y);
|
||||
}
|
||||
|
||||
isValidMove(source, dest) {
|
||||
const [destX, destY] = this.getXandY(dest);
|
||||
|
||||
for (const move of this.getValidMoves(source)) {
|
||||
if (destX === move.x && destY === move.y) {
|
||||
return move;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
isHoldingPiece() {
|
||||
return this.heldPiece() != null;
|
||||
}
|
||||
|
||||
heldPiece() {
|
||||
return (this.state && this.state.hand) ? this.state.hand.heldPiece : null;
|
||||
}
|
||||
|
||||
makeMove(from, to) {
|
||||
const squares = this.state.squares.slice();
|
||||
const move = this.isValidMove(from, to)
|
||||
if (move) {
|
||||
if (move.passant) {
|
||||
const i = this.getIndex(move.passant.x, move.passant.y);
|
||||
squares[i] = new Piece(EMPTY, EMPTY);
|
||||
}
|
||||
if (move.castle) {
|
||||
// .castle holds the position where the rook should end up
|
||||
// King moved left
|
||||
const rookX = move.castle[0] > move.x ? 0 : 7;
|
||||
console.log("Replace " + move.castle + " with " + [rookX, move.castle[1]]);
|
||||
const rookStart = this.getIndex(rookX, move.castle[1]);
|
||||
const rookLanding = this.getIndex(move.castle[0], move.castle[1]);
|
||||
squares[rookLanding] = squares[rookStart];
|
||||
squares[rookStart] = new Piece(EMPTY, EMPTY);
|
||||
}
|
||||
// Remove existing passantable states
|
||||
squares.forEach(square => {
|
||||
if (square) {
|
||||
square.passantable = false;
|
||||
}
|
||||
});
|
||||
if (move.passantable) {
|
||||
squares[from].passantable = true;
|
||||
}
|
||||
const y = this.getXandY(to)[1];
|
||||
squares[to] = squares[from];
|
||||
squares[from] = new Piece(EMPTY, EMPTY);
|
||||
if (squares[to].type === PAWN && (y === 0 || y === 7)) {
|
||||
squares[to].setType(QUEEN);
|
||||
}
|
||||
squares[to].moves++;
|
||||
// setState
|
||||
this.state.squares = squares;
|
||||
this.state.blackIsNext = !this.state.blackIsNext;
|
||||
this.state.hand.heldPiece = null;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
handleClick(i) {
|
||||
if (this.checkmate()) {
|
||||
return;
|
||||
}
|
||||
if (this.isHoldingPiece()) {
|
||||
// Copy the board
|
||||
let board = this.clone();
|
||||
board.state.squares[i] = board.state.squares[board.heldPiece()];
|
||||
board.state.squares[this.heldPiece()] = new Piece(EMPTY, EMPTY);
|
||||
|
||||
const moversKing = this.state.blackIsNext ?
|
||||
new Piece(BLACK, KING) : new Piece(WHITE, KING);
|
||||
if (board.inCheck(moversKing) != null) {
|
||||
return;
|
||||
}
|
||||
if (this.makeMove(this.heldPiece(), i) !== 0) {
|
||||
this.setHand({
|
||||
heldPiece: null,
|
||||
});
|
||||
}
|
||||
} else if (this.state.squares[i].isFull()) {
|
||||
const isSquareBlack = this.state.squares[i].isBlack();
|
||||
if(isSquareBlack === this.state.blackIsNext) {
|
||||
this.setHand({
|
||||
heldPiece: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
togglePopup() {
|
||||
// setState
|
||||
this.state.showPopup = !this.state.showPopup;
|
||||
}
|
||||
|
||||
setSetting(name, value) {
|
||||
let settings = this.state.settings;
|
||||
settings[name] = value;
|
||||
// setState
|
||||
this.state.settings = settings;
|
||||
}
|
||||
|
||||
getSetting(name) {
|
||||
return this.state.settings[name];
|
||||
}
|
||||
|
||||
toggleSetting(name) {
|
||||
console.log("toggle " + settingText(name));
|
||||
let settings = this.state.settings;
|
||||
settings[name] = !settings[name];
|
||||
console.log(settings[name]);
|
||||
// setState
|
||||
this.state.settings = settings;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Board: Board,
|
||||
Piece: Piece,
|
||||
}
|
||||
|
||||
// export default Board;
|
||||
// export {Board, Piece};
|
||||
// export { BLACK, WHITE, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY };
|
|
@ -0,0 +1,112 @@
|
|||
import Board from './backend';
|
||||
import * as game from './backend';
|
||||
|
||||
it('detects friendship and enemyship', () => {
|
||||
const black = new game.Piece(game.BLACK, game.KING);
|
||||
const black2 = new game.Piece(game.BLACK, game.QUEEN);
|
||||
const white = new game.Piece(game.WHITE, game.KING);
|
||||
const white2 = new game.Piece(game.WHITE, game.QUEEN);
|
||||
const empty = new game.Piece(game.EMPTY, game.EMPTY);
|
||||
const empty2 = new game.Piece(game.EMPTY, game.EMPTY);
|
||||
|
||||
const truths = [
|
||||
black.isFriendOf(black2),
|
||||
white.isFriendOf(white2),
|
||||
|
||||
black.isEnemyOf(white),
|
||||
white.isEnemyOf(black),
|
||||
];
|
||||
for (const truth of truths) {
|
||||
expect(truth).toBe(true);
|
||||
}
|
||||
|
||||
const lies = [
|
||||
black.isFriendOf(white), black.isFriendOf(empty),
|
||||
white.isFriendOf(black), white.isFriendOf(empty),
|
||||
empty.isFriendOf(white), empty.isFriendOf(black), empty.isFriendOf(empty2),
|
||||
|
||||
black.isEnemyOf(black2), black.isEnemyOf(empty),
|
||||
white.isEnemyOf(white2), white.isEnemyOf(empty),
|
||||
empty.isEnemyOf(white), empty.isEnemyOf(black), empty.isEnemyOf(empty2),
|
||||
];
|
||||
for (const lie of lies) {
|
||||
expect(lie).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('is created correctly', () => {
|
||||
const board = new Board();
|
||||
const rows = ['B',
|
||||
'rnbqkbnr',
|
||||
'pppppppp',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'PPPPPPPP',
|
||||
'RNBQKBNR'
|
||||
];
|
||||
expect(board.textFromState()).toBe(rows.join(''));
|
||||
for (const square of board.state.squares) {
|
||||
expect(square.hasntMoved()).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('is created from text correctly', () => {
|
||||
const rows = ['B',
|
||||
'pppppppp',
|
||||
'pppppppp',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'PPPPPPPP',
|
||||
'PPPPPPPP'
|
||||
];
|
||||
const board = new Board({text: rows.join('')});
|
||||
expect(board.textFromState()).toBe(rows.join(''));
|
||||
});
|
||||
|
||||
it('detects an obvious checkmate', () => {
|
||||
const rows = ['B',
|
||||
'q_______',
|
||||
'q______K',
|
||||
'q_______',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'k_______'
|
||||
];
|
||||
const board = new Board({text: rows.join('')});
|
||||
const inCheck = board.whoInCheck();
|
||||
expect(inCheck.type).toEqual(game.KING);
|
||||
expect(inCheck.color).toEqual(game.BLACK);
|
||||
});
|
||||
|
||||
it('detects basic castling', () => {
|
||||
const startRows = ['B',
|
||||
'____k___',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'________',
|
||||
'PPPPPPPP',
|
||||
'R___K__R'
|
||||
];
|
||||
// const endRows = ['B',
|
||||
// '____k___',
|
||||
// '________',
|
||||
// '________',
|
||||
// '________',
|
||||
// '________',
|
||||
// '________',
|
||||
// 'PPPPPPPP',
|
||||
// 'R____RK_'
|
||||
// ];
|
||||
let board = new Board({text: startRows.join('')});
|
||||
let move = board.isValidMove(60, 62);
|
||||
expect(move.x).toBe(6);
|
||||
expect(move.y).toBe(7);
|
||||
});
|
|
@ -143,6 +143,9 @@ class Piece {
|
|||
class Board extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (props) {
|
||||
this.onMove = props.onMove;
|
||||
}
|
||||
this.state = (props && props.text) ?
|
||||
this.stateFromText(props.text) : this.originalState();
|
||||
}
|
||||
|
@ -554,6 +557,8 @@ class Board extends React.Component {
|
|||
heldPiece: null,
|
||||
}
|
||||
});
|
||||
console.log("this.onMove({from, to});");
|
||||
this.onMove({from, to});
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
|
27
src/index.js
27
src/index.js
|
@ -1,22 +1,45 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import io from 'socket.io-client';
|
||||
|
||||
import Board from './board';
|
||||
|
||||
import './index.css';
|
||||
|
||||
|
||||
const ENDPOINT = "http://192.168.1.7:4001";
|
||||
|
||||
class Game extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { showPopup: false };
|
||||
this.state = {
|
||||
board: null,
|
||||
socket: io(ENDPOINT),
|
||||
};
|
||||
|
||||
this.state.socket.on("FromAPI", data => {
|
||||
console.log(data);
|
||||
this.setState({
|
||||
board: null,
|
||||
});
|
||||
this.setState({
|
||||
board: (
|
||||
<Board
|
||||
text={data}
|
||||
onMove={(move) => {
|
||||
console.log("ON MOVE");
|
||||
this.state.socket.emit("move", move);
|
||||
}}/>
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="game">
|
||||
<div className="game-board">
|
||||
<Board />
|
||||
{this.state.board}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue