Starting Troggle AI.

master
Ben Burlingham 9 years ago
parent 4c671ec007
commit 568af65c07
  1. 4
      App.js
  2. 6
      actions/board/message.actions.js
  3. 12
      actions/board/muncher.actions.js
  4. 16
      actions/board/troggle.actions.js
  5. 139
      components/board/board.component.js
  6. 2
      components/board/grid.component.js
  7. 4
      components/board/message.component.js
  8. 57
      components/board/muncher.component.js
  9. 13
      components/board/troggle.component.js
  10. 1
      components/welcome/welcome.component.js
  11. 4
      index.js
  12. 5
      reducers/board/message.reducer.js
  13. 30
      reducers/board/muncher.reducer.js
  14. 71
      reducers/board/troggle.reducer.js
  15. 10
      sass/board/troggle.scss

@ -7,8 +7,8 @@ import Board from './components/board/board.component';
import Welcome from './components/welcome/welcome.component'; import Welcome from './components/welcome/welcome.component';
export const SETTINGS = { export const SETTINGS = {
GRID_WIDTH: 3, GRID_WIDTH: 6,
GRID_HEIGHT: 3, GRID_HEIGHT: 5,
LIVES: 3 LIVES: 3
}; };

@ -2,12 +2,10 @@ export const MESSAGE_ACTION = 'MESSAGE_ACTION';
export const DISPLAY = 'DISPLAY'; export const DISPLAY = 'DISPLAY';
export const HIDE = 'HIDE'; export const HIDE = 'HIDE';
export const display = (line1, line2, hidden) => ({ export const display = (message) => ({
type: MESSAGE_ACTION, type: MESSAGE_ACTION,
action: DISPLAY, action: DISPLAY,
line1: line1, message: message
line2: line2,
hidden: hidden
}); });
export const hide = () => ({ export const hide = () => ({

@ -4,6 +4,8 @@ export const RIGHT = 'RIGHT';
export const UP = 'UP'; export const UP = 'UP';
export const DOWN = 'DOWN'; export const DOWN = 'DOWN';
export const MUNCH = 'MUNCH'; export const MUNCH = 'MUNCH';
export const FREEZE = 'FREEZE';
export const UNFREEZE = 'UNFREEZE';
export const moveLeft = () => ({ export const moveLeft = () => ({
type: MUNCHER_ACTION, type: MUNCHER_ACTION,
@ -29,3 +31,13 @@ export const munch = (x, y) => ({
type: MUNCHER_ACTION, type: MUNCHER_ACTION,
action: MUNCH action: MUNCH
}); });
export const freeze = () => ({
type: MUNCHER_ACTION,
action: FREEZE
});
export const unfreeze = () => ({
type: MUNCHER_ACTION,
action:UNFREEZE
});

@ -0,0 +1,16 @@
export const TROGGLE_ACTION = 'TROGGLE_ACTION';
export const CREATE = 'CREATE';
export const MOVE = 'MOVE';
export const create = () => ({
type: TROGGLE_ACTION,
action: CREATE
});
export const move = (index, muncherX, muncherY) => ({
type: TROGGLE_ACTION,
action: MOVE,
index: index,
muncherX: muncherX,
muncherY: muncherY
});

@ -8,14 +8,16 @@ import Titlebar from './titlebar.component';
import Grid from './grid.component'; import Grid from './grid.component';
import Message from './message.component'; import Message from './message.component';
import Muncher from './muncher.component'; import Muncher from './muncher.component';
import Troggle from './troggle.component';
import Values from '../../reducers/Values'; import Values from '../../reducers/Values';
import { SETTINGS } from '../../App'; import { SETTINGS } from '../../App';
import * as BoardActions from '../../actions/board/board.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 ScorebarActions from '../../actions/board/scorebar.actions';
import * as MessageActions from '../../actions/board/message.actions'; import * as MessageActions from '../../actions/board/message.actions';
import * as MuncherActions from '../../actions/board/muncher.actions';
import * as TroggleActions from '../../actions/board/troggle.actions';
const exclamations = [ const exclamations = [
'Congratulations!', 'Congratulations!',
@ -28,95 +30,101 @@ const exclamations = [
'Shazam!' 'Shazam!'
]; ];
let muncherListener = null; const troggleMoveTimers = [];
let messageListener = null; const troggleCreateTimers = [];
export default class Board extends Component {
componentDidMount(n) {
muncherListener = this.muncherKeydown.bind(this);
messageListener = this.messageKeydown.bind(this);
window.addEventListener('keydown', muncherListener); // const toggleMoveTimeout = function() {
// window.addEventListener('keydown', messageListener); // this.props.dispatch(TroggleActions.move());
// };
this.props.dispatch(BoardActions.nextLevel()); const continuations = {
}; muncher: null,
message: null
};
muncherKeydown(e) { let listener = null;
switch (e.keyCode) {
case 32:
this.munch();
break;
case 37: export default class Board extends Component {
this.props.dispatch(MuncherActions.moveLeft()); nextLevel() {
break; this.props.dispatch(BoardActions.nextLevel());
case 38: const troggleCount = 1; //Math.min(Math.ceil(this.props.board.level / 2), 5);
this.props.dispatch(MuncherActions.moveUp()); for (let i = 0; i < troggleCount; i++) {
break; this.props.dispatch(TroggleActions.create());
troggleMoveTimers.push(setTimeout(this.moveTroggle.bind(this, i), 1000));
}
case 39: // toggleTimeout.call(this);
this.props.dispatch(MuncherActions.moveRight()); };
break;
case 40: componentDidMount() {
this.props.dispatch(MuncherActions.moveDown()); listener = this.keydown.bind(this);
break; window.addEventListener('keydown', listener);
} this.nextLevel();
}; };
messageKeydown(e) { componentWillUnmount() {
if (e.keyCode === 32) { window.removeEventListener('keydown', listener);
window.removeEventListener('keydown', messageListener);
window.addEventListener('keydown', muncherListener);
this.props.dispatch(MessageActions.hide()); // destroy all troggle timers
}
}; };
componentWillUnmount() { moveTroggle(index) {
window.removeEventListener('keydown', muncherListener); this.props.dispatch(TroggleActions.move(index));
window.removeEventListener('keydown', messageListener); clearTimeout(troggleMoveTimers[index]);
troggleMoveTimers[index] = setTimeout(this.moveTroggle.bind(this, index), 1000);
}; };
munch() { // Keydown listener for spacebar, since it is bound to munch event and
const { board, muncher, dispatch } = this.props; // message hide event. Couldn't find a more modular way to do this.
const index = muncher.y * SETTINGS.GRID_HEIGHT + muncher.x; keydown(e) {
if (e.keyCode !== 32) {
return;
}
dispatch(MuncherActions.munch()); if (this.props.message.hidden === false) {
this.props.dispatch(MessageActions.hide());
this.props.dispatch(MuncherActions.unfreeze());
if (board.values[index].valid) { if (Values.checkComplete(this.props.board.values, this.props.board.level)) {
dispatch(BoardActions.hideValue(index)); console.warn("NEXT LEVEL")
dispatch(ScorebarActions.munchSucceeded()); }
} }
else { else {
window.removeEventListener('keydown', muncherListener); const index = this.props.muncher.y * SETTINGS.GRID_HEIGHT + this.props.muncher.x
window.addEventListener('keydown', messageListener); const { board, dispatch } = this.props;
const msg = Values.getError(board.values[index].value, board.level); if (board.values[index].valid) {
dispatch(MessageActions.display(msg, 'Press Spacebar to Continue')); dispatch(BoardActions.hideValue(index));
dispatch(ScorebarActions.munchFailed()); dispatch(ScorebarActions.munchSucceeded());
} }
else {
if (Values.checkComplete(this.props.board.values, board.level)) { const msg = Values.getError(board.values[index].value, board.level);
window.removeEventListener('keydown', muncherListener); dispatch(MessageActions.display(msg));
window.addEventListener('keydown', messageListener); dispatch(ScorebarActions.munchFailed());
dispatch(MuncherActions.freeze());
const msg = exclamations[Math.floor(Math.random() * exclamations.length)]; }
dispatch(MessageActions.display(msg, 'Press Spacebar to Continue'));
dispatch(BoardActions.nextLevel()); if (Values.checkComplete(this.props.board.values, board.level)) {
const msg = exclamations[Math.floor(Math.random() * exclamations.length)];
dispatch(MessageActions.display(msg));
}
} }
}; };
render() { render() {
const { board, muncher, message } = this.props; const { board, message, troggles } = this.props;
const troggleElements = [];
for (let i = 0; i < troggles.length; i++) {
troggleElements.push(<Troggle x={troggles[i].x} y={troggles[i].y} key={i} />);
}
return (<div className='board'> return (<div className='board'>
<Scorebar /> <Scorebar />
<Titlebar title={board.title} /> <Titlebar title={board.title} />
<Message hidden={message.hidden} line1={message.line1} line2={message.line2} /> <Message hidden={message.hidden} message={message.message} />
<Muncher x={muncher.x} y={muncher.y} /> <Muncher />
{troggleElements}
<Grid values={board.values} /> <Grid values={board.values} />
</div>); </div>);
}; };
@ -126,7 +134,8 @@ const select = (state) => {
return { return {
board: state.board, board: state.board,
muncher: state.muncher, muncher: state.muncher,
message: state.message message: state.message,
troggles: state.troggles
}; };
} }

@ -11,7 +11,7 @@ export default class Grid extends Component {
this.props.values.map((v, i) => { this.props.values.map((v, i) => {
const x = i % SETTINGS.GRID_WIDTH; const x = i % SETTINGS.GRID_WIDTH;
const y = Math.floor(i / SETTINGS.GRID_HEIGHT); const y = Math.floor(i / SETTINGS.GRID_WIDTH);
cells.push(<GridCell value={v.value} show={v.show} x={x} y={y} key={i} />); cells.push(<GridCell value={v.value} show={v.show} x={x} y={y} key={i} />);
}); });

@ -12,9 +12,9 @@ export default class Message extends Component {
return ( return (
<div className={classname.join(' ')}> <div className={classname.join(' ')}>
{this.props.line1} {this.props.message}
<br /> <br />
{this.props.line2} Press Spacebar to continue.
</div> </div>
); );
}; };

@ -1,8 +1,57 @@
require('../../sass/board/muncher.scss'); require('../../sass/board/muncher.scss');
import { Component } from 'react'; import { Component } from 'react';
import { connect } from 'react-redux';
import * as MuncherActions from '../../actions/board/muncher.actions';
import { SETTINGS } from '../../App';
let listener = null;
export class Muncher extends Component {
componentDidMount() {
listener = this.keydown.bind(this);
window.addEventListener('keydown', listener);
};
componentWillUnmount() {
window.removeEventListener('keydown', listener);
};
keydown(e) {
if (this.props.frozen === true) {
return;
}
const x = this.props.x;
const y = this.props.y;
switch (e.keyCode) {
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;
}
};
export default class Muncher extends Component {
render() { render() {
const classname = ['muncher', 'x' + this.props.x, 'y' + this.props.y]; const classname = ['muncher', 'x' + this.props.x, 'y' + this.props.y];
@ -11,3 +60,9 @@ export default class Muncher extends Component {
); );
}; };
}; };
const select = (state) => {
return state.muncher;
}
export default connect(select)(Muncher);

@ -0,0 +1,13 @@
require('../../sass/board/troggle.scss');
import { Component } from 'react';
export default class Muncher extends Component {
render() {
const classname = ['troggle', 'x' + this.props.x, 'y' + this.props.y];
return (
<div className={classname.join(' ')}></div>
);
};
};

@ -6,7 +6,6 @@ import NewGame from './new-game.component';
import HighScores from './high-scores.component'; import HighScores from './high-scores.component';
export default class Welcome extends Component { export default class Welcome extends Component {
render() { render() {
return ( return (
<div className='welcome'> <div className='welcome'>

@ -11,6 +11,7 @@ import boardReducer from './reducers/board/board.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';
import troggleReducer from './reducers/board/troggle.reducer';
const reducers = combineReducers({ const reducers = combineReducers({
mode: modeReducer, mode: modeReducer,
@ -18,7 +19,8 @@ const reducers = combineReducers({
muncher: muncherReducer, muncher: muncherReducer,
scorebar: scorebarReducer, scorebar: scorebarReducer,
board: boardReducer, board: boardReducer,
message: messageReducer message: messageReducer,
troggles: troggleReducer
}); });
const store = createStore(reducers); const store = createStore(reducers);

@ -2,7 +2,7 @@ const Immutable = require('immutable');
import * as MessageActions from '../../actions/board/message.actions'; import * as MessageActions from '../../actions/board/message.actions';
const initial = { line1: '', line2: '', hidden: true }; const initial = { message: '', hidden: true };
const reducer = (state = initial, action) => { const reducer = (state = initial, action) => {
if (action.type !== MessageActions.MESSAGE_ACTION) { if (action.type !== MessageActions.MESSAGE_ACTION) {
@ -12,9 +12,8 @@ const reducer = (state = initial, action) => {
switch (action.action) { switch (action.action) {
case MessageActions.DISPLAY: case MessageActions.DISPLAY:
return Immutable.Map(state) return Immutable.Map(state)
.set('line1', action.line1)
.set('line2', action.line2)
.set('hidden', false) .set('hidden', false)
.set('message', action.message)
.toObject(); .toObject();
case MessageActions.HIDE: case MessageActions.HIDE:

@ -1,7 +1,8 @@
const Immutable = require('immutable');
import * as MuncherActions from '../../actions/board/muncher.actions'; import * as MuncherActions from '../../actions/board/muncher.actions';
import { SETTINGS } from '../../App'; import { SETTINGS } from '../../App';
const initial = { x: 0, y: 0 }; const initial = { x: 0, y: 0, frozen: false };
const reducer = (state = initial, action) => { const reducer = (state = initial, action) => {
if (action.type !== MuncherActions.MUNCHER_ACTION) { if (action.type !== MuncherActions.MUNCHER_ACTION) {
@ -10,31 +11,22 @@ const reducer = (state = initial, action) => {
switch (action.action) { switch (action.action) {
case MuncherActions.LEFT: case MuncherActions.LEFT:
if (state.x === 0) { return Immutable.Map(state).set('x', state.x - 1).toObject();
return state;
}
return { x: state.x - 1, y: state.y };
case MuncherActions.RIGHT: case MuncherActions.RIGHT:
if (state.x === SETTINGS.GRID_WIDTH - 1) { return Immutable.Map(state).set('x', state.x + 1).toObject();
return state;
}
return { x: state.x + 1, y: state.y };
case MuncherActions.UP: case MuncherActions.UP:
if (state.y === 0) { return Immutable.Map(state).set('y', state.y - 1).toObject();
return state;
}
return { x: state.x, y: state.y - 1 };
case MuncherActions.DOWN: case MuncherActions.DOWN:
if (state.y === SETTINGS.GRID_HEIGHT - 1) { return Immutable.Map(state).set('y', state.y + 1).toObject();
return state;
}
return { x: state.x, y: state.y + 1 };
case MuncherActions.MUNCH: case MuncherActions.FREEZE:
return state; return Immutable.Map(state).set('frozen', true).toObject();
case MuncherActions.UNFREEZE:
return Immutable.Map(state).set('frozen', false).toObject();
} }
return state; return state;

@ -0,0 +1,71 @@
const Immutable = require('immutable');
import * as TroggleActions from '../../actions/board/troggle.actions';
import { SETTINGS } from '../../App';
const initial = [];
const reducer = (state = initial, action) => {
if (action.type !== TroggleActions.TROGGLE_ACTION) {
return state;
}
switch (action.action) {
case TroggleActions.MOVE:
// Randomize movement with boolean flags.
const moveToAttack = Boolean(Math.round(Math.random()));
const moveAlongXAxis = Boolean(Math.round(Math.random()));
const moveInPositiveDirection = Boolean(Math.round(Math.random()));
const x = state[action.index].x;
const y = state[action.index].y;
let newX = x;
let newY = y;
// DO NOT CONSOLIDATE. Attack first, ask questions later.
if (moveAlongXAxis === true) {
if (x === SETTINGS.GRID_WIDTH - 1 ||
(moveToAttack && x >= action.muncherX)) {
newX = x - 1;
}
else if (x === 0 ||
(moveToAttack && x < action.muncherX)) {
newX = x + 1;
}
else if (moveInPositiveDirection) {
newX = x + 1;
}
else if (!moveInPositiveDirection) {
newX = x - 1;
}
}
else {
if (y === SETTINGS.GRID_HEIGHT - 1 ||
(moveToAttack && y >= action.muncherY)) {
newY = y - 1;
}
else if (y === 0 ||
(moveToAttack && y < action.muncherY)) {
newY = y + 1;
}
else if (moveInPositiveDirection) {
newY = y + 1;
}
else if (!moveInPositiveDirection) {
newY = y - 1;
}
}
return Immutable.fromJS(state)
.setIn([action.index, 'x'], newX)
.setIn([action.index, 'y'], newY)
.toJS();
case TroggleActions.CREATE:
return Immutable.List(state).push({ x: 0, y: 0 }).toArray();
break;
}
return state;
};
export default reducer;

@ -0,0 +1,10 @@
.troggle {
$bg: crimson;
background: $bg;
height:100px;
margin-top:110px;
opacity: 0.5;
position:absolute;
width:100px;
}
Loading…
Cancel
Save