Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## chess wee woo

---

attempt at making a chess game in React

technologies:
Expand All @@ -11,9 +13,9 @@ technologies:

todo:

- fix board rendering from x,y to y,x
- add remaining pieces and some custom ones
- improve move system
- allow rendering based on player color
- server setup with firebase
- server setup with supbase
- authentication
- networking
- page to allow matchmaking
2 changes: 1 addition & 1 deletion chess/piece_info.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {piece_id, PieceInfoMap} from "./types";

import {testpiece} from "./pieces/test";
import {testpiece} from "./pieces/piece";
import {rook} from "./pieces/rook";
import {pawn} from "./pieces/pawn";
import {knight} from "./pieces/knight";
Expand Down
34 changes: 14 additions & 20 deletions chess/pieces/bishop.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import Image from "next/image";

import { board, color_id, move, move_type, piece, PieceInfo, PieceRenderProps, point } from "../types";
import { in_bounds } from "../utils";
import {board, color_id, move, move_type, piece, PieceInfo, PieceRenderProps, point} from "../types";
import {in_bounds} from "../utils";
import {edge_mover} from "./piece";

export const bishop: PieceInfo = {
render: (color) => <Bishop color={color} />,
moves: moves_bishop
render: (color) => <Bishop color={color}/>,
moves: moves_bishop
}

function Bishop({ color }: PieceRenderProps) {
return <Image src={`/bishop_${color}.png`} alt={"bishop"} width={50} height={50} />;
function Bishop({color}: PieceRenderProps) {
return <Image src={`/bishop_${color}.png`} alt={"bishop"} width={50} height={50}/>;
}

function moves_bishop(board: board, position: point): move[] {
let moves: move[] = [];
const directions = [
{x: -1, y: -1},
{x: -1, y: +1},
{x: +1, y: -1},
{x: +1, y: +1}
];

const vecs: point[] = [{ x: -1, y: -1 }, { x: -1, y: 1}, { x: 1, y: - 1}, { x: 1, y: 1}];
const my_color = board[position.x][position.y].color;

vecs.forEach( vec => {
for (let i = 1; i < 8; ++i) {
const dest: point = {x: position.x + vec.x * i, y: position.y + vec.y * i};
if (!in_bounds(dest.x) || !in_bounds(dest.y) || board[dest.x][dest.y].color === my_color) { break; }
if (board[dest.x][dest.y].color !== color_id.none) { moves.push({ position: dest, type: move_type.capture }); break; }
moves.push({ position: dest, type: move_type.move })
}
})

return moves;
return edge_mover(board, position, directions);
}
2 changes: 1 addition & 1 deletion chess/pieces/knight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const knight: PieceInfo = {
}

function Knight({color}: PieceRenderProps) {
return <Image src={"/knight_" + color + ".png"} alt={"knight"} width={50} height={50}/>;
return <Image src={`/knight_${color}.png`} alt={"knight"} width={50} height={50}/>;
}

function moves_knight(board: board, position: point): move[] {
Expand Down
2 changes: 1 addition & 1 deletion chess/pieces/pawn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const pawn: PieceInfo = {
}

function Pawn({color}: PieceRenderProps) {
return <Image src={"/pawn_" + color + ".png"} alt={"pawn"} width={50} height={50}/>;
return <Image src={`/pawn_${color}.png`} alt={"pawn"} width={50} height={50}/>;
}

function moves_pawn(board: board, position: point): move[] {
Expand Down
44 changes: 44 additions & 0 deletions chess/pieces/piece.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Image from "next/image";

import {board, color_id, move, move_type, PieceInfo, point} from "../types";
import {in_bounds} from "../utils";

export const testpiece: PieceInfo = {
render: () => <TestPiece/>,
moves: moves_test
}

function TestPiece() {
return <Image src={"thirteen.svg"} alt={"test"} width={50} height={50}/>;
}

function moves_test(board: board, position: point): move[] {
return [
{position: {x: position.x - 1, y: position.y}, type: move_type.move},
{position: {x: position.x + 1, y: position.y}, type: move_type.move},
{position: {x: position.x, y: position.y - 1}, type: move_type.move},
{position: {x: position.x, y: position.y + 1}, type: move_type.move},
]
}

export function edge_mover(board: board, position: point, directions: point[]): move[] {
const piece = board[position.x][position.y];
let moves: move[] = [];

directions.forEach(direction => {
let current_pos = position;
while (true) {
if (!in_bounds(current_pos.x + direction.x) || !in_bounds(current_pos.y + direction.y) || board[current_pos.x + direction.x][current_pos.y + direction.y].color === piece.color) {
break;
}
if (board[current_pos.x + direction.x][current_pos.y + direction.y].color !== color_id.none) {
moves.push({ position: {x: current_pos.x + direction.x, y: current_pos.y + direction.y}, type: move_type.capture });
break;
}
moves.push({ position: {x: current_pos.x + direction.x, y: current_pos.y + direction.y}, type: move_type.move });
current_pos = {x: current_pos.x + direction.x, y: current_pos.y + direction.y};
}
})

return moves;
}
31 changes: 12 additions & 19 deletions chess/pieces/queen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Image from "next/image";

import { board, color_id, move, move_type, piece, PieceInfo, PieceRenderProps, point } from "../types";
import { in_bounds } from "../utils";
import {edge_mover} from "./piece";

export const queen: PieceInfo = {
render: (color) => <Queen color={color} />,
Expand All @@ -13,24 +14,16 @@ function Queen({ color }: PieceRenderProps) {
}

function moves_queen(board: board, position: point): move[] {
let moves: move[] = [];
const directions = [
{x: -1, y: -1},
{x: 0, y: -1},
{x: +1, y: -1},
{x: +1, y: 0},
{x: +1, y: +1},
{x: 0, y: +1},
{x: -1, y: +1},
{x: -1, y: 0},
];

const my_color = board[position.x][position.y].color;
let vecs: point[] = [];
for (let i = -1; i <= 1; ++i) {
for (let j = -1; j <= 1; ++j) {
vecs.push({ x: i, y: j});
}
}

vecs.forEach(vec => {
for (let i = 1; i < 8; ++i) {
const dest: point = { x: position.x + vec.x * i, y: position.y + vec.y * i };
if (!in_bounds(dest.x) || !in_bounds(dest.y) || board[dest.x][dest.y].color === my_color) { break; }
if (board[dest.x][dest.y].color !== color_id.none) { moves.push({ position: dest, type: move_type.capture }); break; }
moves.push({ position: dest, type: move_type.move })
}
})

return moves;
return edge_mover(board, position, directions);
}
50 changes: 10 additions & 40 deletions chess/pieces/rook.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,24 @@
import Image from "next/image";

import {board, move, move_type, piece_id, PieceInfo, PieceRenderProps, point} from "../types";
import {edge_mover} from "./piece";

export const rook: PieceInfo = {
render: (color) => <Rook color={color}/>,
moves: moves_rook
}

function Rook({color}: PieceRenderProps) {
return <Image src={"/rook_" + color + ".png"} alt={"rook"} width={50} height={50}/>;
return <Image src={`/rook_${color}.png`} alt={"rook"} width={50} height={50}/>;
}

function moves_rook(board: board, position: point): move[] {
let moves: move[] = [];

let pos_x = position.x - 1;
while (pos_x >= 0 && board[pos_x][position.y].piece === piece_id.none) {
moves.push({position: {x: pos_x, y: position.y}, type: move_type.move});
pos_x--;
}
if (pos_x >= 0 && board[pos_x][position.y].color !== board[position.x][position.y].color) {
moves.push({position: {x: pos_x, y: position.y}, type: move_type.capture});
}

pos_x = position.x + 1;
while (pos_x <= 7 && board[pos_x][position.y].piece === piece_id.none) {
moves.push({position: {x: pos_x, y: position.y}, type: move_type.move});
pos_x++;
}
if (pos_x <= 7 && board[pos_x][position.y].color !== board[position.x][position.y].color) {
moves.push({position: {x: pos_x, y: position.y}, type: move_type.capture});
}

let pos_y = position.y - 1;
while (pos_y >= 0 && board[position.x][pos_y].piece === piece_id.none) {
moves.push({position: {x: position.x, y: pos_y}, type: move_type.move});
pos_y--;
}
if (pos_y >= 0 && board[position.x][pos_y].color !== board[position.x][position.y].color) {
moves.push({position: {x: position.x, y: pos_y}, type: move_type.capture});
}

pos_y = position.y + 1;
while (pos_y <= 7 && board[position.x][pos_y].piece === piece_id.none) {
moves.push({position: {x: position.x, y: pos_y}, type: move_type.move});
pos_y++;
}
if (pos_y <= 7 && board[position.x][pos_y].color !== board[position.x][position.y].color) {
moves.push({position: {x: position.x, y: pos_y}, type: move_type.capture});
}

return moves;
const directions = [
{x: +1, y: 0},
{x: -1, y: 0},
{x: 0, y: +1},
{x: 0, y: -1},
];

return edge_mover(board, position, directions);
}
21 changes: 0 additions & 21 deletions chess/pieces/test.tsx

This file was deleted.

16 changes: 15 additions & 1 deletion components/board.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {useMemo, useRef, useState} from "react";
import {useEffect, useMemo, useRef, useState} from "react";

import {piece_info} from "../chess/piece_info";
import Square from "./square";
import {black_bishop, black_knight, black_pawn, black_queen, black_rook, board, board_state, BoardProps, color_id, move_type, p, piece, point, white_bishop, white_knight, white_pawn, white_queen, white_rook} from "../chess/types";
import {supabase} from "../chess/supabase";

function get_initial_board(): piece[][] {
return [
Expand All @@ -18,11 +19,24 @@ function get_initial_board(): piece[][] {
}

export default function Board({side}: BoardProps) {
const room_id = "1234";

const [positions, set_positions] = useState<piece[][]>(get_initial_board());
const [selected, set_selected] = useState<point | null>(null);
const board_ref = useRef<HTMLDivElement>(null);
const positions_ref = useRef<board>(positions);

// listen for changes to the current game
useEffect(() => {
const channel = supabase.channel("table-db-changes")
.on("postgres_changes",
{event: "UPDATE", schema: "public", table: "games", filter: "id = room_id"},
(payload => console.log(payload))).subscribe();
return () => {
channel.unsubscribe().then(r => console.log("unsubscribed:" + r));
};
})

const moves = useMemo(() => {
if (selected === null) {
return [];
Expand Down
32 changes: 23 additions & 9 deletions components/game_list.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import {supabase} from "../chess/supabase";
import {useEffect, useState} from "react";

import {supabase} from "../chess/supabase";
import {piece} from "../chess/types";

type game = {
id: string;
created_at: string;
board: piece[][];
players: string[];
}

export function GameList() {
const [payloads, set_payloads] = useState<string[]>([]);
const [games, set_games] = useState<game[]>([]);

useEffect(() => {
supabase.from("games").select().then(x => set_payloads(x.data!.map(x => JSON.stringify(x))));
supabase.from("games").select().then(x => set_games(x.data as game[]));
}, []);

useEffect(() => {
console.log("subscribe")
const channel = supabase.channel("table-db-changes").on("postgres_changes", {event: "UPDATE", schema: "public", table: "games"}, (payload => set_payloads(cur => [...cur, JSON.stringify(payload)]))).subscribe();
const channel = supabase.channel("table-db-changes").on("postgres_changes", {event: "*", schema: "public", table: "games"}, (payload => {
if (payload.eventType === "INSERT") {
set_games(games => [...games, payload.new as game]);
} else if (payload.eventType === "UPDATE") {
set_games(games => games.map(x => x.id === payload.new.id ? payload.new as game : x));
} else if (payload.eventType === "DELETE") {
set_games(games => games.filter(x => x.id !== payload.old.id));
}
})).subscribe();
return () => {
channel.unsubscribe().then(r => console.log("unsubscribed:" + r))
channel.unsubscribe().then(r => console.log("unsubscribed:" + r));
};
}, []);

return <div>
{payloads}
</div>
return <div>{games?.map(x => <div key={x.id}>{JSON.stringify(x)}<br/></div>)}</div>;
}
1 change: 0 additions & 1 deletion components/piece.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export default function Piece({x, y, piece, board, end_move, board_ref}: PiecePr

return (
<motion.div

drag={board.side === piece.color}
style={{
zIndex: 1,
Expand Down
12 changes: 11 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'lh3.googleusercontent.com',
port: '',
pathname: '/a/**',
},
],
}
}

module.exports = nextConfig
Loading