✨ Created Hook separated file
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// ------------------------------------------------------ React --------------------------------------------------------
|
// ------------------------------------------------------ React --------------------------------------------------------
|
||||||
import { MouseEvent, useCallback, useState } from 'react';
|
import { useState } from 'react';
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// ----------------------------------------------------- Context -------------------------------------------------------
|
// ----------------------------------------------------- Context -------------------------------------------------------
|
||||||
@@ -11,96 +11,24 @@ import { useRecoilState } from 'recoil';
|
|||||||
import { gameStateAtom } from '../../contexts/gameState';
|
import { gameStateAtom } from '../../contexts/gameState';
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ------------------------------------------------------ Hooks --------------------------------------------------------
|
||||||
|
import { useActions } from './hooks/useActions';
|
||||||
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// ------------------------------------------------------ Utils --------------------------------------------------------
|
// ------------------------------------------------------ Utils --------------------------------------------------------
|
||||||
import { Difficulty } from '../../types/game';
|
import { genGrid, getCellContent } from '../../utils/game';
|
||||||
import { discoverAroundCell, genGrid, revealAllGrid, startGame } from '../../utils/game';
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// ----------------------------------------------------- Assets --------------------------------------------------------
|
// ----------------------------------------------------- Assets --------------------------------------------------------
|
||||||
import Bomb from '../../assets/bomb.png';
|
|
||||||
import Flag from '../../assets/flag.png';
|
|
||||||
import './styles.scss';
|
|
||||||
import Podium from '../../assets/podium';
|
import Podium from '../../assets/podium';
|
||||||
|
import './styles.scss';
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
const Grid = () => {
|
const Grid = () => {
|
||||||
const [gameState, setGameState] = useRecoilState(gameStateAtom);
|
const [gameState, setGameState] = useRecoilState(gameStateAtom);
|
||||||
|
|
||||||
const [grid, setGrid] = useState(genGrid(gameState.gridSize));
|
const [grid, setGrid] = useState(genGrid(gameState.gridSize));
|
||||||
|
|
||||||
const [, updateGrid] = useState({});
|
const { handleLeftClick, handleRightClick } = useActions(grid, setGrid, gameState, setGameState);
|
||||||
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;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -125,23 +53,7 @@ const Grid = () => {
|
|||||||
onClick={(ev) => handleLeftClick(ev, rowIndex, cellIndex)}
|
onClick={(ev) => handleLeftClick(ev, rowIndex, cellIndex)}
|
||||||
onContextMenu={(ev) => handleRightClick(ev, rowIndex, cellIndex)}
|
onContextMenu={(ev) => handleRightClick(ev, rowIndex, cellIndex)}
|
||||||
>
|
>
|
||||||
{cell.hidden && cell.flag && (
|
{getCellContent(cell)}
|
||||||
<img
|
|
||||||
src={Flag}
|
|
||||||
alt='flat'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!cell.hidden &&
|
|
||||||
(cell.value === 'bomb' ? (
|
|
||||||
<img
|
|
||||||
src={Bomb}
|
|
||||||
alt='bomb'
|
|
||||||
/>
|
|
||||||
) : cell.value !== 'empty' ? (
|
|
||||||
cell.value
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
))}
|
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
};
|
||||||
|
};
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
export type GameState = {
|
||||||
|
status: string;
|
||||||
|
difficulty: string;
|
||||||
|
gridSize: number;
|
||||||
|
bombs: number;
|
||||||
|
placedFlags: number;
|
||||||
|
gameTime: string;
|
||||||
|
endType: string;
|
||||||
|
};
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import { Difficulty, CellValue, GridType } from '../types/game';
|
import { Difficulty, CellValue, GridType } from '../types/game';
|
||||||
import { getRandomArbitrary } from './generics';
|
import { getRandomArbitrary } from './generics';
|
||||||
|
import Bomb from '../assets/bomb.png';
|
||||||
|
import Flag from '../assets/flag.png';
|
||||||
|
|
||||||
export const genGrid = (size: number): GridType => {
|
export const genGrid = (size: number): GridType => {
|
||||||
let grid: GridType = Array.apply(null, Array(size)).map(() => {
|
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 };
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user