add tic tac toe game
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
0e47ca2572
commit
38f9c8d7e3
@ -1,4 +1,4 @@
|
|||||||
import { Box, Typography } from '@mui/material';
|
import { Box, Container, Typography } from '@mui/material';
|
||||||
import { getPostBySlug, getAllSlugs } from '../../../lib/posts';
|
import { getPostBySlug, getAllSlugs } from '../../../lib/posts';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
|
|
||||||
@ -13,10 +13,10 @@ export default async function BlogPost({ params }: Props) {
|
|||||||
const post = await getPostBySlug(slug);
|
const post = await getPostBySlug(slug);
|
||||||
if (!post) return notFound();
|
if (!post) return notFound();
|
||||||
return (
|
return (
|
||||||
<Box component={'article'}>
|
<Container component={'article'}>
|
||||||
<Typography variant='h2'>{post.title}</Typography>
|
<Typography variant='h2'>{post.title}</Typography>
|
||||||
<Typography variant='body2'>{post.date}</Typography>
|
<Typography variant='body2'>{post.date}</Typography>
|
||||||
<Box dangerouslySetInnerHTML={{ __html: post.contentHtml }} />
|
<Box dangerouslySetInnerHTML={{ __html: post.contentHtml }} />
|
||||||
</Box>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import { getAllPosts } from '../../lib/posts';
|
import { getAllPosts } from '../../lib/posts';
|
||||||
import ArticleIcon from '@mui/icons-material/Article';
|
import ArticleIcon from '@mui/icons-material/Article';
|
||||||
import { Avatar, Box, Link, List, ListItem, ListItemAvatar, ListItemButton, ListItemText, Typography } from '@mui/material';
|
import { Avatar, Container, Link, List, ListItem, ListItemAvatar, ListItemButton, ListItemText, Typography } from '@mui/material';
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const posts = getAllPosts();
|
const posts = getAllPosts();
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Container>
|
||||||
<Typography variant='h1' >My Blog</Typography>
|
<Typography variant='h1' >My Blog</Typography>
|
||||||
<List>
|
<List>
|
||||||
{posts.map(post => (
|
{posts.map(post => (
|
||||||
@ -20,6 +20,6 @@ export default function Home() {
|
|||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</Box >
|
</Container >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1,11 +1,12 @@
|
|||||||
import { Box, Typography } from "@mui/material";
|
import Xo from "@/components/Xo/Xo";
|
||||||
|
import { Container } from "@mui/material";
|
||||||
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Container>
|
||||||
<Typography variant={'h1'}>Welcome to the den</Typography>
|
|
||||||
<Typography variant="body1">Here lives the geek bear who is hungry for bits and bytes. Ravaging through the internet dumpster finding the finest 0s and 1s. He looks for speed and performance</Typography>
|
<Xo />
|
||||||
</Box>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,14 +47,13 @@ export default function Header() {
|
|||||||
<Toolbar>
|
<Toolbar>
|
||||||
<IconButton
|
<IconButton
|
||||||
size='large'
|
size='large'
|
||||||
sx={{ color: 'background.paper' }}
|
|
||||||
aria-label="open drawer"
|
aria-label="open drawer"
|
||||||
edge="start"
|
edge="start"
|
||||||
onClick={handleDrawerToggle}
|
onClick={handleDrawerToggle}
|
||||||
>
|
>
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography variant="h6" padding={2} color='background.paper'>
|
<Typography variant="h4" padding={2}>
|
||||||
TCG
|
TCG
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ flexGrow: 1 }} />
|
<Box sx={{ flexGrow: 1 }} />
|
||||||
|
|||||||
121
src/components/Xo/Xo.tsx
Normal file
121
src/components/Xo/Xo.tsx
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
'use client'
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Container,
|
||||||
|
Typography,
|
||||||
|
Grid,
|
||||||
|
Paper,
|
||||||
|
Button,
|
||||||
|
Box,
|
||||||
|
} from '@mui/material';
|
||||||
|
type Player = 'X' | 'O';
|
||||||
|
type Cell = Player | null;
|
||||||
|
const emptyBoard: Cell[] = Array(9).fill(null);
|
||||||
|
const winningCombos = [
|
||||||
|
[0, 1, 2], [3, 4, 5], [6, 7, 8],
|
||||||
|
[0, 3, 6], [1, 4, 7], [2, 5, 8],
|
||||||
|
[0, 4, 8], [2, 4, 6],
|
||||||
|
];
|
||||||
|
function checkWinner(board: Cell[]): Player | 'Draw' | null {
|
||||||
|
for (const [a, b, c] of winningCombos) {
|
||||||
|
if (board[a] && board[a] === board[b] && board[a] === board[c]) {
|
||||||
|
return board[a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return board.includes(null) ? null : 'Draw';
|
||||||
|
}
|
||||||
|
function minimax(board: Cell[], isMaximizing: boolean): { score: number; index: number } {
|
||||||
|
const winner = checkWinner(board);
|
||||||
|
if (winner === 'O') return { score: 1, index: -1 };
|
||||||
|
if (winner === 'X') return { score: -1, index: -1 };
|
||||||
|
if (winner === 'Draw') return { score: 0, index: -1 };
|
||||||
|
let bestMove = -1;
|
||||||
|
let bestScore = isMaximizing ? -Infinity : Infinity;
|
||||||
|
for (let i = 0; i < board.length; i++) {
|
||||||
|
if (board[i] === null) {
|
||||||
|
board[i] = isMaximizing ? 'O' : 'X';
|
||||||
|
const result = minimax(board, !isMaximizing);
|
||||||
|
board[i] = null;
|
||||||
|
if (isMaximizing) {
|
||||||
|
if (result.score > bestScore) {
|
||||||
|
bestScore = result.score;
|
||||||
|
bestMove = i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (result.score < bestScore) {
|
||||||
|
bestScore = result.score;
|
||||||
|
bestMove = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { score: bestScore, index: bestMove };
|
||||||
|
}
|
||||||
|
export default function XOGame() {
|
||||||
|
const [board, setBoard] = useState<Cell[]>([...emptyBoard]);
|
||||||
|
const [isPlayerTurn, setIsPlayerTurn] = useState(true);
|
||||||
|
const [winner, setWinner] = useState<Player | 'Draw' | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isPlayerTurn && !winner) {
|
||||||
|
const move = minimax([...board], true).index;
|
||||||
|
if (move !== -1) {
|
||||||
|
const newBoard = [...board];
|
||||||
|
newBoard[move] = 'O';
|
||||||
|
setBoard(newBoard);
|
||||||
|
setWinner(checkWinner(newBoard));
|
||||||
|
setIsPlayerTurn(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isPlayerTurn, board, winner]);
|
||||||
|
const handleClick = (index: number) => {
|
||||||
|
if (board[index] || winner || !isPlayerTurn) return;
|
||||||
|
const newBoard = [...board];
|
||||||
|
newBoard[index] = 'X';
|
||||||
|
setBoard(newBoard);
|
||||||
|
setWinner(checkWinner(newBoard));
|
||||||
|
setIsPlayerTurn(false);
|
||||||
|
};
|
||||||
|
const resetGame = () => {
|
||||||
|
setBoard([...emptyBoard]);
|
||||||
|
setWinner(null);
|
||||||
|
setIsPlayerTurn(true);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Container maxWidth="sm" sx={{ mt: 5 }}>
|
||||||
|
<Typography variant="h4" align="center" gutterBottom>
|
||||||
|
Tic Tac Toe
|
||||||
|
</Typography>
|
||||||
|
<Grid container spacing={1} >
|
||||||
|
{board.map((cell, idx) => (
|
||||||
|
<Grid key={idx} size={4}>
|
||||||
|
<Paper
|
||||||
|
elevation={3}
|
||||||
|
sx={{
|
||||||
|
height: 100,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
fontSize: '2rem',
|
||||||
|
cursor: cell || winner || !isPlayerTurn ? 'default' : 'pointer',
|
||||||
|
backgroundColor: 'background.paper',
|
||||||
|
}}
|
||||||
|
onClick={() => handleClick(idx)}
|
||||||
|
>
|
||||||
|
{cell}
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
{winner && (
|
||||||
|
<Box mt={4} textAlign="center">
|
||||||
|
<Typography variant="h5" gutterBottom>
|
||||||
|
{winner === 'Draw' ? "It's a draw!" : `${winner} wins!`}
|
||||||
|
</Typography>
|
||||||
|
<Button variant="contained" onClick={resetGame}>
|
||||||
|
Play Again
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
1
src/components/Xo/index.ts
Normal file
1
src/components/Xo/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './Xo';
|
||||||
Loading…
x
Reference in New Issue
Block a user