diff --git a/src/App.js b/src/App.js index 5bb824a..6659750 100644 --- a/src/App.js +++ b/src/App.js @@ -6,27 +6,30 @@ import { GameService } from 'services'; const gameClient = new GameService(); function App() { - const [rows, setRows] = useState(10); const [cols, setCols] = useState(10); - const [mines, setMines] = useState(5); - const [flags, setFlags] = useState(5); - const [mounted, setMounted] = useState(false); const [dummyBoard, setDummyBoard] = useState([]); + const [flags, setFlags] = useState(5); + const [mines, setMines] = useState(5); + const [rows, setRows] = useState(10); const [updateDummyBoard, setUpdateDummyBoard] = useState(true); + const [activeGame, setActiveGame] = useState(null); const handleSetRows = value => { - // TODO can't be less than 3 + if (value < 3 || value > 99) { + return; + } setRows(value); - setUpdateDummyBoard(true); }; const handleSetCols = value => { - // TODO can't be less than 3 + if (value < 3 || value > 99) { + return; + } setCols(value); - setUpdateDummyBoard(true); }; const generateDummyBoard = () => { + setDummyBoard([]); const board = []; for (let row = 0; row < rows; row++) { @@ -41,41 +44,67 @@ function App() { }; const handleSetMines = event => { - // TODO can't be less than 1 - setMines(parseInt(event.target.value)); - setFlags(parseInt(event.target.value)); - generateDummyBoard(); + const value = parseInt(event.target.value); + if (value < 1 || value > 99) { + return; + } + + setMines(value); + setFlags(value); }; useEffect(() => { function bootstrap() { - setMounted(true); - generateDummyBoard(); - } - - if (!mounted) { - bootstrap(); + setUpdateDummyBoard(false); + handleCreateNewGame(); } if (updateDummyBoard) { - setUpdateDummyBoard(false); - generateDummyBoard(); + bootstrap(); + } + + if (activeGame && activeGame.win === true) { + document.getElementsByClassName('reset')[0].innerHTML = '😎'; } }); const handleCellClick = (row, col) => { + if (activeGame.status === 3 || activeGame.win === true) { + return; + } const cell = document.getElementById(`cell_${row}_${col}`); if (cell.classList.contains('flagged')) { return; } if (!cell.classList.contains('revealed')) { - cell.classList.add('revealed'); + cell.classList.add('busy'); + gameClient.cellClick(row, col, activeGame.id).then(response => { + cell.classList.add('revealed'); + cell.classList.remove('busy'); + if (response.active_game.board_progress[row][col] === 0) { + cell.classList.add('empty'); + } else if (response.active_game.board_progress[row][col] > 0) { + const points = `${response.active_game.board_progress[row][col]}`; + cell.classList.add('point'); + cell.classList.add(`point-${points}`); + cell.innerHTML = points; + } else { + cell.classList.add('mined'); + document.getElementsByClassName('reset')[0].innerHTML = '👻'; + } + + setActiveGame(response.active_game); + }); } }; const handleCellContextMenu = (event, row, col) => { event.preventDefault(); + if (activeGame.win === true) { + return; + } + const cell = document.getElementById(`cell_${row}_${col}`); if (cell.classList.contains('revealed')) { return; @@ -83,18 +112,22 @@ function App() { if (cell.classList.contains('flagged')) { cell.classList.remove('flagged'); - } else { + setFlags(flags + 1); + } else if (flags > 0) { cell.classList.add('flagged'); + setFlags(flags - 1); } }; - const handleCreateNewGame = event => { - gameClient - .createNewGame(rows, cols, mines) - .then(response => console.log(response)); + const handleCreateNewGame = () => { + gameClient.createNewGame(rows, cols, mines).then(response => { + setActiveGame(response); + setFlags(mines); + generateDummyBoard(); + }); }; - if (!mounted) { + if (!activeGame) { return null; } @@ -111,6 +144,7 @@ function App() { setCols={handleSetCols} setMines={setMines} setRows={handleSetRows} + setUpdateDummyBoard={setUpdateDummyBoard} /> { return (
- {dummyBoard.map((cols, rowId) => ( -
- {cols.map((col, colId) => ( -
handleCellClick(rowId, colId)} - onContextMenu={event => - handleCellContextMenu(event, rowId, colId) - }> - {' '} -
- ))} -
- ))} +
+
+ {dummyBoard.map((cols, rowId) => ( +
+ {cols.map((col, colId) => ( +
handleCellClick(rowId, colId)} + onContextMenu={event => + handleCellContextMenu(event, rowId, colId) + }> + {' '} +
+ ))} +
+ ))} +
+
); }; diff --git a/src/components/Board/styles.scss b/src/components/Board/styles.scss index bbda6e0..51e042a 100644 --- a/src/components/Board/styles.scss +++ b/src/components/Board/styles.scss @@ -2,7 +2,20 @@ .board { display: flex; - flex-direction: column; + + &-col-left, + &-col-right { + flex: 1 1 auto; + } + + &-col-center { + flex: 0 0 auto; + border-width: 3px; + border-style: solid; + border-color: darken($gray, 20%) lighten($gray, 20%) lighten($gray, 20%) + darken($gray, 20%); + } + &-row { display: flex; justify-content: center; @@ -14,8 +27,52 @@ } &-cell.revealed { - margin: 1px; - border: 2px solid $gray-dark; + padding: 2px; + border: 1px solid $gray-border; + } + + &-cell.busy { + background-color: $gray-mid; + margin: 3px; + border: none; + } + + &-cell.point { + text-align: center; + font-size: 90%; + font-weight: bold; + } + + &-cell.point-1 { + color: #0000ff; + } + &-cell.point-2 { + color: #037d02; + } + &-cell.point-3 { + color: #fd0000; + } + &-cell.point-4 { + color: #010180; + } + &-cell.point-5 { + color: #830101; + } + &-cell.point-6 { + color: #038081; + } + &-cell.point-7 { + color: #000000; + } + &-cell.point-8 { + color: #808080; + } + + &-cell.mined { + background-image: url(../../assets/images/mine.png); + background-repeat: no-repeat; + background-position: center center; + background-size: 90%; } &-cell { diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js index 498fb95..691889f 100644 --- a/src/components/Header/Header.js +++ b/src/components/Header/Header.js @@ -11,45 +11,51 @@ const Header = ({ mines, rows, setCols, - setRows + setRows, + setUpdateDummyBoard }) => { return (
-
{flags}
-
- setRows(parseInt(event.target.value))} - type="number" - value={rows} - /> - setCols(parseInt(event.target.value))} - type="number" - value={cols} - /> - handleSetMines(event)} - type="number" - value={mines} - /> + setRows(parseInt(event.target.value))} + type="number" + value={rows} + /> + setCols(parseInt(event.target.value))} + type="number" + value={cols} + /> + handleSetMines(event)} + type="number" + value={mines} + /> + +
+
+
{flags}
+
{ + event.target.innerHTML = '😮'; + }} + onMouseUp={event => { + event.target.innerHTML = '🙂'; + handleCreateNewGame(event); + }}> + 🙂
+
000
-
{ - event.target.innerHTML = '😮'; - }} - onMouseUp={event => { - event.target.innerHTML = '🙂'; - handleCreateNewGame(event); - }}> - 🙂 -
-
000
); }; @@ -63,7 +69,8 @@ Header.propTypes = { rows: PropTypes.number, setCols: PropTypes.func.isRequired, setMines: PropTypes.func.isRequired, - setRows: PropTypes.func.isRequired + setRows: PropTypes.func.isRequired, + setUpdateDummyBoard: PropTypes.func.isRequired }; export default Header; diff --git a/src/components/Header/styles.scss b/src/components/Header/styles.scss index 9d645d3..a23d641 100644 --- a/src/components/Header/styles.scss +++ b/src/components/Header/styles.scss @@ -3,42 +3,54 @@ .header { max-width: 500px; width: 100%; - display: flex; - justify-content: space-between; padding: 5px; margin: 0 auto; - - .led-panel { - font-family: 'Space Mono', monospace; - background: $gray-dark; - color: $red; - text-shadow: 0 0 2px rgba($red, 1); - line-height: 30px; - letter-spacing: 0.05em; - text-align: center; - width: 30px; - } + display: flex; + justify-content: space-between; + flex-direction: column; .settings { max-width: 221px; display: flex; - justify-content: space-between; + justify-content: center; + margin: 10px auto; - .custom { - display: flex; - justify-content: space-between; + input { + width: 40px; + height: 30px; + line-height: 30px; + text-align: center; + background: $gray-light; + margin: 0 2px; + } - input { - width: 30px; - text-align: center; - } + .button { + cursor: pointer; + margin: 0 2px; } } - .reset { - width: 30px; - line-height: 30px; - text-align: center; - cursor: pointer; + .canvas { + display: flex; + justify-content: space-between; + flex-direction: row; + + .led-panel { + font-family: 'Space Mono', monospace; + background: $gray-dark; + color: $red; + text-shadow: 0 0 2px rgba($red, 1); + line-height: 30px; + letter-spacing: 0.05em; + text-align: center; + width: 30px; + } + + .reset { + width: 30px; + line-height: 30px; + text-align: center; + cursor: pointer; + } } } diff --git a/src/services/game.js b/src/services/game.js index a8596cf..9625c58 100644 --- a/src/services/game.js +++ b/src/services/game.js @@ -3,9 +3,17 @@ import { RestClient, getResponseData } from './base'; export class GameService extends RestClient { base = '/'; + CLICK_NAIVE = 8; + createNewGame(rows, cols, mines) { return this.client .post(`${this.base}games`, { rows, cols, mines }) .then(getResponseData); } + + cellClick(row, col, gameId) { + return this.client + .post(`${this.base}games/${gameId}/events`, { row, col }) + .then(getResponseData); + } }