✨ (game): Added Bombs & Flags count
Added placed flags by bombs count. Fix timer startng only when first click is triggered
This commit is contained in:
@@ -3,12 +3,17 @@
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------ React --------------------------------------------------------
|
||||
import { MouseEvent, useCallback, useEffect, useState } from 'react';
|
||||
import { MouseEvent, useCallback, useState } from 'react';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------- Context -------------------------------------------------------
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { gameStateAtom } from '../../contexts/gameState';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------ Utils --------------------------------------------------------
|
||||
import { Difficulty } from '../../types/game';
|
||||
import { discoverAroundCell, genBombs, genGrid, genNumbers } from '../../utils/game';
|
||||
import { discoverAroundCell, genGrid, startGame } from '../../utils/game';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------- Assets --------------------------------------------------------
|
||||
@@ -18,8 +23,9 @@ import './styles.scss';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Grid = ({ size = 12, difficulty = 'beginner' }) => {
|
||||
const [gameState, setGameState] = useRecoilState(gameStateAtom);
|
||||
|
||||
const [grid, setGrid] = useState(genGrid(size));
|
||||
const [gameStatus, setGameStatus] = useState('idle');
|
||||
|
||||
const [, updateGrid] = useState({});
|
||||
const forceUpdate = useCallback(() => updateGrid({}), []);
|
||||
@@ -30,11 +36,15 @@ const Grid = ({ size = 12, difficulty = 'beginner' }) => {
|
||||
|
||||
if (grid[rowIndex][colIndex].hidden && !grid[rowIndex][colIndex].flag) {
|
||||
setGrid((prev) => {
|
||||
if (gameStatus === 'idle') {
|
||||
do {
|
||||
prev = genNumbers(genBombs(prev, difficulty as Difficulty));
|
||||
} while (prev[rowIndex][colIndex].value !== 'empty');
|
||||
setGameStatus('started');
|
||||
if (gameState.status === 'idle') {
|
||||
const { grid: newGrid, bombsCount } = startGame(prev, difficulty as Difficulty, true, rowIndex, colIndex);
|
||||
prev = newGrid;
|
||||
|
||||
setGameState((prevGameState) => ({
|
||||
...prevGameState,
|
||||
status: 'playing',
|
||||
bombs: bombsCount,
|
||||
}));
|
||||
}
|
||||
|
||||
return discoverAroundCell(prev, rowIndex, colIndex);
|
||||
@@ -48,10 +58,26 @@ const Grid = ({ size = 12, difficulty = 'beginner' }) => {
|
||||
|
||||
if (grid[rowIndex][colIndex].hidden) {
|
||||
setGrid((prev) => {
|
||||
if (gameState.status === 'idle') {
|
||||
const { grid: newGrid, bombsCount } = startGame(prev, 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,
|
||||
@@ -65,21 +91,6 @@ const Grid = ({ size = 12, difficulty = 'beginner' }) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// --- Development
|
||||
useEffect(() => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
document.addEventListener('keyup', (ev) => {
|
||||
if (ev.key === 'v') {
|
||||
setGrid(() => {
|
||||
let newGrid = genGrid(size);
|
||||
|
||||
return genNumbers(genBombs(newGrid, difficulty as Difficulty));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [size, difficulty]);
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
//! Imports
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------- Recoil --------------------------------------------------------
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { gameStateAtom } from '../../../contexts/gameState';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------- Assets --------------------------------------------------------
|
||||
import Flag from '../../../assets/flag';
|
||||
import '../styles.scss';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const MinesCounter = () => {
|
||||
const [{ bombs, placedFlags }] = useRecoilState(gameStateAtom);
|
||||
|
||||
return (
|
||||
<div className='statContainer'>
|
||||
<Flag />
|
||||
<p>
|
||||
{placedFlags} / {bombs}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MinesCounter;
|
||||
@@ -7,32 +7,46 @@ import { useEffect, useState } from 'react';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------- Assets --------------------------------------------------------
|
||||
import Clock from '../../assets/clock';
|
||||
import './styles.scss';
|
||||
import Clock from '../../../assets/clock';
|
||||
import '../styles.scss';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { gameStateAtom } from '../../../contexts/gameState';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Timer = () => {
|
||||
const [startedTime] = useState<number>(Date.now());
|
||||
const [{ status }] = useRecoilState(gameStateAtom);
|
||||
|
||||
const [startedTime, setStartedTime] = useState<number | null>(null);
|
||||
const [displayedTime, setDisplayedTime] = useState<string>('00:00');
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
const elapsedTime = (Date.now() - startedTime) / 1000;
|
||||
if (status === 'playing') {
|
||||
setStartedTime(Date.now());
|
||||
} else if (status === 'win' || status === 'loose') {
|
||||
setStartedTime(null);
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
const seconds = Math.floor(elapsedTime % 60);
|
||||
const strSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
||||
useEffect(() => {
|
||||
if (startedTime) {
|
||||
const interval = setInterval(() => {
|
||||
const elapsedTime = (Date.now() - startedTime) / 1000;
|
||||
|
||||
const minutes = Math.floor(elapsedTime / 60);
|
||||
const strMinute = minutes < 10 ? `0${minutes}` : `${minutes}`;
|
||||
const seconds = Math.floor(elapsedTime % 60);
|
||||
const strSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
||||
|
||||
setDisplayedTime(`${strMinute}:${strSeconds}`);
|
||||
}, 500);
|
||||
const minutes = Math.floor(elapsedTime / 60);
|
||||
const strMinute = minutes < 10 ? `0${minutes}` : `${minutes}`;
|
||||
|
||||
return () => clearInterval(interval);
|
||||
setDisplayedTime(`${strMinute}:${strSeconds}`);
|
||||
}, 500);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [startedTime]);
|
||||
|
||||
return (
|
||||
<div className='timer'>
|
||||
<div className='statContainer'>
|
||||
<Clock />
|
||||
<p>{displayedTime}</p>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
.timer {
|
||||
.statContainer {
|
||||
display: grid;
|
||||
grid-template-columns: 25px 40px;
|
||||
align-items: center;
|
||||
Reference in New Issue
Block a user