refactoring game for separate folders for game boards and common logic for player

This commit is contained in:
2025-12-01 20:36:46 +05:30
parent df0f502191
commit cc1f45457c
11 changed files with 23 additions and 94 deletions

View File

@@ -1,16 +1,14 @@
import React, { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { useNakama } from "./providers/NakamaProvider";
import Board from "./Board";
import Player from "./Player";
import { PlayerModel } from "./Board";
import { PlayerModel } from "./models/player";
export default function TicTacToe() {
const [board, setBoard] = useState<string[][]>([
["", "", ""],
["", "", ""],
["", "", ""]
]);
import TicTacToeBoard from "./games/tictactoe/TicTacToeBoard";
export default function App() {
// setting up a 2D game board
const [board, setBoard] = useState<string[][]>([[]]);
const [turn, setTurn] = useState<number>(0);
const [winner, setWinner] = useState<string | null>(null);
const [gameOver, setGameOver] = useState<boolean | null>(null);
@@ -115,7 +113,7 @@ export default function TicTacToe() {
minWidth: "300px",
}}
>
<Board
<TicTacToeBoard
board={board}
turn={turn}
winner={winner}

View File

@@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import Leaderboard from "./Leaderboard";
import { useNakama } from "./providers/NakamaProvider";
export default function Player({
@@ -238,7 +237,6 @@ export default function Player({
)}
<div style={{ marginTop: "24px" }}>
<Leaderboard />
</div>
<motion.button

View File

@@ -1,14 +1,8 @@
import React, { useEffect, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useNakama } from "./providers/NakamaProvider";
import getHaiku from "./utils/haikus";
export interface PlayerModel {
user_id: string;
username: string;
index: number;
metadata: Record<string, string>; // e.g. { symbol: "X" }
}
import { useNakama } from "../../providers/NakamaProvider";
import getHaiku from "../../utils/haikus";
import { PlayerModel } from "../../models/player";
interface BoardProps {
board: string[][];
@@ -20,7 +14,7 @@ interface BoardProps {
onCellClick: (row: number, col: number) => void;
}
export default function Board({
export default function TicTacToeBoard({
board,
turn,
winner,

View File

@@ -4,9 +4,9 @@ import {
ApiLeaderboardRecordList,
// @ts-ignore
} from "@heroiclabs/nakama-js/dist/api.gen"
import { useNakama } from "./providers/NakamaProvider";
import { useNakama } from "../../providers/NakamaProvider";
export default function Leaderboard({
export default function TicTacToeLeaderboard({
intervalMs = 10000,
}: {
intervalMs?: number;

View File

@@ -1,14 +1,14 @@
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import TicTacToe from './tictactoe/TicTacToe';
import { NakamaProvider } from './tictactoe/providers/NakamaProvider';
import "./tictactoe/styles.css";
import App from './App';
import { NakamaProvider } from './providers/NakamaProvider';
import "./styles.css";
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
root.render(
<NakamaProvider>
<TicTacToe />
<App />
</NakamaProvider>,
);

6
src/models/player.ts Normal file
View File

@@ -0,0 +1,6 @@
export interface PlayerModel {
user_id: string;
username: string;
index: number;
metadata: Record<string, string>; // e.g. { symbol: "X" }
}

View File

@@ -1,55 +0,0 @@
import { Match } from "@heroiclabs/nakama-js";
interface MatchListProps {
matches: Match[];
}
export default function MatchList({ matches }: MatchListProps) {
if (!matches.length) return <p>No open matches</p>;
return (
<div style={{ marginTop: "20px" }}>
<h3>Open Matches</h3>
<table
style={{
width: "100%",
borderCollapse: "collapse",
marginTop: "10px",
}}
>
<thead>
<tr>
<th style={th}>Sr No.</th>
<th style={th}>Match ID</th>
<th style={th}>Label</th>
</tr>
</thead>
<tbody>
{matches
.filter(m => m.size ?? 0 > 0)
.map((m, index) => (
<tr key={m.match_id}>
<td style={td}>{index + 1}</td>
<td style={td}>{m.match_id}</td>
<td style={td}>{m.label ?? "-"}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
const th: React.CSSProperties = {
textAlign: "left",
padding: "8px",
background: "#f2f2f2",
borderBottom: "1px solid #ccc",
};
const td: React.CSSProperties = {
padding: "8px",
borderBottom: "1px solid #eee",
};

View File

@@ -1,12 +0,0 @@
interface SquareProps {
value: string;
onClick: () => void;
}
export default function Square({ value, onClick } : SquareProps) {
return (
<button className="square" onClick={onClick}>
{value}
</button>
);
}