diff --git a/src/actions/index.js b/src/actions/index.js index 5f3ca00..dbb8683 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,4 +1,4 @@ -import { RESET_GAME, PLAYER_MOVE } from './types' +import { RESET_GAME, PLAYER_MOVE, GAME_WON } from './types' function resetGame() { return { @@ -6,8 +6,15 @@ function resetGame() { } } +function gameWon(player) { + return { + type: GAME_WON, + payload: player + } +} + function playerMove(coords) { return { type: PLAYER_MOVE, payload: coords } } -export { resetGame, playerMove } +export { resetGame, playerMove, gameWon } diff --git a/src/components/GameBoard/game-board.jsx b/src/components/GameBoard/game-board.jsx index bd4c724..6688c1b 100644 --- a/src/components/GameBoard/game-board.jsx +++ b/src/components/GameBoard/game-board.jsx @@ -23,7 +23,33 @@ function fill(player) { } } -const GameBoard = ({ board, playerMove }) => { +const min = num => Math.max(0, num) +const max = num => Math.min(6, num) + +function checkHorizontalWin(board, turn, lastMove) { + const start = min(lastMove.x - 3) + const end = max(lastMove.x + 3) + const lastTurn = turn === 1 ? 2 : 1 + + let count = 0 + + for (let x = start; x <= end; x += 1) { + if (board[x][lastMove.y] === lastTurn) { + count += 1 + + if (count === 4) { + return true + } + } else { + count = 0 + } + } + + return false +} + +/* eslint-disable max-lines-per-function */ +const GameBoard = ({ board, playerMove, gameWon, lastMove, turn }) => { const boardSize = { width: 450, height: 390 @@ -31,6 +57,12 @@ const GameBoard = ({ board, playerMove }) => { const offset = 40 + if (lastMove) { + if (checkHorizontalWin(board, turn, lastMove)) { + gameWon(turn === 1 ? 2 : 1) + } + } + const showBoard = board.map((column, x) => column.map((cell, y) => ( { ) } +/* eslint-enable max-lines-per-function */ GameBoard.propTypes = { board: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)).isRequired, - playerMove: PropTypes.func.isRequired + playerMove: PropTypes.func.isRequired, + lastMove: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.shape({ + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired + }) + ]).isRequired, + turn: PropTypes.number.isRequired, + gameWon: PropTypes.func.isRequired } export default GameBoard diff --git a/src/components/GameBoard/game-board.module.css b/src/components/GameBoard/game-board.module.css index e6167d0..5d0f8da 100644 --- a/src/components/GameBoard/game-board.module.css +++ b/src/components/GameBoard/game-board.module.css @@ -11,7 +11,7 @@ } .cells { - fill: hsl(0, 50%, 5%); + fill: hsl(0, 50%, 97%); } .cell { @@ -24,7 +24,7 @@ } .cellPlayer1 { - fill: hsl(75, 100%, 50%); + fill: hsl(0, 0%, 8%); } .cellPlayer2 { diff --git a/src/components/GameBoard/index.js b/src/components/GameBoard/index.js index 124dc7a..3612d8f 100644 --- a/src/components/GameBoard/index.js +++ b/src/components/GameBoard/index.js @@ -1,11 +1,15 @@ import { connect } from 'react-redux' import GameBoard from './game-board' -import { playerMove } from '../../actions' +import { playerMove, gameWon } from '../../actions' -const mapStateToProps = ({ game: { board } }) => ({ board }) +const mapStateToProps = ({ game: { board, lastMove, turn } }) => ({ + board, + lastMove, + turn +}) export default connect( mapStateToProps, - { playerMove } + { playerMove, gameWon } )(GameBoard) diff --git a/src/reducers/game-reducer.js b/src/reducers/game-reducer.js index 77bc2d0..0a10f33 100644 --- a/src/reducers/game-reducer.js +++ b/src/reducers/game-reducer.js @@ -2,6 +2,7 @@ const { GAME_WON, RESET_GAME, PLAYER_MOVE } = require('../actions/types') export const defaultState = { turn: 1, + lastMove: false, board: Array(7).fill(Array(6).fill(0)) } @@ -18,17 +19,30 @@ export default function gameReducer(state = defaultState, action) { case PLAYER_MOVE: { const newBoard = [...state.board].map(col => [...col]) - let y = false + const y = newBoard[action.payload.x].reduce((acc, cell, index) => { + switch (cell) { + case 0: { + return index + } - for (let i = newBoard[action.payload.x].length - 1; i > 0; i--) { - if (y === false && newBoard[action.payload.x][i] === 0) { - y = i + default: { + return acc + } } - } + }, false) - newBoard[action.payload.x][y] = state.turn + if (y !== false) { + newBoard[action.payload.x][y] = state.turn - return { ...state, board: newBoard, turn: state.turn === 1 ? 2 : 1 } + return { + ...state, + board: newBoard, + turn: state.turn === 1 ? 2 : 1, + lastMove: { ...action.payload, y } + } + } + + return { ...state } } default: { diff --git a/src/reducers/status-reducer.js b/src/reducers/status-reducer.js index bb1e3fe..1683aab 100644 --- a/src/reducers/status-reducer.js +++ b/src/reducers/status-reducer.js @@ -1,5 +1,15 @@ +import { GAME_WON, RESET_GAME } from '../actions/types' + export default function statusReducer(state = false, action) { switch (action.type) { + case RESET_GAME: { + return false + } + + case GAME_WON: { + return `Player ${action.payload} won` + } + default: { return state } diff --git a/src/style.css b/src/style.css index b88df25..bc9ab29 100644 --- a/src/style.css +++ b/src/style.css @@ -7,6 +7,7 @@ body { display: flex; align-items: center; justify-content: center; + background-color: #ffebcd; height: 100vh; margin: 0; }