diff --git a/src/components/Grid/Grid.tsx b/src/components/Grid/Grid.tsx index 1c84c2c..824c97d 100644 --- a/src/components/Grid/Grid.tsx +++ b/src/components/Grid/Grid.tsx @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------------------------------------------------- // ------------------------------------------------------ React -------------------------------------------------------- -import { MouseEvent, useCallback, useState } from 'react'; +import { useState } from 'react'; // --------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------- Context ------------------------------------------------------- @@ -11,96 +11,24 @@ import { useRecoilState } from 'recoil'; import { gameStateAtom } from '../../contexts/gameState'; // --------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------------ Hooks -------------------------------------------------------- +import { useActions } from './hooks/useActions'; +// --------------------------------------------------------------------------------------------------------------------- + // ------------------------------------------------------ Utils -------------------------------------------------------- -import { Difficulty } from '../../types/game'; -import { discoverAroundCell, genGrid, revealAllGrid, startGame } from '../../utils/game'; +import { genGrid, getCellContent } from '../../utils/game'; // --------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------- Assets -------------------------------------------------------- -import Bomb from '../../assets/bomb.png'; -import Flag from '../../assets/flag.png'; -import './styles.scss'; import Podium from '../../assets/podium'; +import './styles.scss'; // --------------------------------------------------------------------------------------------------------------------- const Grid = () => { const [gameState, setGameState] = useRecoilState(gameStateAtom); - const [grid, setGrid] = useState(genGrid(gameState.gridSize)); - const [, updateGrid] = useState({}); - const forceUpdate = useCallback(() => updateGrid({}), []); - - // ----------------------------------------------------- Actions ------------------------------------------------------- - const handleLeftClick = (ev: MouseEvent, rowIndex: number, colIndex: number) => { - ev.preventDefault(); - - if (grid[rowIndex][colIndex].hidden && !grid[rowIndex][colIndex].flag) { - setGrid((prev) => { - if (gameState.status === 'idle') { - const { grid: newGrid, bombsCount } = startGame(prev, gameState.difficulty as Difficulty, true, rowIndex, colIndex); - prev = newGrid; - - setGameState((prevGameState) => ({ - ...prevGameState, - status: 'playing', - bombs: bombsCount, - })); - } - - if (prev[rowIndex][colIndex].value === 'bomb') { - setGameState((prev) => ({ - ...prev, - endType: 'loose', - })); - return revealAllGrid(grid, true); - } - - return discoverAroundCell(prev, rowIndex, colIndex); - }); - forceUpdate(); - } - }; - - const handleRightClick = (ev: MouseEvent, rowIndex: number, colIndex: number) => { - ev.preventDefault(); - - if (grid[rowIndex][colIndex].hidden) { - setGrid((prev) => { - if (gameState.status === 'idle') { - const { grid: newGrid, bombsCount } = startGame(prev, gameState.difficulty as Difficulty, false); - prev = newGrid; - - setGameState((prevGameState) => ({ - ...prevGameState, - status: 'playing', - bombs: bombsCount, - })); - } - - return prev.map((row, idx) => { - if (idx === rowIndex) { - return row.map((col, idy) => { - if (idy === colIndex) { - setGameState((prevGameState) => ({ - ...prevGameState, - placedFlags: col.flag ? prevGameState.placedFlags - 1 : prevGameState.placedFlags + 1, - })); - - return { - ...col, - flag: !col.flag, - }; - } - return col; - }); - } - return row; - }); - }); - } - }; - // --------------------------------------------------------------------------------------------------------------------- + const { handleLeftClick, handleRightClick } = useActions(grid, setGrid, gameState, setGameState); return (
{ onClick={(ev) => handleLeftClick(ev, rowIndex, cellIndex)} onContextMenu={(ev) => handleRightClick(ev, rowIndex, cellIndex)} > - {cell.hidden && cell.flag && ( - flat - )} - {!cell.hidden && - (cell.value === 'bomb' ? ( - bomb - ) : cell.value !== 'empty' ? ( - cell.value - ) : ( - '' - ))} + {getCellContent(cell)} ); })} diff --git a/src/components/Grid/hooks/useActions.ts b/src/components/Grid/hooks/useActions.ts new file mode 100644 index 0000000..cd97f21 --- /dev/null +++ b/src/components/Grid/hooks/useActions.ts @@ -0,0 +1,88 @@ +// --------------------------------------------------------------------------------------------------------------------- +//! Imports +// --------------------------------------------------------------------------------------------------------------------- + +import { MouseEvent, useCallback, useState } from 'react'; +import { Difficulty, GridType } from '../../../types/game'; +import { discoverAroundCell, revealAllGrid, startGame } from '../../../utils/game'; +import { GameState } from '../../../types/gameState'; +import { SetterOrUpdater } from 'recoil'; + +export const useActions = (grid: GridType, setGrid: React.Dispatch>, gameState: GameState, setGameState: SetterOrUpdater) => { + const [, updateGrid] = useState({}); + const forceUpdate = useCallback(() => updateGrid({}), []); + + const handleLeftClick = (ev: MouseEvent, rowIndex: number, colIndex: number) => { + ev.preventDefault(); + + if (grid[rowIndex][colIndex].hidden && !grid[rowIndex][colIndex].flag) { + setGrid((prev) => { + if (gameState.status === 'idle') { + const { grid: newGrid, bombsCount } = startGame(prev, gameState.difficulty as Difficulty, true, rowIndex, colIndex); + prev = newGrid; + + setGameState((prevGameState) => ({ + ...prevGameState, + status: 'playing', + bombs: bombsCount, + })); + } + + if (prev[rowIndex][colIndex].value === 'bomb') { + setGameState((prev) => ({ + ...prev, + endType: 'loose', + })); + return revealAllGrid(grid, true); + } + + return discoverAroundCell(prev, rowIndex, colIndex); + }); + forceUpdate(); + } + }; + + const handleRightClick = (ev: MouseEvent, rowIndex: number, colIndex: number) => { + ev.preventDefault(); + + if (grid[rowIndex][colIndex].hidden) { + setGrid((prev) => { + if (gameState.status === 'idle') { + const { grid: newGrid, bombsCount } = startGame(prev, gameState.difficulty as Difficulty, false); + prev = newGrid; + + setGameState((prevGameState) => ({ + ...prevGameState, + status: 'playing', + bombs: bombsCount, + })); + } + + return prev.map((row, idx) => { + if (idx === rowIndex) { + return row.map((col, idy) => { + if (idy === colIndex) { + setGameState((prevGameState) => ({ + ...prevGameState, + placedFlags: col.flag ? prevGameState.placedFlags - 1 : prevGameState.placedFlags + 1, + })); + + return { + ...col, + flag: !col.flag, + }; + } + return col; + }); + } + return row; + }); + }); + } + }; + + return { + handleLeftClick, + handleRightClick, + }; +}; diff --git a/src/types/gameState.d.ts b/src/types/gameState.d.ts new file mode 100644 index 0000000..bdf34b3 --- /dev/null +++ b/src/types/gameState.d.ts @@ -0,0 +1,9 @@ +export type GameState = { + status: string; + difficulty: string; + gridSize: number; + bombs: number; + placedFlags: number; + gameTime: string; + endType: string; +}; diff --git a/src/utils/game.ts b/src/utils/game.tsx similarity index 91% rename from src/utils/game.ts rename to src/utils/game.tsx index be5d260..3dbd35e 100644 --- a/src/utils/game.ts +++ b/src/utils/game.tsx @@ -1,5 +1,7 @@ import { Difficulty, CellValue, GridType } from '../types/game'; import { getRandomArbitrary } from './generics'; +import Bomb from '../assets/bomb.png'; +import Flag from '../assets/flag.png'; export const genGrid = (size: number): GridType => { let grid: GridType = Array.apply(null, Array(size)).map(() => { @@ -175,3 +177,28 @@ export const startGame = (grid: GridType, difficulty: Difficulty, needEmpty: boo return { grid, bombsCount }; }; + +export const getCellContent = (cell: { hidden: boolean; flag: boolean; value: CellValue }) => { + if (cell.hidden && cell.flag) { + return ( + flag + ); + } + + if (!cell.hidden) { + if (cell.value === 'bomb') { + return ( + bomb + ); + } + if (cell.value !== 'empty') { + return cell.value; + } + } +};