From faeae938924a1b9e82f3d9420e2764c491c94c0d Mon Sep 17 00:00:00 2001 From: Ben Burlingham Date: Sat, 23 Apr 2016 14:59:16 -0700 Subject: [PATCH] Extracting logic into separate objects and simplifying dependencies. --- actions/board/grid.actions.js | 11 ++++ actions/board/muncher.actions.js | 42 +------------ components/board/board.component.js | 81 +++++--------------------- components/board/grid.component.js | 17 +++++- components/board/message.component.js | 10 ++-- components/board/muncher.component.js | 54 +---------------- components/board/titlebar.component.js | 2 +- index.js | 4 +- logic/board.logic.js | 67 +++++++++++++++++++++ logic/grid.logic.js | 27 +++++++++ logic/message.logic.js | 9 +++ logic/muncher.logic.js | 46 +++++++++++++++ logic/values.logic.js | 4 +- reducers/board/grid.reducer.js | 20 +++++++ reducers/board/message.reducer.js | 12 ++-- reducers/board/muncher.reducer.js | 25 +++----- 16 files changed, 241 insertions(+), 190 deletions(-) create mode 100644 actions/board/grid.actions.js create mode 100644 logic/board.logic.js create mode 100644 logic/grid.logic.js create mode 100644 logic/message.logic.js create mode 100644 logic/muncher.logic.js create mode 100644 reducers/board/grid.reducer.js diff --git a/actions/board/grid.actions.js b/actions/board/grid.actions.js new file mode 100644 index 0000000..9413657 --- /dev/null +++ b/actions/board/grid.actions.js @@ -0,0 +1,11 @@ +export const GRID_ACTION = 'GRID_ACTION'; +export const UPDATE = 'UPDATE'; + +const GridActions = { + update: () => ({ + type: GRID_ACTION, + action: UPDATE + }) +}; + +export default GridActions; diff --git a/actions/board/muncher.actions.js b/actions/board/muncher.actions.js index 6ba10cc..4acb013 100644 --- a/actions/board/muncher.actions.js +++ b/actions/board/muncher.actions.js @@ -1,43 +1,7 @@ export const MUNCHER_ACTION = 'MUNCHER_ACTION'; -export const LEFT = 'LEFT'; -export const RIGHT = 'RIGHT'; -export const UP = 'UP'; -export const DOWN = 'DOWN'; -export const MUNCH = 'MUNCH'; -export const FREEZE = 'FREEZE'; -export const UNFREEZE = 'UNFREEZE'; +export const UPDATE = 'UPDATE'; -export const moveLeft = () => ({ +export const update = () => ({ type: MUNCHER_ACTION, - action: LEFT -}); - -export const moveRight = () => ({ - type: MUNCHER_ACTION, - action: RIGHT -}); - -export const moveUp = () => ({ - type: MUNCHER_ACTION, - action: UP -}); - -export const moveDown = () => ({ - type: MUNCHER_ACTION, - action: DOWN -}); - -export const munch = (x, y) => ({ - type: MUNCHER_ACTION, - action: MUNCH -}); - -export const freeze = () => ({ - type: MUNCHER_ACTION, - action: FREEZE -}); - -export const unfreeze = () => ({ - type: MUNCHER_ACTION, - action:UNFREEZE + action: UPDATE }); diff --git a/components/board/board.component.js b/components/board/board.component.js index ef7acbe..e7dc273 100644 --- a/components/board/board.component.js +++ b/components/board/board.component.js @@ -2,7 +2,7 @@ require('../../sass/board/board.scss'); import { Component } from 'react'; import { connect } from 'react-redux'; -import { getState } from 'react-redux'; + import Scorebar from './scorebar.component'; import Titlebar from './titlebar.component'; import Grid from './grid.component'; @@ -10,82 +10,33 @@ import Message from './message.component'; import Muncher from './muncher.component'; import Troggles from './troggles.component'; -import ValuesLogic from '../../logic/values.logic.js'; -import TroggleLogic from '../../logic/troggle.logic.js'; -import { SETTINGS } from '../../App'; - -import * as BoardActions from '../../actions/board/board.actions'; -import * as ScorebarActions from '../../actions/board/scorebar.actions'; -import * as MessageActions from '../../actions/board/message.actions'; -import * as MuncherActions from '../../actions/board/muncher.actions'; +import BoardLogic from '../../logic/board.logic'; -let nextLevelFlag = false; +let listener; -export default class Board extends Component { +export class Board extends Component { componentDidMount() { - this.nextLevel(); - }; - - nextLevel() { - this.props.dispatch(BoardActions.nextLevel()); - TroggleLogic.clearAll(this.props.dispatch); - TroggleLogic.createTroggles(this.props.dispatch); - }; + BoardLogic.setDispatch(this.props.dispatch); + BoardLogic.nextLevel(); - messageNext() { - if (nextLevelFlag === true) { - this.nextLevel(); - nextLevelFlag = false; - } - this.props.dispatch(MessageActions.hide()); - ReactDOM.findDOMNode(this.refs.muncher).focus(); + listener = BoardLogic.keyListener.bind(BoardLogic); + window.addEventListener('keydown', listener); }; - muncherNext(x, y) { - const index = y * SETTINGS.GRID_WIDTH + x; - - if (this.props.values[index].valid) { - this.props.dispatch(BoardActions.hideValue(index)); - this.props.dispatch(ScorebarActions.munchSucceeded()); - - // State will not have been updated; temporary state created for checking. - const tmp = this.props.values.slice(0); - tmp[index].show = false; - if (ValuesLogic.checkComplete(tmp, this.props.level)) { - nextLevelFlag = true; - this.props.dispatch(MessageActions.exclaim()); - ReactDOM.findDOMNode(this.refs.message).focus(); - } - } - else { - const msg = ValuesLogic.getError(this.props.values[index].value, this.props.level); - this.props.dispatch(MessageActions.show(msg)); - this.props.dispatch(ScorebarActions.munchFailed()); - ReactDOM.findDOMNode(this.refs.message).focus(); - } - // - // if (troggles[i].x === muncher.x && troggles[i].y === muncher.y) { - // this.props.dispatch(MessageActions.show("You've been eaten by a troggle!")); - // this.props.dispatch(ScorebarActions.munchFailed()); - // TroggleLogic.frozen = true; - // ReactDOM.findDOMNode(this.refs.message).focus(); - // } + componentWillUnmount() { + window.removeEventListener('keydown', listener); }; render() { return (
- - - - - + + + + +
); }; }; -const select = (state) => { - return state.board; -} - -export default connect(select)(Board); +export default connect()(Board) diff --git a/components/board/grid.component.js b/components/board/grid.component.js index 4f3d6a6..5aa1010 100644 --- a/components/board/grid.component.js +++ b/components/board/grid.component.js @@ -1,10 +1,17 @@ require('../../sass/board/grid.scss'); import { Component } from 'react'; +import { connect } from 'react-redux'; + import GridCell from './grid-cell.component'; +import GridActions from '../../actions/board/grid.actions'; import { SETTINGS } from '../../App'; -export default class Grid extends Component { +export class Grid extends Component { + componentDidMount() { + this.props.dispatch(GridActions.update()); + }; + render() { const { values } = this.props.values; const cells = []; @@ -18,3 +25,11 @@ export default class Grid extends Component { return (
{cells}
); }; }; + +const select = (state) => { + return { + values: state.grid + } +} + +export default connect(select)(Grid); diff --git a/components/board/message.component.js b/components/board/message.component.js index c15b767..0fa210e 100644 --- a/components/board/message.component.js +++ b/components/board/message.component.js @@ -8,12 +8,12 @@ let refocusListener = null; export class Message extends Component { componentDidMount() { - refocusListener = this.refocus.bind(this); - window.addEventListener('click', refocusListener); + // refocusListener = this.refocus.bind(this); + // window.addEventListener('click', refocusListener); }; componentWillUnmount() { - window.removeEventListener('click', refocusListener); + // window.removeEventListener('click', refocusListener); }; refocus() { @@ -33,8 +33,10 @@ export class Message extends Component { classname.push('hidden'); } + //
+ return ( -
+
{this.props.message}
Press Spacebar to continue. diff --git a/components/board/muncher.component.js b/components/board/muncher.component.js index 310586c..00f0b62 100644 --- a/components/board/muncher.component.js +++ b/components/board/muncher.component.js @@ -2,65 +2,13 @@ require('../../sass/board/muncher.scss'); import { Component } from 'react'; import { connect } from 'react-redux'; -import * as MuncherActions from '../../actions/board/muncher.actions'; -import { SETTINGS } from '../../App'; - -let focusListener = null; export class Muncher extends Component { - componentDidMount() { - this.focus(); - focusListener = this.focus.bind(this); - window.addEventListener('click', focusListener); - }; - - componentWillUnmount() { - window.removeEventListener('click', focusListener); - }; - - focus() { - ReactDOM.findDOMNode(this).focus(); - }; - - keydown(e) { - const x = this.props.x; - const y = this.props.y; - - switch (e.keyCode) { - case 32: - this.props.onMunch(x, y); - break; - case 37: - if (x !== 0) { - this.props.dispatch(MuncherActions.moveLeft()); - } - break; - - case 38: - if (y !== 0) { - this.props.dispatch(MuncherActions.moveUp()); - } - break; - - case 39: - if (x !== SETTINGS.GRID_WIDTH - 1) { - this.props.dispatch(MuncherActions.moveRight()); - } - break; - - case 40: - if (y !== SETTINGS.GRID_HEIGHT - 1) { - this.props.dispatch(MuncherActions.moveDown()); - } - break; - } - }; - render() { const classname = ['muncher', 'x' + this.props.x, 'y' + this.props.y]; return ( -
+
); }; }; diff --git a/components/board/titlebar.component.js b/components/board/titlebar.component.js index a279c10..a8d1cff 100644 --- a/components/board/titlebar.component.js +++ b/components/board/titlebar.component.js @@ -4,6 +4,6 @@ import { Component } from 'react'; export default class Titlebar extends Component { render() { - return (
{this.props.title}
); + return (
Connect titlebar
); }; }; diff --git a/index.js b/index.js index 7bcc0a7..32b0cea 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ import App from './App'; import modeReducer from './reducers/mode.reducer'; import newgameReducer from './reducers/welcome/new-game.reducer'; import boardReducer from './reducers/board/board.reducer'; +import gridReducer from './reducers/board/grid.reducer'; import muncherReducer from './reducers/board/muncher.reducer'; import scorebarReducer from './reducers/board/scorebar.reducer'; import messageReducer from './reducers/board/message.reducer'; @@ -20,7 +21,8 @@ const reducers = combineReducers({ scorebar: scorebarReducer, board: boardReducer, message: messageReducer, - troggles: troggleReducer + troggles: troggleReducer, + grid: gridReducer }); const store = createStore(reducers); diff --git a/logic/board.logic.js b/logic/board.logic.js new file mode 100644 index 0000000..7f21b6d --- /dev/null +++ b/logic/board.logic.js @@ -0,0 +1,67 @@ +import { SETTINGS } from '../App.js'; + +import * as ScorebarActions from '../actions/board/scorebar.actions'; +import * as MessageActions from '../actions/board/message.actions'; + +import TroggleLogic from './troggle.logic'; +import MessageLogic from './message.logic'; +import MuncherLogic from './muncher.logic'; +import GridLogic from './grid.logic'; + +const level = 0; +let dispatch; + +const BoardLogic = { + setDispatch: (d) => { + dispatch: d, + GridLogic.setDispatch(d); + MuncherLogic.setDispatch(d); + }, + + munch() { + const index = MuncherLogic.getY() * SETTINGS.GRID_WIDTH + MuncherLogic.getX(); + + if (GridLogic.getValues()[index].valid) { + GridLogic.hideValue(index); + + if (GridLogic.isCompleted() === true) { + dispatch(MessageActions.exclaim()); + } + } + else { + const msg = Values.getError(values[index].value, level); + dispatch(MessageActions.show(msg)); + } + }, + + keyListener(e) { + if (e.keyCode === 32 && GridLogic.isCompleted() === true) { + this.nextLevel(); + dispatch(MessageActions.hide()); + } + else if (e.keyCode === 32 && MessageLogic.isShowing() === true) { + dispatch(MessageActions.hide()); + } + else if (e.keyCode === 32 && MessageLogic.isShowing() === false) { + this.munch(); + } + else if (MessageLogic.isShowing() === false) { + MuncherLogic.move(e); + } + }, + + nextLevel() { + GridLogic.generateValues(level); + // TroggleLogic.clearAll(this.props.dispatch); + // TroggleLogic.createTroggles(this.props.dispatch); + }, + + // if (troggles[i].x === muncher.x && troggles[i].y === muncher.y) { + // this.props.dispatch(MessageActions.show("You've been eaten by a troggle!")); + // this.props.dispatch(ScorebarActions.munchFailed()); + // TroggleLogic.frozen = true; + // ReactDOM.findDOMNode(this.refs.message).focus(); + // } +}; + +export default BoardLogic; diff --git a/logic/grid.logic.js b/logic/grid.logic.js new file mode 100644 index 0000000..ac2939e --- /dev/null +++ b/logic/grid.logic.js @@ -0,0 +1,27 @@ +import GridActions from '../actions/board/grid.actions'; +import ValuesLogic from './values.logic'; +import { SETTINGS } from '../App'; + +let values; +let dispatch; + +const GridLogic = { + setDispatch: d => dispatch = d, + getValues: () => values, + + generateValues: (level) => { + values = ValuesLogic.generate(SETTINGS.GRID_WIDTH * SETTINGS.GRID_HEIGHT, level); + dispatch(GridActions.update()); + }, + + isCompleted: (level) => { + return ValuesLogic.checkComplete(values, level) + }, + + hideValue: (index) => { + values[index].show = false; + dispatch(GridActions.update()); + } +}; + +export default GridLogic; diff --git a/logic/message.logic.js b/logic/message.logic.js new file mode 100644 index 0000000..409b962 --- /dev/null +++ b/logic/message.logic.js @@ -0,0 +1,9 @@ +let show = false; + +const MessageLogic = { + hide: () => show = false, + show: () => show = true, + isShowing: () => show +}; + +export default MessageLogic; diff --git a/logic/muncher.logic.js b/logic/muncher.logic.js new file mode 100644 index 0000000..a38fd9d --- /dev/null +++ b/logic/muncher.logic.js @@ -0,0 +1,46 @@ +import * as MuncherActions from '../actions/board/muncher.actions'; +import { SETTINGS } from '../App'; + +let x = 0; +let y = 0; +let dispatch; + +const MuncherLogic = { + getX: () => x, + getY: () => y, + setDispatch: d => dispatch = d, + + move: (e) => { + switch (e.keyCode) { + case 37: + if (x !== 0) { + x -= 1; + dispatch(MuncherActions.update()); + } + break; + + case 38: + if (y !== 0) { + y -= 1; + dispatch(MuncherActions.update()); + } + break; + + case 39: + if (x !== SETTINGS.GRID_WIDTH - 1) { + x += 1; + dispatch(MuncherActions.update()); + } + break; + + case 40: + if (y !== SETTINGS.GRID_HEIGHT - 1) { + y += 1; + dispatch(MuncherActions.update()); + } + break; + } + } +}; + +export default MuncherLogic; diff --git a/logic/values.logic.js b/logic/values.logic.js index ba85331..cfc6054 100644 --- a/logic/values.logic.js +++ b/logic/values.logic.js @@ -4,7 +4,7 @@ const validate = function(value, level) { return ((value || -1) % (level + 2) === 0); }; -const Values = { +const ValuesLogic = { // Anagrams, multiples, equality generate(n, level) { const values = []; @@ -41,4 +41,4 @@ const Values = { } }; -export default Values; +export default ValuesLogic; diff --git a/reducers/board/grid.reducer.js b/reducers/board/grid.reducer.js new file mode 100644 index 0000000..7f1f37d --- /dev/null +++ b/reducers/board/grid.reducer.js @@ -0,0 +1,20 @@ +const Immutable = require('immutable'); + +import * as GridActions from '../../actions/board/grid.actions'; +import GridLogic from '../../logic/grid.logic.js'; + +const initial = []; + +const reducer = (state = initial, action) => { + if (action.type !== GridActions.GRID_ACTION) { + return state; + } + + if (action.action === GridActions.UPDATE) { + return Immutable.List(GridLogic.getValues()).toArray(); + } + + return state; +}; + +export default reducer; diff --git a/reducers/board/message.reducer.js b/reducers/board/message.reducer.js index 7eff970..a73f8fe 100644 --- a/reducers/board/message.reducer.js +++ b/reducers/board/message.reducer.js @@ -1,5 +1,8 @@ const Immutable = require('immutable'); +import * as MessageActions from '../../actions/board/message.actions'; +import MessageLogic from '../../logic/message.logic'; + const exclamations = [ 'Congratulations!', 'Yippee!', @@ -11,9 +14,6 @@ const exclamations = [ 'Shazam!' ]; -import * as MessageActions from '../../actions/board/message.actions'; -import TroggleLogic from '../../logic/troggle.logic.js'; - const initial = { message: '', hidden: true }; const reducer = (state = initial, action) => { @@ -23,7 +23,7 @@ const reducer = (state = initial, action) => { switch (action.action) { case MessageActions.EXCLAIM: - TroggleLogic.frozen = true; + MessageLogic.show(); const msg = exclamations[Math.floor(Math.random() * exclamations.length)]; return Immutable.Map(state) .set('hidden', false) @@ -31,14 +31,14 @@ const reducer = (state = initial, action) => { .toObject(); case MessageActions.SHOW: - TroggleLogic.frozen = true; + MessageLogic.show(); return Immutable.Map(state) .set('hidden', false) .set('message', action.message) .toObject(); case MessageActions.HIDE: - TroggleLogic.frozen = false; + MessageLogic.hide(); return Immutable.Map(state) .set('hidden', true) .toObject(); diff --git a/reducers/board/muncher.reducer.js b/reducers/board/muncher.reducer.js index fa444d8..a4d4bf1 100644 --- a/reducers/board/muncher.reducer.js +++ b/reducers/board/muncher.reducer.js @@ -1,5 +1,6 @@ const Immutable = require('immutable'); import * as MuncherActions from '../../actions/board/muncher.actions'; +import MuncherLogic from '../../logic/muncher.logic'; import { SETTINGS } from '../../App'; const initial = { x: 0, y: 0, frozen: false }; @@ -9,24 +10,12 @@ const reducer = (state = initial, action) => { return state; } - switch (action.action) { - case MuncherActions.LEFT: - return Immutable.Map(state).set('x', state.x - 1).toObject(); - - case MuncherActions.RIGHT: - return Immutable.Map(state).set('x', state.x + 1).toObject(); - - case MuncherActions.UP: - return Immutable.Map(state).set('y', state.y - 1).toObject(); - - case MuncherActions.DOWN: - return Immutable.Map(state).set('y', state.y + 1).toObject(); - - case MuncherActions.FREEZE: - return Immutable.Map(state).set('frozen', true).toObject(); - - case MuncherActions.UNFREEZE: - return Immutable.Map(state).set('frozen', false).toObject(); + if (action.action === MuncherActions.UPDATE) { + return Immutable.Map(state) + .set('x', MuncherLogic.getX()) + .set('y', MuncherLogic.getY()) + .set('frozen', false) + .toObject(); } return state;