Skip to content

Commit

Permalink
TicTacToe project finished (desktop).
Browse files Browse the repository at this point in the history
  • Loading branch information
carla-ng committed Jul 1, 2024
1 parent f70faaf commit aa29d33
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export const WINNING_COMBINATIONS = [
[
{ row: 0, column: 0 },
{ row: 0, column: 1 },
{ row: 0, column: 2 },
],
[
{ row: 1, column: 0 },
{ row: 1, column: 1 },
{ row: 1, column: 2 },
],
[
{ row: 2, column: 0 },
{ row: 2, column: 1 },
{ row: 2, column: 2 },
],
[
{ row: 0, column: 0 },
{ row: 1, column: 0 },
{ row: 2, column: 0 },
],
[
{ row: 0, column: 1 },
{ row: 1, column: 1 },
{ row: 2, column: 1 },
],
[
{ row: 0, column: 2 },
{ row: 1, column: 2 },
{ row: 2, column: 2 },
],
[
{ row: 0, column: 0 },
{ row: 1, column: 1 },
{ row: 2, column: 2 },
],
[
{ row: 0, column: 2 },
{ row: 1, column: 1 },
{ row: 2, column: 0 },
],
];
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { useState } from 'react';

const initialBoard = [
[null, null, null],
[null, null, null],
[null, null, null],
]

const TicTacToeBoard = function({ onSelectSquare, activePlayerSymbol }) {
const TicTacToeBoard = function({ onSelectSquare, board }) {
/*
const [board, setBoard] = useState(initialBoard)
const handleSelectSquare = function(rowIndex, colIndex) {
Expand All @@ -18,12 +12,13 @@ const TicTacToeBoard = function({ onSelectSquare, activePlayerSymbol }) {
onSelectSquare()
}
*/

return <ol id="game-board">
{ board.map((row, rowIndex) => <li key={rowIndex}>
<ol>
{ row.map((playerSymbol, colIndex) => <li key={colIndex}>
<button onClick={() => handleSelectSquare(rowIndex, colIndex)}>{ playerSymbol }</button>
<button onClick={() => onSelectSquare(rowIndex, colIndex)} disabled={playerSymbol !== null}>{ playerSymbol }</button>
</li> )}
</ol>
</li> )}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const TicTacToeGameOver = function({ winner, onRestart }) {
return <div id="game-over">
<h2>Game Over!</h2>
{ winner && <p>{winner} won!</p> }
{ !winner && <p>It&apos;s a draw!</p> }
<p>
<button onClick={onRestart}>Rematch!</button>
</p>
</div>
}

export default TicTacToeGameOver
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const TicTacToeLog = function({ turns }) {
return <ol id="log">
{ turns.map(turn =>
<li key={`${turn.square.row}${turn.square.col}`}>{turn.player} selected {turn.square.row}, {turn.square.col}</li>
)}
</ol>
}

export default TicTacToeLog
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useState } from "react"

const TicTacToePlayer = function({ initialName, symbol, isActive }) {
const TicTacToePlayer = function({ initialName, symbol, isActive, onChangeName }) {
const [isEditing, setIsEditing] = useState(false)
const [playerName, setPlayerName] = useState(initialName)

const handleEditing = function() {
setIsEditing(editing => !editing)

if ( isEditing ) {
onChangeName(symbol, playerName)
}
}

const handleChange = function( event ) {
Expand Down
6 changes: 3 additions & 3 deletions react-practice/main-project/src/TicTacToe/css/TicTacToe.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
),
url('../assets/images/bg-pattern-dark.png');
background-repeat: repeat;
background-size: 100% 100%, 30% 30%, 100% 100%;
background-size: auto;
min-height: 100vh;

header {
Expand Down Expand Up @@ -248,8 +248,8 @@
max-width: 20rem;
color: #3f3b00;
list-style: none;
margin: 2rem auto;
padding: 0;
margin: 0 auto;
padding: 0.5rem 0 2rem 0;
text-align: center;
}

Expand Down
116 changes: 110 additions & 6 deletions react-practice/main-project/src/TicTacToe/pages/TicTacToePage.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,105 @@
import { useState } from 'react';

import '../css/TicTacToe.css'
import { WINNING_COMBINATIONS } from '../assets/data/winning-combinations.js'
import GameLogo from '../assets/images/game-logo.png'

import TicTacToeBoard from '../components/TicTacToeBoard'
import TicTacToeGameOver from '../components/TicTacToeGameOver'
import TicTacToeLog from '../components/TicTacToeLog'
import TicTacToePlayer from "../components/TicTacToePlayer"


const PLAYERS = {
X : 'Player 1',
O : 'Player 2',
}

const INITIAL_BOARD = [
[null, null, null],
[null, null, null],
[null, null, null],
]


const deriveActivePlayer = function( gameTurns ) {
let currentPlayer = 'X'

if ( gameTurns.length > 0 && gameTurns[0].player === 'X' ) {
currentPlayer = 'O'
}

return currentPlayer
}


const deriveBoard = function( gameTurns ) {
let board = [...INITIAL_BOARD.map(array => [...array])]

for ( const turn of gameTurns ) {
const { square, player } = turn
const { row, col } = square

board[row][col] = player
}

return board
}


const deriveWinner = function( board, players ) {
let winner

for ( const combination of WINNING_COMBINATIONS ) {
const firstSquareSymbol = board[combination[0].row][combination[0].column]
const secondSquareSymbol = board[combination[1].row][combination[1].column]
const thirdSquareSymbol = board[combination[2].row][combination[2].column]

if ( firstSquareSymbol &&
firstSquareSymbol == secondSquareSymbol &&
firstSquareSymbol == thirdSquareSymbol
) {
winner = players[firstSquareSymbol]
}
}

return winner
}


const TicTacToePage = function() {
const [activePlayer, setActivePlayer] = useState('X')
const [players, setPlayers] = useState(PLAYERS)
const [gameTurns, setGameTurns] = useState([])

const handleSelectSquare = function() {
setActivePlayer(prevActivePlayer => prevActivePlayer === 'X' ? 'O' : 'X')
const activePlayer = deriveActivePlayer(gameTurns)
const board = deriveBoard(gameTurns)
const winner = deriveWinner(board, players)
const itsADraw = gameTurns.length === 9 && !winner

const handleSelectSquare = function( rowIndex, colIndex ) {
setGameTurns(prevTurns => {
const currentPlayer = deriveActivePlayer(prevTurns)

const updatedTurns = [
{ square: { row: rowIndex, col: colIndex }, player: currentPlayer },
...prevTurns
]

return updatedTurns
})
}

const handleRestart = function() {
setGameTurns([])
}

const handlePlayerNameChange = function( symbol, newName ) {
setPlayers(prevPlayers => {
return {
...prevPlayers,
[symbol]: newName
}
})
}

return (
Expand All @@ -26,12 +114,28 @@ const TicTacToePage = function() {

<div id="game-container">
<ol id="players" className="highlight-player">
<TicTacToePlayer initialName="Player 1" symbol="X" isActive={ activePlayer === 'X' } />
<TicTacToePlayer initialName="Player 2" symbol="O" isActive={ activePlayer === 'O' } />
<TicTacToePlayer
initialName={PLAYERS.X}
symbol="X"
isActive={ activePlayer === 'X' }
onChangeName={handlePlayerNameChange}
/>
<TicTacToePlayer
initialName={PLAYERS.O}
symbol="O"
isActive={ activePlayer === 'O' }
onChangeName={handlePlayerNameChange}
/>
</ol>

<TicTacToeBoard onSelectSquare={handleSelectSquare} activePlayerSymbol={activePlayer} />
{ ( winner || itsADraw ) && <TicTacToeGameOver winner={winner} onRestart={handleRestart} /> }
<TicTacToeBoard
onSelectSquare={handleSelectSquare}
board={board}
/>
</div>

<TicTacToeLog turns={gameTurns} />
</div>
</>
)
Expand Down

0 comments on commit aa29d33

Please sign in to comment.