Compare commits
10 Commits
b4d75a7855
...
5e21219d00
Author | SHA1 | Date |
---|---|---|
Sage Vaillancourt | 5e21219d00 | |
Sage Vaillancourt | f447d64a2b | |
Sage Vaillancourt | f3dd68cad9 | |
Sage Vaillancourt | 2f1a169962 | |
Sage Vaillancourt | 48f9a0f6c0 | |
Sage Vaillancourt | eeff3c226f | |
Sage Vaillancourt | 6bdee0edc4 | |
Sage Vaillancourt | 5b18d3c0eb | |
Sage Vaillancourt | ed281b51f4 | |
Sage Vaillancourt | 7ad5079289 |
|
@ -1,8 +1,7 @@
|
||||||
# QuickChess
|
# QuickChess
|
||||||
|
|
||||||
This is a simple implementation of Chess in React. It supports nearly all moves,
|
This is a simple implementation of Chess in React. It supports all moves, including castling and en passant. A live build can be seen here:
|
||||||
with castling still to be added. A live build can be seen here:
|
[https://quickchess.win/](https://quickchess.win/). Assets
|
||||||
[https://sagev.space/quickchess/](https://sagev.space/quickchess/). Assets
|
|
||||||
borrowed from Wikipedia.
|
borrowed from Wikipedia.
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
|
@ -1,14 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "chess",
|
"name": "quickchess",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^14.0.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"react": "^17.0.1",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^18.2.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"socket.io": "^3.0.5",
|
"socket.io": "^3.0.5",
|
||||||
"socket.io-client": "^3.0.5",
|
"socket.io-client": "^3.0.5",
|
||||||
|
@ -16,9 +17,10 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
"build": "react-scripts build",
|
"build": "npm ci && react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject",
|
||||||
|
"server": "node server.js"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
@ -38,8 +40,8 @@
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"homepage": "./",
|
"homepage": "https://quickchess.sage.boats",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"react-test-renderer": "^17.0.1"
|
"react-test-renderer": "^18.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
server.js
18
server.js
|
@ -1,9 +1,9 @@
|
||||||
const { textFromBoard } = require('./src/logic')
|
import { textFromBoard } from './src/logic.js'
|
||||||
const { Board } = require('./src/backend');
|
import { Board } from './src/backend.js';
|
||||||
|
|
||||||
const express = require('express');
|
import express from 'express';
|
||||||
const http = require('http');
|
import http from 'http';
|
||||||
const socketIo = require('socket.io');
|
import { Server } from 'socket.io';
|
||||||
|
|
||||||
const port = process.env.PORT || 4001;
|
const port = process.env.PORT || 4001;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ const app = express();
|
||||||
|
|
||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
|
|
||||||
const io = socketIo(server, {
|
const io = new Server(server, {
|
||||||
cors: {
|
cors: {
|
||||||
cors: true,
|
cors: true,
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,9 @@ io.on("connection", (socket) => {
|
||||||
}
|
}
|
||||||
//interval = setInterval(() => getApiAndEmit(socket), 5000);
|
//interval = setInterval(() => getApiAndEmit(socket), 5000);
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
console.log("Client disconnected");
|
const game = socket.connectedGame
|
||||||
|
const gameMessage = game ? `from game '${game.key}'` : "and was not attached to a game"
|
||||||
|
console.log("Client disconnected " + gameMessage);
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -41,12 +43,14 @@ io.on("connection", (socket) => {
|
||||||
game.sockets.push(socket);
|
game.sockets.push(socket);
|
||||||
} else {
|
} else {
|
||||||
game = {
|
game = {
|
||||||
|
key,
|
||||||
sockets: [socket],
|
sockets: [socket],
|
||||||
board: new Board(),
|
board: new Board(),
|
||||||
moveDate: null,
|
moveDate: null,
|
||||||
};
|
};
|
||||||
console.log(`Created game '${key}'`);
|
console.log(`Created game '${key}'`);
|
||||||
}
|
}
|
||||||
|
socket.connectedGame = game;
|
||||||
games.set(key, game);
|
games.set(key, game);
|
||||||
getApiAndEmit(socket, game.board);
|
getApiAndEmit(socket, game.board);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,16 +1,4 @@
|
||||||
import { Piece } from './logic'
|
import { Piece, startingBoard, BLACK, WHITE, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY } from './logic.js'
|
||||||
|
|
||||||
|
|
||||||
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;
|
const SHUFFLING_ENABLED = 0;
|
||||||
|
|
||||||
|
@ -27,22 +15,10 @@ function settingText(setting) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function range(n) {
|
export class Board {
|
||||||
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 Board {
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
this.state = props?.text ?
|
this.state = props?.text ?
|
||||||
this.stateFromText(props.text) : this.originalState();
|
this.stateFromText(props.text) : startingBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
setHand(hand) {
|
setHand(hand) {
|
||||||
|
@ -452,8 +428,6 @@ class Board {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { Board }
|
|
||||||
|
|
||||||
// export default Board;
|
// export default Board;
|
||||||
// export {Board, Piece};
|
// export {Board, Piece};
|
||||||
// export { BLACK, WHITE, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY };
|
// export { BLACK, WHITE, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY };
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Popup from './Popup';
|
import Popup from './Popup.js';
|
||||||
|
|
||||||
import '../index.css';
|
import '../index.css';
|
||||||
import { Piece, startingBoard, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY, BLACK, WHITE } from '../logic';
|
import { Piece, startingBoard, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY, BLACK, WHITE } from '../logic.js';
|
||||||
|
|
||||||
|
|
||||||
const Images = [
|
const Images = [
|
||||||
'./white_pawn.svg',
|
'./white_pawn.svg',
|
||||||
|
@ -620,5 +619,4 @@ class Board extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Board;
|
export default Board;
|
||||||
export {Piece};
|
export { Piece, BLACK, WHITE, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY };
|
||||||
export { BLACK, WHITE, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY };
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
|
|
||||||
class Popup extends React.Component {
|
class Popup extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className='popup'>
|
<div className='popup'>
|
||||||
|
|
|
@ -10,6 +10,13 @@ body {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
ol, ul {
|
ol, ul {
|
||||||
padding-left: 30px;
|
padding-left: 30px;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +61,11 @@ ol, ul {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.game {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.square {
|
.square {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -94,6 +106,7 @@ ol, ul {
|
||||||
|
|
||||||
.game-board {
|
.game-board {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
@ -111,4 +124,4 @@ ol, ul {
|
||||||
.icon:hover {
|
.icon:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
margin-top: -0.35em;
|
margin-top: -0.35em;
|
||||||
}
|
}
|
||||||
|
|
18
src/index.js
18
src/index.js
|
@ -2,12 +2,11 @@ import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import io from 'socket.io-client';
|
import io from 'socket.io-client';
|
||||||
|
|
||||||
import Board from './components/Board';
|
import Board from './components/Board.js';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
|
const ENDPOINT = process.env.REACT_APP_QUICKCHESS_API || "https://api.quickchess.win";
|
||||||
const ENDPOINT = "https://quickchess.undercover.cafe";
|
|
||||||
|
|
||||||
class NameForm extends React.Component {
|
class NameForm extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -35,7 +34,7 @@ class NameForm extends React.Component {
|
||||||
</label>
|
</label>
|
||||||
<div style={{ textAlign: 'center', width: '80%' }}>
|
<div style={{ textAlign: 'center', width: '80%' }}>
|
||||||
<input className='big-input' style={{ width: '50%' }} name='lobby-name' type="text" value={this.state.value} onChange={this.handleChange} />
|
<input className='big-input' style={{ width: '50%' }} name='lobby-name' type="text" value={this.state.value} onChange={this.handleChange} />
|
||||||
<input className='big-input' style={{ marginLeft: '8px' }} type="submit" value="Submit" />
|
<input className='big-input' style={{ marginLeft: '8px' }} type="submit" value="Join" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
@ -78,11 +77,14 @@ class Game extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="game">
|
<>
|
||||||
<div className="game-board">
|
<h2 className="white-on-light">QuickChess</h2>
|
||||||
{this.state.gameKey ? this.state.board : <NameForm onSubmit={this.setGameKey.bind(this)} />}
|
<div className="game">
|
||||||
|
<div className="game-board">
|
||||||
|
{this.state.gameKey ? this.state.board : <NameForm onSubmit={this.setGameKey.bind(this)} />}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
src/logic.js
30
src/logic.js
|
@ -1,16 +1,16 @@
|
||||||
const BLACK = 0;
|
export const BLACK = 0;
|
||||||
const WHITE = 1;
|
export const WHITE = 1;
|
||||||
|
|
||||||
const PAWN = 0;
|
export const PAWN = 0;
|
||||||
const ROOK = 1;
|
export const ROOK = 1;
|
||||||
const KNIGHT = 2;
|
export const KNIGHT = 2;
|
||||||
const BISHOP = 3;
|
export const BISHOP = 3;
|
||||||
const QUEEN = 4;
|
export const QUEEN = 4;
|
||||||
const KING = 5;
|
export const KING = 5;
|
||||||
|
|
||||||
const EMPTY = -1;
|
export const EMPTY = -1;
|
||||||
|
|
||||||
class Piece {
|
export class Piece {
|
||||||
constructor(color, type) {
|
constructor(color, type) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -75,7 +75,7 @@ class Piece {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const startingBoard = () => {
|
export const startingBoard = () => {
|
||||||
let squares = [];
|
let squares = [];
|
||||||
const mainRow = [ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK];
|
const mainRow = [ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK];
|
||||||
function add(num, color, type) {
|
function add(num, color, type) {
|
||||||
|
@ -101,9 +101,9 @@ const startingBoard = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const textFromBoard = ({ state }) => {
|
export const textFromBoard = ({ state }) => {
|
||||||
const turn = (this.state.blackIsNext? 'B' : 'W');
|
const turn = state?.blackIsNext ? 'B' : 'W';
|
||||||
return turn + this.state.squares.map(square => {
|
return turn + state?.squares.map(square => {
|
||||||
if (!square) {
|
if (!square) {
|
||||||
return '_';
|
return '_';
|
||||||
}
|
}
|
||||||
|
@ -128,5 +128,3 @@ const textFromBoard = ({ state }) => {
|
||||||
}
|
}
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Piece, startingBoard, textFromBoard, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, EMPTY, BLACK, WHITE }
|
|
||||||
|
|
Loading…
Reference in New Issue