2026-04-10 21:53:50 +02:00
|
|
|
/**
|
|
|
|
|
* This file is part of the SplendidBear Websites' projects.
|
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 2026 @ www.splendidbear.org
|
|
|
|
|
*
|
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-04-10 17:57:26 +02:00
|
|
|
import React from 'react';
|
2026-04-10 21:53:50 +02:00
|
|
|
import { useGame } from '@mine-contexts';
|
2026-04-10 17:57:26 +02:00
|
|
|
import GridField from './GridField';
|
|
|
|
|
import UserControl from '../user/UserControl';
|
2026-04-10 21:53:50 +02:00
|
|
|
import { BOMB_SYMBOLS, bombRadius } from '@mine-utils';
|
2026-04-10 17:57:26 +02:00
|
|
|
|
|
|
|
|
const GridControl = ({ onClick, resign }) => {
|
|
|
|
|
const {
|
|
|
|
|
overlay, overlayTitle, overlaySubTitle,
|
2026-04-10 19:09:05 +02:00
|
|
|
webPlayer, activePlayer, bombSelected,
|
|
|
|
|
cells, setCells,
|
2026-04-10 17:57:26 +02:00
|
|
|
} = useGame();
|
|
|
|
|
|
|
|
|
|
const handleHover = (row, col) => {
|
|
|
|
|
if (!bombSelected) return;
|
|
|
|
|
const activeColor = activePlayer ? 'blue' : 'red';
|
|
|
|
|
if (activeColor !== webPlayer) return;
|
|
|
|
|
|
|
|
|
|
setCells(prev => {
|
|
|
|
|
const next = prev.map(r => r.map(c =>
|
|
|
|
|
null !== c.bombTargetArea ? { ...c, bombTargetArea: null } : c,
|
|
|
|
|
));
|
|
|
|
|
bombRadius(row, col, prev.length, prev[0]?.length ?? 0).forEach(([r, c], i) => {
|
|
|
|
|
if (!next[r]?.[c]) return;
|
|
|
|
|
|
|
|
|
|
next[r] = [...next[r]];
|
|
|
|
|
next[r][c] = { ...next[r][c], bombTargetArea: BOMB_SYMBOLS[i] };
|
|
|
|
|
});
|
|
|
|
|
return next;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="game-wrapper">
|
|
|
|
|
<div className={`game-overlay${overlay ? '' : ' hide'}`}>
|
|
|
|
|
<div className="game-overlay-window">
|
|
|
|
|
<h1>{overlayTitle}</h1>
|
|
|
|
|
<h2>{overlaySubTitle}</h2>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<UserControl
|
|
|
|
|
resign={resign}
|
|
|
|
|
/>
|
|
|
|
|
<div className="grid-container">
|
|
|
|
|
<div className="grid">
|
|
|
|
|
{cells.flatMap((row, r) =>
|
|
|
|
|
row.map((cell, c) => (
|
|
|
|
|
<GridField
|
|
|
|
|
key={`${r}_${c}`}
|
|
|
|
|
cell={cell}
|
|
|
|
|
onClick={() => onClick([r, c])}
|
|
|
|
|
onMouseEnter={() => handleHover(r, c)}
|
|
|
|
|
/>
|
2026-04-10 19:09:05 +02:00
|
|
|
)),
|
2026-04-10 17:57:26 +02:00
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default GridControl;
|