Compare commits

...

10 Commits

Author SHA1 Message Date
Sage Vaillancourt 5e21219d00 Update default API url 2023-05-24 14:30:41 -04:00
Sage Vaillancourt f447d64a2b Update to React 18 and correct some more module trickiness 2023-05-23 15:41:27 -04:00
Sage Vaillancourt f3dd68cad9 Add npm run server to start up the backend.
Pull ENDPOINT value from REACT_APP_QUICKCHESS_API.
Switch to ES Modules.
2023-05-18 11:57:15 -04:00
Sage Vaillancourt 2f1a169962 Patch up some imports and exports. 2023-05-18 11:20:11 -04:00
Sage Vaillancourt 48f9a0f6c0 Update README.md 2022-12-30 14:26:16 +00:00
Sage Vaillancourt eeff3c226f Quick backend patch 2022-10-19 00:56:10 +00:00
Sage Vaillancourt 6bdee0edc4 Another quick backend fix. 2022-10-17 16:18:39 -04:00
Sage Vaillancourt 5b18d3c0eb Patch up some import/exports for the backend. 2022-10-17 16:15:32 -04:00
Sage Vaillancourt ed281b51f4 Add 'QuickChess' label to top of page 2022-10-13 10:24:29 -04:00
Sage Vaillancourt 7ad5079289 Rename package to quickchess
Change "Submit" button to "Join"
2022-10-13 00:28:33 -04:00
10 changed files with 2152 additions and 13900 deletions

View File

@ -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

15906
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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"
} }
} }

View File

@ -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);
}); });

View File

@ -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 };

View File

@ -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 };

View File

@ -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'>

View File

@ -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;
} }

View File

@ -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> </>
); );
} }
} }

View File

@ -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 }