init basic tictactoe game

This commit is contained in:
2025-11-27 16:26:51 +05:30
commit c6c9d10476
13 changed files with 4251 additions and 0 deletions

16
.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
.env
# dependencies
node_modules
# React Router
.react-router
build
# misc
.DS_Store
dist
dist-ssr
*.local
.idea

41
README.md Normal file
View File

@@ -0,0 +1,41 @@
# Material UI - React Router example in TypeScript
## How to use
Download the example [or clone the repo](https://github.com/mui/material-ui):
<!-- #target-branch-reference -->
```bash
curl https://codeload.github.com/mui/material-ui/tar.gz/master | tar -xz --strip=2 material-ui-master/examples/material-ui-react-router-ts
cd material-ui-react-router-ts
```
Install it and run:
```bash
npm install
npm run dev
```
or:
<!-- #target-branch-reference -->
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/sandbox/github/mui/material-ui/tree/master/examples/material-ui-react-router-ts)
[![Edit on StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mui/material-ui/tree/master/examples/material-ui-react-router-ts)
## The idea behind the example
<!-- #host-reference -->
This example demonstrates how you can use Material UI with [React Router](https://reactrouter.com/) in [TypeScript](https://github.com/Microsoft/TypeScript).
It includes `@mui/material` and its peer dependencies, including [Emotion](https://emotion.sh/docs/introduction), the default style engine in Material UI.
## What's next?
<!-- #host-reference -->
You now have a working example project.
You can head back to the documentation and continue by browsing the [templates](https://mui.com/material-ui/getting-started/templates/) section.

18
index.html Normal file
View File

@@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, width=device-width" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<title>Blog - Aetoskia</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

3974
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

27
package.json Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "tictactoe-vite",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"@emotion/react": "latest",
"@emotion/styled": "latest",
"@mui/material": "latest",
"@mui/icons-material": "latest",
"react": "latest",
"react-dom": "latest",
"react-markdown": "latest",
"markdown-to-jsx": "latest",
"remark-gfm": "latest",
"marked": "latest",
"axios": "latest"
},
"devDependencies": {
"@vitejs/plugin-react": "latest",
"vite": "latest"
}
}

14
src/main.jsx Normal file
View File

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

11
src/tictactoe/Board.tsx Normal file
View File

@@ -0,0 +1,11 @@
import Square from "./Square";
export default function Board({ squares, onClick }) {
return (
<div className="board">
{squares.map((value, i) => (
<Square key={i} value={value} onClick={() => onClick(i)} />
))}
</div>
);
}

7
src/tictactoe/Square.tsx Normal file
View File

@@ -0,0 +1,7 @@
export default function Square({ value, onClick }) {
return (
<button className="square" onClick={onClick}>
{value}
</button>
);
}

View File

@@ -0,0 +1,52 @@
import { useState } from "react";
import Board from "./Board";
export default function TicTacToe() {
const [board, setBoard] = useState(Array(9).fill(null));
const [xIsNext, setXIsNext] = useState(true);
const winner = calculateWinner(board);
function handleSquareClick(i: number) {
if (board[i] || winner) return;
const newBoard = board.slice();
newBoard[i] = xIsNext ? "X" : "O";
setBoard(newBoard);
setXIsNext(!xIsNext);
}
function reset() {
setBoard(Array(9).fill(null));
setXIsNext(true);
}
const status = winner
? `Winner: ${winner}`
: `Next player: ${xIsNext ? "X" : "O"}`;
return (
<div className="game-container">
<h1>Tic Tac Toe</h1>
<div className="status">{status}</div>
<Board squares={board} onClick={handleSquareClick} />
<button className="reset-btn" onClick={reset}>Reset</button>
</div>
);
}
// --- winner logic ---
function calculateWinner(sq: any[]) {
const lines = [
[0,1,2],[3,4,5],[6,7,8],
[0,3,6],[1,4,7],[2,5,8],
[0,4,8],[2,4,6]
];
for (let [a,b,c] of lines) {
if (sq[a] && sq[a] === sq[b] && sq[a] === sq[c]) {
return sq[a];
}
}
return null;
}

53
src/tictactoe/styles.css Normal file
View File

@@ -0,0 +1,53 @@
body {
font-family: sans-serif;
background: #f4f4f4;
display: flex;
justify-content: center;
padding-top: 50px;
margin: 0;
}
.game-container {
text-align: center;
}
.board {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
margin: 20px auto;
}
.square {
background: white;
border: 2px solid #333;
font-size: 2rem;
font-weight: bold;
cursor: pointer;
height: 100px;
width: 100px;
}
.square:hover {
background: #eee;
}
.status {
font-size: 1.4rem;
margin-bottom: 10px;
}
.reset-btn {
padding: 10px 20px;
background: #333;
color: white;
border: none;
cursor: pointer;
font-size: 1rem;
}
.reset-btn:hover {
background: #555;
}

9
src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_WS_BASE_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

22
tsconfig.json Normal file
View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
// 👇 This line tells TypeScript how to handle JSX
"jsx": "react-jsx"
},
"include": ["src"]
}

7
vite.config.js Normal file
View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
});