Created Hook separated file

This commit is contained in:
2024-02-18 17:15:10 +01:00
parent 65a66a9f35
commit 7413a5f6a1
4 changed files with 133 additions and 97 deletions
+9 -97
View File
@@ -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 (
<div
@@ -125,23 +53,7 @@ const Grid = () => {
onClick={(ev) => handleLeftClick(ev, rowIndex, cellIndex)}
onContextMenu={(ev) => handleRightClick(ev, rowIndex, cellIndex)}
>
{cell.hidden && cell.flag && (
<img
src={Flag}
alt='flat'
/>
)}
{!cell.hidden &&
(cell.value === 'bomb' ? (
<img
src={Bomb}
alt='bomb'
/>
) : cell.value !== 'empty' ? (
cell.value
) : (
''
))}
{getCellContent(cell)}
</button>
);
})}
+88
View File
@@ -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<React.SetStateAction<GridType>>, gameState: GameState, setGameState: SetterOrUpdater<GameState>) => {
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,
};
};
+9
View File
@@ -0,0 +1,9 @@
export type GameState = {
status: string;
difficulty: string;
gridSize: number;
bombs: number;
placedFlags: number;
gameTime: string;
endType: string;
};
+27
View File
@@ -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 (
<img
src={Flag}
alt='flag'
/>
);
}
if (!cell.hidden) {
if (cell.value === 'bomb') {
return (
<img
src={Bomb}
alt='bomb'
/>
);
}
if (cell.value !== 'empty') {
return cell.value;
}
}
};