Skip to content
Merged
15 changes: 15 additions & 0 deletions src/meta/play-meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ QuoteGenerator,
PasswordGenerator,
WhyTypescript,
NetlifyCardGame,
TicTacToeGame,
Calendar,
FunQuiz,
//import play here
Expand Down Expand Up @@ -243,6 +244,20 @@ export const plays = [
language: 'js',
featured: true,
}, {
id: 'pl-tic-tac-toe-game',
name: 'Tic Tac Toe Game',
description: 'This game is coded in ReactJS and VanillaCSS',
component: () => {return <TicTacToeGame />},
path: '/plays/tic-tac-toe-game',
level: 'Beginner',
tags: 'Hooks,JSX,Functions,ResetState,CSS',
github: 'tejinder-sharma',
cover: '',
blog: '',
video: '',
language: 'js',
},
{
id: 'pl-calendar',
name: 'Calendar',
description: 'Simple calendar app to manage events',
Expand Down
4 changes: 4 additions & 0 deletions src/plays/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export { default as AnalogClock } from 'plays/analog-clock/AnalogClock';
export { default as PasswordGenerator } from 'plays/password-generator/PasswordGenerator';
export { default as WhyTypescript } from 'plays/why-typescript/WhyTypescript';
export { default as NetlifyCardGame } from 'plays/memory-game/NetlifyCardGame';

export { default as TicTacToeGame } from 'plays/tic-tac-toe-game/TicTacToeGame';

export { default as Calendar } from 'plays/calendar/Calendar';
export { default as FunQuiz } from 'plays/fun-quiz/FunQuiz';

//add export here
17 changes: 17 additions & 0 deletions src/plays/tic-tac-toe-game/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Tic Tac Toe Game

It is a Tic Tac Toe Game to made with React.


## What will you learn?

- Functional Components
- Event handling for user interaction.
- Update of states.
- How to reuse the components.(e.g we reused our game square button many times).
- How to reset the states.


The file `TicTacToeGAme` is the main file along with the css.

If you want to implement your learnings about states and useEffect hooks try implementing it on your own!
32 changes: 32 additions & 0 deletions src/plays/tic-tac-toe-game/TicTacToeGame.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getPlayById } from 'meta/play-meta-util';

import PlayHeader from 'common/playlists/PlayHeader';

import React from "react";

import Game from "./components/Game.jsx"

import "./styles/tic-tac-toe-tj.css";

function TicTacToeGame(props) {
// Do not remove the below lines.
// The following code is to fetch the current play from the URL
const { id } = props;
const play = getPlayById(id);

// Your Code Start below.
return (
<>
<div className="play-details">
<PlayHeader play={play} />
<div className="play-details-body tic-tac-toe-tj">
{/* Your Code Starts Here */}
<Game />
{/* Your Code Ends Here */}
</div>
</div>
</>
);
}

export default TicTacToeGame;
120 changes: 120 additions & 0 deletions src/plays/tic-tac-toe-game/components/Game.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React, { useState } from "react";

function Square(props) {
return (
<button className={`squareButton ${props.winningSquare?.includes(props.index) && "bg-yellow-500"}`} onClick={props.onClick}>
{props.value}
</button>
);
}
function Restart({ onClick }) {
return (
<button className="jumpButton" onClick={onClick}>
Play again
</button>
);
}

function Game() {
const [squares, setSquares] = useState(Array(9).fill(null));
const [isXNext, setIsXNext] = useState(true);

const nextSymbol = isXNext ? "X" : "O";

const winner = calculateWinner(squares);


function renderSquare(i) {
return (
<Square
key={i}
index={i}
winningSquare={winner ? winner.line : null}
value={squares[i]}
onClick={() => {
const nextSquares = squares.slice();
if (squares[i] != null || winner != null) {
return;
}
nextSquares[i] = nextSymbol;
setSquares(nextSquares);
setIsXNext(!isXNext);
}}
/>
);
}
function getStatus() {
if (winner) {
return `Winner: ${winner.player}`;
} else if (isBoardFull(squares)) {
return "Draw!";
} else {
return `Next player: ${nextSymbol}`;
}
}
function renderRestartButton() {
return (
<Restart
onClick={() => {
setSquares(Array(9).fill(null));
setIsXNext(true);
}}
/>
);
}
function renderSquares(n) {
let squares = [];
for (let i = n; i < n + 3; i++) {
squares.push(renderSquare(i));
}
return squares;
}

function renderRow(i) {
return <div className="row ">{renderSquares(i)}</div>;
}

return (
<div className="container">
<header className="header">Tic Tac Toe Game</header>
<div className="boardMain">
{renderRow(0)}
{renderRow(3)}
{renderRow(6)}
</div>
<div className="status">{getStatus()}</div>
<div>{renderRestartButton()}</div>
</div>
);
}

function calculateWinner(squares) {
const possibleLines = [
[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 i = 0; i < possibleLines.length; i++) {
const [a, b, c] = possibleLines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return {player:squares[a], line:[a, b, c]};
}
}
return null;
}

function isBoardFull(squares) {
for (let i = 0; i < squares.length; i++) {
if (squares[i] == null) {
return false;
}
}
return true;
}

export default Game;
Binary file added src/plays/tic-tac-toe-game/cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions src/plays/tic-tac-toe-game/styles/tic-tac-toe-tj.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.tic-tac-toe-tj .container{
text-align: center;
}


.tic-tac-toe-tj .squareButton{
width: 5rem;
height: 5rem;
margin: 1px;
background-color: #EC4899;

display: inline-flex;
justify-content: center;
align-items: center;

border: none;
font: bold;
font-size: 32px;
color: white;
}
.tic-tac-toe-tj .squareButton:hover{
background-color: #10B981;
}
.tic-tac-toe-tj .row{
display: flex;
}
.tic-tac-toe-tj .jumpButton{
padding: 0.5rem 1rem;
background-color: #10B981;

display: inline-flex;
justify-content: center;
align-items: center;

border: none;
color: white;
font-size: 18px;
border-radius: 4px;
margin-top: 1rem;
}
.tic-tac-toe-tj .bg-yellow-500{
background-color: #f59e0b;
}
.tic-tac-toe-tj .jumpButton:hover{
background-color: #EC4899;
}
.tic-tac-toe-tj .list{
margin-top: 1rem;
}
.tic-tac-toe-tj .status{
margin-top: 1rem;
font-size: 24px;
}
.tic-tac-toe-tj .header{
width: 100%;
padding: 16px 8px;
color: white;
font-size: 24px;

display: grid;
place-content: center;

background-color: #010326;
margin-bottom: 2rem;
}

.tic-tac-toe-tj .boardMain{
display: grid;
place-content: center;
}