refactoring game for separate folders for game boards and common logic for player
This commit is contained in:
@@ -1,16 +1,14 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { useNakama } from "./providers/NakamaProvider";
|
import { useNakama } from "./providers/NakamaProvider";
|
||||||
import Board from "./Board";
|
|
||||||
import Player from "./Player";
|
import Player from "./Player";
|
||||||
import { PlayerModel } from "./Board";
|
import { PlayerModel } from "./models/player";
|
||||||
|
|
||||||
export default function TicTacToe() {
|
import TicTacToeBoard from "./games/tictactoe/TicTacToeBoard";
|
||||||
const [board, setBoard] = useState<string[][]>([
|
|
||||||
["", "", ""],
|
export default function App() {
|
||||||
["", "", ""],
|
// setting up a 2D game board
|
||||||
["", "", ""]
|
const [board, setBoard] = useState<string[][]>([[]]);
|
||||||
]);
|
|
||||||
const [turn, setTurn] = useState<number>(0);
|
const [turn, setTurn] = useState<number>(0);
|
||||||
const [winner, setWinner] = useState<string | null>(null);
|
const [winner, setWinner] = useState<string | null>(null);
|
||||||
const [gameOver, setGameOver] = useState<boolean | null>(null);
|
const [gameOver, setGameOver] = useState<boolean | null>(null);
|
||||||
@@ -115,7 +113,7 @@ export default function TicTacToe() {
|
|||||||
minWidth: "300px",
|
minWidth: "300px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Board
|
<TicTacToeBoard
|
||||||
board={board}
|
board={board}
|
||||||
turn={turn}
|
turn={turn}
|
||||||
winner={winner}
|
winner={winner}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import Leaderboard from "./Leaderboard";
|
|
||||||
import { useNakama } from "./providers/NakamaProvider";
|
import { useNakama } from "./providers/NakamaProvider";
|
||||||
|
|
||||||
export default function Player({
|
export default function Player({
|
||||||
@@ -238,7 +237,6 @@ export default function Player({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div style={{ marginTop: "24px" }}>
|
<div style={{ marginTop: "24px" }}>
|
||||||
<Leaderboard />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<motion.button
|
<motion.button
|
||||||
@@ -1,14 +1,8 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { useNakama } from "./providers/NakamaProvider";
|
import { useNakama } from "../../providers/NakamaProvider";
|
||||||
import getHaiku from "./utils/haikus";
|
import getHaiku from "../../utils/haikus";
|
||||||
|
import { PlayerModel } from "../../models/player";
|
||||||
export interface PlayerModel {
|
|
||||||
user_id: string;
|
|
||||||
username: string;
|
|
||||||
index: number;
|
|
||||||
metadata: Record<string, string>; // e.g. { symbol: "X" }
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BoardProps {
|
interface BoardProps {
|
||||||
board: string[][];
|
board: string[][];
|
||||||
@@ -20,7 +14,7 @@ interface BoardProps {
|
|||||||
onCellClick: (row: number, col: number) => void;
|
onCellClick: (row: number, col: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Board({
|
export default function TicTacToeBoard({
|
||||||
board,
|
board,
|
||||||
turn,
|
turn,
|
||||||
winner,
|
winner,
|
||||||
@@ -4,9 +4,9 @@ import {
|
|||||||
ApiLeaderboardRecordList,
|
ApiLeaderboardRecordList,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
} from "@heroiclabs/nakama-js/dist/api.gen"
|
} 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 = 10000,
|
||||||
}: {
|
}: {
|
||||||
intervalMs?: number;
|
intervalMs?: number;
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import TicTacToe from './tictactoe/TicTacToe';
|
import App from './App';
|
||||||
import { NakamaProvider } from './tictactoe/providers/NakamaProvider';
|
import { NakamaProvider } from './providers/NakamaProvider';
|
||||||
import "./tictactoe/styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
const rootElement = document.getElementById('root');
|
const rootElement = document.getElementById('root');
|
||||||
const root = createRoot(rootElement);
|
const root = createRoot(rootElement);
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<NakamaProvider>
|
<NakamaProvider>
|
||||||
<TicTacToe />
|
<App />
|
||||||
</NakamaProvider>,
|
</NakamaProvider>,
|
||||||
);
|
);
|
||||||
|
|||||||
6
src/models/player.ts
Normal file
6
src/models/player.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export interface PlayerModel {
|
||||||
|
user_id: string;
|
||||||
|
username: string;
|
||||||
|
index: number;
|
||||||
|
metadata: Record<string, string>; // e.g. { symbol: "X" }
|
||||||
|
}
|
||||||
@@ -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",
|
|
||||||
};
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user