diff --git a/README.md b/README.md index ef7968a..1a7eea9 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Versioning and Build - [x] Each cell is an object that stores pertinent information for that cell (ie. wasClicked, isBomb, adjacentBombCount...) - [x] One way to store these values to keep track of position is an adjacency matrix . - [x] One could also have a property pointing to adjacent cells directly on the cell object. -- [ ] Add the ability to change the difficulty (size of the board and quantity of mines). +- [x] Add the ability to change the difficulty (size of the board and quantity of mines). - [ ] Add a timer to the game. - [ ] View a list of recently played user times and difficulty setting. - [ ] Define a RESTful API that connects to a postgres database. diff --git a/src/App.css b/src/App.css index 642d8a2..5d56fec 100644 --- a/src/App.css +++ b/src/App.css @@ -8,45 +8,36 @@ margin-bottom: 10px; } -.game-result { - color: red; +.game-difficulty { + text-align: center; + margin-bottom: 10px; + display: grid; + grid: 1fr 1fr 1fr / 1fr auto 1fr; } -/* .App { - text-align: center; +.game-difficulty span { + grid-column: 1 / 2; + text-align: end; } -.App-logo { - height: 40vmin; - pointer-events: none; +.game-difficulty input { + grid-column: 2 / 3; + max-width: 50px; + margin: auto 10px; } -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } +.game-difficulty .columns { + grid-row: 1 / 2; } -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; +.game-difficulty .rows { + grid-row: 2 / 3; } -.App-link { - color: #61dafb; +.game-difficulty button { + grid-area: 1/3/4/4; } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} */ +.game-result { + color: red; +} diff --git a/src/App.tsx b/src/App.tsx index b2fee03..b4ca8b4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,6 +14,10 @@ export interface BoardContextInterface { setAttributeCount: Dispatch>; gameResult: GameResult; setGameResult: Dispatch>; + rows: number; + cols: number; + mines: number; + setCurrentMines: Dispatch>; } export const BoardContext = createContext( undefined, @@ -30,13 +34,25 @@ const App: React.FC = () => { const [gameResult, setGameResult] = useState(''); - const global = { - rows: 20, - cols: 30, - mines: 10, + const [rows, setRows] = useState(10); + const [cols, setCols] = useState(10); + const [mines, setMines] = useState(10); + const [currentMines, setCurrentMines] = useState(10); + + const handleColumnsChange = (e: React.ChangeEvent) => { + setCols(parseInt(e.target.value)); + }; + + const handleRowsChange = (e: React.ChangeEvent) => { + setRows(parseInt(e.target.value)); + }; + + const handleMinesChange = (e: React.ChangeEvent) => { + setMines(parseInt(e.target.value)); }; - const handleGameRestartClick = () => { + const handleNewGameClick = (e: React.FormEvent) => { + e.preventDefault(); setGameResult(''); setGameId(gameId + 1); @@ -62,6 +78,10 @@ const App: React.FC = () => { setAttributeCount, gameResult, setGameResult, + rows, + cols, + mines, + setCurrentMines, }} >
@@ -70,17 +90,47 @@ const App: React.FC = () => { Game ID: {gameId}
Remaining Unflagged Mines:{' '} - {global.mines - attributeCount.flaggedCount >= 0 - ? global.mines - attributeCount.flaggedCount + {/* TODO: store initial mine count for this */} + {currentMines - attributeCount.flaggedCount >= 0 + ? currentMines - attributeCount.flaggedCount : 0}
+
+ Columns: + + + Rows: + + + Mines: + + + +
{endMessage} -
{gameResult !== '' ? ( - + ) : null}
- +
diff --git a/src/components/Board.tsx b/src/components/Board.tsx index 57bb048..174c32b 100644 --- a/src/components/Board.tsx +++ b/src/components/Board.tsx @@ -2,15 +2,18 @@ import './Board.css'; import { useContext, useState } from 'react'; import { BoardContext, BoardContextInterface } from '../App.tsx'; -interface Global { - rows: number; - cols: number; - mines: number; -} -const Board = ({ global }: { global: Global }) => { +const Board = () => { const tmpBoardContext = useContext(BoardContext); - const { gameId, setAttributeCount, gameResult, setGameResult } = - tmpBoardContext as BoardContextInterface; + const { + gameId, + setAttributeCount, + gameResult, + setGameResult, + rows, + cols, + mines, + setCurrentMines, + } = tmpBoardContext as BoardContextInterface; type Board = Array>; const [board, setBoard] = useState([]); @@ -79,11 +82,7 @@ const Board = ({ global }: { global: Global }) => { }; } - const buildBoard = ( - rows = global.rows, - cols = global.cols, - mines = global.mines, - ) => { + const buildBoard = (rows: number, cols: number, mines: number) => { const emptyBoard = generateEmptyBoard(rows, cols); const minedBoard = placeMines(rows, cols, mines, emptyBoard); @@ -98,10 +97,7 @@ const Board = ({ global }: { global: Global }) => { setBoard(minedBoard); }; - const generateEmptyBoard = ( - rows = global.rows, - cols = global.cols, - ): Board => { + const generateEmptyBoard = (rows: number, cols: number): Board => { const grid = []; for (let row = 0; row < rows; row++) { const rowArray = []; @@ -119,14 +115,13 @@ const Board = ({ global }: { global: Global }) => { mines: number, board: Board, ) => { + setCurrentMines(mines); const updatedBoard = board; while (mines > 0) { const randRow = randInRange(0, rows - 1); const randCol = randInRange(0, cols - 1); - // console.log('placing mine at:', randRow, randCol); - // mines--; if (!updatedBoard[randRow][randCol].mine) { updatedBoard[randRow][randCol].setMined(); mines--; @@ -153,7 +148,7 @@ const Board = ({ global }: { global: Global }) => { const hiddenCount = board.length * board[0].length - revealedCount; - if (hiddenCount === global.mines) { + if (hiddenCount === mines) { setGameResult('win'); } @@ -263,7 +258,7 @@ const Board = ({ global }: { global: Global }) => { // Build new boards when necessary if (renderedGame !== gameId) { - buildBoard(); + buildBoard(rows, cols, mines); setRenderedGame(gameId); }