diff --git a/AppSettings.js b/AppSettings.js
index c5d63de..906dc13 100644
--- a/AppSettings.js
+++ b/AppSettings.js
@@ -1,7 +1,8 @@
const SETTINGS = {
GRID_WIDTH: 6,
GRID_HEIGHT: 5,
- LIVES: 3
+ LIVES: 3,
+ LOCAL_STORAGE_KEY: 'number-munchers-high-scores'
};
export default SETTINGS;
diff --git a/actions/welcome/new-game.actions.js b/actions/welcome/new-game.actions.js
deleted file mode 100644
index 8622a33..0000000
--- a/actions/welcome/new-game.actions.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// New game component actions and action creators.
-export const NEWGAME_ACTION = 'NEWGAME_ACTION';
-export const BLINK = 'BLINK';
-
-export const blink = () => ({
- type: NEWGAME_ACTION,
- action: BLINK
-});
diff --git a/actions/welcome/welcome.actions.js b/actions/welcome/welcome.actions.js
new file mode 100644
index 0000000..521bcbc
--- /dev/null
+++ b/actions/welcome/welcome.actions.js
@@ -0,0 +1,15 @@
+export const WELCOME_ACTION = 'WELCOME_ACTION';
+export const UPDATE_SCORES = 'WELCOME_UPDATE_SCORES';
+export const UPDATE_INITIALS = 'WELCOME_UDPATE_INITIALS';
+
+export const updateScores = (scores) => ({
+ type: WELCOME_ACTION,
+ action: UPDATE_SCORES,
+ scores: scores
+});
+
+export const updateInitials = (initials) => ({
+ type: WELCOME_ACTION,
+ action: UPDATE_INITIALS,
+ initials: initials
+});
diff --git a/components/welcome/high-score-entry.component.js b/components/welcome/high-score.component.js
similarity index 100%
rename from components/welcome/high-score-entry.component.js
rename to components/welcome/high-score.component.js
diff --git a/components/welcome/high-scores.component.js b/components/welcome/high-scores.component.js
deleted file mode 100644
index 19868fc..0000000
--- a/components/welcome/high-scores.component.js
+++ /dev/null
@@ -1,26 +0,0 @@
-require('../../sass/welcome/highscores.scss');
-
-import { Component } from 'react';
-import HighScoreEntry from './high-score-entry.component';
-
-export default class HighScores extends Component {
- render() {
- const vals = [
- { initials: "ABA", score: "219283", rank: "1" },
- { initials: "ABA", score: "107112", rank: "2" },
- { initials: "ABA", score: "81091", rank: "3" },
- { initials: "ABA", score: "67747", rank: "4" },
- { initials: "ABA", score: "9283", rank: "5" },
- { initials: "ABA", score: "928", rank: "6" }
- ];
-
- var entries = [];
- vals.map(function(v, i) {
- entries.push();
- });
-
- return (
-
{entries}
- );
- }
-};
diff --git a/components/welcome/initials.component.js b/components/welcome/initials.component.js
new file mode 100644
index 0000000..d108c4c
--- /dev/null
+++ b/components/welcome/initials.component.js
@@ -0,0 +1,42 @@
+import { Component } from 'react';
+import { connect } from 'react-redux';
+
+import InitialsCtrl from '../../controllers/welcome/initials.controller';
+
+export class Initials extends Component {
+ componentDidMount() {
+ InitialsCtrl.setDispatch(this.props.dispatch);
+ };
+
+ render() {
+ const class1 = ['initial'];
+ const class2 = ['initial'];
+ const class3 = ['initial'];
+
+ if (this.props.initials[0].active === true) {
+ class1.push('blink');
+ }
+ if (this.props.initials[1].active === true) {
+ class2.push('blink');
+ }
+ if (this.props.initials[2].active === true) {
+ class3.push('blink');
+ }
+
+ return (
+
+
{this.props.initials[0].initial}
+
{this.props.initials[1].initial}
+
{this.props.initials[2].initial}
+
+ );
+ };
+};
+
+const select = (state) => {
+ return {
+ initials: state.welcome.initials
+ }
+};
+
+export default connect(select)(Initials);
diff --git a/components/welcome/new-game.component.js b/components/welcome/new-game.component.js
deleted file mode 100644
index 768cbac..0000000
--- a/components/welcome/new-game.component.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import { Component } from 'react';
-import { connect } from 'react-redux';
-
-import * as ModeActions from '../../actions/mode.actions';
-import * as NewGameActions from '../../actions/welcome/new-game.actions';
-
-let blinkTimer = null;
-let newgameListener = null;
-
-const toggleTimeout = function() {
- var hidden = this.props.blink;
- this.props.dispatch(NewGameActions.blink());
- blinkTimer = setTimeout(toggleTimeout.bind(this), 600);
-};
-
-export default class NewGame extends Component {
- componentDidMount() {
- newgameListener = this.handleKeydown.bind(this);
- window.addEventListener('keydown', newgameListener);
- toggleTimeout.call(this);
- };
-
- componentWillUnmount() {
- window.removeEventListener('keydown', newgameListener);
- clearTimeout(blinkTimer);
- };
-
- handleKeydown(e) {
- if (e.keyCode === 32) {
- this.props.dispatch(ModeActions.options());
- }
- };
-
- render() {
- const classname = ['newgame'];
-
- if (this.props.hidden === true) {
- classname.push('hidden');
- }
-
- return (
- Press Space Bar To Play
- );
- };
-};
-
-const select = (state) => {
- return state.newgame;
-};
-
-export default connect(select)(NewGame);
diff --git a/components/welcome/welcome.component.js b/components/welcome/welcome.component.js
index c6158cc..2385d95 100644
--- a/components/welcome/welcome.component.js
+++ b/components/welcome/welcome.component.js
@@ -1,18 +1,50 @@
require('../../sass/welcome/welcome.scss');
import { Component } from 'react';
+import { connect } from 'react-redux';
+import Initials from './initials.component';
-import NewGame from './new-game.component';
-import HighScores from './high-scores.component';
+import * as ModeActions from '../../actions/mode.actions';
+import WelcomeCtrl from '../../controllers/welcome/welcome.controller';
+
+let listener;
+
+export class Welcome extends Component {
+ componentDidMount() {
+ listener = WelcomeCtrl.keydown.bind(WelcomeCtrl);
+ window.addEventListener('keydown', listener);
+
+ // HighScoreCtrl.setDispatch(this.props.dispatch);
+ // HighScoreCtrl.retrieveScores();
+ // HighScoreCtrl.updateScores(ScorebarCtrl.currentScore);
+ };
+
+ componentWillUnmount() {
+ window.removeEventListener('keydown', listener);
+ };
-export default class Welcome extends Component {
render() {
+ // var entries = [];
+ // this.props.values.map(function(v, i) {
+ // entries.push();
+ // });
+
return (

-
-
+
Press Spacebar for new game
+
New high score!
+
Enter your initials:
+
);
};
};
+
+const select = (state) => {
+ return {
+ values: state.welcome.scores
+ }
+};
+
+export default connect(select)(Welcome);
diff --git a/controllers/board/board.controller.js b/controllers/board/board.controller.js
index d743e4c..a3b97e8 100644
--- a/controllers/board/board.controller.js
+++ b/controllers/board/board.controller.js
@@ -6,6 +6,7 @@ import MuncherCtrl from './muncher.controller';
import GridCtrl from './grid.controller';
import TitlebarCtrl from './titlebar.controller';
import ScorebarCtrl from './scorebar.controller';
+import WelcomeCtrl from '../welcome/welcome.controller';
import ModeCtrl from '../mode.controller';
let level = -1;
@@ -51,13 +52,14 @@ const BoardCtrl = {
}
else if (ScorebarCtrl.isGameOver()) {
level = -1;
+ WelcomeCtrl.gameOver(ScorebarCtrl.getCurrentScore());
ScorebarCtrl.reset();
MessageCtrl.hide();
TroggleCtrl.unfreeze();
ModeCtrl.welcome();
}
else if (ScorebarCtrl.getLives() === 0) {
- ScorebarCtrl.flagGameOver();
+ ScorebarCtrl.gameOver();
MessageCtrl.show("Game over!");
}
else if (GridCtrl.isCompleted() === true) {
diff --git a/controllers/board/grid.controller.js b/controllers/board/grid.controller.js
index 821ccbb..7be27b6 100644
--- a/controllers/board/grid.controller.js
+++ b/controllers/board/grid.controller.js
@@ -1,5 +1,5 @@
import * as GridActions from '../../actions/board/grid.actions';
-import SubtractionModel from '../../models/subtraction.model';
+import FactorsModel from '../../models/factors.model';
import SETTINGS from '../../AppSettings';
let values;
@@ -10,12 +10,12 @@ const GridCtrl = {
getValues: () => values,
generateValues: (level) => {
- values = SubtractionModel.generate(SETTINGS.GRID_WIDTH * SETTINGS.GRID_HEIGHT, level);
+ values = FactorsModel.generate(SETTINGS.GRID_WIDTH * SETTINGS.GRID_HEIGHT, level);
dispatch(GridActions.update(values));
},
isCompleted: (level) => {
- return SubtractionModel.checkComplete(values, level)
+ return FactorsModel.checkComplete(values, level)
},
hideValue: (index) => {
diff --git a/controllers/board/scorebar.controller.js b/controllers/board/scorebar.controller.js
index dc2f703..23e46df 100644
--- a/controllers/board/scorebar.controller.js
+++ b/controllers/board/scorebar.controller.js
@@ -1,21 +1,32 @@
import * as ScorebarActions from '../../actions/board/scorebar.actions';
import SETTINGS from '../../AppSettings';
+const stored = localStorage.getItem(SETTINGS.LOCAL_STORAGE_KEY) || [{ score: 0 }];
+
let dispatch;
let lives = SETTINGS.LIVES;
let currentScore = 0;
-let highScore = 7;
+let previousHighScore = stored[0].score;
+let highScore = stored[0].score;
let gameOver = false;
const ScorebarCtrl = {
setDispatch: d => dispatch = d,
getLives: () => lives,
+ getCurrentScore: () => currentScore,
- flagGameOver: () => gameOver = true,
isGameOver: () => gameOver,
update: () => {
+ // Note that loss of points may cause new high to drop below previous.
+ if (currentScore > previousHighScore) {
+ highScore = currentScore;
+ }
+ else {
+ highScore = previousHighScore;
+ }
+
dispatch(ScorebarActions.update(lives, currentScore, highScore));
},
@@ -37,9 +48,18 @@ const ScorebarCtrl = {
levelUp: (level) => {
currentScore += 25;
+
+ if (level % 3 === 0) {
+ lives++;
+ }
+
ScorebarCtrl.update();
},
+ gameOver: () => {
+ gameOver = true;
+ },
+
reset: () => {
lives = SETTINGS.LIVES;
currentScore = 0;
diff --git a/controllers/board/titlebar.controller.js b/controllers/board/titlebar.controller.js
index 9d29caa..6197ef9 100644
--- a/controllers/board/titlebar.controller.js
+++ b/controllers/board/titlebar.controller.js
@@ -1,5 +1,5 @@
import * as TitlebarActions from '../../actions/board/titlebar.actions';
-import SubtractionModel from '../../models/subtraction.model';
+import FactorsModel from '../../models/factors.model';
let dispatch;
@@ -7,7 +7,7 @@ const TitlebarCtrl = {
setDispatch: d => dispatch = d,
setTitle: (level) => {
- const title = SubtractionModel.getTitle(level);
+ const title = FactorsModel.getTitle(level);
dispatch(TitlebarActions.update(title));
}
};
diff --git a/controllers/options/options.controller.js b/controllers/options/options.controller.js
index 2e05fbd..c69e2aa 100644
--- a/controllers/options/options.controller.js
+++ b/controllers/options/options.controller.js
@@ -16,6 +16,10 @@ const OptionsCtrl = {
keyListener(e) {
if (e.keyCode === 32) {
+ let model =
+ // switch (selected) {
+ // case 0:
+ // }
ModeCtrl.board();
}
else if (e.keyCode === 38) {
diff --git a/controllers/welcome/initials.controller.js b/controllers/welcome/initials.controller.js
new file mode 100644
index 0000000..4dd736c
--- /dev/null
+++ b/controllers/welcome/initials.controller.js
@@ -0,0 +1,91 @@
+import * as WelcomeActions from '../../actions/welcome/welcome.actions';
+
+let dispatch;
+
+let initials = [
+ { initial: 'A', active: true },
+ { initial: 'A', active: false },
+ { initial: 'A', active: false }
+];
+
+let active = 0;
+let code;
+
+const InitialsCtrl = {
+ setDispatch: (d) => dispatch = d,
+
+ keydown: function(e) {
+ switch (e.keyCode) {
+ case 13:
+ case 32:
+ break;
+ case 37:
+ active--;
+ if (active === -1) {
+ active = initials.length - 1;
+ }
+ this.updateInitials();
+ break;
+ case 38:
+ code = initials[active].initial.charCodeAt(0);
+ code--;
+ if (code === 64) {
+ code = 90;
+ }
+ initials[active].initial = String.fromCharCode(code);
+ this.updateInitials();
+ break;
+ case 39:
+ active++;
+ if (active === initials.length) {
+ active = 0;
+ }
+ this.updateInitials();
+ break;
+ case 40:
+ code = initials[active].initial.charCodeAt(0);
+ code++;
+ if (code === 91) {
+ code = 65;
+ }
+ initials[active].initial = String.fromCharCode(code);
+ this.updateInitials();
+ break;
+ }
+
+ if (e.keyCode >= 65 && e.keyCode <= 90) {
+ initials[active].initial = String.fromCharCode(e.keyCode);
+
+ if (active < initials.length - 1) {
+ active++;
+ }
+ this.updateInitials();
+ }
+ },
+
+ updateInitials: () => {
+ initials = initials.map((v) => {
+ v.active = false;
+ return v;
+ });
+
+ initials[active].active = true;
+
+ dispatch(WelcomeActions.updateInitials(initials));
+ },
+
+ updateScores: (scores) => {
+ // [
+ // { initials: "ABA", score: "219283", rank: "1" },
+ // { initials: "ABA", score: "107112", rank: "2" },
+ // { initials: "ABA", score: "81091", rank: "3" },
+ // { initials: "ABA", score: "67747", rank: "4" },
+ // { initials: "ABA", score: "9283", rank: "5" },
+ // { initials: "ABA", score: "928", rank: "6" }
+ // ];
+
+ // localStorage.setItem(SETTINGS.LOCAL_STORAGE_KEY, scores);
+ }
+};
+
+export default InitialsCtrl;
diff --git a/controllers/welcome/welcome.controller.js b/controllers/welcome/welcome.controller.js
new file mode 100644
index 0000000..50f5a9f
--- /dev/null
+++ b/controllers/welcome/welcome.controller.js
@@ -0,0 +1,43 @@
+import * as WelcomeActions from '../../actions/welcome/welcome.actions';
+import InitialsCtrl from './initials.controller';
+import SETTINGS from '../../AppSettings';
+
+let dispatch;
+let update = true;
+
+const HighScoreCtrl = {
+ setDispatch: (d) => dispatch = d,
+
+ keydown: (e) => {
+ if (update === true) {
+ InitialsCtrl.keydown(e);
+ }
+ else if (e.keyCode === 32) {
+ this.props.dispatch(ModeActions.options());
+ }
+ },
+
+ getHighScore: () => {
+ const scores = localStorage.getItem(SETTINGS.LOCAL_STORAGE_KEY);
+
+ if (scores !== null) {
+ return scores[0].score;
+ }
+
+ return 0;
+ },
+
+ gameOver: (score) => {
+
+ },
+
+ retrieveScores: () => {
+ const scores = localStorage.getItem(SETTINGS.LOCAL_STORAGE_KEY);
+
+ if (scores !== null) {
+ dispatch(WelcomeActions.updateScores(scores));
+ }
+ }
+};
+
+export default HighScoreCtrl;
diff --git a/index.js b/index.js
index 86198cc..fe96ca2 100644
--- a/index.js
+++ b/index.js
@@ -6,25 +6,28 @@ import { Provider } from 'react-redux';
import App from './App';
import modeReducer from './reducers/mode.reducer';
-import newgameReducer from './reducers/welcome/new-game.reducer';
+import welcomeReducer from './reducers/welcome/welcome.reducer';
+import optionsReducer from './reducers/options/options.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';
import troggleReducer from './reducers/board/troggle.reducer';
import titlebarReducer from './reducers/board/titlebar.reducer';
-import optionsReducer from './reducers/options/options.reducer';
const reducers = combineReducers({
mode: modeReducer,
- newgame: newgameReducer,
+
+ welcome: welcomeReducer,
+
+ options: optionsReducer,
+
muncher: muncherReducer,
scorebar: scorebarReducer,
message: messageReducer,
troggles: troggleReducer,
grid: gridReducer,
- titlebar: titlebarReducer,
- options: optionsReducer
+ titlebar: titlebarReducer
});
const store = createStore(reducers);
diff --git a/reducers/mode.reducer.js b/reducers/mode.reducer.js
index 862a058..d1e9045 100644
--- a/reducers/mode.reducer.js
+++ b/reducers/mode.reducer.js
@@ -1,6 +1,6 @@
import * as ModeActions from '../actions/mode.actions';
-const initial = ModeActions.OPTIONS;
+const initial = ModeActions.WELCOME;
const reducer = (state = initial, action) => {
if (action.type !== ModeActions.MODE_ACTION) {
diff --git a/reducers/welcome/high-scores.reducer.js b/reducers/welcome/high-scores.reducer.js
deleted file mode 100644
index e69de29..0000000
diff --git a/reducers/welcome/new-game.reducer.js b/reducers/welcome/new-game.reducer.js
deleted file mode 100644
index f14042e..0000000
--- a/reducers/welcome/new-game.reducer.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import * as NewGameActions from '../../actions/welcome/new-game.actions';
-
-const initial = { hidden: false };
-const reducer = (state = initial, action) => {
- if (action.type !== NewGameActions.NEWGAME_ACTION) {
- return state;
- }
-
- if (action.action === NewGameActions.BLINK) {
- return (state.hidden ? { hidden: false } : { hidden: true });
- }
-
- return state;
-};
-
-export default reducer;
diff --git a/reducers/welcome/welcome.reducer.js b/reducers/welcome/welcome.reducer.js
new file mode 100644
index 0000000..79a1ddc
--- /dev/null
+++ b/reducers/welcome/welcome.reducer.js
@@ -0,0 +1,40 @@
+const Immutable = require('immutable');
+
+import * as WelcomeActions from '../../actions/welcome/welcome.actions';
+
+const initial = {
+ scores: [
+ { initials: "AAA", score: "0", rank: "1" },
+ { initials: "AAA", score: "0", rank: "1" },
+ { initials: "AAA", score: "0", rank: "1" },
+ { initials: "AAA", score: "0", rank: "1" },
+ { initials: "AAA", score: "0", rank: "1" },
+ { initials: "AAA", score: "0", rank: "1" }
+ ],
+
+ initials: [
+ { initial: 'A', active: true },
+ { initial: 'A', active: false },
+ { initial: 'A', active: false }
+ ]
+};
+
+const reducer = (state = initial, action) => {
+ if (action.type !== WelcomeActions.WELCOME_ACTION) {
+ return state;
+ }
+
+ // if (action.action === WelcomeActions.UPDATE_SCORES) {
+ // return action.scores;
+ // }
+ switch (action.action) {
+ case WelcomeActions.UPDATE_INITIALS:
+ return Immutable.Map(state)
+ .set('initials', action.initials)
+ .toObject();
+ }
+
+ return state;
+};
+
+export default reducer;
diff --git a/sass/board/scorebar.scss b/sass/board/scorebar.scss
index cea5df1..4aa627d 100644
--- a/sass/board/scorebar.scss
+++ b/sass/board/scorebar.scss
@@ -18,25 +18,25 @@
}
.current-score {
- width:30%;
+ width:35%;
}
.high-score {
text-align:center;
- width:40%;
+ width:30%;
}
.lives {
text-align:right;
- width:30%;
+ width:35%;
}
.life {
background:lime;
display:inline-block;
- height:36px;
- margin-left:10px;
+ height:30px;
+ margin-left:5px;
vertical-align:middle;
- width:36px;
+ width:30px;
}
}
diff --git a/sass/reset.scss b/sass/reset.scss
index 79a9e07..8c02784 100644
--- a/sass/reset.scss
+++ b/sass/reset.scss
@@ -2,6 +2,5 @@
box-sizing:border-box;
font-family:Emulogic;
margin: 0;
- outline:none;
padding: 0;
}
diff --git a/sass/welcome/highscores.scss b/sass/welcome/highscores.scss
deleted file mode 100644
index 6434667..0000000
--- a/sass/welcome/highscores.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-.highscores {
- font-size: 0;
-
- .entry {
- font-size:16px;
- line-height:40px;
- }
-
- .rank {
- display:inline-block;
- text-align:left;
- width:50px;
- }
-
- .initials {
- display:inline-block;
- width:100px;
- }
-
- .score {
- display:inline-block;
- text-align:right;
- width:200px;
- }
-}
diff --git a/sass/welcome/welcome.scss b/sass/welcome/welcome.scss
index 88cc3b0..a36a045 100644
--- a/sass/welcome/welcome.scss
+++ b/sass/welcome/welcome.scss
@@ -1,22 +1,100 @@
.welcome {
+ $w: 350px;
+
padding:20px;
text-align:center;
img {
- width:350px;
+ width:$w;
}
- .highscores {
- margin:0 auto;
- width:350px;
+ .line {
+ line-height:30px;
}
- .newgame {
- margin:20px 0;
- transition:opacity 0.1s ease;
+ @keyframes blink {
+ 50% {
+ opacity: 0.6;
+ }
+ }
- &.hidden {
- opacity: 0.5;
+ @-webkit-keyframes blink {
+ 50% {
+ opacity: 0.6;
}
}
+
+ .blink {
+ animation: blink 1s step-start 0s infinite;
+ -webkit-animation: blink 1s step-start 0s infinite;
+ }
+
+ .initial {
+ display:inline-block;
+ }
+
+ // .highscores {
+ // margin:0 auto;
+ // width:350px;
+ // }
+ //
+ // .newgame {
+ // margin:20px 0;
+ // transition:opacity 0.1s ease;
+ //
+ // &.hidden {
+ // opacity: 0.5;
+ // }
+ // }
}
+//
+// .highscores {
+// $w: 350px;
+//
+// font-size: 0;
+//
+// hr {
+// border:0;
+// border-top:1px solid #ccc;
+// margin:20px auto;
+// width: $w;
+// }
+//
+// .blink {
+// animation: blinker 1s none infinite;
+// }
+//
+// @keyframes blinker {
+// 50% { opacity: 0.6; }
+// }
+//
+// .line {
+// font-size:16px;
+// line-height:30px;
+// margin: 10px auto;
+// text-align:center;
+// width:$w;
+// };
+//
+// .entry {
+// font-size:16px;
+// line-height:40px;
+// }
+//
+// .rank {
+// display:inline-block;
+// text-align:left;
+// width:50px;
+// }
+//
+// .initials {
+// display:inline-block;
+// width:100px;
+// }
+//
+// .score {
+// display:inline-block;
+// text-align:right;
+// width:200px;
+// }
+// }