diff --git a/actions/board/board.actions.js b/actions/board/board.actions.js new file mode 100644 index 0000000..c8a4f4f --- /dev/null +++ b/actions/board/board.actions.js @@ -0,0 +1,35 @@ +export const BOARD_ACTION = 'BOARD_ACTION'; +export const GENERATE = 'GENERATE'; +export const UPDATE = 'UPDATE'; +export const HIDE = 'HIDE'; +export const SHOW = 'SHOW'; +export const NEXT_LEVEL = 'NEXT_LEVEL'; + +export const generateValues = () => ({ + type: BOARD_ACTION, + action: GENERATE +}); + +export const updateValue = (index, value) => ({ + type: BOARD_ACTION, + action: UPDATE, + index: index, + value: value +}); + +export const showValue = (index) => ({ + type: BOARD_ACTION, + action: SHOW, + index: index +}); + +export const hideValue = (index) => ({ + type: BOARD_ACTION, + action: HIDE, + index: index +}); + +export const nextLevel = () => ({ + type: BOARD_ACTION, + action: NEXT_LEVEL +}); diff --git a/actions/board/grid.actions.js b/actions/board/grid.actions.js deleted file mode 100644 index 98f9a3f..0000000 --- a/actions/board/grid.actions.js +++ /dev/null @@ -1,18 +0,0 @@ -// Grid component actions and action creators. -export const GRID_ACTION = 'GRID_ACTION'; -export const GENERATE = 'GENERATE'; -export const UPDATE = 'UPDATE'; - -export const generateValues = (count, level) => ({ - type: GRID_ACTION, - action: GENERATE, - count: count, - level: level -}); - -export const updateValues = (index, value) => ({ - type: GRID_ACTION, - action: UPDATE, - index: index, - value: value -}); diff --git a/actions/board/message.actions.js b/actions/board/message.actions.js index 8c5c90a..243b076 100644 --- a/actions/board/message.actions.js +++ b/actions/board/message.actions.js @@ -1,13 +1,12 @@ -// Message component actions and action creators. export const MESSAGE_ACTION = 'MESSAGE_ACTION'; export const DISPLAY = 'DISPLAY'; export const HIDE = 'HIDE'; -export const display = (msg1, msg2, hidden) => ({ +export const display = (line1, line2, hidden) => ({ type: MESSAGE_ACTION, action: DISPLAY, - message1: msg1, - message2: msg2, + line1: line1, + line2: line2, hidden: hidden }); diff --git a/actions/board/muncher.actions.js b/actions/board/muncher.actions.js index 575b23b..35d7af5 100644 --- a/actions/board/muncher.actions.js +++ b/actions/board/muncher.actions.js @@ -1,4 +1,3 @@ -// Muncher component actions and action creators. export const MUNCHER_ACTION = 'MUNCHER_ACTION'; export const LEFT = 'LEFT'; export const RIGHT = 'RIGHT'; diff --git a/actions/board/scorebar.actions.js b/actions/board/scorebar.actions.js index 434ea50..766d646 100644 --- a/actions/board/scorebar.actions.js +++ b/actions/board/scorebar.actions.js @@ -1,4 +1,3 @@ -// Scorebar component actions and action creators. export const SCOREBAR_ACTION = 'SCOREBAR_ACTION'; export const MUNCH_SUCCEEDED = 'MUNCH_SUCCEEDED'; export const MUNCH_FAILED = 'MUNCH_FAILED'; diff --git a/components/board/board.component.js b/components/board/board.component.js index 3cd41e4..c76977b 100644 --- a/components/board/board.component.js +++ b/components/board/board.component.js @@ -8,15 +8,16 @@ import Titlebar from './titlebar.component'; import Grid from './grid.component'; import Message from './message.component'; import Muncher from './muncher.component'; + import Values from '../../reducers/Values'; import { SETTINGS } from '../../App'; -import * as GridActions from '../../actions/board/grid.actions'; +import * as BoardActions from '../../actions/board/board.actions'; import * as MuncherActions from '../../actions/board/muncher.actions'; import * as ScorebarActions from '../../actions/board/scorebar.actions'; import * as MessageActions from '../../actions/board/message.actions'; -var exclamations = [ +const exclamations = [ 'Congratulations!', 'Yippee!', 'Woohoo!', @@ -27,35 +28,106 @@ var exclamations = [ 'Shazam!' ]; +let muncherListener = null; +let messageListener = null; + export default class Board extends Component { - munch(x, y) { - this.props.dispatch(MuncherActions.munch()); + componentDidMount(n) { + muncherListener = this.muncherKeydown.bind(this); + messageListener = this.messageKeydown.bind(this); - const index = y * SETTINGS.GRID_HEIGHT + x - const valid = Values.validate(this.props.grid[index], 0); + window.addEventListener('keydown', muncherListener); + // window.addEventListener('keydown', messageListener); - if (valid) { - const msg = exclamations[Math.floor(Math.random() * exclamations.length)]; + this.props.dispatch(BoardActions.nextLevel()); + }; + + muncherKeydown(e) { + switch (e.keyCode) { + case 32: + this.munch(); + break; + + case 37: + this.props.dispatch(MuncherActions.moveLeft()); + break; + + case 38: + this.props.dispatch(MuncherActions.moveUp()); + break; - this.props.dispatch(GridActions.updateValues(index, '')); - this.props.dispatch(ScorebarActions.munchSucceeded()); - this.props.dispatch(MessageActions.display(msg, 'Press Spacebar to Continue')); + case 39: + this.props.dispatch(MuncherActions.moveRight()); + break; + + case 40: + this.props.dispatch(MuncherActions.moveDown()); + break; + } + }; + + messageKeydown(e) { + if (e.keyCode === 32) { + window.removeEventListener('keydown', messageListener); + window.addEventListener('keydown', muncherListener); + + this.props.dispatch(MessageActions.hide()); + } + }; + + componentWillUnmount() { + window.removeEventListener('keydown', muncherListener); + window.removeEventListener('keydown', messageListener); + }; + + munch() { + const { board, muncher, dispatch } = this.props; + const index = muncher.y * SETTINGS.GRID_HEIGHT + muncher.x; + + dispatch(MuncherActions.munch()); + + if (board.values[index].valid) { + dispatch(BoardActions.hideValue(index)); + dispatch(ScorebarActions.munchSucceeded()); } else { - this.props.dispatch(ScorebarActions.munchFailed()); + window.removeEventListener('keydown', muncherListener); + window.addEventListener('keydown', messageListener); + + const msg = Values.getError(board.values[index].value, board.level); + dispatch(MessageActions.display(msg, 'Press Spacebar to Continue')); + dispatch(ScorebarActions.munchFailed()); + } + + if (Values.checkComplete(this.props.board.values, board.level)) { + window.removeEventListener('keydown', muncherListener); + window.addEventListener('keydown', messageListener); + + const msg = exclamations[Math.floor(Math.random() * exclamations.length)]; + dispatch(MessageActions.display(msg, 'Press Spacebar to Continue')); + dispatch(BoardActions.nextLevel()); } }; render() { + const { board, muncher, message } = this.props; + return (
- - - - + +
); }; }; -// Connect state for inspection to determine dispatching flow. -export default connect((s) => s)(Board); +const select = (state) => { + return { + board: state.board, + muncher: state.muncher, + message: state.message + }; +} + +export default connect(select)(Board); diff --git a/components/board/grid-cell.component.js b/components/board/grid-cell.component.js index 749d770..c680a31 100644 --- a/components/board/grid-cell.component.js +++ b/components/board/grid-cell.component.js @@ -4,6 +4,8 @@ export default class GridCell extends Component { render() { const classname = ['cell', 'x' + this.props.x, 'y' + this.props.y]; - return (
{this.props.value}
); + const value = (this.props.show ? this.props.value : ''); + + return (
{value}
); } }; diff --git a/components/board/grid.component.js b/components/board/grid.component.js index 2a62608..dba8402 100644 --- a/components/board/grid.component.js +++ b/components/board/grid.component.js @@ -1,36 +1,20 @@ require('../../sass/board/grid.scss'); import { Component } from 'react'; -import { connect } from 'react-redux'; import GridCell from './grid-cell.component'; -import * as Actions from '../../actions/board/grid.actions'; import { SETTINGS } from '../../App'; export default class Grid extends Component { - componentDidMount(n) { - this.props.dispatch(Actions.generateValues(SETTINGS.GRID_WIDTH * SETTINGS.GRID_HEIGHT, 1)); - }; - render() { - const { values } = this.props; + const { values } = this.props.values; const cells = []; - let i; - for (let x = 0; x < SETTINGS.GRID_WIDTH; x++) { - for (let y = 0; y < SETTINGS.GRID_HEIGHT; y++) { - i = y * SETTINGS.GRID_WIDTH + x; - cells.push(); - } - } + this.props.values.map((v, i) => { + const x = i % SETTINGS.GRID_WIDTH; + const y = Math.floor(i / SETTINGS.GRID_HEIGHT); + cells.push(); + }); 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 46b4a6d..b6ce4c6 100644 --- a/components/board/message.component.js +++ b/components/board/message.component.js @@ -1,58 +1,8 @@ require('../../sass/board/message.scss'); import { Component } from 'react'; -import { connect } from 'react-redux'; -import * as MessageActions from '../../actions/board/message.actions'; - -const exclamations = [ - 'Congratulations!', - 'Yippee!', - 'Woohoo!', - 'Nice work!', - 'Great job!', - 'Boom!', - 'All finished!', - 'Shazam!' -]; - -let listener = null; - -export class Message extends Component { - keydown(e) { - if (e.keyCode === 32) { - this.props.dispatch(MessageActions.hide()); - } - }; - - componentDidMount() { - listener = this.keydown.bind(this); - window.addEventListener('keydown', listener); - }; - - componentWillUnmount() { - window.removeEventListener('keydown', listener); - }; - - // munchFailed(value) { - // var self = this; - // - // // var msg = Values.getError(value, State.level); - // // this.setState({ hidden: false, message1: msg }); - // }; - // - // levelComplete() { - // function keydown(e) { - // if (e.keyCode === 32) { - // window.removeEventListener('keydown', keydown); - // // State.publish('level/next'); - // } - // }; - // - // var msg = exclamations[Math.floor(Math.random() * exclamations.length)]; - // // this.setState({ hidden: false, message1: msg }); - // window.addEventListener('keydown', keydown); - // }; +export default class Message extends Component { render() { var classname = ['message']; @@ -62,16 +12,10 @@ export class Message extends Component { return (
- {this.props.message1} + {this.props.line1}
- {this.props.message2} + {this.props.line2}
); }; }; - -const select = (state) => { - return state.message; -}; - -export default connect(select)(Message); diff --git a/components/board/muncher.component.js b/components/board/muncher.component.js index f015f79..f903cc4 100644 --- a/components/board/muncher.component.js +++ b/components/board/muncher.component.js @@ -1,48 +1,8 @@ require('../../sass/board/muncher.scss'); import { Component } from 'react'; -import { connect } from 'react-redux'; -import * as Actions from '../../actions/board/muncher.actions'; - -let listener = null; - -export class Muncher extends Component { - keydown(e) { - const x = this.props.x; - const y = this.props.y; - - switch (e.keyCode) { - case 32: - this.props.munch(x, y); - break; - - case 37: - this.props.dispatch(Actions.moveLeft()); - break; - - case 38: - this.props.dispatch(Actions.moveUp()); - break; - - case 39: - this.props.dispatch(Actions.moveRight()); - break; - - case 40: - this.props.dispatch(Actions.moveDown()); - break; - } - }; - - componentDidMount() { - listener = this.keydown.bind(this); - window.addEventListener('keydown', listener); - }; - - componentWillUnmount() { - window.removeEventListener('keydown', listener); - }; +export default class Muncher extends Component { render() { const classname = ['muncher', 'x' + this.props.x, 'y' + this.props.y]; @@ -51,9 +11,3 @@ export class Muncher extends Component { ); }; }; - -const select = (state) => { - return state.muncher; -}; - -export default connect(select)(Muncher); diff --git a/components/board/titlebar.component.js b/components/board/titlebar.component.js index 26ee142..a279c10 100644 --- a/components/board/titlebar.component.js +++ b/components/board/titlebar.component.js @@ -3,15 +3,7 @@ require('../../sass/board/titlebar.scss'); import { Component } from 'react'; export default class Titlebar extends Component { - componentDidMount() { - // State.subscribe('level/next', this.levelNext); - }; - - levelNext() { - // this.setState({ title: Values.getDescription(State.level) }); - }; - render() { - return (
DYNAMIC TITLE
); + return (
{this.props.title}
); }; }; diff --git a/index.js b/index.js index a5a42ed..da09496 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,7 @@ import { Provider } from 'react-redux'; import App from './App'; import modeReducer from './reducers/mode.reducer'; import newgameReducer from './reducers/welcome/new-game.reducer'; -import gridReducer from './reducers/board/grid.reducer'; +import boardReducer from './reducers/board/board.reducer'; import muncherReducer from './reducers/board/muncher.reducer'; import scorebarReducer from './reducers/board/scorebar.reducer'; import messageReducer from './reducers/board/message.reducer'; @@ -17,7 +17,7 @@ const reducers = combineReducers({ newgame: newgameReducer, muncher: muncherReducer, scorebar: scorebarReducer, - grid: gridReducer, + board: boardReducer, message: messageReducer }); diff --git a/reducers/Values.js b/reducers/Values.js index 79eb58e..cab023e 100644 --- a/reducers/Values.js +++ b/reducers/Values.js @@ -1,11 +1,21 @@ +const validate = function(value, level) { + return ((value || -1) % (level + 2) === 0); +}; + const Values = { // Anagrams, multiples, equality - generate(n) { - var values = []; - - for (var i = 0; i < n; i++) { - values.push(Math.ceil(Math.random() * 1000)); - } + generate(n, level) { + const values = []; + let v; + + for (let i = 0; i < n; i++) { + v = Math.ceil(Math.random() * 1000); + values.push({ + value: v, + show: true, + valid: validate(v, level) + }); + }; return values; }, @@ -18,21 +28,14 @@ const Values = { return `Oops! ${value} is not a multiple of ${level + 2}.`; }, - validate(value, level) { - return ((value || -1) % (level + 2) === 0); - }, - checkComplete(values, level) { - var len = values.length; - var remaining = 0; - - for (var i = 0; i < len; i++) { - if (module.exports.validate(values[i], level) === true) { - remaining++; + for (let i = 0; i < values.length; i++) { + if (values[i].valid === true && values[i].show === true) { + return false; } } - return (remaining === 0); + return true; } }; diff --git a/reducers/board/board.reducer.js b/reducers/board/board.reducer.js new file mode 100644 index 0000000..4ab6159 --- /dev/null +++ b/reducers/board/board.reducer.js @@ -0,0 +1,42 @@ +const Immutable = require('immutable'); + +import * as BoardActions from '../../actions/board/board.actions'; +import Values from '../Values'; +import { SETTINGS } from '../../App'; + +const initial = { + level: -1, + values: [], + title: 'Setting up...' +}; + +const count = SETTINGS.GRID_WIDTH * SETTINGS.GRID_HEIGHT; + +const reducer = (state = initial, action) => { + if (action.type !== BoardActions.BOARD_ACTION) { + return state; + } + + switch (action.action) { + case BoardActions.UPDATE: + return Immutable.fromJS(state).setIn(['values', action.index, 'value'], action.value).toJS(); + + case BoardActions.SHOW: + return Immutable.fromJS(state).setIn(['values', action.index, 'show'], true).toJS(); + + case BoardActions.HIDE: + return Immutable.fromJS(state).setIn(['values', action.index, 'show'], false).toJS(); + + case BoardActions.NEXT_LEVEL: + const lvl = state.level + 1; + return Immutable.Map(state) + .set('level', lvl) + .set('title', Values.getDescription(lvl)) + .set('values', Values.generate(count, lvl)) + .toObject(); + } + + return state; +}; + +export default reducer; diff --git a/reducers/board/grid.reducer.js b/reducers/board/grid.reducer.js deleted file mode 100644 index 167fbce..0000000 --- a/reducers/board/grid.reducer.js +++ /dev/null @@ -1,24 +0,0 @@ -const Immutable = require('immutable'); - -import * as GridActions from '../../actions/board/grid.actions'; -import Values from '../Values'; - -const initial = []; - -const reducer = (state = initial, action) => { - if (action.type !== GridActions.GRID_ACTION) { - return state; - } - - switch (action.action) { - case GridActions.GENERATE: - return Values.generate(action.count, action.level); - - case GridActions.UPDATE: - return Immutable.List(state).set(action.index, action.value).toArray(); - } - - return state; -}; - -export default reducer; diff --git a/reducers/board/message.reducer.js b/reducers/board/message.reducer.js index 437fc8d..eac90e6 100644 --- a/reducers/board/message.reducer.js +++ b/reducers/board/message.reducer.js @@ -2,7 +2,7 @@ const Immutable = require('immutable'); import * as MessageActions from '../../actions/board/message.actions'; -const initial = { message1: '', message2: '', hidden: true }; +const initial = { line1: '', line2: '', hidden: true }; const reducer = (state = initial, action) => { if (action.type !== MessageActions.MESSAGE_ACTION) { @@ -12,8 +12,8 @@ const reducer = (state = initial, action) => { switch (action.action) { case MessageActions.DISPLAY: return Immutable.Map(state) - .set('message1', action.message1) - .set('message2', action.message2) + .set('line1', action.line1) + .set('line2', action.line2) .set('hidden', false) .toObject(); diff --git a/reducers/board/scorebar.reducer.js b/reducers/board/scorebar.reducer.js index 7eee9d5..c8156ba 100644 --- a/reducers/board/scorebar.reducer.js +++ b/reducers/board/scorebar.reducer.js @@ -11,16 +11,12 @@ const reducer = (state = initial, action) => { return state; } - const result = Immutable.Map(state); - switch (action.action) { - case ScorebarActions.MUNCH: - if (action.success) { - return result.set('current', state.current + 10).toObject(); - } - else { - return result.set('lives', state.lives - 1).toObject(); - } + case ScorebarActions.MUNCH_SUCCEEDED: + return Immutable.Map(state).set('current', state.current + 10).toObject(); + + case ScorebarActions.MUNCH_FAILED: + return Immutable.Map(state).set('lives', state.lives - 1).toObject(); } return state;