Skip to content
This repository has been archived by the owner on May 26, 2018. It is now read-only.

Commit

Permalink
Prevent progress loss returning to previous level.
Browse files Browse the repository at this point in the history
  • Loading branch information
mminer committed Nov 19, 2017
1 parent 187ab2c commit 72ea438
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 119 deletions.
3 changes: 2 additions & 1 deletion src/components/cell.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { h } from 'virtual-dom';
import { SQUARE_SIZE } from '../constants/misc';
import { BROKEN, PRESSED, UNPRESSED } from '../constants/tile-codes';
import { moveTo } from '../game';

const classNames = {
[BROKEN]: 'broken',
[PRESSED]: 'pressed',
[UNPRESSED]: 'unpressed',
};

export default function Cell ({ column, moveTo, row, tile }) {
export default function Cell ({ column, row, tile }) {
return h('div.cell', {
className: classNames[tile],
key: `${row} ${column}`,
Expand Down
3 changes: 2 additions & 1 deletion src/components/difficulty-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
DIFFICULTY_LABELS,
STARTING_LEVEL_NUMBERS,
} from '../constants/difficulty';
import { loadLevel } from '../game';

export default function DifficultyButton ({ difficulty, loadLevel }) {
export default function DifficultyButton ({ difficulty }) {
return h('button.difficulty-button', {
key: difficulty,
onclick: () => loadLevel(STARTING_LEVEL_NUMBERS[difficulty]),
Expand Down
4 changes: 2 additions & 2 deletions src/components/difficulty-buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { h } from 'virtual-dom';
import DifficultyButton from '../components/difficulty-button';
import { EASY, MEDIUM, HARD } from '../constants/difficulty-levels';

export default function DifficultyButtons ({ loadLevel }) {
export default function DifficultyButtons () {
return h('div.difficulty-buttons', [EASY, MEDIUM, HARD].map(difficulty =>
DifficultyButton({ difficulty, loadLevel })
DifficultyButton({ difficulty })
));
}
8 changes: 6 additions & 2 deletions src/components/difficulty-row.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import { levelNumbersInDifficulty } from '../util';
export default function DifficultyRow ({
currentDifficulty,
currentLevelNumber,
loadLevel,
maxLevelReached,
}) {
const levelNumbers = levelNumbersInDifficulty(currentDifficulty);

return h('div.difficulty-row', levelNumbers.map(
levelNumber => LevelButton({ currentLevelNumber, levelNumber, loadLevel })
levelNumber => LevelButton({
currentLevelNumber,
levelNumber,
maxLevelReached,
})
));
}
3 changes: 2 additions & 1 deletion src/components/difficulty-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { h } from 'virtual-dom';
import DifficultyOption from '../components/difficulty-option';
import { EASY, MEDIUM, HARD } from '../constants/difficulty-levels';
import { STARTING_LEVEL_NUMBERS } from '../constants/difficulty';
import { loadLevel } from '../game';

export default function DifficultySelector ({ currentDifficulty, loadLevel }) {
export default function DifficultySelector ({ currentDifficulty }) {
return h('select.difficulty-selector', {
onchange: evt => {
const newDifficulty = evt.target.value;
Expand Down
23 changes: 11 additions & 12 deletions src/components/level-button.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
import { h } from 'virtual-dom';
import { DEV_MODE_ENABLED } from '../constants/prefs';
import { loadLevel } from '../game';

function getClassName (levelNumber, currentLevelNumber) {
let className = '';

if (levelNumber < currentLevelNumber) {
className = 'complete';
} else if (levelNumber === currentLevelNumber) {
className = 'current';
function getClassName (levelNumber, currentLevelNumber, maxLevelReached) {
if (levelNumber === currentLevelNumber) {
return 'current';
} else if (levelNumber <= maxLevelReached) {
return 'complete';
} else {
return '';
}

return className;
}

export default function LevelButton ({
currentLevelNumber,
levelNumber,
loadLevel,
maxLevelReached,
}) {
// Only allow jumping to completed levels (unless we're in dev mode).
// Jumping to the current level effectively resets it.
const isLevelAvailable = DEV_MODE_ENABLED ||
(levelNumber <= currentLevelNumber);
(levelNumber <= maxLevelReached);

return h('button.level-button', {
className: getClassName(levelNumber, currentLevelNumber),
className: getClassName(levelNumber, currentLevelNumber, maxLevelReached),
key: levelNumber,
onclick: isLevelAvailable ? () => loadLevel(levelNumber) : null,
title: `Level ${levelNumber}`,
Expand Down
6 changes: 3 additions & 3 deletions src/components/level-navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import DifficultySelector from '../components/difficulty-selector';
export default function LevelNavigator ({
currentDifficulty,
currentLevelNumber,
loadLevel,
maxLevelReached,
}) {
return h('nav', [
DifficultySelector({ currentDifficulty, loadLevel }),
DifficultyRow({ currentDifficulty, currentLevelNumber, loadLevel }),
DifficultySelector({ currentDifficulty }),
DifficultyRow({ currentDifficulty, currentLevelNumber, maxLevelReached }),
]);
}
5 changes: 3 additions & 2 deletions src/components/level.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { h } from 'virtual-dom';
import { SQUARE_SIZE } from '../constants/misc';
import Cell from '../components/cell';
import Player from '../components/player';
import { moveTo } from '../game';

export default function Level ({ moveTo, playerPosition, tiles }) {
export default function Level ({ playerPosition, tiles }) {
const cells = tiles.reduce((cellArray, rowTiles, row) => {
const rowCells = rowTiles.map((tile, column) =>
Cell({ column, moveTo, row, tile })
Cell({ column, row, tile })
);

return cellArray.concat(rowCells);
Expand Down
4 changes: 1 addition & 3 deletions src/entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import './main.css';
import fastClick from 'fastclick';
import render from './render';
import store from './store';
import { loadLevel, move, moveTo, reset } from './game';
import { move, reset } from './game';
import { PLAYING } from './constants/game-statuses';
import { DOWN, LEFT, R, RIGHT, UP } from './constants/key-codes';

Expand Down Expand Up @@ -52,8 +52,6 @@ document.addEventListener('keyup', evt => {
// Provides the UI with the game state.
function renderProps () {
const props = store.getState();
props.loadLevel = loadLevel;
props.moveTo = moveTo;
render(props);
}

Expand Down
89 changes: 0 additions & 89 deletions src/reducer.js

This file was deleted.

92 changes: 92 additions & 0 deletions src/reducers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import levels from './levels';
import { createReducer } from './util';
import { LOAD_LEVEL, LOSE, MOVE, WIN } from './constants/actions';
import { STARTING_LEVEL_NUMBERS } from './constants/difficulty';
import { EASY, MEDIUM, HARD } from './constants/difficulty-levels';
import { LOST, MAIN_MENU, PLAYING, WON } from './constants/game-statuses';
import { PRESSED, UNPRESSED } from './constants/tile-codes';

export const currentDifficulty = createReducer(EASY, {
[LOAD_LEVEL] (state, { levelNumber }) {
if (levelNumber < STARTING_LEVEL_NUMBERS[MEDIUM]) {
state = EASY;
} else if (levelNumber < STARTING_LEVEL_NUMBERS[HARD]) {
state = MEDIUM;
} else {
state = HARD;
}

return state;
},
});

export const currentLevelNumber = createReducer(0, {
[LOAD_LEVEL] (state, { levelNumber }) {
return levelNumber;
},
});

export const maxLevelReached = createReducer(0, {
[LOAD_LEVEL] (state, { levelNumber }) {
return Math.max(state, levelNumber);
},
});

export const maxMoves = createReducer(Infinity, {
[LOAD_LEVEL] (state, { levelNumber }) {
const level = levels[levelNumber];
return level.maxMoves;
},
});

export const moveCount = createReducer(0, {
[LOAD_LEVEL] () {
return 0;
},

[MOVE] (state) {
return state + 1;
},
});

export const playerPosition = createReducer({ row: 0, column: 0 }, {
[LOAD_LEVEL] (state, { levelNumber }) {
const level = levels[levelNumber];
const { row, column } = level.playerPosition;
return { row, column };
},

[MOVE] (state, { row, column }) {
return { row, column };
},
});

export const status = createReducer(MAIN_MENU, {
[LOAD_LEVEL] () {
return PLAYING;
},

[LOSE] () {
return LOST;
},

[WIN] () {
return WON;
},
});

export const tiles = createReducer([[]], {
[LOAD_LEVEL] (state, { levelNumber }) {
const level = levels[levelNumber];
return level.tiles.map(rowTiles => rowTiles.slice());
},

[MOVE] (state, { row, column }) {
// Toggle the tile at the new position.
const currentTile = state[row][column];
const newTile = currentTile === PRESSED ? UNPRESSED : PRESSED;
state = state.map(rowTiles => rowTiles.slice());
state[row][column] = newTile;
return state;
},
});
7 changes: 4 additions & 3 deletions src/store.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createStore } from 'redux';
import reducer from './reducer';
import { combineReducers, createStore } from 'redux';
import * as reducers from './reducers';

export default createStore(reducer);
const rootReducer = combineReducers(reducers);
export default createStore(rootReducer);

0 comments on commit 72ea438

Please sign in to comment.