Extracting logic into separate objects and simplifying dependencies.

master
Ben Burlingham 9 years ago
parent 49baf89a5e
commit faeae93892
  1. 11
      actions/board/grid.actions.js
  2. 42
      actions/board/muncher.actions.js
  3. 81
      components/board/board.component.js
  4. 17
      components/board/grid.component.js
  5. 10
      components/board/message.component.js
  6. 54
      components/board/muncher.component.js
  7. 2
      components/board/titlebar.component.js
  8. 4
      index.js
  9. 67
      logic/board.logic.js
  10. 27
      logic/grid.logic.js
  11. 9
      logic/message.logic.js
  12. 46
      logic/muncher.logic.js
  13. 4
      logic/values.logic.js
  14. 20
      reducers/board/grid.reducer.js
  15. 12
      reducers/board/message.reducer.js
  16. 25
      reducers/board/muncher.reducer.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;

@ -1,43 +1,7 @@
export const MUNCHER_ACTION = 'MUNCHER_ACTION'; export const MUNCHER_ACTION = 'MUNCHER_ACTION';
export const LEFT = 'LEFT'; export const UPDATE = 'UPDATE';
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 moveLeft = () => ({ export const update = () => ({
type: MUNCHER_ACTION, type: MUNCHER_ACTION,
action: LEFT action: UPDATE
});
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
}); });

@ -2,7 +2,7 @@ require('../../sass/board/board.scss');
import { Component } from 'react'; import { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getState } from 'react-redux';
import Scorebar from './scorebar.component'; import Scorebar from './scorebar.component';
import Titlebar from './titlebar.component'; import Titlebar from './titlebar.component';
import Grid from './grid.component'; import Grid from './grid.component';
@ -10,82 +10,33 @@ import Message from './message.component';
import Muncher from './muncher.component'; import Muncher from './muncher.component';
import Troggles from './troggles.component'; import Troggles from './troggles.component';
import ValuesLogic from '../../logic/values.logic.js'; import BoardLogic from '../../logic/board.logic';
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';
let nextLevelFlag = false; let listener;
export default class Board extends Component { export class Board extends Component {
componentDidMount() { componentDidMount() {
this.nextLevel(); BoardLogic.setDispatch(this.props.dispatch);
}; BoardLogic.nextLevel();
nextLevel() {
this.props.dispatch(BoardActions.nextLevel());
TroggleLogic.clearAll(this.props.dispatch);
TroggleLogic.createTroggles(this.props.dispatch);
};
messageNext() { listener = BoardLogic.keyListener.bind(BoardLogic);
if (nextLevelFlag === true) { window.addEventListener('keydown', listener);
this.nextLevel();
nextLevelFlag = false;
}
this.props.dispatch(MessageActions.hide());
ReactDOM.findDOMNode(this.refs.muncher).focus();
}; };
muncherNext(x, y) { componentWillUnmount() {
const index = y * SETTINGS.GRID_WIDTH + x; window.removeEventListener('keydown', listener);
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();
// }
}; };
render() { render() {
return (<div className='board'> return (<div className='board'>
<Scorebar /> <Scorebar />
<Titlebar title={this.props.title} /> <Muncher />
<Message ref='message' next={this.messageNext.bind(this)} /> <Message />
<Grid values={this.props.values} /> <Titlebar />
<Muncher ref='muncher' onMunch={this.muncherNext.bind(this)} /> <Grid />
<Troggles ref='troggles' /> <Troggles />
</div>); </div>);
}; };
}; };
const select = (state) => { export default connect()(Board)
return state.board;
}
export default connect(select)(Board);

@ -1,10 +1,17 @@
require('../../sass/board/grid.scss'); require('../../sass/board/grid.scss');
import { Component } from 'react'; import { Component } from 'react';
import { connect } from 'react-redux';
import GridCell from './grid-cell.component'; import GridCell from './grid-cell.component';
import GridActions from '../../actions/board/grid.actions';
import { SETTINGS } from '../../App'; import { SETTINGS } from '../../App';
export default class Grid extends Component { export class Grid extends Component {
componentDidMount() {
this.props.dispatch(GridActions.update());
};
render() { render() {
const { values } = this.props.values; const { values } = this.props.values;
const cells = []; const cells = [];
@ -18,3 +25,11 @@ export default class Grid extends Component {
return (<div className='grid'>{cells}</div>); return (<div className='grid'>{cells}</div>);
}; };
}; };
const select = (state) => {
return {
values: state.grid
}
}
export default connect(select)(Grid);

@ -8,12 +8,12 @@ let refocusListener = null;
export class Message extends Component { export class Message extends Component {
componentDidMount() { componentDidMount() {
refocusListener = this.refocus.bind(this); // refocusListener = this.refocus.bind(this);
window.addEventListener('click', refocusListener); // window.addEventListener('click', refocusListener);
}; };
componentWillUnmount() { componentWillUnmount() {
window.removeEventListener('click', refocusListener); // window.removeEventListener('click', refocusListener);
}; };
refocus() { refocus() {
@ -33,8 +33,10 @@ export class Message extends Component {
classname.push('hidden'); classname.push('hidden');
} }
//<div className={classname.join(' ')} tabIndex='1' onKeyDown={this.keydown.bind(this)}>
return ( return (
<div className={classname.join(' ')} tabIndex='1' onKeyDown={this.keydown.bind(this)}> <div className={classname.join(' ')}>
{this.props.message} {this.props.message}
<br /> <br />
Press Spacebar to continue. Press Spacebar to continue.

@ -2,65 +2,13 @@ require('../../sass/board/muncher.scss');
import { Component } from 'react'; import { Component } from 'react';
import { connect } from 'react-redux'; 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 { 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() { render() {
const classname = ['muncher', 'x' + this.props.x, 'y' + this.props.y]; const classname = ['muncher', 'x' + this.props.x, 'y' + this.props.y];
return ( return (
<div className={classname.join(' ')} tabIndex='1' onKeyDown={this.keydown.bind(this)}></div> <div className={classname.join(' ')}></div>
); );
}; };
}; };

@ -4,6 +4,6 @@ import { Component } from 'react';
export default class Titlebar extends Component { export default class Titlebar extends Component {
render() { render() {
return (<div className='titlebar'>{this.props.title}</div>); return (<div className='titlebar'>Connect titlebar</div>);
}; };
}; };

@ -8,6 +8,7 @@ import App from './App';
import modeReducer from './reducers/mode.reducer'; import modeReducer from './reducers/mode.reducer';
import newgameReducer from './reducers/welcome/new-game.reducer'; import newgameReducer from './reducers/welcome/new-game.reducer';
import boardReducer from './reducers/board/board.reducer'; import boardReducer from './reducers/board/board.reducer';
import gridReducer from './reducers/board/grid.reducer';
import muncherReducer from './reducers/board/muncher.reducer'; import muncherReducer from './reducers/board/muncher.reducer';
import scorebarReducer from './reducers/board/scorebar.reducer'; import scorebarReducer from './reducers/board/scorebar.reducer';
import messageReducer from './reducers/board/message.reducer'; import messageReducer from './reducers/board/message.reducer';
@ -20,7 +21,8 @@ const reducers = combineReducers({
scorebar: scorebarReducer, scorebar: scorebarReducer,
board: boardReducer, board: boardReducer,
message: messageReducer, message: messageReducer,
troggles: troggleReducer troggles: troggleReducer,
grid: gridReducer
}); });
const store = createStore(reducers); const store = createStore(reducers);

@ -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;

@ -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;

@ -0,0 +1,9 @@
let show = false;
const MessageLogic = {
hide: () => show = false,
show: () => show = true,
isShowing: () => show
};
export default MessageLogic;

@ -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;

@ -4,7 +4,7 @@ const validate = function(value, level) {
return ((value || -1) % (level + 2) === 0); return ((value || -1) % (level + 2) === 0);
}; };
const Values = { const ValuesLogic = {
// Anagrams, multiples, equality // Anagrams, multiples, equality
generate(n, level) { generate(n, level) {
const values = []; const values = [];
@ -41,4 +41,4 @@ const Values = {
} }
}; };
export default Values; export default ValuesLogic;

@ -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;

@ -1,5 +1,8 @@
const Immutable = require('immutable'); const Immutable = require('immutable');
import * as MessageActions from '../../actions/board/message.actions';
import MessageLogic from '../../logic/message.logic';
const exclamations = [ const exclamations = [
'Congratulations!', 'Congratulations!',
'Yippee!', 'Yippee!',
@ -11,9 +14,6 @@ const exclamations = [
'Shazam!' 'Shazam!'
]; ];
import * as MessageActions from '../../actions/board/message.actions';
import TroggleLogic from '../../logic/troggle.logic.js';
const initial = { message: '', hidden: true }; const initial = { message: '', hidden: true };
const reducer = (state = initial, action) => { const reducer = (state = initial, action) => {
@ -23,7 +23,7 @@ const reducer = (state = initial, action) => {
switch (action.action) { switch (action.action) {
case MessageActions.EXCLAIM: case MessageActions.EXCLAIM:
TroggleLogic.frozen = true; MessageLogic.show();
const msg = exclamations[Math.floor(Math.random() * exclamations.length)]; const msg = exclamations[Math.floor(Math.random() * exclamations.length)];
return Immutable.Map(state) return Immutable.Map(state)
.set('hidden', false) .set('hidden', false)
@ -31,14 +31,14 @@ const reducer = (state = initial, action) => {
.toObject(); .toObject();
case MessageActions.SHOW: case MessageActions.SHOW:
TroggleLogic.frozen = true; MessageLogic.show();
return Immutable.Map(state) return Immutable.Map(state)
.set('hidden', false) .set('hidden', false)
.set('message', action.message) .set('message', action.message)
.toObject(); .toObject();
case MessageActions.HIDE: case MessageActions.HIDE:
TroggleLogic.frozen = false; MessageLogic.hide();
return Immutable.Map(state) return Immutable.Map(state)
.set('hidden', true) .set('hidden', true)
.toObject(); .toObject();

@ -1,5 +1,6 @@
const Immutable = require('immutable'); const Immutable = require('immutable');
import * as MuncherActions from '../../actions/board/muncher.actions'; import * as MuncherActions from '../../actions/board/muncher.actions';
import MuncherLogic from '../../logic/muncher.logic';
import { SETTINGS } from '../../App'; import { SETTINGS } from '../../App';
const initial = { x: 0, y: 0, frozen: false }; const initial = { x: 0, y: 0, frozen: false };
@ -9,24 +10,12 @@ const reducer = (state = initial, action) => {
return state; return state;
} }
switch (action.action) { if (action.action === MuncherActions.UPDATE) {
case MuncherActions.LEFT: return Immutable.Map(state)
return Immutable.Map(state).set('x', state.x - 1).toObject(); .set('x', MuncherLogic.getX())
.set('y', MuncherLogic.getY())
case MuncherActions.RIGHT: .set('frozen', false)
return Immutable.Map(state).set('x', state.x + 1).toObject(); .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();
} }
return state; return state;

Loading…
Cancel
Save