diff --git a/src/App.css b/src/App.css index 74b5e05..52df60a 100644 --- a/src/App.css +++ b/src/App.css @@ -24,6 +24,16 @@ color: white; } +.App-body { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: white; +} + .App-link { color: #61dafb; } diff --git a/src/App.tsx b/src/App.tsx index a53698a..0a4760b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,26 +1,16 @@ import React from 'react'; -import logo from './logo.svg'; import './App.css'; +import TicTacToe from './TicTacToe/Root'; + function App() { - return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
-
- ); + return ( +
+
+ +
+
+ ); } export default App; diff --git a/src/TicTacToe/Root.tsx b/src/TicTacToe/Root.tsx new file mode 100644 index 0000000..d565e6e --- /dev/null +++ b/src/TicTacToe/Root.tsx @@ -0,0 +1,159 @@ +import React from 'react'; +import { useState } from 'react'; +import './style.css'; + +function TicTacToe() { + const [gridState, setGridState] = useState(Array(9).fill(0)); + const [playerState, setPlayerState] = useState(false); + const [winState, setWinState] = useState(0); + let localWinState = winState; + + function updateGridState(index : number, state : number) { + gridState[index] = state; + setGridState(gridState); + } + + function playTurn(index : number) { + if (gridState[index]) return; + if (winState) return; + + const newState = playerState ? 2 : 1; + updateGridState(index, newState); + + const winner = checkWinCondition() + if (winner) { + localWinState = winner; + setWinState(winner); + return; + } + + setPlayerState(!playerState); + } + + function checkWinCondition() : number { + + function getWinningValue( + a : number, + b : number, + c : number + ) { + if ((a === b) && (b === c) && (a === c)) { + return a; + } + return 0 + } + /* + * Diagonals + */ + { + const a = gridState[3 * 0 + 0]; + const b = gridState[3 * 1 + 1]; + const c = gridState[3 * 2 + 2]; + const winner = getWinningValue(a, b, c); + if (winner) return winner; + } + { + const a = gridState[3 * 0 + 2]; + const b = gridState[3 * 1 + 1]; + const c = gridState[3 * 2 + 0]; + const winner = getWinningValue(a, b, c); + if (winner) return winner; + } + /* + * Rows and Columns + */ + for (let row = 0; row < 3; row++) { + const a = gridState[3 * row + 0]; + const b = gridState[3 * row + 1]; + const c = gridState[3 * row + 2]; + const winner = getWinningValue(a, b, c); + if (winner) return winner; + } + + for (let column = 0; column < 3; column++) { + const a = gridState[3 * 0 + column]; + const b = gridState[3 * 1 + column]; + const c = gridState[3 * 2 + column]; + const winner = getWinningValue(a, b, c); + if (winner) return winner; + } + + const isDrawState = () => { + for (let i in gridState) { + if (!gridState[i]) return false; + }; + return true; + } + if (isDrawState()) return 3; + + return 0; + } + + let stateString = ""; + if (localWinState === 3) { + stateString = `Game draw.` + } + else if (localWinState) { + stateString = `Player ${getStateChar(localWinState)} wins.`; + } + else { + stateString = `Player ${getStateChar(playerState ? 2 : 1)} turn.` + } + + return ( +
+

{stateString}

+
+ { + gridState.map((item, index) => { + const getState = () => { return gridState[index] }; + const callback = () => { playTurn(index) }; + return (); + }) + } +
+
+ ); +} + +interface CellProps { + getState: () => number; + callback: () => void; +} + +function TicTacToeCell({ getState, callback }: CellProps) { + + function handleClick() { + callback() + } + + return ( +
+

{getStateChar(getState())}

+
+ ); +} + +function getStateChar(state : number) { + switch (state) { + case 1: + return "O"; + case 2: + return "X"; + default: + return ""; + } +} + +function getStateClass(state : number) { + switch (state) { + case 1: + return "CellRed"; + case 2: + return "CellBlue"; + default: + return ""; + } +} + +export default TicTacToe; diff --git a/src/TicTacToe/style.css b/src/TicTacToe/style.css new file mode 100644 index 0000000..12841da --- /dev/null +++ b/src/TicTacToe/style.css @@ -0,0 +1,40 @@ +.TicTacToe { + background-color: #3B3E49; + color: #B9B8D6; +} + +.TicTacToeGrid { + display: grid; + width: 50vh; + height: 50vh; + grid-template-columns: auto auto auto; +} + +.TicTacToeCell { + min-width: 33.33%; + min-height: 33.33%; + background-color: #4d4f5d; + text-align: center; + position: relative; +} + +.TicTacToeCell:hover { + opacity: 0.9; +} + +.TicTacToeCell > p { + margin: 0; + padding: 0; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} + +.CellRed { + color: #D6B8B8; +} + +.CellBlue { + color: #B8C7D6; +}