├── tmp └── .gitkeep ├── .npmignore ├── models ├── Model.es6 ├── things │ ├── WallThingModel.es6 │ ├── PlayerThingModel.es6 │ ├── UpstairsThingModel.es6 │ ├── PicksThingModel.es6 │ ├── BonusTime5ThingModel.es6 │ ├── PenaltyTime3ThingModel.es6 │ └── ThingModel.es6 ├── GameResultModel.es6 ├── ThingIndexerModel.es6 └── CellModel.es6 ├── circle.yml ├── doc ├── demo.gif ├── demo-2.gif └── demo-3.gif ├── test ├── support │ ├── some-es5-module.js │ ├── some-es6-module.es6 │ └── helpers.es6 ├── mocha.opts ├── conf │ └── index.es6 ├── models │ ├── GameResultModel.es6 │ ├── things │ │ ├── WallThingModel.es6 │ │ ├── PlayerThingModel.es6 │ │ └── ThingModel.es6 │ ├── ThingIndexerModel.es6 │ └── CellModel.es6 ├── stores │ ├── ScreenStore.es6 │ ├── Store.es6 │ └── GameStore.es6 ├── vendors │ └── power-assert.es6 ├── app.es6 ├── input │ └── AppInput.es6 └── lib │ ├── stages │ └── index.es6 │ ├── mixins │ └── SingletonMixin.es6 │ ├── util.es6 │ └── apis │ └── index.es6 ├── server └── aws-lambda │ ├── aws-config.example.json │ ├── package.json │ ├── local-runner.js │ └── index.js ├── consts ├── index.es6 ├── keys.es6 ├── events.es6 └── actions.es6 ├── env ├── development.js ├── test.js └── production.js ├── dist ├── test │ ├── support │ │ ├── some-es6-module.js │ │ └── helpers.js │ ├── conf │ │ └── index.js │ ├── models │ │ ├── GameResultModel.js │ │ ├── ThingIndexerModel.js │ │ ├── things │ │ │ ├── WallThingModel.js │ │ │ ├── PlayerThingModel.js │ │ │ └── ThingModel.js │ │ └── CellModel.js │ ├── stores │ │ ├── ScreenStore.js │ │ ├── Store.js │ │ └── GameStore.js │ ├── vendors │ │ └── power-assert.js │ ├── lib │ │ ├── stages │ │ │ └── index.js │ │ ├── util.js │ │ ├── mixins │ │ │ └── SingletonMixin.js │ │ └── apis │ │ │ └── index.js │ ├── app.js │ └── input │ │ └── AppInput.js ├── consts │ ├── index.js │ ├── keys.js │ ├── events.js │ └── actions.js ├── models │ ├── Model.js │ ├── things │ │ ├── WallThingModel.js │ │ ├── PlayerThingModel.js │ │ ├── PicksThingModel.js │ │ ├── UpstairsThingModel.js │ │ ├── BonusTime5ThingModel.js │ │ ├── PenaltyTime3ThingModel.js │ │ └── ThingModel.js │ ├── GameResultModel.js │ ├── ThingIndexerModel.js │ └── CellModel.js ├── components │ ├── variables.js │ ├── Screen.js │ ├── pages │ │ └── WelcomePageComponent.js │ └── DialogComponent.js ├── conf │ └── index.js ├── input │ ├── subscriptions │ │ ├── error.js │ │ ├── timer.js │ │ └── keypress.js │ └── AppInput.js ├── lib │ ├── mixins │ │ └── SingletonMixin.js │ ├── EventManager.js │ ├── stages │ │ └── index.js │ ├── util.js │ └── apis │ │ └── index.js ├── stores │ ├── Store.js │ ├── DialogStore.js │ └── ScreenStore.js ├── dispatcher │ └── AppDispatcher.js ├── actions │ ├── ScreenActionCreators.js │ └── GameActionCreators.js └── app.js ├── dispatcher └── AppDispatcher.es6 ├── input ├── subscriptions │ ├── error.es6 │ ├── timer.es6 │ └── keypress.es6 └── AppInput.es6 ├── conf └── index.es6 ├── gulpfile.js ├── components ├── variables.es6 ├── pages │ ├── WelcomePageComponent.es6 │ └── GamePageComponent.es6 ├── Screen.es6 ├── DialogComponent.es6 └── RootComponent.es6 ├── lib ├── EventManager.es6 ├── mixins │ └── SingletonMixin.es6 ├── stages │ └── index.es6 ├── util.es6 └── apis │ └── index.es6 ├── stores ├── Store.es6 ├── ScreenStore.es6 └── DialogStore.es6 ├── .gitignore ├── .eslintrc ├── README.md ├── LICENSE ├── bin └── escape-from-the-maze ├── actions ├── ScreenActionCreators.es6 └── GameActionCreators.es6 ├── app.es6 └── package.json /tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .envrc 2 | /server 3 | -------------------------------------------------------------------------------- /models/Model.es6: -------------------------------------------------------------------------------- 1 | export default class Model { 2 | } 3 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: "0.12" 4 | -------------------------------------------------------------------------------- /doc/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjirou/escape-from-the-maze/HEAD/doc/demo.gif -------------------------------------------------------------------------------- /test/support/some-es5-module.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | foo: 1, 3 | bar: 2 4 | }; 5 | -------------------------------------------------------------------------------- /test/support/some-es6-module.es6: -------------------------------------------------------------------------------- 1 | export default { 2 | foo: 1, 3 | bar: 2 4 | }; 5 | -------------------------------------------------------------------------------- /doc/demo-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjirou/escape-from-the-maze/HEAD/doc/demo-2.gif -------------------------------------------------------------------------------- /doc/demo-3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjirou/escape-from-the-maze/HEAD/doc/demo-3.gif -------------------------------------------------------------------------------- /server/aws-lambda/aws-config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "accessKeyId": "", 3 | "secretAccessKey": "" 4 | } 5 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --compilers es6:espower-babel/guess 2 | --require env/test 3 | --timeout 10000 4 | --recursive 5 | -------------------------------------------------------------------------------- /consts/index.es6: -------------------------------------------------------------------------------- 1 | export const ACTIONS = require('./actions'); 2 | export const EVENTS = require('./events'); 3 | export const KEYS = require('./keys'); 4 | -------------------------------------------------------------------------------- /env/development.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'development'; 2 | process.env.NODE_PATH = __dirname + '/..'; 3 | require('module')._initPaths(); 4 | require('babel/register'); 5 | -------------------------------------------------------------------------------- /consts/keys.es6: -------------------------------------------------------------------------------- 1 | const KEYS = { 2 | STAGE_SELECTION: { 3 | 'a': 'simple', 4 | 'b': 'easy', 5 | 'c': 'normal', 6 | 'd': 'hard', 7 | 'e': 'lunatic' 8 | } 9 | }; 10 | 11 | 12 | export default KEYS; 13 | -------------------------------------------------------------------------------- /env/test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test'; 2 | process.env.NODE_PATH = __dirname + '/..'; 3 | require('module')._initPaths(); 4 | require('babel/register'); 5 | 6 | var conf = require('conf'); 7 | conf.ignoreScreenOutput = true; 8 | -------------------------------------------------------------------------------- /dist/test/support/some-es6-module.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports["default"] = { 7 | foo: 1, 8 | bar: 2 9 | }; 10 | module.exports = exports["default"]; -------------------------------------------------------------------------------- /dispatcher/AppDispatcher.es6: -------------------------------------------------------------------------------- 1 | import {Dispatcher} from 'flux'; 2 | 3 | import SingletonMixin from 'lib/mixins/SingletonMixin'; 4 | 5 | 6 | export default class AppDispatcher extends Dispatcher { 7 | } 8 | 9 | Object.assign(AppDispatcher, SingletonMixin); 10 | -------------------------------------------------------------------------------- /input/subscriptions/error.es6: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | import ScreenActionCreators from 'actions/ScreenActionCreators'; 4 | 5 | 6 | export function onError(err) { 7 | console.error(chalk.red(err)); 8 | ScreenActionCreators.throwRuntimeError(err); 9 | } 10 | -------------------------------------------------------------------------------- /conf/index.es6: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | 4 | const conf = { 5 | apiUrl: 'https://94uubrff77.execute-api.us-east-1.amazonaws.com/prod', 6 | fps: 60, 7 | ignoreScreenOutput: false, 8 | root: path.join(__dirname, '/..') 9 | }; 10 | 11 | 12 | export default conf; 13 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gulpBabel = require('gulp-babel'); 3 | 4 | 5 | var DIST_DIR = './dist'; 6 | 7 | 8 | gulp.task('build', function (){ 9 | return gulp.src('**/*.es6') 10 | .pipe(gulpBabel()) 11 | .pipe(gulp.dest(DIST_DIR)) 12 | ; 13 | }); 14 | -------------------------------------------------------------------------------- /consts/events.es6: -------------------------------------------------------------------------------- 1 | import keymirror from 'keymirror'; 2 | 3 | 4 | const EVENTS = keymirror({ 5 | CHANGE_PAGE: null, 6 | EXIT: null, 7 | UPDATE_DIALOG: null, 8 | UPDATE_ERRORS: null, 9 | UPDATE_GAME_STATUS: null, 10 | UPDATE_MAZE: null 11 | }); 12 | 13 | 14 | export default EVENTS; 15 | -------------------------------------------------------------------------------- /components/variables.es6: -------------------------------------------------------------------------------- 1 | const variables = { 2 | pageBoxProps: { 3 | top: 'top', 4 | left: 'left', 5 | width: '100%', 6 | height: '100%', 7 | tags: true, 8 | style: { 9 | fg: 'white', 10 | bg: 'black' 11 | } 12 | } 13 | }; 14 | 15 | 16 | export default variables; 17 | -------------------------------------------------------------------------------- /dist/consts/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var ACTIONS = require('./actions'); 7 | exports.ACTIONS = ACTIONS; 8 | var EVENTS = require('./events'); 9 | exports.EVENTS = EVENTS; 10 | var KEYS = require('./keys'); 11 | exports.KEYS = KEYS; -------------------------------------------------------------------------------- /server/aws-lambda/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "for-aws-lambda", 3 | "version": "0.0.0", 4 | "description": "For ZIP file creation that is uploaded to AWS Lambda", 5 | "dependencies": { 6 | "async": "1.4.2", 7 | "aws-sdk": "2.1.48", 8 | "lodash": "3.10.1" 9 | }, 10 | "private": true 11 | } 12 | -------------------------------------------------------------------------------- /test/support/helpers.es6: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | import conf from 'conf'; 4 | 5 | 6 | export function heading(filePath) { 7 | let relativePath = path.relative(conf.root, filePath); 8 | relativePath = relativePath.replace(/^test\//, ''); 9 | relativePath = relativePath.replace(/\.es6$/, ''); 10 | return relativePath; 11 | } 12 | -------------------------------------------------------------------------------- /models/things/WallThingModel.es6: -------------------------------------------------------------------------------- 1 | import ThingModel from 'models/things/ThingModel'; 2 | 3 | 4 | export default class WallThingModel extends ThingModel { 5 | 6 | constructor() { 7 | super(); 8 | 9 | this._symbol = '#'; 10 | this._isPassable = false; 11 | } 12 | } 13 | 14 | Object.assign(WallThingModel, { 15 | typeId: 'wall' 16 | }); 17 | -------------------------------------------------------------------------------- /dist/consts/keys.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var KEYS = { 7 | STAGE_SELECTION: { 8 | 'a': 'simple', 9 | 'b': 'easy', 10 | 'c': 'normal', 11 | 'd': 'hard', 12 | 'e': 'lunatic' 13 | } 14 | }; 15 | 16 | exports['default'] = KEYS; 17 | module.exports = exports['default']; -------------------------------------------------------------------------------- /test/conf/index.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | import path from 'path'; 3 | 4 | import conf from 'conf'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('root', function() { 11 | let App = require(path.join(conf.root, 'app.es6')); 12 | assert.strictEqual(typeof App, 'function'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /models/GameResultModel.es6: -------------------------------------------------------------------------------- 1 | import Model from 'models/Model'; 2 | 3 | 4 | export default class GameResultModel extends Model { 5 | 6 | constructor({ timeLimit, lastGameTime }) { 7 | super(); 8 | 9 | this._timeLimit = timeLimit; 10 | this._lastGameTime = lastGameTime; 11 | } 12 | 13 | calculateScore() { 14 | return this._timeLimit - this._lastGameTime; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/EventManager.es6: -------------------------------------------------------------------------------- 1 | import {EventEmitter} from 'events'; 2 | 3 | import SingletonMixin from 'lib/mixins/SingletonMixin'; 4 | 5 | 6 | export default class EventManager { 7 | 8 | constructor() { 9 | 10 | this._emitter = new EventEmitter(); 11 | 12 | Object.defineProperty(this, 'emitter', { get() { return this._emitter; } }); 13 | } 14 | } 15 | 16 | Object.assign(EventManager, SingletonMixin); 17 | -------------------------------------------------------------------------------- /models/things/PlayerThingModel.es6: -------------------------------------------------------------------------------- 1 | import ThingModel from 'models/things/ThingModel'; 2 | 3 | 4 | export default class PlayerThingModel extends ThingModel { 5 | 6 | constructor() { 7 | super(); 8 | 9 | this._symbol = '@'; 10 | } 11 | 12 | toContent() { 13 | return '{magenta-fg}' + this._symbol + '{/}'; 14 | } 15 | } 16 | 17 | Object.assign(PlayerThingModel, { 18 | typeId: 'player' 19 | }); 20 | -------------------------------------------------------------------------------- /models/things/UpstairsThingModel.es6: -------------------------------------------------------------------------------- 1 | import ThingModel from 'models/things/ThingModel'; 2 | 3 | 4 | export default class UpstairsThingModel extends ThingModel { 5 | 6 | constructor() { 7 | super(); 8 | 9 | this._symbol = '<'; 10 | } 11 | 12 | toContent() { 13 | return '{magenta-fg}' + this._symbol + '{/}'; 14 | } 15 | } 16 | 17 | Object.assign(UpstairsThingModel, { 18 | typeId: 'upstairs' 19 | }); 20 | -------------------------------------------------------------------------------- /stores/Store.es6: -------------------------------------------------------------------------------- 1 | import SingletonMixin from 'lib/mixins/SingletonMixin'; 2 | 3 | 4 | export default class Store { 5 | 6 | constructor() { 7 | this._dispatchToken = null; 8 | } 9 | 10 | getDispatchToken() { 11 | if (!this._dispatchToken) { 12 | throw new Error('dispatchToken does not exist'); 13 | } 14 | return this._dispatchToken; 15 | } 16 | } 17 | 18 | Object.assign(Store, SingletonMixin); 19 | -------------------------------------------------------------------------------- /dist/models/Model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 8 | 9 | var Model = function Model() { 10 | _classCallCheck(this, Model); 11 | }; 12 | 13 | exports["default"] = Model; 14 | module.exports = exports["default"]; -------------------------------------------------------------------------------- /models/things/PicksThingModel.es6: -------------------------------------------------------------------------------- 1 | import ThingModel from 'models/things/ThingModel'; 2 | 3 | 4 | export default class PicksThingModel extends ThingModel { 5 | 6 | constructor() { 7 | super(); 8 | 9 | this._symbol = 'T'; 10 | this._isPickable = true; 11 | } 12 | 13 | toContent() { 14 | return '{yellow-fg}' + this._symbol + '{/}'; 15 | } 16 | } 17 | 18 | Object.assign(PicksThingModel, { 19 | typeId: 'picks' 20 | }); 21 | -------------------------------------------------------------------------------- /test/models/GameResultModel.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import GameResultModel from 'models/GameResultModel'; 4 | import {heading} from 'test/support/helpers'; 5 | 6 | 7 | describe(heading(__filename), function() { 8 | 9 | it('calculateScore', function() { 10 | let store = new GameResultModel({ timeLimit: 100000, lastGameTime: 77777 }); 11 | assert.strictEqual(store.calculateScore(), 22223); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /dist/components/variables.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var variables = { 7 | pageBoxProps: { 8 | top: 'top', 9 | left: 'left', 10 | width: '100%', 11 | height: '100%', 12 | tags: true, 13 | style: { 14 | fg: 'white', 15 | bg: 'black' 16 | } 17 | } 18 | }; 19 | 20 | exports['default'] = variables; 21 | module.exports = exports['default']; -------------------------------------------------------------------------------- /models/things/BonusTime5ThingModel.es6: -------------------------------------------------------------------------------- 1 | import ThingModel from 'models/things/ThingModel'; 2 | 3 | 4 | export default class BonusTime5ThingModel extends ThingModel { 5 | 6 | constructor() { 7 | super(); 8 | 9 | this._symbol = '5'; 10 | this._isPickable = true; 11 | } 12 | 13 | toContent() { 14 | return '{green-fg}' + this._symbol + '{/}'; 15 | } 16 | } 17 | 18 | Object.assign(BonusTime5ThingModel, { 19 | typeId: 'bonus_time_5' 20 | }); 21 | -------------------------------------------------------------------------------- /models/things/PenaltyTime3ThingModel.es6: -------------------------------------------------------------------------------- 1 | import ThingModel from 'models/things/ThingModel'; 2 | 3 | 4 | export default class PenaltyTime3ThingModel extends ThingModel { 5 | 6 | constructor() { 7 | super(); 8 | 9 | this._symbol = '3'; 10 | this._isPickable = true; 11 | } 12 | 13 | toContent() { 14 | return '{red-fg}' + this._symbol + '{/}'; 15 | } 16 | } 17 | 18 | Object.assign(PenaltyTime3ThingModel, { 19 | typeId: 'penalty_time_3' 20 | }); 21 | -------------------------------------------------------------------------------- /env/production.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'production'; 2 | process.env.NODE_PATH = [ 3 | // At first, look for the transpiled code 4 | __dirname + '/../dist', 5 | //__dirname + '/..' 6 | ].join(':'); 7 | require('module')._initPaths(); 8 | require("babel/polyfill"); 9 | // Does not work `require('babel/register');` at installed globally. 10 | // Ref) https://babeljs.io/docs/usage/require/ 11 | //require('babel/register')({ 12 | // ignore: false, 13 | // extensions: ['.es6'] 14 | //}); 15 | -------------------------------------------------------------------------------- /test/stores/ScreenStore.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import ScreenStore from 'stores/ScreenStore'; 4 | import {heading} from 'test/support/helpers'; 5 | 6 | 7 | describe(heading(__filename), function() { 8 | 9 | it('should be defined', function() { 10 | assert.strictEqual(typeof ScreenStore, 'function'); 11 | }); 12 | 13 | it('pageId', function() { 14 | var store = new ScreenStore(); 15 | store._pageId = 'foo'; 16 | assert.strictEqual(store.pageId, 'foo'); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | *.egg 3 | *.egg-info 4 | *.gem 5 | *.idea 6 | *.log 7 | *.mo 8 | *.orig 9 | *.py[cod] 10 | *.secret 11 | *.sqlite 12 | *.swp 13 | *.tap 14 | *.DS_Store 15 | .bundle 16 | .config 17 | .coverage 18 | .envrc 19 | .installed.cfg 20 | .mr.developer.cfg 21 | .project 22 | .pydevproject 23 | .sqlite3-journal 24 | .svn/ 25 | .tox/ 26 | bower_components/ 27 | develop-eggs/ 28 | eggs/ 29 | node_modules/ 30 | coverage 31 | nosetests.xml 32 | npm-debug.log 33 | pip-log.txt 34 | testem.*.*.*.json 35 | 36 | 37 | /tmp/*.* 38 | aws-config.json 39 | -------------------------------------------------------------------------------- /lib/mixins/SingletonMixin.es6: -------------------------------------------------------------------------------- 1 | const SingletomMixin = { 2 | 3 | _instance: null, 4 | 5 | getInstance: function getInstance(...args) { 6 | if (this._instance && this._instance instanceof this) { 7 | return this._instance; 8 | } 9 | this._instance = new this(...args); 10 | return this._instance; 11 | }, 12 | 13 | clearInstance: function clearInstance() { 14 | if (this._destructInstance) { 15 | this._destructInstance(); 16 | } 17 | this._instance = null; 18 | } 19 | }; 20 | 21 | 22 | export default SingletomMixin; 23 | -------------------------------------------------------------------------------- /models/ThingIndexerModel.es6: -------------------------------------------------------------------------------- 1 | import Model from 'models/Model'; 2 | 3 | 4 | export default class ThingIndexerModel extends Model { 5 | 6 | constructor() { 7 | super(); 8 | 9 | this._indexes = {}; 10 | } 11 | 12 | update(id, pos) { 13 | this._indexes[id] = pos; 14 | } 15 | 16 | remove(id) { 17 | delete this._indexes[id]; 18 | } 19 | 20 | get(id) { 21 | return this._indexes[id] || null; 22 | } 23 | 24 | has(id) { 25 | return id in this._indexes; 26 | } 27 | 28 | getIds() { 29 | return Object.keys(this._indexes); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dist/conf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _path = require('path'); 10 | 11 | var _path2 = _interopRequireDefault(_path); 12 | 13 | var conf = { 14 | apiUrl: 'https://94uubrff77.execute-api.us-east-1.amazonaws.com/prod', 15 | fps: 60, 16 | ignoreScreenOutput: false, 17 | root: _path2['default'].join(__dirname, '/..') 18 | }; 19 | 20 | exports['default'] = conf; 21 | module.exports = exports['default']; -------------------------------------------------------------------------------- /test/stores/Store.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import Store from 'stores/Store'; 4 | import {heading} from 'test/support/helpers'; 5 | 6 | 7 | describe(heading(__filename), function() { 8 | 9 | it('should be defined', function() { 10 | assert.strictEqual(typeof Store, 'function'); 11 | }); 12 | 13 | it('should be inherited', function() { 14 | class SubStore extends Store {} 15 | 16 | let store = SubStore.getInstance(); 17 | let store2 = SubStore.getInstance(); 18 | assert.strictEqual(store, store2, 'Can use inherited static props'); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /dist/consts/events.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _keymirror = require('keymirror'); 10 | 11 | var _keymirror2 = _interopRequireDefault(_keymirror); 12 | 13 | var EVENTS = (0, _keymirror2['default'])({ 14 | CHANGE_PAGE: null, 15 | EXIT: null, 16 | UPDATE_DIALOG: null, 17 | UPDATE_ERRORS: null, 18 | UPDATE_GAME_STATUS: null, 19 | UPDATE_MAZE: null 20 | }); 21 | 22 | exports['default'] = EVENTS; 23 | module.exports = exports['default']; -------------------------------------------------------------------------------- /test/vendors/power-assert.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import someEs5Module from '../support/some-es5-module'; 4 | import someEs6Module from '../support/some-es6-module'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('should assert .js codes as ES5', function() { 11 | assert.deepEqual(someEs5Module, { 12 | foo: 1, 13 | bar: 2 14 | }); 15 | }); 16 | 17 | it('should assert .es6 codes as ES6', function() { 18 | assert.deepEqual(someEs6Module, { 19 | foo: 1, 20 | bar: 2 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /input/subscriptions/timer.es6: -------------------------------------------------------------------------------- 1 | import GameActionCreators from 'actions/GameActionCreators'; 2 | import GameStore from 'stores/GameStore'; 3 | 4 | 5 | export function onTimer({ value, interval }) { 6 | let gameStore = GameStore.getInstance(); 7 | 8 | if (gameStore.isPlaying()) { 9 | GameActionCreators.forwardGameTimeByFrame(); 10 | } 11 | 12 | if (gameStore.didPlayerGetVictoryJustNow()) { 13 | if (gameStore.hasNextMaze()) { 14 | GameActionCreators.advanceToNextMaze(); 15 | } else { 16 | GameActionCreators.saveVictory(); 17 | } 18 | } else if (gameStore.didPlayerGetDefeatJustNow()) { 19 | GameActionCreators.saveDefeat(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dist/input/subscriptions/error.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | exports.onError = onError; 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9 | 10 | var _chalk = require('chalk'); 11 | 12 | var _chalk2 = _interopRequireDefault(_chalk); 13 | 14 | var _actionsScreenActionCreators = require('actions/ScreenActionCreators'); 15 | 16 | var _actionsScreenActionCreators2 = _interopRequireDefault(_actionsScreenActionCreators); 17 | 18 | function onError(err) { 19 | console.error(_chalk2['default'].red(err)); 20 | _actionsScreenActionCreators2['default'].throwRuntimeError(err); 21 | } -------------------------------------------------------------------------------- /consts/actions.es6: -------------------------------------------------------------------------------- 1 | import keymirror from 'keymirror'; 2 | 3 | 4 | const ACTIONS = keymirror({ 5 | ADVANCE_TO_NEXT_MAZE: null, 6 | ASSUME_PICKS_MODE: null, 7 | CLOSE_DIALOG: null, 8 | CANCEL_PICKS_MODE: null, 9 | CHANGE_PAGE: null, 10 | CRUSH_WALL_BY_PLAYER: null, 11 | DELETE_LAST_INPUT_FROM_DIALOG: null, 12 | EXIT: null, 13 | FORWARD_GAME_TIME_BY_FRAME: null, 14 | INPUT_KEY_TO_DIALOG: null, 15 | OPEN_DIALOG: null, 16 | PREPARE_GAME: null, 17 | REQUEST_ADDING_GAME_RESULT: null, 18 | RESET_GAME: null, 19 | SAVE_DEFEAT: null, 20 | SAVE_VICTORY: null, 21 | SELECT_STAGE: null, 22 | THROW_RUNTIME_ERROR: null, 23 | WALK_PLAYER: null 24 | }); 25 | 26 | 27 | export default ACTIONS; 28 | -------------------------------------------------------------------------------- /dist/test/support/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | exports.heading = heading; 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9 | 10 | var _path = require('path'); 11 | 12 | var _path2 = _interopRequireDefault(_path); 13 | 14 | var _conf = require('conf'); 15 | 16 | var _conf2 = _interopRequireDefault(_conf); 17 | 18 | function heading(filePath) { 19 | var relativePath = _path2['default'].relative(_conf2['default'].root, filePath); 20 | relativePath = relativePath.replace(/^test\//, ''); 21 | relativePath = relativePath.replace(/\.es6$/, ''); 22 | return relativePath; 23 | } -------------------------------------------------------------------------------- /server/aws-lambda/local-runner.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | global.ESCAPE_FROM_THE_MAZE_AWS_LAMBDA_DEBUG = true; 4 | 5 | var awsLambda = require('./index'); 6 | 7 | 8 | var eventMock; 9 | if (0) { 10 | eventMock = { 11 | api_mode: 'add_game_result', 12 | name: 'Testuser', 13 | stage: 'simple', 14 | score: ~~(Math.random() * 50000) 15 | }; 16 | } else { 17 | eventMock = { 18 | api_mode: 'get_ranking' 19 | }; 20 | } 21 | 22 | var contextMock = { 23 | done: function done(err, response) { 24 | if (err) { 25 | console.error(err); 26 | process.exit(1); 27 | } 28 | console.log(response); 29 | process.exit(0); 30 | } 31 | }; 32 | 33 | 34 | awsLambda.handler(eventMock, contextMock); 35 | -------------------------------------------------------------------------------- /models/things/ThingModel.es6: -------------------------------------------------------------------------------- 1 | import uuid from 'uuid'; 2 | 3 | import Model from 'models/Model'; 4 | 5 | 6 | export default class ThingModel extends Model { 7 | 8 | constructor() { 9 | super(); 10 | 11 | this.uuid = uuid.v4(); 12 | this._symbol = '?'; 13 | this._isPassable = true; 14 | this._isPickable = false; 15 | } 16 | 17 | getTypeId() { 18 | return this.constructor.typeId; 19 | } 20 | 21 | getSymbol() { 22 | return this._symbol; 23 | } 24 | 25 | isPassable() { 26 | return this._isPassable; 27 | } 28 | 29 | isPickable() { 30 | return this._isPickable; 31 | } 32 | 33 | toContent() { 34 | return this._symbol; 35 | } 36 | } 37 | 38 | Object.assign(ThingModel, { 39 | typeId: '_thing' 40 | }); 41 | -------------------------------------------------------------------------------- /dist/test/conf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _path = require('path'); 10 | 11 | var _path2 = _interopRequireDefault(_path); 12 | 13 | var _conf = require('conf'); 14 | 15 | var _conf2 = _interopRequireDefault(_conf); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | it('root', function () { 22 | var App = require(_path2['default'].join(_conf2['default'].root, 'app.es6')); 23 | _powerAssert2['default'].strictEqual(typeof App, 'function'); 24 | }); 25 | }); -------------------------------------------------------------------------------- /dist/test/models/GameResultModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _modelsGameResultModel = require('models/GameResultModel'); 10 | 11 | var _modelsGameResultModel2 = _interopRequireDefault(_modelsGameResultModel); 12 | 13 | var _testSupportHelpers = require('test/support/helpers'); 14 | 15 | describe((0, _testSupportHelpers.heading)(__filename), function () { 16 | 17 | it('calculateScore', function () { 18 | var store = new _modelsGameResultModel2['default']({ timeLimit: 100000, lastGameTime: 77777 }); 19 | _powerAssert2['default'].strictEqual(store.calculateScore(), 22223); 20 | }); 21 | }); -------------------------------------------------------------------------------- /test/app.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import App from 'app'; 4 | import EventManager from 'lib/EventManager'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | beforeEach(function() { 11 | App.purgeInstances(); 12 | }); 13 | 14 | it('should create instance', function() { 15 | let app = new App(); 16 | assert.strictEqual(typeof app, 'object'); 17 | assert.strictEqual(app instanceof App, true); 18 | }); 19 | 20 | it('purgeInstances', function() { 21 | assert.strictEqual(EventManager._instance, null); 22 | EventManager.getInstance(); 23 | assert.strictEqual(EventManager._instance instanceof EventManager, true); 24 | App.purgeInstances(); 25 | assert.strictEqual(EventManager._instance, null); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "modules": true 4 | }, 5 | "rules": { 6 | "linebreak-style": [ 7 | 2, 8 | "unix" 9 | ], 10 | "no-console": 0, 11 | "no-unused-vars": [ 12 | 2, 13 | { 14 | "args": "none" 15 | } 16 | ], 17 | "quotes": [ 18 | 2, 19 | "single" 20 | ], 21 | "semi": [ 22 | 2, 23 | "always" 24 | ] 25 | }, 26 | "env": { 27 | "es6": true, 28 | "node": true 29 | }, 30 | "extends": "eslint:recommended", 31 | "globals": { 32 | "after": true, 33 | "afterEach": true, 34 | "before": true, 35 | "beforeEach": true, 36 | "context": true, 37 | "describe": true, 38 | "it": true 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dist/lib/mixins/SingletonMixin.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var _bind = Function.prototype.bind; 7 | var SingletomMixin = { 8 | 9 | _instance: null, 10 | 11 | getInstance: function getInstance() { 12 | if (this._instance && this._instance instanceof this) { 13 | return this._instance; 14 | } 15 | 16 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 17 | args[_key] = arguments[_key]; 18 | } 19 | 20 | this._instance = new (_bind.apply(this, [null].concat(args)))(); 21 | return this._instance; 22 | }, 23 | 24 | clearInstance: function clearInstance() { 25 | if (this._destructInstance) { 26 | this._destructInstance(); 27 | } 28 | this._instance = null; 29 | } 30 | }; 31 | 32 | exports["default"] = SingletomMixin; 33 | module.exports = exports["default"]; -------------------------------------------------------------------------------- /dist/test/stores/ScreenStore.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _storesScreenStore = require('stores/ScreenStore'); 10 | 11 | var _storesScreenStore2 = _interopRequireDefault(_storesScreenStore); 12 | 13 | var _testSupportHelpers = require('test/support/helpers'); 14 | 15 | describe((0, _testSupportHelpers.heading)(__filename), function () { 16 | 17 | it('should be defined', function () { 18 | _powerAssert2['default'].strictEqual(typeof _storesScreenStore2['default'], 'function'); 19 | }); 20 | 21 | it('pageId', function () { 22 | var store = new _storesScreenStore2['default'](); 23 | store._pageId = 'foo'; 24 | _powerAssert2['default'].strictEqual(store.pageId, 'foo'); 25 | }); 26 | }); -------------------------------------------------------------------------------- /test/input/AppInput.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | import sinon from 'sinon'; 3 | 4 | import App from 'app'; 5 | import AppInput from 'input/AppInput'; 6 | import {heading} from 'test/support/helpers'; 7 | 8 | 9 | describe(heading(__filename), function() { 10 | 11 | beforeEach(function() { 12 | App.purgeInstances(); 13 | }); 14 | 15 | it('should create instance', function() { 16 | var input = new AppInput(); 17 | assert(input instanceof AppInput); 18 | }); 19 | 20 | it('should destruct all observable sequences at clearInstance', function() { 21 | var input = AppInput.getInstance(); 22 | var spies = []; 23 | spies.push(sinon.spy(input._timerSubscription, 'dispose')); 24 | spies.push(sinon.spy(input._keypressSubscription, 'dispose')); 25 | AppInput.clearInstance(); 26 | assert.strictEqual(spies[0].callCount, 1); 27 | assert.strictEqual(spies[1].callCount, 1); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/lib/stages/index.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import assert from 'power-assert'; 3 | 4 | import { 5 | Stage, 6 | stageList, 7 | stages 8 | } from 'lib/stages'; 9 | import {heading} from 'test/support/helpers'; 10 | 11 | 12 | describe(heading(__filename), function() { 13 | 14 | context('Stage', function() { 15 | 16 | it('getName', function() { 17 | const FooBarStage = Object.assign({}, Stage, { 18 | typeId: 'foo_bar' 19 | }); 20 | assert.strictEqual(FooBarStage.getName(), 'Foo Bar'); 21 | }); 22 | }); 23 | 24 | context('stageList, stages', function() { 25 | 26 | it('should be', function() { 27 | assert(stageList.length > 0); 28 | assert.strictEqual(stageList.length, Object.keys(stages).length); 29 | 30 | let descriptions = stageList.map(v => v.description); 31 | assert.strictEqual(descriptions.length, _.unique(descriptions).length); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/lib/mixins/SingletonMixin.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import assert from 'power-assert'; 3 | 4 | import SingletonMixin from 'lib/mixins/SingletonMixin'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('should be defined', function() { 11 | assert.strictEqual(typeof SingletonMixin, 'object'); 12 | }); 13 | 14 | it('getInstance, clearInstance', () => { 15 | class Foo { 16 | constructor(x, y) { 17 | this.data = { 18 | x: x, 19 | y: y 20 | }; 21 | } 22 | } 23 | _.assign(Foo, SingletonMixin); 24 | 25 | let foo = Foo.getInstance(1, 2); 26 | assert.deepEqual(foo.data, { x: 1, y: 2 }); 27 | let foo2 = Foo.getInstance(); 28 | assert(foo === foo2); 29 | 30 | Foo.clearInstance(); 31 | let foo3 = Foo.getInstance(2, 3); 32 | assert(foo !== foo3); 33 | assert.deepEqual(foo3.data, { x: 2, y: 3 }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # escape-from-the-maze 2 | 3 | [![npm version](https://badge.fury.io/js/escape-from-the-maze.svg)](http://badge.fury.io/js/escape-from-the-maze) 4 | [![Circle CI](https://circleci.com/gh/kjirou/escape-from-the-maze.svg?style=svg)](https://circleci.com/gh/kjirou/escape-from-the-maze) 5 | 6 | A simple & tiny CUI maze game 7 | 8 | ![](https://raw.githubusercontent.com/kjirou/escape-from-the-maze/master/doc/demo-3.gif) 9 | 10 | 11 | ## Installation 12 | 13 | ```bash 14 | npm install -g escape-from-the-maze 15 | ``` 16 | 17 | 18 | ## Usage 19 | 20 | Start game: 21 | 22 | ```bash 23 | escape-from-the-maze 24 | ``` 25 | 26 | Show ranking: 27 | 28 | ```bash 29 | escape-from-the-maze --ranking 30 | escape-from-the-maze -r 31 | ``` 32 | 33 | Show help: 34 | 35 | ```bash 36 | escape-from-the-maze --help 37 | escape-from-the-maze -h 38 | ``` 39 | 40 | 41 | ## Development 42 | 43 | ```bash 44 | git clone git@github.com:kjirou/escape-from-the-maze.git 45 | cd ./escape-from-the-maze 46 | npm install 47 | npm start 48 | ``` 49 | -------------------------------------------------------------------------------- /dist/lib/EventManager.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 10 | 11 | var _events = require('events'); 12 | 13 | var _libMixinsSingletonMixin = require('lib/mixins/SingletonMixin'); 14 | 15 | var _libMixinsSingletonMixin2 = _interopRequireDefault(_libMixinsSingletonMixin); 16 | 17 | var EventManager = function EventManager() { 18 | _classCallCheck(this, EventManager); 19 | 20 | this._emitter = new _events.EventEmitter(); 21 | 22 | Object.defineProperty(this, 'emitter', { get: function get() { 23 | return this._emitter; 24 | } }); 25 | }; 26 | 27 | exports['default'] = EventManager; 28 | 29 | Object.assign(EventManager, _libMixinsSingletonMixin2['default']); 30 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/consts/actions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _keymirror = require('keymirror'); 10 | 11 | var _keymirror2 = _interopRequireDefault(_keymirror); 12 | 13 | var ACTIONS = (0, _keymirror2['default'])({ 14 | ADVANCE_TO_NEXT_MAZE: null, 15 | ASSUME_PICKS_MODE: null, 16 | CLOSE_DIALOG: null, 17 | CANCEL_PICKS_MODE: null, 18 | CHANGE_PAGE: null, 19 | CRUSH_WALL_BY_PLAYER: null, 20 | DELETE_LAST_INPUT_FROM_DIALOG: null, 21 | EXIT: null, 22 | FORWARD_GAME_TIME_BY_FRAME: null, 23 | INPUT_KEY_TO_DIALOG: null, 24 | OPEN_DIALOG: null, 25 | PREPARE_GAME: null, 26 | REQUEST_ADDING_GAME_RESULT: null, 27 | RESET_GAME: null, 28 | SAVE_DEFEAT: null, 29 | SAVE_VICTORY: null, 30 | SELECT_STAGE: null, 31 | THROW_RUNTIME_ERROR: null, 32 | WALK_PLAYER: null 33 | }); 34 | 35 | exports['default'] = ACTIONS; 36 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/test/vendors/power-assert.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _supportSomeEs5Module = require('../support/some-es5-module'); 10 | 11 | var _supportSomeEs5Module2 = _interopRequireDefault(_supportSomeEs5Module); 12 | 13 | var _supportSomeEs6Module = require('../support/some-es6-module'); 14 | 15 | var _supportSomeEs6Module2 = _interopRequireDefault(_supportSomeEs6Module); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | it('should assert .js codes as ES5', function () { 22 | _powerAssert2['default'].deepEqual(_supportSomeEs5Module2['default'], { 23 | foo: 1, 24 | bar: 2 25 | }); 26 | }); 27 | 28 | it('should assert .es6 codes as ES6', function () { 29 | _powerAssert2['default'].deepEqual(_supportSomeEs6Module2['default'], { 30 | foo: 1, 31 | bar: 2 32 | }); 33 | }); 34 | }); -------------------------------------------------------------------------------- /test/models/things/WallThingModel.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | import validatorjs from 'validator'; 3 | 4 | import WallThingModel from 'models/things/WallThingModel'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('should be defined', function() { 11 | assert.strictEqual(typeof WallThingModel, 'function'); 12 | }); 13 | 14 | it('uuid', function() { 15 | let thing = new WallThingModel(); 16 | assert(validatorjs.isUUID(thing.uuid, 4)); 17 | }); 18 | 19 | it('getTypeId', function() { 20 | let thing = new WallThingModel(); 21 | assert.strictEqual(thing.getTypeId(), 'wall'); 22 | }); 23 | 24 | it('getSymbol', function() { 25 | let thing = new WallThingModel(); 26 | assert.strictEqual(thing.getSymbol(), '#'); 27 | }); 28 | 29 | it('isPassable', function() { 30 | let thing = new WallThingModel(); 31 | assert.strictEqual(thing.isPassable(), false); 32 | }); 33 | 34 | it('toContent', function() { 35 | let thing = new WallThingModel(); 36 | assert.strictEqual(thing.toContent(), '#'); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Koujirou Ishii 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /test/models/things/PlayerThingModel.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | import validatorjs from 'validator'; 3 | 4 | import PlayerThingModel from 'models/things/PlayerThingModel'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('should be defined', function() { 11 | assert.strictEqual(typeof PlayerThingModel, 'function'); 12 | }); 13 | 14 | it('uuid', function() { 15 | let thing = new PlayerThingModel(); 16 | assert(validatorjs.isUUID(thing.uuid, 4)); 17 | }); 18 | 19 | it('getTypeId', function() { 20 | let thing = new PlayerThingModel(); 21 | assert.strictEqual(thing.getTypeId(), 'player'); 22 | }); 23 | 24 | it('getSymbol', function() { 25 | let thing = new PlayerThingModel(); 26 | assert.strictEqual(thing.getSymbol(), '@'); 27 | }); 28 | 29 | it('isPassable', function() { 30 | let thing = new PlayerThingModel(); 31 | assert.strictEqual(thing.isPassable(), true); 32 | }); 33 | 34 | it('toContent', function() { 35 | let thing = new PlayerThingModel(); 36 | assert.strictEqual(thing.toContent(), '{magenta-fg}@{/}'); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /bin/escape-from-the-maze: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var minimist = require('minimist'); 4 | 5 | var commandOptions = minimist(process.argv.slice(2), { 6 | default: { 7 | development: false, 8 | help: false, 9 | ranking: false, 10 | version: false 11 | }, 12 | alias: { 13 | development: ['d'], 14 | help: ['h'], 15 | ranking: ['r'], 16 | version: ['v'] 17 | } 18 | }); 19 | 20 | if (commandOptions.development) { 21 | require('../env/development'); 22 | } else { 23 | require('../env/production'); 24 | } 25 | 26 | var pkg = require('../package.json'); 27 | var App = require('app'); 28 | var apis = require('lib/apis'); 29 | var libUtil = require('lib/util'); 30 | 31 | 32 | if (commandOptions.help) { 33 | console.log(libUtil.createHelpText()); 34 | process.exit(0); 35 | } else if (commandOptions.version) { 36 | console.log(pkg.version); 37 | process.exit(0); 38 | } else if (commandOptions.ranking) { 39 | apis.requestRanking(function(err, text) { 40 | if (err) { 41 | console.error(err); 42 | return process.exit(1); 43 | } 44 | console.log(text); 45 | process.exit(0); 46 | }); 47 | } else { 48 | var app = App.getInstance(); 49 | app.start(); 50 | } 51 | -------------------------------------------------------------------------------- /test/models/ThingIndexerModel.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | import uuidModule from 'uuid'; 3 | 4 | import ThingIndexerModel from 'models/ThingIndexerModel'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('should be defined', function() { 11 | assert.strictEqual(typeof ThingIndexerModel, 'function'); 12 | }); 13 | 14 | it('update, get, getIds', function() { 15 | let indexer = new ThingIndexerModel(); 16 | assert.deepEqual(indexer.getIds(), []); 17 | let uuid = uuidModule.v4(); 18 | indexer.update(uuid, [1, 2]); 19 | indexer.update(uuid, [1, 3]); 20 | assert.deepEqual(indexer.get(uuid), [1, 3]); 21 | assert.deepEqual(indexer.getIds(), [uuid]); 22 | assert.strictEqual(indexer.get('not-existing-uuid'), null); 23 | }); 24 | 25 | it('remove', function() { 26 | let indexer = new ThingIndexerModel(); 27 | let uuid1 = uuidModule.v4(); 28 | let uuid2 = uuidModule.v4(); 29 | indexer.update(uuid1, [1, 2]); 30 | indexer.update(uuid2, [1, 3]); 31 | assert.deepEqual(indexer.get(uuid1), [1, 2]); 32 | indexer.remove(uuid1); 33 | assert.strictEqual(indexer.get(uuid1), null); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /dist/input/subscriptions/timer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | exports.onTimer = onTimer; 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9 | 10 | var _actionsGameActionCreators = require('actions/GameActionCreators'); 11 | 12 | var _actionsGameActionCreators2 = _interopRequireDefault(_actionsGameActionCreators); 13 | 14 | var _storesGameStore = require('stores/GameStore'); 15 | 16 | var _storesGameStore2 = _interopRequireDefault(_storesGameStore); 17 | 18 | function onTimer(_ref) { 19 | var value = _ref.value; 20 | var interval = _ref.interval; 21 | 22 | var gameStore = _storesGameStore2['default'].getInstance(); 23 | 24 | if (gameStore.isPlaying()) { 25 | _actionsGameActionCreators2['default'].forwardGameTimeByFrame(); 26 | } 27 | 28 | if (gameStore.didPlayerGetVictoryJustNow()) { 29 | if (gameStore.hasNextMaze()) { 30 | _actionsGameActionCreators2['default'].advanceToNextMaze(); 31 | } else { 32 | _actionsGameActionCreators2['default'].saveVictory(); 33 | } 34 | } else if (gameStore.didPlayerGetDefeatJustNow()) { 35 | _actionsGameActionCreators2['default'].saveDefeat(); 36 | } 37 | } -------------------------------------------------------------------------------- /test/lib/util.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import conf from 'conf'; 4 | import { 5 | calculateMillisecondsPerFrame, 6 | createCounter, 7 | createHelpText, 8 | dictionarize 9 | } from 'lib/util'; 10 | import {heading} from 'test/support/helpers'; 11 | 12 | 13 | describe(heading(__filename), function() { 14 | 15 | it('createCounter', function() { 16 | let counter; 17 | counter = createCounter(); 18 | assert.strictEqual(counter(), 1); 19 | assert.strictEqual(counter(), 2); 20 | counter = createCounter(-2); 21 | assert.strictEqual(counter(), -2); 22 | assert.strictEqual(counter(), -1); 23 | }); 24 | 25 | it('calculateMillisecondsPerFrame', function() { 26 | assert.strictEqual(calculateMillisecondsPerFrame(), ~~(1000 / conf.fps)); 27 | }); 28 | 29 | it('dictionarize', function() { 30 | assert.deepEqual( 31 | dictionarize([ 32 | { type: 'foo', value: 1 }, 33 | { type: 'bar', value: 2 } 34 | ], 'type'), 35 | { 36 | foo: { type: 'foo', value: 1 }, 37 | bar: { type: 'bar', value: 2 } 38 | } 39 | ); 40 | }); 41 | 42 | it('createHelpText', function() { 43 | assert.strictEqual(typeof createHelpText(), 'string'); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/models/things/ThingModel.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | import validatorjs from 'validator'; 3 | 4 | import ThingModel from 'models/things/ThingModel'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('should be defined', function() { 11 | assert.strictEqual(typeof ThingModel, 'function'); 12 | }); 13 | 14 | it('uuid', function() { 15 | let thingModel = new ThingModel(); 16 | assert(validatorjs.isUUID(thingModel.uuid, 4)); 17 | }); 18 | 19 | it('getTypeId', function() { 20 | let thingModel = new ThingModel(); 21 | assert.strictEqual(thingModel.getTypeId(), '_thing'); 22 | }); 23 | 24 | it('getSymbol', function() { 25 | let thingModel = new ThingModel(); 26 | assert.strictEqual(thingModel.getSymbol(), '?'); 27 | }); 28 | 29 | it('isPassable', function() { 30 | let thingModel = new ThingModel(); 31 | assert.strictEqual(thingModel.isPassable(), true); 32 | thingModel._isPassable = false; 33 | assert.strictEqual(thingModel.isPassable(), false); 34 | }); 35 | 36 | it('toContent', function() { 37 | let thingModel = new ThingModel(); 38 | assert.strictEqual(thingModel.toContent(), thingModel.getSymbol()); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /components/pages/WelcomePageComponent.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React, {Component} from 'react'; 3 | 4 | import variables from '../variables'; 5 | import {KEYS} from 'consts'; 6 | import {stageList} from 'lib/stages'; 7 | 8 | 9 | export default class WelcomePageComponent extends Component { 10 | 11 | render() { 12 | 13 | let content = ''; 14 | 15 | // Title 16 | content += '{magenta-fg}Escape From The Maze{/}\n\n'; 17 | 18 | // Overview 19 | content += 'The purpose of the game is to escape from the maze by operating the "{magenta-fg}@{/}" '; 20 | content += 'by [{green-fg}wasd{/}] [{green-fg}hjkl{/}] or {green-fg}arrow keys{/}. '; 21 | content += 'Futher, by using [{green-fg}space{/}], you can also break the wall by consuming a pickaxe.\n'; 22 | content += '{yellow-fg}--help{/} option shows more helps!\n\n'; 23 | 24 | // Choices of stages 25 | let invertedKeys = _.invert(KEYS.STAGE_SELECTION); 26 | content += 'Push a {green-fg}key{/} for stage selection.\n\n'; 27 | content += stageList.map((Stage) => { 28 | return `[{green-fg}${invertedKeys[Stage.typeId]}{/}] ${Stage.getName()}: ${Stage.description}`; 29 | }).join('\n'); 30 | 31 | let props = Object.assign({}, variables.pageBoxProps); 32 | 33 | return ( 34 | 35 | {content} 36 | 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /dist/test/lib/stages/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _lodash = require('lodash'); 6 | 7 | var _lodash2 = _interopRequireDefault(_lodash); 8 | 9 | var _powerAssert = require('power-assert'); 10 | 11 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 12 | 13 | var _libStages = require('lib/stages'); 14 | 15 | var _testSupportHelpers = require('test/support/helpers'); 16 | 17 | describe((0, _testSupportHelpers.heading)(__filename), function () { 18 | 19 | context('Stage', function () { 20 | 21 | it('getName', function () { 22 | var FooBarStage = Object.assign({}, _libStages.Stage, { 23 | typeId: 'foo_bar' 24 | }); 25 | _powerAssert2['default'].strictEqual(FooBarStage.getName(), 'Foo Bar'); 26 | }); 27 | }); 28 | 29 | context('stageList, stages', function () { 30 | 31 | it('should be', function () { 32 | (0, _powerAssert2['default'])(_libStages.stageList.length > 0); 33 | _powerAssert2['default'].strictEqual(_libStages.stageList.length, Object.keys(_libStages.stages).length); 34 | 35 | var descriptions = _libStages.stageList.map(function (v) { 36 | return v.description; 37 | }); 38 | _powerAssert2['default'].strictEqual(descriptions.length, _lodash2['default'].unique(descriptions).length); 39 | }); 40 | }); 41 | }); -------------------------------------------------------------------------------- /dist/test/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _app = require('app'); 10 | 11 | var _app2 = _interopRequireDefault(_app); 12 | 13 | var _libEventManager = require('lib/EventManager'); 14 | 15 | var _libEventManager2 = _interopRequireDefault(_libEventManager); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | beforeEach(function () { 22 | _app2['default'].purgeInstances(); 23 | }); 24 | 25 | it('should create instance', function () { 26 | var app = new _app2['default'](); 27 | _powerAssert2['default'].strictEqual(typeof app, 'object'); 28 | _powerAssert2['default'].strictEqual(app instanceof _app2['default'], true); 29 | }); 30 | 31 | it('purgeInstances', function () { 32 | _powerAssert2['default'].strictEqual(_libEventManager2['default']._instance, null); 33 | _libEventManager2['default'].getInstance(); 34 | _powerAssert2['default'].strictEqual(_libEventManager2['default']._instance instanceof _libEventManager2['default'], true); 35 | _app2['default'].purgeInstances(); 36 | _powerAssert2['default'].strictEqual(_libEventManager2['default']._instance, null); 37 | }); 38 | }); -------------------------------------------------------------------------------- /actions/ScreenActionCreators.es6: -------------------------------------------------------------------------------- 1 | import ACTIONS from 'consts/actions'; 2 | import AppDispatcher from 'dispatcher/AppDispatcher'; 3 | 4 | 5 | const ScreenActionCreators = { 6 | 7 | changePage(pageId) { 8 | AppDispatcher.getInstance().dispatch({ 9 | type: ACTIONS.CHANGE_PAGE, 10 | pageId 11 | }); 12 | }, 13 | 14 | closeDialog() { 15 | AppDispatcher.getInstance().dispatch({ 16 | type: ACTIONS.CLOSE_DIALOG 17 | }); 18 | }, 19 | 20 | deleteLastInputFromDialog() { 21 | AppDispatcher.getInstance().dispatch({ 22 | type: ACTIONS.DELETE_LAST_INPUT_FROM_DIALOG 23 | }); 24 | }, 25 | 26 | exit() { 27 | AppDispatcher.getInstance().dispatch({ 28 | type: ACTIONS.EXIT 29 | }); 30 | }, 31 | 32 | inputKeyToDialog(keyName) { 33 | AppDispatcher.getInstance().dispatch({ 34 | type: ACTIONS.INPUT_KEY_TO_DIALOG, 35 | keyName 36 | }); 37 | }, 38 | 39 | openDialog() { 40 | AppDispatcher.getInstance().dispatch({ 41 | type: ACTIONS.OPEN_DIALOG 42 | }); 43 | }, 44 | 45 | prepareGame(stageTypeId) { 46 | AppDispatcher.getInstance().dispatch({ 47 | type: ACTIONS.PREPARE_GAME, 48 | stageTypeId 49 | }); 50 | }, 51 | 52 | /* 53 | * @param err {Error} 54 | */ 55 | throwRuntimeError(err) { 56 | AppDispatcher.getInstance().dispatch({ 57 | type: ACTIONS.THROW_RUNTIME_ERROR, 58 | err 59 | }); 60 | } 61 | }; 62 | 63 | 64 | export default ScreenActionCreators; 65 | -------------------------------------------------------------------------------- /components/Screen.es6: -------------------------------------------------------------------------------- 1 | import blessed from 'blessed'; 2 | import chalk from 'chalk'; 3 | import devnull from 'dev-null'; 4 | import _ from 'lodash'; 5 | import React from 'react'; 6 | import {render} from 'react-blessed'; 7 | 8 | import RootComponent from './RootComponent'; 9 | import conf from 'conf'; 10 | import {EVENTS} from 'consts'; 11 | import EventManager from 'lib/EventManager'; 12 | import SingletonMixin from 'lib/mixins/SingletonMixin'; 13 | import ScreenStore from 'stores/ScreenStore'; 14 | 15 | 16 | export default class Screen { 17 | 18 | constructor() { 19 | 20 | let screen = blessed.screen(this._createBlessedOptions()); 21 | screen.debugLog.unkey(['q', 'escape']); 22 | render(, screen); 23 | this._screen = screen; 24 | 25 | let {emitter} = EventManager.getInstance(); 26 | emitter.on(EVENTS.UPDATE_ERRORS, this._debug.bind(this)); 27 | emitter.on(EVENTS.EXIT, this._exit.bind(this)); 28 | } 29 | 30 | _createBlessedOptions() { 31 | let options = { 32 | debug: true, 33 | title: 'Escape From The Maze' 34 | }; 35 | 36 | if (conf.ignoreScreenOutput) { 37 | options.output = devnull(); 38 | } 39 | 40 | return options; 41 | } 42 | 43 | _exit() { 44 | process.stdin.pause(); 45 | process.exit(0); 46 | } 47 | 48 | _debug() { 49 | let screenStore = ScreenStore.getInstance(); 50 | var err = screenStore.getLastRuntimeError(); 51 | this._screen.debug(chalk.red(err)); 52 | } 53 | } 54 | 55 | Object.assign(Screen, SingletonMixin); 56 | -------------------------------------------------------------------------------- /dist/test/input/AppInput.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _sinon = require('sinon'); 10 | 11 | var _sinon2 = _interopRequireDefault(_sinon); 12 | 13 | var _app = require('app'); 14 | 15 | var _app2 = _interopRequireDefault(_app); 16 | 17 | var _inputAppInput = require('input/AppInput'); 18 | 19 | var _inputAppInput2 = _interopRequireDefault(_inputAppInput); 20 | 21 | var _testSupportHelpers = require('test/support/helpers'); 22 | 23 | describe((0, _testSupportHelpers.heading)(__filename), function () { 24 | 25 | beforeEach(function () { 26 | _app2['default'].purgeInstances(); 27 | }); 28 | 29 | it('should create instance', function () { 30 | var input = new _inputAppInput2['default'](); 31 | (0, _powerAssert2['default'])(input instanceof _inputAppInput2['default']); 32 | }); 33 | 34 | it('should destruct all observable sequences at clearInstance', function () { 35 | var input = _inputAppInput2['default'].getInstance(); 36 | var spies = []; 37 | spies.push(_sinon2['default'].spy(input._timerSubscription, 'dispose')); 38 | spies.push(_sinon2['default'].spy(input._keypressSubscription, 'dispose')); 39 | _inputAppInput2['default'].clearInstance(); 40 | _powerAssert2['default'].strictEqual(spies[0].callCount, 1); 41 | _powerAssert2['default'].strictEqual(spies[1].callCount, 1); 42 | }); 43 | }); -------------------------------------------------------------------------------- /dist/test/lib/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _conf = require('conf'); 10 | 11 | var _conf2 = _interopRequireDefault(_conf); 12 | 13 | var _libUtil = require('lib/util'); 14 | 15 | var _testSupportHelpers = require('test/support/helpers'); 16 | 17 | describe((0, _testSupportHelpers.heading)(__filename), function () { 18 | 19 | it('createCounter', function () { 20 | var counter = undefined; 21 | counter = (0, _libUtil.createCounter)(); 22 | _powerAssert2['default'].strictEqual(counter(), 1); 23 | _powerAssert2['default'].strictEqual(counter(), 2); 24 | counter = (0, _libUtil.createCounter)(-2); 25 | _powerAssert2['default'].strictEqual(counter(), -2); 26 | _powerAssert2['default'].strictEqual(counter(), -1); 27 | }); 28 | 29 | it('calculateMillisecondsPerFrame', function () { 30 | _powerAssert2['default'].strictEqual((0, _libUtil.calculateMillisecondsPerFrame)(), ~ ~(1000 / _conf2['default'].fps)); 31 | }); 32 | 33 | it('dictionarize', function () { 34 | _powerAssert2['default'].deepEqual((0, _libUtil.dictionarize)([{ type: 'foo', value: 1 }, { type: 'bar', value: 2 }], 'type'), { 35 | foo: { type: 'foo', value: 1 }, 36 | bar: { type: 'bar', value: 2 } 37 | }); 38 | }); 39 | 40 | it('createHelpText', function () { 41 | _powerAssert2['default'].strictEqual(typeof (0, _libUtil.createHelpText)(), 'string'); 42 | }); 43 | }); -------------------------------------------------------------------------------- /stores/ScreenStore.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import {ACTIONS, EVENTS} from 'consts'; 4 | import AppDispatcher from 'dispatcher/AppDispatcher'; 5 | import EventManager from 'lib/EventManager'; 6 | import GameStore from 'stores/GameStore'; 7 | import Store from 'stores/Store'; 8 | 9 | 10 | const DIALOG_INPUT_MATCHER = /^[a-zA-Z0-9]{1,12}$/; 11 | function validateDialogInput(input) { 12 | return DIALOG_INPUT_MATCHER.test(input); 13 | } 14 | 15 | 16 | class ScreenStore extends Store { 17 | 18 | constructor() { 19 | super(); 20 | 21 | this._pageId = 'welcome'; 22 | this._runtimeErrors = []; 23 | 24 | Object.defineProperty(this, 'pageId', { get() { return this._pageId; } }); 25 | 26 | let dispatcher = AppDispatcher.getInstance(); 27 | let {emitter} = EventManager.getInstance(); 28 | let gameStore = GameStore.getInstance(); 29 | this._dispatchToken = dispatcher.register((action) => { 30 | dispatcher.waitFor([ 31 | gameStore.getDispatchToken() 32 | ]); 33 | 34 | switch (action.type) { 35 | case ACTIONS.CHANGE_PAGE: 36 | this._pageId = action.pageId; 37 | emitter.emit(EVENTS.CHANGE_PAGE); 38 | break; 39 | case ACTIONS.EXIT: 40 | emitter.emit(EVENTS.EXIT); 41 | break; 42 | case ACTIONS.THROW_RUNTIME_ERROR: 43 | this._runtimeErrors.push(action.err); 44 | emitter.emit(EVENTS.UPDATE_ERRORS); 45 | break; 46 | } 47 | }); 48 | } 49 | 50 | getLastRuntimeError() { 51 | return _.last(this._runtimeErrors); 52 | } 53 | } 54 | 55 | 56 | export default ScreenStore; 57 | -------------------------------------------------------------------------------- /app.es6: -------------------------------------------------------------------------------- 1 | import ScreenActionCreators from 'actions/ScreenActionCreators'; 2 | import Screen from 'components/Screen'; 3 | import conf from 'conf'; 4 | import AppDispatcher from 'dispatcher/AppDispatcher'; 5 | import AppInput from 'input/AppInput'; 6 | import EventManager from 'lib/EventManager'; 7 | import SingletonMixin from 'lib/mixins/SingletonMixin'; 8 | import DialogStore from 'stores/DialogStore'; 9 | import GameStore from 'stores/GameStore'; 10 | import ScreenStore from 'stores/ScreenStore'; 11 | 12 | 13 | export default class App { 14 | 15 | /* 16 | * Initialize unique instances in consideration of the order 17 | */ 18 | static initializeInstances() { 19 | [ 20 | () => EventManager.getInstance(), 21 | () => AppDispatcher.getInstance(), 22 | () => DialogStore.getInstance(), 23 | () => GameStore.getInstance(), 24 | () => ScreenStore.getInstance(), 25 | () => AppInput.getInstance() 26 | ].forEach(task => task()); 27 | } 28 | 29 | static purgeInstances() { 30 | [ 31 | () => Screen.clearInstance(), 32 | () => AppInput.clearInstance(), 33 | () => ScreenStore.clearInstance(), 34 | () => DialogStore.clearInstance(), 35 | () => GameStore.clearInstance(), 36 | () => AppDispatcher.clearInstance(), 37 | () => EventManager.clearInstance() 38 | ].forEach(task => task()); 39 | } 40 | 41 | constructor() { 42 | this.constructor.initializeInstances(); 43 | } 44 | 45 | start() { 46 | Screen.getInstance({ componentMode: conf.componentMode }); 47 | ScreenActionCreators.changePage('welcome'); 48 | } 49 | } 50 | 51 | Object.assign(App, SingletonMixin); 52 | -------------------------------------------------------------------------------- /dist/stores/Store.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | var _libMixinsSingletonMixin = require('lib/mixins/SingletonMixin'); 14 | 15 | var _libMixinsSingletonMixin2 = _interopRequireDefault(_libMixinsSingletonMixin); 16 | 17 | var Store = (function () { 18 | function Store() { 19 | _classCallCheck(this, Store); 20 | 21 | this._dispatchToken = null; 22 | } 23 | 24 | _createClass(Store, [{ 25 | key: 'getDispatchToken', 26 | value: function getDispatchToken() { 27 | if (!this._dispatchToken) { 28 | throw new Error('dispatchToken does not exist'); 29 | } 30 | return this._dispatchToken; 31 | } 32 | }]); 33 | 34 | return Store; 35 | })(); 36 | 37 | exports['default'] = Store; 38 | 39 | Object.assign(Store, _libMixinsSingletonMixin2['default']); 40 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/test/lib/mixins/SingletonMixin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6 | 7 | var _lodash = require('lodash'); 8 | 9 | var _lodash2 = _interopRequireDefault(_lodash); 10 | 11 | var _powerAssert = require('power-assert'); 12 | 13 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 14 | 15 | var _libMixinsSingletonMixin = require('lib/mixins/SingletonMixin'); 16 | 17 | var _libMixinsSingletonMixin2 = _interopRequireDefault(_libMixinsSingletonMixin); 18 | 19 | var _testSupportHelpers = require('test/support/helpers'); 20 | 21 | describe((0, _testSupportHelpers.heading)(__filename), function () { 22 | 23 | it('should be defined', function () { 24 | _powerAssert2['default'].strictEqual(typeof _libMixinsSingletonMixin2['default'], 'object'); 25 | }); 26 | 27 | it('getInstance, clearInstance', function () { 28 | var Foo = function Foo(x, y) { 29 | _classCallCheck(this, Foo); 30 | 31 | this.data = { 32 | x: x, 33 | y: y 34 | }; 35 | }; 36 | 37 | _lodash2['default'].assign(Foo, _libMixinsSingletonMixin2['default']); 38 | 39 | var foo = Foo.getInstance(1, 2); 40 | _powerAssert2['default'].deepEqual(foo.data, { x: 1, y: 2 }); 41 | var foo2 = Foo.getInstance(); 42 | (0, _powerAssert2['default'])(foo === foo2); 43 | 44 | Foo.clearInstance(); 45 | var foo3 = Foo.getInstance(2, 3); 46 | (0, _powerAssert2['default'])(foo !== foo3); 47 | _powerAssert2['default'].deepEqual(foo3.data, { x: 2, y: 3 }); 48 | }); 49 | }); -------------------------------------------------------------------------------- /actions/GameActionCreators.es6: -------------------------------------------------------------------------------- 1 | import ACTIONS from 'consts/actions'; 2 | import AppDispatcher from 'dispatcher/AppDispatcher'; 3 | 4 | 5 | const GameActionCreators = { 6 | 7 | advanceToNextMaze() { 8 | AppDispatcher.getInstance().dispatch({ 9 | type: ACTIONS.ADVANCE_TO_NEXT_MAZE 10 | }); 11 | }, 12 | 13 | assumePicksMode() { 14 | AppDispatcher.getInstance().dispatch({ 15 | type: ACTIONS.ASSUME_PICKS_MODE 16 | }); 17 | }, 18 | 19 | cancelPicksMode() { 20 | AppDispatcher.getInstance().dispatch({ 21 | type: ACTIONS.CANCEL_PICKS_MODE 22 | }); 23 | }, 24 | 25 | crushWallByPlayer(direction) { 26 | AppDispatcher.getInstance().dispatch({ 27 | type: ACTIONS.CRUSH_WALL_BY_PLAYER, 28 | direction 29 | }); 30 | }, 31 | 32 | forwardGameTimeByFrame() { 33 | AppDispatcher.getInstance().dispatch({ 34 | type: ACTIONS.FORWARD_GAME_TIME_BY_FRAME 35 | }); 36 | }, 37 | 38 | /* async */ 39 | requestAddingGameResult(playerName) { 40 | AppDispatcher.getInstance().dispatch({ 41 | type: ACTIONS.REQUEST_ADDING_GAME_RESULT, 42 | playerName 43 | }); 44 | }, 45 | 46 | resetGame() { 47 | AppDispatcher.getInstance().dispatch({ 48 | type: ACTIONS.RESET_GAME 49 | }); 50 | }, 51 | 52 | saveDefeat() { 53 | AppDispatcher.getInstance().dispatch({ 54 | type: ACTIONS.SAVE_DEFEAT 55 | }); 56 | }, 57 | 58 | saveVictory() { 59 | AppDispatcher.getInstance().dispatch({ 60 | type: ACTIONS.SAVE_VICTORY 61 | }); 62 | }, 63 | 64 | walkPlayer(direction) { 65 | AppDispatcher.getInstance().dispatch({ 66 | type: ACTIONS.WALK_PLAYER, 67 | direction 68 | }); 69 | } 70 | }; 71 | 72 | 73 | export default GameActionCreators; 74 | -------------------------------------------------------------------------------- /dist/test/models/ThingIndexerModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _uuid = require('uuid'); 10 | 11 | var _uuid2 = _interopRequireDefault(_uuid); 12 | 13 | var _modelsThingIndexerModel = require('models/ThingIndexerModel'); 14 | 15 | var _modelsThingIndexerModel2 = _interopRequireDefault(_modelsThingIndexerModel); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | it('should be defined', function () { 22 | _powerAssert2['default'].strictEqual(typeof _modelsThingIndexerModel2['default'], 'function'); 23 | }); 24 | 25 | it('update, get, getIds', function () { 26 | var indexer = new _modelsThingIndexerModel2['default'](); 27 | _powerAssert2['default'].deepEqual(indexer.getIds(), []); 28 | var uuid = _uuid2['default'].v4(); 29 | indexer.update(uuid, [1, 2]); 30 | indexer.update(uuid, [1, 3]); 31 | _powerAssert2['default'].deepEqual(indexer.get(uuid), [1, 3]); 32 | _powerAssert2['default'].deepEqual(indexer.getIds(), [uuid]); 33 | _powerAssert2['default'].strictEqual(indexer.get('not-existing-uuid'), null); 34 | }); 35 | 36 | it('remove', function () { 37 | var indexer = new _modelsThingIndexerModel2['default'](); 38 | var uuid1 = _uuid2['default'].v4(); 39 | var uuid2 = _uuid2['default'].v4(); 40 | indexer.update(uuid1, [1, 2]); 41 | indexer.update(uuid2, [1, 3]); 42 | _powerAssert2['default'].deepEqual(indexer.get(uuid1), [1, 2]); 43 | indexer.remove(uuid1); 44 | _powerAssert2['default'].strictEqual(indexer.get(uuid1), null); 45 | }); 46 | }); -------------------------------------------------------------------------------- /dist/test/models/things/WallThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _validator = require('validator'); 10 | 11 | var _validator2 = _interopRequireDefault(_validator); 12 | 13 | var _modelsThingsWallThingModel = require('models/things/WallThingModel'); 14 | 15 | var _modelsThingsWallThingModel2 = _interopRequireDefault(_modelsThingsWallThingModel); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | it('should be defined', function () { 22 | _powerAssert2['default'].strictEqual(typeof _modelsThingsWallThingModel2['default'], 'function'); 23 | }); 24 | 25 | it('uuid', function () { 26 | var thing = new _modelsThingsWallThingModel2['default'](); 27 | (0, _powerAssert2['default'])(_validator2['default'].isUUID(thing.uuid, 4)); 28 | }); 29 | 30 | it('getTypeId', function () { 31 | var thing = new _modelsThingsWallThingModel2['default'](); 32 | _powerAssert2['default'].strictEqual(thing.getTypeId(), 'wall'); 33 | }); 34 | 35 | it('getSymbol', function () { 36 | var thing = new _modelsThingsWallThingModel2['default'](); 37 | _powerAssert2['default'].strictEqual(thing.getSymbol(), '#'); 38 | }); 39 | 40 | it('isPassable', function () { 41 | var thing = new _modelsThingsWallThingModel2['default'](); 42 | _powerAssert2['default'].strictEqual(thing.isPassable(), false); 43 | }); 44 | 45 | it('toContent', function () { 46 | var thing = new _modelsThingsWallThingModel2['default'](); 47 | _powerAssert2['default'].strictEqual(thing.toContent(), '#'); 48 | }); 49 | }); -------------------------------------------------------------------------------- /lib/stages/index.es6: -------------------------------------------------------------------------------- 1 | import _s from 'underscore.string'; 2 | 3 | import {createCounter, dictionarize} from 'lib/util'; 4 | 5 | let counter = createCounter(); 6 | 7 | 8 | export const Stage = { 9 | typeId: '_stage', 10 | sortOrder: 0, 11 | mazeCount: 1, 12 | timeLimit: 60000, 13 | bonusTimeThingCount: 5, 14 | penaltyTimeThingCount: 3, 15 | picksThingCount: 1, 16 | picksCount: 0, 17 | description: '----', 18 | getName() { 19 | return _s.titleize(_s.humanize(this.typeId)); 20 | } 21 | }; 22 | 23 | 24 | const SimpleStage = Object.assign({}, Stage, { 25 | typeId: 'simple', 26 | sortOrder: counter(), 27 | bonusTimeThingCount: 0, 28 | penaltyTimeThingCount: 0, 29 | picksThingCount: 0, 30 | description: 'Just run, no gimmick' 31 | }); 32 | 33 | const EasyStage = Object.assign({}, Stage, { 34 | typeId: 'easy', 35 | sortOrder: counter(), 36 | picksCount: 1, 37 | timeLimit: 45000, 38 | description: 'Enable gimmicks' 39 | }); 40 | 41 | const NormalStage = Object.assign({}, Stage, { 42 | typeId: 'normal', 43 | sortOrder: counter(), 44 | mazeCount: 2, 45 | timeLimit: 45000, 46 | picksCount: 1, 47 | description: 'Plural mazes continue' 48 | }); 49 | 50 | const HardStage = Object.assign({}, Stage, { 51 | typeId: 'hard', 52 | sortOrder: counter(), 53 | mazeCount: 3, 54 | timeLimit: 45000, 55 | picksCount: 1, 56 | description: 'More difficult' 57 | }); 58 | 59 | const LunaticStage = Object.assign({}, Stage, { 60 | typeId: 'lunatic', 61 | sortOrder: counter(), 62 | mazeCount: 5, 63 | timeLimit: 60000, 64 | picksCount: 2, 65 | description: 'For a person of leisure' 66 | }); 67 | 68 | 69 | export const stageList = [ 70 | SimpleStage, 71 | EasyStage, 72 | NormalStage, 73 | HardStage, 74 | LunaticStage 75 | ]; 76 | export const stages = dictionarize(stageList, 'typeId'); 77 | -------------------------------------------------------------------------------- /dist/test/models/things/PlayerThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _validator = require('validator'); 10 | 11 | var _validator2 = _interopRequireDefault(_validator); 12 | 13 | var _modelsThingsPlayerThingModel = require('models/things/PlayerThingModel'); 14 | 15 | var _modelsThingsPlayerThingModel2 = _interopRequireDefault(_modelsThingsPlayerThingModel); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | it('should be defined', function () { 22 | _powerAssert2['default'].strictEqual(typeof _modelsThingsPlayerThingModel2['default'], 'function'); 23 | }); 24 | 25 | it('uuid', function () { 26 | var thing = new _modelsThingsPlayerThingModel2['default'](); 27 | (0, _powerAssert2['default'])(_validator2['default'].isUUID(thing.uuid, 4)); 28 | }); 29 | 30 | it('getTypeId', function () { 31 | var thing = new _modelsThingsPlayerThingModel2['default'](); 32 | _powerAssert2['default'].strictEqual(thing.getTypeId(), 'player'); 33 | }); 34 | 35 | it('getSymbol', function () { 36 | var thing = new _modelsThingsPlayerThingModel2['default'](); 37 | _powerAssert2['default'].strictEqual(thing.getSymbol(), '@'); 38 | }); 39 | 40 | it('isPassable', function () { 41 | var thing = new _modelsThingsPlayerThingModel2['default'](); 42 | _powerAssert2['default'].strictEqual(thing.isPassable(), true); 43 | }); 44 | 45 | it('toContent', function () { 46 | var thing = new _modelsThingsPlayerThingModel2['default'](); 47 | _powerAssert2['default'].strictEqual(thing.toContent(), '{magenta-fg}@{/}'); 48 | }); 49 | }); -------------------------------------------------------------------------------- /models/CellModel.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import Model from 'models/Model'; 4 | 5 | 6 | export default class CellModel extends Model { 7 | 8 | constructor() { 9 | super(); 10 | 11 | this._things = []; 12 | } 13 | 14 | getThings() { 15 | return this._things; 16 | } 17 | 18 | getThing() { 19 | return this.getThings()[0] || null; 20 | } 21 | 22 | getThingOrError() { 23 | let thing = this.getThing(); 24 | if (thing) { 25 | return thing; 26 | } else { 27 | throw new Error('Can not get a thing'); 28 | } 29 | } 30 | 31 | findThing(thing) { 32 | return _.find(this._things, function(thing_) { 33 | return thing === thing_; 34 | }) || null; 35 | } 36 | 37 | findThingOrError(thing) { 38 | let thing_ = this.findThing(thing); 39 | if (thing_) { 40 | return thing_; 41 | } else { 42 | throw new Error('Can not find the thing'); 43 | } 44 | } 45 | 46 | hasThing(thing) { 47 | return !!this.findThing(thing); 48 | } 49 | 50 | setThing(thing) { 51 | if (this.hasThing(thing)) { 52 | throw new Error('The thing is duplicated'); 53 | } 54 | this._things.push(thing); 55 | } 56 | 57 | /* 58 | * @param {Thing} thing 59 | * @return {boolean} Removed or not removed 60 | */ 61 | removeThing(thing) { 62 | let removed = _.remove(this._things, function(thing_) { 63 | return thing === thing_; 64 | }); 65 | return removed.length > 0; 66 | } 67 | 68 | isPassable() { 69 | if (this._things.length === 0) { 70 | return true; 71 | } 72 | return this._things.every(function(thing) { 73 | return thing.isPassable(); 74 | }); 75 | } 76 | 77 | toContent() { 78 | if (this._things.length > 0) { 79 | return this._things[0].toContent(); 80 | } else { 81 | return ' '; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/util.es6: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | import conf from 'conf'; 4 | 5 | 6 | export function createCounter(start = 1) { 7 | start -= 1; 8 | return () => start += 1; 9 | } 10 | 11 | export function calculateMillisecondsPerFrame() { 12 | return ~~(1000 / conf.fps); 13 | } 14 | 15 | /* 16 | * Convert from list to dict by property-name 17 | * 18 | * @param {string} propertyName 19 | * @return {Object} 20 | */ 21 | export function dictionarize(list, propertyName) { 22 | let dict = {}; 23 | list.forEach(v => dict[v[propertyName]] = v); 24 | return dict; 25 | } 26 | 27 | export function createHelpText() { 28 | let playerSymbol = chalk.magenta.bgBlack('@'); 29 | let wallSymbol = chalk.white.bgBlack('#'); 30 | let pickaxeSymbol = chalk.yellow.bgBlack('T'); 31 | let bonusTime5Symbol = chalk.green.bgBlack('5'); 32 | let penaltyTime3Symbol = chalk.red.bgBlack('3'); 33 | 34 | let lines = [ 35 | '# Escape From The Maze - Help', 36 | '', 37 | '## Operation of player', 38 | '- You can move the player(' + playerSymbol + ') by [w][a][s][d], [h][j][k][l] or [arrow keys].', 39 | '- If you move after you press the [space], you can break the wall(' + wallSymbol + ') to consume one pickaxe.', 40 | '', 41 | '## Victory or defat, and score', 42 | '- It is a victory if escape the maze within the time limit.', 43 | '- The number of maze is different for each stage.', 44 | '- If you win, the remaining milliseconds will be the score.', 45 | '', 46 | '## Treasures', 47 | '- "' + pickaxeSymbol + '" You get a extra pickaxe.', 48 | '- "' + bonusTime5Symbol + '" Time limit is increased 5 seconds.', 49 | '- "' + penaltyTime3Symbol + '" Time limit is reduced 3 seconds.', 50 | '', 51 | '## Others', 52 | '- You can look ranking by `escape-from-the-maze --ranking`.', 53 | ]; 54 | return lines.join('\n'); 55 | } 56 | -------------------------------------------------------------------------------- /components/DialogComponent.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React, {Component} from 'react'; 3 | 4 | import variables from './variables'; 5 | 6 | 7 | export default class DialogComponent extends Component { 8 | 9 | constructor(props) { 10 | super(props); 11 | } 12 | 13 | render() { 14 | 15 | let content = ''; 16 | content += '\n'; 17 | content += 'What\'s your name?\n'; 18 | content += '\n'; 19 | content += '\n'; 20 | content += '\n'; 21 | content += 'by /{green-fg}[-_a-zA-Z0-9]{open}1,12{close}{/}/\n'; 22 | content += '\n'; 23 | content += 'Submit is [{green-fg}enter{/}]\n'; 24 | content += 'Cancel is [{green-fg}escape{/}]\n'; 25 | 26 | let props = { 27 | ref: 'root', 28 | top: 'center', 29 | left: 'center', 30 | width: 33, 31 | height: 12, 32 | tags: true, 33 | border: { 34 | type: 'line' 35 | }, 36 | align: 'center', 37 | style: { 38 | fg: 'white', 39 | bg: 'black', 40 | border: { 41 | fg: 'white' 42 | } 43 | }, 44 | content: content, 45 | hidden: !this.props.isDialogActive, 46 | }; 47 | if (this.props.isDialogActive) { 48 | this.refs.root.setFront(); 49 | } 50 | 51 | let inputBoxProps = { 52 | top: 3, 53 | left: 'center', 54 | width: 25, 55 | height: 1, 56 | style: { 57 | fg: (this.props.isValidDialogInput) ? 'black' : 'red', 58 | bg: 'white', 59 | }, 60 | content: this.props.dialogInputValue, 61 | }; 62 | 63 | return ( 64 | 65 | 66 | 67 | ); 68 | } 69 | } 70 | 71 | Object.assign(DialogComponent, { 72 | 73 | propTypes: { 74 | isDialogActive: React.PropTypes.bool.isRequired, 75 | dialogInputValue: React.PropTypes.string.isRequired, 76 | isValidDialogInput: React.PropTypes.bool.isRequired, 77 | } 78 | }); 79 | -------------------------------------------------------------------------------- /dist/test/models/things/ThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _validator = require('validator'); 10 | 11 | var _validator2 = _interopRequireDefault(_validator); 12 | 13 | var _modelsThingsThingModel = require('models/things/ThingModel'); 14 | 15 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | it('should be defined', function () { 22 | _powerAssert2['default'].strictEqual(typeof _modelsThingsThingModel2['default'], 'function'); 23 | }); 24 | 25 | it('uuid', function () { 26 | var thingModel = new _modelsThingsThingModel2['default'](); 27 | (0, _powerAssert2['default'])(_validator2['default'].isUUID(thingModel.uuid, 4)); 28 | }); 29 | 30 | it('getTypeId', function () { 31 | var thingModel = new _modelsThingsThingModel2['default'](); 32 | _powerAssert2['default'].strictEqual(thingModel.getTypeId(), '_thing'); 33 | }); 34 | 35 | it('getSymbol', function () { 36 | var thingModel = new _modelsThingsThingModel2['default'](); 37 | _powerAssert2['default'].strictEqual(thingModel.getSymbol(), '?'); 38 | }); 39 | 40 | it('isPassable', function () { 41 | var thingModel = new _modelsThingsThingModel2['default'](); 42 | _powerAssert2['default'].strictEqual(thingModel.isPassable(), true); 43 | thingModel._isPassable = false; 44 | _powerAssert2['default'].strictEqual(thingModel.isPassable(), false); 45 | }); 46 | 47 | it('toContent', function () { 48 | var thingModel = new _modelsThingsThingModel2['default'](); 49 | _powerAssert2['default'].strictEqual(thingModel.toContent(), thingModel.getSymbol()); 50 | }); 51 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "escape-from-the-maze", 3 | "description": "A simple & tiny CUI maze game", 4 | "version": "1.1.0", 5 | "author": "kjirou", 6 | "bin": { 7 | "escape-from-the-maze": "./bin/escape-from-the-maze" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/kjirou/escape-from-the-maze/issues" 11 | }, 12 | "dependencies": { 13 | "babel": "5.8.21", 14 | "blessed": "0.1.21", 15 | "chalk": "1.1.1", 16 | "dev-null": "0.1.1", 17 | "flux": "2.0.3", 18 | "generate-maze-by-clustering": "0.0.4", 19 | "keymirror": "0.1.1", 20 | "keypress": "0.2.1", 21 | "lodash": "3.10.1", 22 | "minimist": "1.2.0", 23 | "react": "0.14.0-beta3", 24 | "react-blessed": "0.1.0", 25 | "request": "2.61.0", 26 | "rx": "3.0.0", 27 | "underscore.string": "3.1.1", 28 | "uuid": "2.0.1" 29 | }, 30 | "devDependencies": { 31 | "eslint": "1.1.0", 32 | "espower-babel": "3.2.0", 33 | "fixpack": "2.2.0", 34 | "gulp": "3.9.0", 35 | "gulp-babel": "5.2.1", 36 | "mocha": "2.2.5", 37 | "power-assert": "0.11.0", 38 | "sinon": "1.16.0", 39 | "validator": "4.0.3" 40 | }, 41 | "engines": { 42 | "node": ">=0.12", 43 | "npm": ">=2" 44 | }, 45 | "homepage": "https://github.com/kjirou/escape-from-the-maze#readme", 46 | "keywords": [ 47 | "cui", 48 | "game", 49 | "maze" 50 | ], 51 | "license": "MIT", 52 | "main": "app.es6", 53 | "repository": { 54 | "type": "git", 55 | "url": "git+https://github.com/kjirou/escape-from-the-maze.git" 56 | }, 57 | "scripts": { 58 | "build": "gulp build", 59 | "help": "node bin/escape-from-the-maze -d -h", 60 | "lint": "eslint --ext .es6 *.es6 actions components conf consts dispatcher env input lib models stores test", 61 | "ranking": "node bin/escape-from-the-maze -d -r", 62 | "start": "node bin/escape-from-the-maze -d", 63 | "test": "mocha", 64 | "zip-server": "cd server/aws-lambda && npm i && zip -r ../../tmp/aws-lambda-`date '+%Y%m%d-%H%M%S'`.zip index.js aws-config.json node_modules && cd ../.." 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/models/CellModel.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import CellModel from 'models/CellModel'; 4 | import ThingModel from 'models/things/ThingModel'; 5 | import {heading} from 'test/support/helpers'; 6 | 7 | 8 | describe(heading(__filename), function() { 9 | 10 | it('should be defined', function() { 11 | assert.strictEqual(typeof CellModel, 'function'); 12 | }); 13 | 14 | it('thing accessors', function() { 15 | let cell = new CellModel(); 16 | let thing = new ThingModel(); 17 | 18 | assert.strictEqual(cell.findThing(thing), null); 19 | assert.strictEqual(cell.hasThing(thing), false); 20 | cell.setThing(thing); 21 | assert.strictEqual(cell.findThing(thing), thing); 22 | assert.strictEqual(cell.findThingOrError(thing), thing); 23 | assert.strictEqual(cell.hasThing(thing), true); 24 | 25 | let anotherThing = new ThingModel(); 26 | assert.strictEqual(cell.findThing(anotherThing), null); 27 | assert.throws(function() { 28 | cell.findThingOrError(anotherThing); 29 | }, /Can not /); 30 | 31 | assert.strictEqual(cell.removeThing(anotherThing), false); 32 | assert.strictEqual(cell.hasThing(thing), true); 33 | assert.strictEqual(cell.removeThing(thing), true); 34 | assert.strictEqual(cell.hasThing(thing), false); 35 | }); 36 | 37 | it('isPassable', function() { 38 | let cell, thing; 39 | cell = new CellModel(); 40 | assert.strictEqual(cell.isPassable(), true); 41 | 42 | thing = new ThingModel(); 43 | thing._isPassable = true; 44 | cell.setThing(thing); 45 | assert.strictEqual(cell.isPassable(), true); 46 | 47 | thing = new ThingModel(); 48 | thing._isPassable = false; 49 | cell.setThing(thing); 50 | assert.strictEqual(cell.isPassable(), false); 51 | 52 | thing = new ThingModel(); 53 | thing._isPassable = true; 54 | cell.setThing(thing); 55 | assert.strictEqual(cell.isPassable(), false); 56 | }); 57 | 58 | it('toContent', function() { 59 | let cell; 60 | cell = new CellModel(); 61 | assert.strictEqual(cell.toContent(), ' '); 62 | cell.setThing(new ThingModel()); 63 | assert.strictEqual(cell.toContent(), '?'); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /stores/DialogStore.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import {ACTIONS, EVENTS} from 'consts'; 4 | import AppDispatcher from 'dispatcher/AppDispatcher'; 5 | import EventManager from 'lib/EventManager'; 6 | import Store from 'stores/Store'; 7 | 8 | 9 | const DIALOG_INPUT_MATCHER = /^[a-zA-Z0-9]{1,12}$/; 10 | function validateDialogInput(input) { 11 | return DIALOG_INPUT_MATCHER.test(input); 12 | } 13 | 14 | 15 | class DialogStore extends Store { 16 | 17 | constructor() { 18 | super(); 19 | 20 | this._isDialogActive = false; 21 | this._dialogInputValue = ''; 22 | this._isValidDialogInput = false; 23 | 24 | Object.defineProperty(this, 'isDialogActive', { get() { return this._isDialogActive; } }); 25 | Object.defineProperty(this, 'dialogInputValue', { get() { return this._dialogInputValue; } }); 26 | Object.defineProperty(this, 'isValidDialogInput', { get() { return this._isValidDialogInput; } }); 27 | 28 | let dispatcher = AppDispatcher.getInstance(); 29 | let {emitter} = EventManager.getInstance(); 30 | this._dispatchToken = dispatcher.register((action) => { 31 | switch (action.type) { 32 | case ACTIONS.CLOSE_DIALOG: 33 | this._isDialogActive = false; 34 | this._dialogInputValue = ''; 35 | emitter.emit(EVENTS.UPDATE_DIALOG); 36 | break; 37 | case ACTIONS.DELETE_LAST_INPUT_FROM_DIALOG: 38 | this._dialogInputValue = this._dialogInputValue.slice(0, -1); 39 | this._isValidDialogInput = validateDialogInput(this._dialogInputValue); 40 | emitter.emit(EVENTS.UPDATE_DIALOG); 41 | break; 42 | case ACTIONS.INPUT_KEY_TO_DIALOG: 43 | this._dialogInputValue += action.keyName; 44 | this._isValidDialogInput = validateDialogInput(this._dialogInputValue); 45 | emitter.emit(EVENTS.UPDATE_DIALOG); 46 | break; 47 | case ACTIONS.OPEN_DIALOG: 48 | this._isDialogActive = true; 49 | this._dialogInputValue = ''; 50 | this._isValidDialogInput = false; 51 | emitter.emit(EVENTS.UPDATE_DIALOG); 52 | break; 53 | } 54 | }); 55 | } 56 | } 57 | 58 | 59 | export default DialogStore; 60 | -------------------------------------------------------------------------------- /input/AppInput.es6: -------------------------------------------------------------------------------- 1 | import keypress from 'keypress'; 2 | import Rx from 'rx'; 3 | 4 | import {onError} from 'input/subscriptions/error'; 5 | import {onKeypress} from 'input/subscriptions/keypress'; 6 | import {onTimer} from 'input/subscriptions/timer'; 7 | import SingletonMixin from 'lib/mixins/SingletonMixin'; 8 | import {calculateMillisecondsPerFrame} from 'lib/util'; 9 | 10 | keypress(process.stdin); 11 | process.stdin.setRawMode(true); 12 | process.stdin.resume(); 13 | 14 | 15 | export default class AppInput { 16 | 17 | constructor() { 18 | let pauser = new Rx.Subject(); 19 | 20 | let timerSource = Rx.Observable 21 | .timer(0, calculateMillisecondsPerFrame()) 22 | .timeInterval() 23 | .map((data) => { 24 | pauser.onNext(true); 25 | return data; 26 | }) 27 | ; 28 | 29 | let wrappedHandler; 30 | let keypressSource = Rx.Observable 31 | .fromEventPattern( 32 | (handler) => { 33 | wrappedHandler = function(chr, key) { 34 | if (!key) { 35 | key = { 36 | name: chr, 37 | ctrl: false, 38 | sequence: chr 39 | }; 40 | } 41 | handler(key); 42 | }; 43 | process.stdin.addListener('keypress', wrappedHandler); 44 | }, 45 | () => { 46 | process.stdin.removeListener('keypress', wrappedHandler); 47 | } 48 | ) 49 | .pausable(pauser) 50 | .filter(function() { 51 | var isStopped = pauser.isStopped; 52 | pauser.onNext(false); 53 | return !isStopped; 54 | }) 55 | ; 56 | 57 | this._timerSubscription = timerSource.subscribe( 58 | onTimer, 59 | onError 60 | ); 61 | this._keypressSubscription = keypressSource.subscribe( 62 | onKeypress, 63 | onError 64 | ); 65 | } 66 | 67 | _destructor() { 68 | this._timerSubscription.dispose(); 69 | this._keypressSubscription.dispose(); 70 | } 71 | } 72 | 73 | Object.assign(AppInput, SingletonMixin); 74 | 75 | AppInput._destructInstance = function _destructInstance() { 76 | if (this._instance) { 77 | this._instance._destructor(); 78 | } 79 | }; 80 | -------------------------------------------------------------------------------- /dist/lib/stages/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _underscoreString = require('underscore.string'); 10 | 11 | var _underscoreString2 = _interopRequireDefault(_underscoreString); 12 | 13 | var _libUtil = require('lib/util'); 14 | 15 | var counter = (0, _libUtil.createCounter)(); 16 | 17 | var Stage = { 18 | typeId: '_stage', 19 | sortOrder: 0, 20 | mazeCount: 1, 21 | timeLimit: 60000, 22 | bonusTimeThingCount: 5, 23 | penaltyTimeThingCount: 3, 24 | picksThingCount: 1, 25 | picksCount: 0, 26 | description: '----', 27 | getName: function getName() { 28 | return _underscoreString2['default'].titleize(_underscoreString2['default'].humanize(this.typeId)); 29 | } 30 | }; 31 | 32 | exports.Stage = Stage; 33 | var SimpleStage = Object.assign({}, Stage, { 34 | typeId: 'simple', 35 | sortOrder: counter(), 36 | bonusTimeThingCount: 0, 37 | penaltyTimeThingCount: 0, 38 | picksThingCount: 0, 39 | description: 'Just run, no gimmick' 40 | }); 41 | 42 | var EasyStage = Object.assign({}, Stage, { 43 | typeId: 'easy', 44 | sortOrder: counter(), 45 | picksCount: 1, 46 | timeLimit: 45000, 47 | description: 'Enable gimmicks' 48 | }); 49 | 50 | var NormalStage = Object.assign({}, Stage, { 51 | typeId: 'normal', 52 | sortOrder: counter(), 53 | mazeCount: 2, 54 | timeLimit: 45000, 55 | picksCount: 1, 56 | description: 'Plural mazes continue' 57 | }); 58 | 59 | var HardStage = Object.assign({}, Stage, { 60 | typeId: 'hard', 61 | sortOrder: counter(), 62 | mazeCount: 3, 63 | timeLimit: 45000, 64 | picksCount: 1, 65 | description: 'More difficult' 66 | }); 67 | 68 | var LunaticStage = Object.assign({}, Stage, { 69 | typeId: 'lunatic', 70 | sortOrder: counter(), 71 | mazeCount: 5, 72 | timeLimit: 60000, 73 | picksCount: 2, 74 | description: 'For a person of leisure' 75 | }); 76 | 77 | var stageList = [SimpleStage, EasyStage, NormalStage, HardStage, LunaticStage]; 78 | exports.stageList = stageList; 79 | var stages = (0, _libUtil.dictionarize)(stageList, 'typeId'); 80 | exports.stages = stages; -------------------------------------------------------------------------------- /dist/dispatcher/AppDispatcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 14 | 15 | var _flux = require('flux'); 16 | 17 | var _libMixinsSingletonMixin = require('lib/mixins/SingletonMixin'); 18 | 19 | var _libMixinsSingletonMixin2 = _interopRequireDefault(_libMixinsSingletonMixin); 20 | 21 | var AppDispatcher = (function (_Dispatcher) { 22 | _inherits(AppDispatcher, _Dispatcher); 23 | 24 | function AppDispatcher() { 25 | _classCallCheck(this, AppDispatcher); 26 | 27 | _get(Object.getPrototypeOf(AppDispatcher.prototype), 'constructor', this).apply(this, arguments); 28 | } 29 | 30 | return AppDispatcher; 31 | })(_flux.Dispatcher); 32 | 33 | exports['default'] = AppDispatcher; 34 | 35 | Object.assign(AppDispatcher, _libMixinsSingletonMixin2['default']); 36 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/things/WallThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 14 | 15 | var _modelsThingsThingModel = require('models/things/ThingModel'); 16 | 17 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 18 | 19 | var WallThingModel = (function (_ThingModel) { 20 | _inherits(WallThingModel, _ThingModel); 21 | 22 | function WallThingModel() { 23 | _classCallCheck(this, WallThingModel); 24 | 25 | _get(Object.getPrototypeOf(WallThingModel.prototype), 'constructor', this).call(this); 26 | 27 | this._symbol = '#'; 28 | this._isPassable = false; 29 | } 30 | 31 | return WallThingModel; 32 | })(_modelsThingsThingModel2['default']); 33 | 34 | exports['default'] = WallThingModel; 35 | 36 | Object.assign(WallThingModel, { 37 | typeId: 'wall' 38 | }); 39 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/lib/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | exports.createCounter = createCounter; 7 | exports.calculateMillisecondsPerFrame = calculateMillisecondsPerFrame; 8 | exports.dictionarize = dictionarize; 9 | exports.createHelpText = createHelpText; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | var _chalk = require('chalk'); 14 | 15 | var _chalk2 = _interopRequireDefault(_chalk); 16 | 17 | var _conf = require('conf'); 18 | 19 | var _conf2 = _interopRequireDefault(_conf); 20 | 21 | function createCounter() { 22 | var start = arguments.length <= 0 || arguments[0] === undefined ? 1 : arguments[0]; 23 | 24 | start -= 1; 25 | return function () { 26 | return start += 1; 27 | }; 28 | } 29 | 30 | function calculateMillisecondsPerFrame() { 31 | return ~ ~(1000 / _conf2['default'].fps); 32 | } 33 | 34 | /* 35 | * Convert from list to dict by property-name 36 | * 37 | * @param {string} propertyName 38 | * @return {Object} 39 | */ 40 | 41 | function dictionarize(list, propertyName) { 42 | var dict = {}; 43 | list.forEach(function (v) { 44 | return dict[v[propertyName]] = v; 45 | }); 46 | return dict; 47 | } 48 | 49 | function createHelpText() { 50 | var playerSymbol = _chalk2['default'].magenta.bgBlack('@'); 51 | var wallSymbol = _chalk2['default'].white.bgBlack('#'); 52 | var pickaxeSymbol = _chalk2['default'].yellow.bgBlack('T'); 53 | var bonusTime5Symbol = _chalk2['default'].green.bgBlack('5'); 54 | var penaltyTime3Symbol = _chalk2['default'].red.bgBlack('3'); 55 | 56 | var lines = ['# Escape From The Maze - Help', '', '## Operation of player', '- You can move the player(' + playerSymbol + ') by [w][a][s][d], [h][j][k][l] or [arrow keys].', '- If you move after you press the [space], you can break the wall(' + wallSymbol + ') to consume one pickaxe.', '', '## Victory or defat, and score', '- It is a victory if escape the maze within the time limit.', '- The number of maze is different for each stage.', '- If you win, the remaining milliseconds will be the score.', '', '## Treasures', '- "' + pickaxeSymbol + '" You get a extra pickaxe.', '- "' + bonusTime5Symbol + '" Time limit is increased 5 seconds.', '- "' + penaltyTime3Symbol + '" Time limit is reduced 3 seconds.', '', '## Others', '- You can look ranking by `escape-from-the-maze --ranking`.']; 57 | return lines.join('\n'); 58 | } -------------------------------------------------------------------------------- /dist/actions/ScreenActionCreators.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _constsActions = require('consts/actions'); 10 | 11 | var _constsActions2 = _interopRequireDefault(_constsActions); 12 | 13 | var _dispatcherAppDispatcher = require('dispatcher/AppDispatcher'); 14 | 15 | var _dispatcherAppDispatcher2 = _interopRequireDefault(_dispatcherAppDispatcher); 16 | 17 | var ScreenActionCreators = { 18 | 19 | changePage: function changePage(pageId) { 20 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 21 | type: _constsActions2['default'].CHANGE_PAGE, 22 | pageId: pageId 23 | }); 24 | }, 25 | 26 | closeDialog: function closeDialog() { 27 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 28 | type: _constsActions2['default'].CLOSE_DIALOG 29 | }); 30 | }, 31 | 32 | deleteLastInputFromDialog: function deleteLastInputFromDialog() { 33 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 34 | type: _constsActions2['default'].DELETE_LAST_INPUT_FROM_DIALOG 35 | }); 36 | }, 37 | 38 | exit: function exit() { 39 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 40 | type: _constsActions2['default'].EXIT 41 | }); 42 | }, 43 | 44 | inputKeyToDialog: function inputKeyToDialog(keyName) { 45 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 46 | type: _constsActions2['default'].INPUT_KEY_TO_DIALOG, 47 | keyName: keyName 48 | }); 49 | }, 50 | 51 | openDialog: function openDialog() { 52 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 53 | type: _constsActions2['default'].OPEN_DIALOG 54 | }); 55 | }, 56 | 57 | prepareGame: function prepareGame(stageTypeId) { 58 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 59 | type: _constsActions2['default'].PREPARE_GAME, 60 | stageTypeId: stageTypeId 61 | }); 62 | }, 63 | 64 | /* 65 | * @param err {Error} 66 | */ 67 | throwRuntimeError: function throwRuntimeError(err) { 68 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 69 | type: _constsActions2['default'].THROW_RUNTIME_ERROR, 70 | err: err 71 | }); 72 | } 73 | }; 74 | 75 | exports['default'] = ScreenActionCreators; 76 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/test/stores/Store.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 4 | 5 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6 | 7 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8 | 9 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 10 | 11 | var _powerAssert = require('power-assert'); 12 | 13 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 14 | 15 | var _storesStore = require('stores/Store'); 16 | 17 | var _storesStore2 = _interopRequireDefault(_storesStore); 18 | 19 | var _testSupportHelpers = require('test/support/helpers'); 20 | 21 | describe((0, _testSupportHelpers.heading)(__filename), function () { 22 | 23 | it('should be defined', function () { 24 | _powerAssert2['default'].strictEqual(typeof _storesStore2['default'], 'function'); 25 | }); 26 | 27 | it('should be inherited', function () { 28 | var SubStore = (function (_Store) { 29 | _inherits(SubStore, _Store); 30 | 31 | function SubStore() { 32 | _classCallCheck(this, SubStore); 33 | 34 | _get(Object.getPrototypeOf(SubStore.prototype), 'constructor', this).apply(this, arguments); 35 | } 36 | 37 | return SubStore; 38 | })(_storesStore2['default']); 39 | 40 | var store = SubStore.getInstance(); 41 | var store2 = SubStore.getInstance(); 42 | _powerAssert2['default'].strictEqual(store, store2, 'Can use inherited static props'); 43 | }); 44 | }); -------------------------------------------------------------------------------- /dist/actions/GameActionCreators.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _constsActions = require('consts/actions'); 10 | 11 | var _constsActions2 = _interopRequireDefault(_constsActions); 12 | 13 | var _dispatcherAppDispatcher = require('dispatcher/AppDispatcher'); 14 | 15 | var _dispatcherAppDispatcher2 = _interopRequireDefault(_dispatcherAppDispatcher); 16 | 17 | var GameActionCreators = { 18 | 19 | advanceToNextMaze: function advanceToNextMaze() { 20 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 21 | type: _constsActions2['default'].ADVANCE_TO_NEXT_MAZE 22 | }); 23 | }, 24 | 25 | assumePicksMode: function assumePicksMode() { 26 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 27 | type: _constsActions2['default'].ASSUME_PICKS_MODE 28 | }); 29 | }, 30 | 31 | cancelPicksMode: function cancelPicksMode() { 32 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 33 | type: _constsActions2['default'].CANCEL_PICKS_MODE 34 | }); 35 | }, 36 | 37 | crushWallByPlayer: function crushWallByPlayer(direction) { 38 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 39 | type: _constsActions2['default'].CRUSH_WALL_BY_PLAYER, 40 | direction: direction 41 | }); 42 | }, 43 | 44 | forwardGameTimeByFrame: function forwardGameTimeByFrame() { 45 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 46 | type: _constsActions2['default'].FORWARD_GAME_TIME_BY_FRAME 47 | }); 48 | }, 49 | 50 | /* async */ 51 | requestAddingGameResult: function requestAddingGameResult(playerName) { 52 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 53 | type: _constsActions2['default'].REQUEST_ADDING_GAME_RESULT, 54 | playerName: playerName 55 | }); 56 | }, 57 | 58 | resetGame: function resetGame() { 59 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 60 | type: _constsActions2['default'].RESET_GAME 61 | }); 62 | }, 63 | 64 | saveDefeat: function saveDefeat() { 65 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 66 | type: _constsActions2['default'].SAVE_DEFEAT 67 | }); 68 | }, 69 | 70 | saveVictory: function saveVictory() { 71 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 72 | type: _constsActions2['default'].SAVE_VICTORY 73 | }); 74 | }, 75 | 76 | walkPlayer: function walkPlayer(direction) { 77 | _dispatcherAppDispatcher2['default'].getInstance().dispatch({ 78 | type: _constsActions2['default'].WALK_PLAYER, 79 | direction: direction 80 | }); 81 | } 82 | }; 83 | 84 | exports['default'] = GameActionCreators; 85 | module.exports = exports['default']; -------------------------------------------------------------------------------- /components/RootComponent.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React, {Component} from 'react'; 3 | 4 | import DialogComponent from './DialogComponent'; 5 | import GamePageComponent from './pages/GamePageComponent'; 6 | import WelcomePageComponent from './pages/WelcomePageComponent'; 7 | import {EVENTS} from 'consts'; 8 | import EventManager from 'lib/EventManager'; 9 | import DialogStore from 'stores/DialogStore'; 10 | import GameStore from 'stores/GameStore'; 11 | import ScreenStore from 'stores/ScreenStore'; 12 | 13 | 14 | const PAGE_COMPONENTS = { 15 | game: GamePageComponent, 16 | welcome: WelcomePageComponent 17 | }; 18 | 19 | function getStateFromStores() { 20 | let screenStore = ScreenStore.getInstance(); 21 | let dialogStore = DialogStore.getInstance(); 22 | let gameStore = GameStore.getInstance(); 23 | return { 24 | dialogInputValue: dialogStore.dialogInputValue, 25 | hasBeenDefeat: gameStore.hasBeenDefeat, 26 | hasBeenVictory: gameStore.hasBeenVictory, 27 | gameTime: gameStore.gameTime, 28 | isAssumedPicksMode: gameStore.isAssumedPicksMode, 29 | isDialogActive: dialogStore.isDialogActive, 30 | isValidDialogInput: dialogStore.isValidDialogInput, 31 | mazeContent: gameStore.isStarted() ? gameStore.maze.toContent() : '', 32 | mazeCount: gameStore.getMazeCount(), 33 | pageId: screenStore.pageId, 34 | picksCount: gameStore.picksCount, 35 | score: gameStore.gameResult ? gameStore.gameResult.calculateScore() : 0, 36 | runningMazeCount: gameStore.runningMazeCount, 37 | timeLimit: gameStore.timeLimit 38 | }; 39 | } 40 | 41 | function getInitialState() { 42 | return getStateFromStores(); 43 | } 44 | 45 | 46 | export default class RootComponent extends Component { 47 | 48 | constructor(props) { 49 | super(props); 50 | 51 | this.state = getInitialState(); 52 | 53 | let {emitter} = EventManager.getInstance(); 54 | emitter.on(EVENTS.CHANGE_PAGE, () => { 55 | this.setState(getStateFromStores()); 56 | }); 57 | emitter.on(EVENTS.UPDATE_DIALOG, () => { 58 | this.setState(getStateFromStores()); 59 | }); 60 | emitter.on(EVENTS.UPDATE_MAZE, () => { 61 | this.setState(getStateFromStores()); 62 | }) 63 | emitter.on(EVENTS.UPDATE_GAME_STATUS, () => { 64 | this.setState(getStateFromStores()); 65 | }); 66 | } 67 | 68 | render() { 69 | let props = { 70 | top: 'top', 71 | left: 'left', 72 | width: 41, 73 | height: 22, 74 | style: { 75 | fg: 'white', 76 | bg: 'blue' 77 | } 78 | }; 79 | 80 | let dialogProps = Object.assign({}, this.state); 81 | 82 | let ActivePageComponent = PAGE_COMPONENTS[this.state.pageId]; 83 | let pageProps = Object.assign({}, this.state); 84 | 85 | return ( 86 | 87 | 88 | 89 | 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /dist/models/GameResultModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _modelsModel = require('models/Model'); 18 | 19 | var _modelsModel2 = _interopRequireDefault(_modelsModel); 20 | 21 | var GameResultModel = (function (_Model) { 22 | _inherits(GameResultModel, _Model); 23 | 24 | function GameResultModel(_ref) { 25 | var timeLimit = _ref.timeLimit; 26 | var lastGameTime = _ref.lastGameTime; 27 | 28 | _classCallCheck(this, GameResultModel); 29 | 30 | _get(Object.getPrototypeOf(GameResultModel.prototype), 'constructor', this).call(this); 31 | 32 | this._timeLimit = timeLimit; 33 | this._lastGameTime = lastGameTime; 34 | } 35 | 36 | _createClass(GameResultModel, [{ 37 | key: 'calculateScore', 38 | value: function calculateScore() { 39 | return this._timeLimit - this._lastGameTime; 40 | } 41 | }]); 42 | 43 | return GameResultModel; 44 | })(_modelsModel2['default']); 45 | 46 | exports['default'] = GameResultModel; 47 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/things/PlayerThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _modelsThingsThingModel = require('models/things/ThingModel'); 18 | 19 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 20 | 21 | var PlayerThingModel = (function (_ThingModel) { 22 | _inherits(PlayerThingModel, _ThingModel); 23 | 24 | function PlayerThingModel() { 25 | _classCallCheck(this, PlayerThingModel); 26 | 27 | _get(Object.getPrototypeOf(PlayerThingModel.prototype), 'constructor', this).call(this); 28 | 29 | this._symbol = '@'; 30 | } 31 | 32 | _createClass(PlayerThingModel, [{ 33 | key: 'toContent', 34 | value: function toContent() { 35 | return '{magenta-fg}' + this._symbol + '{/}'; 36 | } 37 | }]); 38 | 39 | return PlayerThingModel; 40 | })(_modelsThingsThingModel2['default']); 41 | 42 | exports['default'] = PlayerThingModel; 43 | 44 | Object.assign(PlayerThingModel, { 45 | typeId: 'player' 46 | }); 47 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/things/PicksThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _modelsThingsThingModel = require('models/things/ThingModel'); 18 | 19 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 20 | 21 | var PicksThingModel = (function (_ThingModel) { 22 | _inherits(PicksThingModel, _ThingModel); 23 | 24 | function PicksThingModel() { 25 | _classCallCheck(this, PicksThingModel); 26 | 27 | _get(Object.getPrototypeOf(PicksThingModel.prototype), 'constructor', this).call(this); 28 | 29 | this._symbol = 'T'; 30 | this._isPickable = true; 31 | } 32 | 33 | _createClass(PicksThingModel, [{ 34 | key: 'toContent', 35 | value: function toContent() { 36 | return '{yellow-fg}' + this._symbol + '{/}'; 37 | } 38 | }]); 39 | 40 | return PicksThingModel; 41 | })(_modelsThingsThingModel2['default']); 42 | 43 | exports['default'] = PicksThingModel; 44 | 45 | Object.assign(PicksThingModel, { 46 | typeId: 'picks' 47 | }); 48 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/things/UpstairsThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _modelsThingsThingModel = require('models/things/ThingModel'); 18 | 19 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 20 | 21 | var UpstairsThingModel = (function (_ThingModel) { 22 | _inherits(UpstairsThingModel, _ThingModel); 23 | 24 | function UpstairsThingModel() { 25 | _classCallCheck(this, UpstairsThingModel); 26 | 27 | _get(Object.getPrototypeOf(UpstairsThingModel.prototype), 'constructor', this).call(this); 28 | 29 | this._symbol = '<'; 30 | } 31 | 32 | _createClass(UpstairsThingModel, [{ 33 | key: 'toContent', 34 | value: function toContent() { 35 | return '{magenta-fg}' + this._symbol + '{/}'; 36 | } 37 | }]); 38 | 39 | return UpstairsThingModel; 40 | })(_modelsThingsThingModel2['default']); 41 | 42 | exports['default'] = UpstairsThingModel; 43 | 44 | Object.assign(UpstairsThingModel, { 45 | typeId: 'upstairs' 46 | }); 47 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/things/BonusTime5ThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _modelsThingsThingModel = require('models/things/ThingModel'); 18 | 19 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 20 | 21 | var BonusTime5ThingModel = (function (_ThingModel) { 22 | _inherits(BonusTime5ThingModel, _ThingModel); 23 | 24 | function BonusTime5ThingModel() { 25 | _classCallCheck(this, BonusTime5ThingModel); 26 | 27 | _get(Object.getPrototypeOf(BonusTime5ThingModel.prototype), 'constructor', this).call(this); 28 | 29 | this._symbol = '5'; 30 | this._isPickable = true; 31 | } 32 | 33 | _createClass(BonusTime5ThingModel, [{ 34 | key: 'toContent', 35 | value: function toContent() { 36 | return '{green-fg}' + this._symbol + '{/}'; 37 | } 38 | }]); 39 | 40 | return BonusTime5ThingModel; 41 | })(_modelsThingsThingModel2['default']); 42 | 43 | exports['default'] = BonusTime5ThingModel; 44 | 45 | Object.assign(BonusTime5ThingModel, { 46 | typeId: 'bonus_time_5' 47 | }); 48 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/things/PenaltyTime3ThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _modelsThingsThingModel = require('models/things/ThingModel'); 18 | 19 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 20 | 21 | var PenaltyTime3ThingModel = (function (_ThingModel) { 22 | _inherits(PenaltyTime3ThingModel, _ThingModel); 23 | 24 | function PenaltyTime3ThingModel() { 25 | _classCallCheck(this, PenaltyTime3ThingModel); 26 | 27 | _get(Object.getPrototypeOf(PenaltyTime3ThingModel.prototype), 'constructor', this).call(this); 28 | 29 | this._symbol = '3'; 30 | this._isPickable = true; 31 | } 32 | 33 | _createClass(PenaltyTime3ThingModel, [{ 34 | key: 'toContent', 35 | value: function toContent() { 36 | return '{red-fg}' + this._symbol + '{/}'; 37 | } 38 | }]); 39 | 40 | return PenaltyTime3ThingModel; 41 | })(_modelsThingsThingModel2['default']); 42 | 43 | exports['default'] = PenaltyTime3ThingModel; 44 | 45 | Object.assign(PenaltyTime3ThingModel, { 46 | typeId: 'penalty_time_3' 47 | }); 48 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/test/models/CellModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _modelsCellModel = require('models/CellModel'); 10 | 11 | var _modelsCellModel2 = _interopRequireDefault(_modelsCellModel); 12 | 13 | var _modelsThingsThingModel = require('models/things/ThingModel'); 14 | 15 | var _modelsThingsThingModel2 = _interopRequireDefault(_modelsThingsThingModel); 16 | 17 | var _testSupportHelpers = require('test/support/helpers'); 18 | 19 | describe((0, _testSupportHelpers.heading)(__filename), function () { 20 | 21 | it('should be defined', function () { 22 | _powerAssert2['default'].strictEqual(typeof _modelsCellModel2['default'], 'function'); 23 | }); 24 | 25 | it('thing accessors', function () { 26 | var cell = new _modelsCellModel2['default'](); 27 | var thing = new _modelsThingsThingModel2['default'](); 28 | 29 | _powerAssert2['default'].strictEqual(cell.findThing(thing), null); 30 | _powerAssert2['default'].strictEqual(cell.hasThing(thing), false); 31 | cell.setThing(thing); 32 | _powerAssert2['default'].strictEqual(cell.findThing(thing), thing); 33 | _powerAssert2['default'].strictEqual(cell.findThingOrError(thing), thing); 34 | _powerAssert2['default'].strictEqual(cell.hasThing(thing), true); 35 | 36 | var anotherThing = new _modelsThingsThingModel2['default'](); 37 | _powerAssert2['default'].strictEqual(cell.findThing(anotherThing), null); 38 | _powerAssert2['default'].throws(function () { 39 | cell.findThingOrError(anotherThing); 40 | }, /Can not /); 41 | 42 | _powerAssert2['default'].strictEqual(cell.removeThing(anotherThing), false); 43 | _powerAssert2['default'].strictEqual(cell.hasThing(thing), true); 44 | _powerAssert2['default'].strictEqual(cell.removeThing(thing), true); 45 | _powerAssert2['default'].strictEqual(cell.hasThing(thing), false); 46 | }); 47 | 48 | it('isPassable', function () { 49 | var cell = undefined, 50 | thing = undefined; 51 | cell = new _modelsCellModel2['default'](); 52 | _powerAssert2['default'].strictEqual(cell.isPassable(), true); 53 | 54 | thing = new _modelsThingsThingModel2['default'](); 55 | thing._isPassable = true; 56 | cell.setThing(thing); 57 | _powerAssert2['default'].strictEqual(cell.isPassable(), true); 58 | 59 | thing = new _modelsThingsThingModel2['default'](); 60 | thing._isPassable = false; 61 | cell.setThing(thing); 62 | _powerAssert2['default'].strictEqual(cell.isPassable(), false); 63 | 64 | thing = new _modelsThingsThingModel2['default'](); 65 | thing._isPassable = true; 66 | cell.setThing(thing); 67 | _powerAssert2['default'].strictEqual(cell.isPassable(), false); 68 | }); 69 | 70 | it('toContent', function () { 71 | var cell = undefined; 72 | cell = new _modelsCellModel2['default'](); 73 | _powerAssert2['default'].strictEqual(cell.toContent(), ' '); 74 | cell.setThing(new _modelsThingsThingModel2['default']()); 75 | _powerAssert2['default'].strictEqual(cell.toContent(), '?'); 76 | }); 77 | }); -------------------------------------------------------------------------------- /dist/models/ThingIndexerModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _modelsModel = require('models/Model'); 18 | 19 | var _modelsModel2 = _interopRequireDefault(_modelsModel); 20 | 21 | var ThingIndexerModel = (function (_Model) { 22 | _inherits(ThingIndexerModel, _Model); 23 | 24 | function ThingIndexerModel() { 25 | _classCallCheck(this, ThingIndexerModel); 26 | 27 | _get(Object.getPrototypeOf(ThingIndexerModel.prototype), 'constructor', this).call(this); 28 | 29 | this._indexes = {}; 30 | } 31 | 32 | _createClass(ThingIndexerModel, [{ 33 | key: 'update', 34 | value: function update(id, pos) { 35 | this._indexes[id] = pos; 36 | } 37 | }, { 38 | key: 'remove', 39 | value: function remove(id) { 40 | delete this._indexes[id]; 41 | } 42 | }, { 43 | key: 'get', 44 | value: function get(id) { 45 | return this._indexes[id] || null; 46 | } 47 | }, { 48 | key: 'has', 49 | value: function has(id) { 50 | return id in this._indexes; 51 | } 52 | }, { 53 | key: 'getIds', 54 | value: function getIds() { 55 | return Object.keys(this._indexes); 56 | } 57 | }]); 58 | 59 | return ThingIndexerModel; 60 | })(_modelsModel2['default']); 61 | 62 | exports['default'] = ThingIndexerModel; 63 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/things/ThingModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _uuid = require('uuid'); 18 | 19 | var _uuid2 = _interopRequireDefault(_uuid); 20 | 21 | var _modelsModel = require('models/Model'); 22 | 23 | var _modelsModel2 = _interopRequireDefault(_modelsModel); 24 | 25 | var ThingModel = (function (_Model) { 26 | _inherits(ThingModel, _Model); 27 | 28 | function ThingModel() { 29 | _classCallCheck(this, ThingModel); 30 | 31 | _get(Object.getPrototypeOf(ThingModel.prototype), 'constructor', this).call(this); 32 | 33 | this.uuid = _uuid2['default'].v4(); 34 | this._symbol = '?'; 35 | this._isPassable = true; 36 | this._isPickable = false; 37 | } 38 | 39 | _createClass(ThingModel, [{ 40 | key: 'getTypeId', 41 | value: function getTypeId() { 42 | return this.constructor.typeId; 43 | } 44 | }, { 45 | key: 'getSymbol', 46 | value: function getSymbol() { 47 | return this._symbol; 48 | } 49 | }, { 50 | key: 'isPassable', 51 | value: function isPassable() { 52 | return this._isPassable; 53 | } 54 | }, { 55 | key: 'isPickable', 56 | value: function isPickable() { 57 | return this._isPickable; 58 | } 59 | }, { 60 | key: 'toContent', 61 | value: function toContent() { 62 | return this._symbol; 63 | } 64 | }]); 65 | 66 | return ThingModel; 67 | })(_modelsModel2['default']); 68 | 69 | exports['default'] = ThingModel; 70 | 71 | Object.assign(ThingModel, { 72 | typeId: '_thing' 73 | }); 74 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/input/AppInput.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | var _keypress = require('keypress'); 14 | 15 | var _keypress2 = _interopRequireDefault(_keypress); 16 | 17 | var _rx = require('rx'); 18 | 19 | var _rx2 = _interopRequireDefault(_rx); 20 | 21 | var _inputSubscriptionsError = require('input/subscriptions/error'); 22 | 23 | var _inputSubscriptionsKeypress = require('input/subscriptions/keypress'); 24 | 25 | var _inputSubscriptionsTimer = require('input/subscriptions/timer'); 26 | 27 | var _libMixinsSingletonMixin = require('lib/mixins/SingletonMixin'); 28 | 29 | var _libMixinsSingletonMixin2 = _interopRequireDefault(_libMixinsSingletonMixin); 30 | 31 | var _libUtil = require('lib/util'); 32 | 33 | (0, _keypress2['default'])(process.stdin); 34 | process.stdin.setRawMode(true); 35 | process.stdin.resume(); 36 | 37 | var AppInput = (function () { 38 | function AppInput() { 39 | _classCallCheck(this, AppInput); 40 | 41 | var pauser = new _rx2['default'].Subject(); 42 | 43 | var timerSource = _rx2['default'].Observable.timer(0, (0, _libUtil.calculateMillisecondsPerFrame)()).timeInterval().map(function (data) { 44 | pauser.onNext(true); 45 | return data; 46 | }); 47 | 48 | var wrappedHandler = undefined; 49 | var keypressSource = _rx2['default'].Observable.fromEventPattern(function (handler) { 50 | wrappedHandler = function (chr, key) { 51 | if (!key) { 52 | key = { 53 | name: chr, 54 | ctrl: false, 55 | sequence: chr 56 | }; 57 | } 58 | handler(key); 59 | }; 60 | process.stdin.addListener('keypress', wrappedHandler); 61 | }, function () { 62 | process.stdin.removeListener('keypress', wrappedHandler); 63 | }).pausable(pauser).filter(function () { 64 | var isStopped = pauser.isStopped; 65 | pauser.onNext(false); 66 | return !isStopped; 67 | }); 68 | 69 | this._timerSubscription = timerSource.subscribe(_inputSubscriptionsTimer.onTimer, _inputSubscriptionsError.onError); 70 | this._keypressSubscription = keypressSource.subscribe(_inputSubscriptionsKeypress.onKeypress, _inputSubscriptionsError.onError); 71 | } 72 | 73 | _createClass(AppInput, [{ 74 | key: '_destructor', 75 | value: function _destructor() { 76 | this._timerSubscription.dispose(); 77 | this._keypressSubscription.dispose(); 78 | } 79 | }]); 80 | 81 | return AppInput; 82 | })(); 83 | 84 | exports['default'] = AppInput; 85 | 86 | Object.assign(AppInput, _libMixinsSingletonMixin2['default']); 87 | 88 | AppInput._destructInstance = function _destructInstance() { 89 | if (this._instance) { 90 | this._instance._destructor(); 91 | } 92 | }; 93 | module.exports = exports['default']; -------------------------------------------------------------------------------- /components/pages/GamePageComponent.es6: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React, {Component} from 'react'; 3 | 4 | import variables from '../variables'; 5 | 6 | 7 | function generateStatusBarContent({ 8 | runningMazeCount, mazeCount, timeLimit, gameTime, picksCount, isAssumedPicksMode 9 | }) { 10 | 11 | let gameTimeBySeconds = ~~(gameTime / 1000); 12 | let timeLimitBySeconds = ~~(timeLimit / 1000); 13 | 14 | let content = `${runningMazeCount}/${mazeCount}F, ` + 15 | `Time: ${gameTimeBySeconds}/${timeLimitBySeconds}, `; 16 | 17 | let picksContent = `Pickaxe: ${picksCount}`; 18 | if (isAssumedPicksMode) { 19 | content += `{green-fg}${picksContent}{/}`; 20 | } else { 21 | content += picksContent; 22 | } 23 | 24 | return content; 25 | } 26 | 27 | function generateVictoryResultBoxContent({ score }) { 28 | return `Escape success!\n\nScore: ${score}\n\nSend to server? [{green-fg}Y{/}/{green-fg}n{/}]`; 29 | } 30 | 31 | function generateDefeatResultBoxContent() { 32 | return 'Escape failure..\n\nPush [{green-fg}enter{/}]'; 33 | } 34 | 35 | 36 | export default class GamePageComponent extends Component { 37 | 38 | constructor(props) { 39 | super(props); 40 | } 41 | 42 | render() { 43 | 44 | let props = Object.assign({}, variables.pageBoxProps); 45 | 46 | let mazeBoxProps = { 47 | key: 'maze', 48 | top: 'top', 49 | left: 'left', 50 | width: '100%', 51 | height: 21, 52 | tags: true, 53 | style: { 54 | fg: 'white', 55 | bg: 'black' 56 | }, 57 | content: this.props.mazeContent 58 | }; 59 | 60 | let resultBoxProps = { 61 | top: 'center', 62 | left: 'center', 63 | width: 27, 64 | height: 9, 65 | tags: true, 66 | border: { 67 | type: 'line' 68 | }, 69 | align: 'center', 70 | valign: 'middle', 71 | style: { 72 | fg: 'white', 73 | bg: 'black', 74 | border: { 75 | fg: 'green' 76 | } 77 | }, 78 | hidden: true 79 | }; 80 | 81 | if (this.props.hasBeenVictory) { 82 | Object.assign(resultBoxProps, { 83 | content: generateVictoryResultBoxContent(this.props), 84 | hidden: false 85 | }); 86 | } else if (this.props.hasBeenDefeat) { 87 | Object.assign(resultBoxProps, { 88 | content: generateDefeatResultBoxContent(), 89 | hidden: false 90 | }); 91 | resultBoxProps.style.border.fg = 'red'; 92 | } 93 | 94 | let statusBarBoxProps = { 95 | key: 'status_bar', 96 | top: mazeBoxProps.height, 97 | left: 'left', 98 | width: '100%', 99 | height: 1, 100 | tags: true, 101 | style: { 102 | fg: 'white', 103 | bg: 'black' 104 | }, 105 | content: generateStatusBarContent(this.props) 106 | }; 107 | 108 | return ( 109 | 110 | 111 | 112 | 113 | 114 | 115 | ); 116 | } 117 | } 118 | 119 | Object.assign(GamePageComponent, { 120 | 121 | propTypes: { 122 | gameTime: React.PropTypes.number.isRequired, 123 | hasBeenDefeat: React.PropTypes.bool.isRequired, 124 | hasBeenVictory: React.PropTypes.bool.isRequired, 125 | isAssumedPicksMode: React.PropTypes.bool.isRequired, 126 | mazeCount: React.PropTypes.number.isRequired, 127 | mazeContent: React.PropTypes.string.isRequired, 128 | picksCount: React.PropTypes.number.isRequired, 129 | runningMazeCount: React.PropTypes.number.isRequired, 130 | score: React.PropTypes.number.isRequired, 131 | timeLimit: React.PropTypes.number.isRequired 132 | } 133 | }); 134 | -------------------------------------------------------------------------------- /dist/components/Screen.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | var _blessed = require('blessed'); 14 | 15 | var _blessed2 = _interopRequireDefault(_blessed); 16 | 17 | var _chalk = require('chalk'); 18 | 19 | var _chalk2 = _interopRequireDefault(_chalk); 20 | 21 | var _devNull = require('dev-null'); 22 | 23 | var _devNull2 = _interopRequireDefault(_devNull); 24 | 25 | var _lodash = require('lodash'); 26 | 27 | var _lodash2 = _interopRequireDefault(_lodash); 28 | 29 | var _react = require('react'); 30 | 31 | var _react2 = _interopRequireDefault(_react); 32 | 33 | var _reactBlessed = require('react-blessed'); 34 | 35 | var _RootComponent = require('./RootComponent'); 36 | 37 | var _RootComponent2 = _interopRequireDefault(_RootComponent); 38 | 39 | var _conf = require('conf'); 40 | 41 | var _conf2 = _interopRequireDefault(_conf); 42 | 43 | var _consts = require('consts'); 44 | 45 | var _libEventManager = require('lib/EventManager'); 46 | 47 | var _libEventManager2 = _interopRequireDefault(_libEventManager); 48 | 49 | var _libMixinsSingletonMixin = require('lib/mixins/SingletonMixin'); 50 | 51 | var _libMixinsSingletonMixin2 = _interopRequireDefault(_libMixinsSingletonMixin); 52 | 53 | var _storesScreenStore = require('stores/ScreenStore'); 54 | 55 | var _storesScreenStore2 = _interopRequireDefault(_storesScreenStore); 56 | 57 | var Screen = (function () { 58 | function Screen() { 59 | _classCallCheck(this, Screen); 60 | 61 | var screen = _blessed2['default'].screen(this._createBlessedOptions()); 62 | screen.debugLog.unkey(['q', 'escape']); 63 | (0, _reactBlessed.render)(_react2['default'].createElement(_RootComponent2['default'], null), screen); 64 | this._screen = screen; 65 | 66 | var _EventManager$getInstance = _libEventManager2['default'].getInstance(); 67 | 68 | var emitter = _EventManager$getInstance.emitter; 69 | 70 | emitter.on(_consts.EVENTS.UPDATE_ERRORS, this._debug.bind(this)); 71 | emitter.on(_consts.EVENTS.EXIT, this._exit.bind(this)); 72 | } 73 | 74 | _createClass(Screen, [{ 75 | key: '_createBlessedOptions', 76 | value: function _createBlessedOptions() { 77 | var options = { 78 | debug: true, 79 | title: 'Escape From The Maze' 80 | }; 81 | 82 | if (_conf2['default'].ignoreScreenOutput) { 83 | options.output = (0, _devNull2['default'])(); 84 | } 85 | 86 | return options; 87 | } 88 | }, { 89 | key: '_exit', 90 | value: function _exit() { 91 | process.stdin.pause(); 92 | process.exit(0); 93 | } 94 | }, { 95 | key: '_debug', 96 | value: function _debug() { 97 | var screenStore = _storesScreenStore2['default'].getInstance(); 98 | var err = screenStore.getLastRuntimeError(); 99 | this._screen.debug(_chalk2['default'].red(err)); 100 | } 101 | }]); 102 | 103 | return Screen; 104 | })(); 105 | 106 | exports['default'] = Screen; 107 | 108 | Object.assign(Screen, _libMixinsSingletonMixin2['default']); 109 | module.exports = exports['default']; -------------------------------------------------------------------------------- /server/aws-lambda/index.js: -------------------------------------------------------------------------------- 1 | // arn:aws:lambda:ap-northeast-1:227307664587:function:serveEscapeFromTheMazeAPI 2 | 3 | var async = require('async'); 4 | var AWS = require('aws-sdk'); 5 | var _ = require('lodash'); 6 | 7 | var awsConfig = require('./aws-config.json'); 8 | 9 | 10 | var AWS_ENDPOINT = 's3-us-west-1.amazonaws.com'; 11 | var BUCKET_NAME = 'escape-from-the-maze'; 12 | var GAME_RESULTS_BUCKET_KEY = 'game-results.json'; 13 | if (global.ESCAPE_FROM_THE_MAZE_AWS_LAMBDA_DEBUG || process.env.ESCAPE_FROM_THE_MAZE_AWS_LAMBDA_DEBUG) { 14 | GAME_RESULTS_BUCKET_KEY = 'game-results-for-local-test.json'; 15 | } 16 | 17 | var START_TIME = (new Date()).getTime(); 18 | var API_MODES = [ 19 | 'add_game_result', 20 | 'get_ranking' 21 | ]; 22 | var STAGE_TYPE_IDS = [ 23 | 'simple', 24 | 'easy', 25 | 'normal', 26 | 'hard', 27 | 'lunatic' 28 | ]; 29 | 30 | function isWithinMonth(timestamp) { 31 | var monthTime = 86400 * 30 * 1000; 32 | return timestamp >= START_TIME - monthTime; 33 | } 34 | 35 | 36 | exports.handler = function(event, context) { 37 | 38 | // 39 | // Arrange and validate inputs 40 | // 41 | // Notice: 42 | // 43 | // Don't forget to sync AWS Gateway's Integration Request settings 44 | // Ref) https://gyazo.com/055d399e5b26ddb5be8a87527826ff97 45 | // 46 | 47 | var apiMode = event.api_mode; 48 | var stageTypeId = event.stage; 49 | var playerName = event.name; 50 | var score = ~~(event.score); 51 | 52 | if (API_MODES.indexOf(apiMode) === -1) { 53 | return context.done(null, apiMode + ' is invalid api_mode'); 54 | } 55 | 56 | if (apiMode === 'add_game_result') { 57 | 58 | if (STAGE_TYPE_IDS.indexOf(stageTypeId) === -1) { 59 | return context.done(null, stageTypeId + ' is invalid stage'); 60 | } 61 | 62 | if (!playerName) { 63 | return context.done(null, 'name is blank'); 64 | } 65 | 66 | if (score < 1) { 67 | return context.done(null, score + ' is invalid score'); 68 | } 69 | } 70 | 71 | 72 | // Must configure the endpoint. 73 | // Occured the following error at running AWS Lambda (but, not occured in local). 74 | // ---- 75 | // PermanentRedirect: The bucket you are attempting to access must be addressed using the specified endpoint. 76 | // Please send all future requests to this endpoint. 77 | // ---- 78 | var endpoint = new AWS.Endpoint(AWS_ENDPOINT); 79 | var s3 = new AWS.S3(_.assign({}, awsConfig, { 80 | endpoint: endpoint 81 | })); 82 | 83 | var gameResults; 84 | 85 | async.series([ 86 | 87 | function readGameResults(next) { 88 | var params = { 89 | Bucket: BUCKET_NAME, 90 | Key: GAME_RESULTS_BUCKET_KEY 91 | }; 92 | s3.getObject(params, function(err, data) { 93 | if (err) { 94 | return next(err); 95 | } 96 | gameResults = JSON.parse(data.Body.toString()); 97 | next(); 98 | }); 99 | }, 100 | 101 | function addGameResult(next) { 102 | if (apiMode !== 'add_game_result') { 103 | return next(); 104 | } 105 | 106 | gameResults.push({ 107 | created_at: (new Date()).getTime(), 108 | name: playerName.slice(0, 16), 109 | score: score, 110 | stage: stageTypeId 111 | }); 112 | 113 | var params = { 114 | Bucket: BUCKET_NAME, 115 | Key: GAME_RESULTS_BUCKET_KEY, 116 | Body: JSON.stringify(gameResults) 117 | }; 118 | s3.upload(params, function(err, data) { 119 | if (err) { 120 | return next(err); 121 | } 122 | next(); 123 | }); 124 | }, 125 | 126 | function filterGameResults(next) { 127 | gameResults = gameResults.filter(function(v) { 128 | return isWithinMonth(v.created_at); 129 | }); 130 | next(); 131 | } 132 | 133 | ], function(err) { 134 | 135 | if (err) { 136 | console.error(err); 137 | return; 138 | } 139 | context.done(null, gameResults); 140 | }); 141 | }; 142 | -------------------------------------------------------------------------------- /test/stores/GameStore.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | import sinon from 'sinon'; 3 | 4 | import GameActionCreators from 'actions/GameActionCreators'; 5 | import ScreenActionCreators from 'actions/ScreenActionCreators'; 6 | import App from 'app'; 7 | import {Stage} from 'lib/stages'; 8 | import GameResultModel from 'models/GameResultModel'; 9 | import MazeModel from 'models/MazeModel'; 10 | import BonusTime5ThingModel from 'models/things/BonusTime5ThingModel'; 11 | import PenaltyTime3ThingModel from 'models/things/PenaltyTime3ThingModel'; 12 | import GameStore from 'stores/GameStore'; 13 | import {heading} from 'test/support/helpers'; 14 | 15 | 16 | describe(heading(__filename), function() { 17 | 18 | function _createGameStore() { 19 | var store = new GameStore(); 20 | ScreenActionCreators.prepareGame('simple'); 21 | return store; 22 | } 23 | 24 | beforeEach(function() { 25 | App.purgeInstances(); 26 | }); 27 | 28 | it('should be defined', function() { 29 | assert.strictEqual(typeof GameStore, 'function'); 30 | }); 31 | 32 | it('hasNextMaze', function() { 33 | const FooStage = Object.assign({}, Stage); 34 | FooStage.mazeCount = 5; 35 | 36 | var store = _createGameStore(); 37 | store._prepare(); 38 | store._runningMazeCount = 4; 39 | sinon.stub(store, '_getStage', () => FooStage); 40 | 41 | assert.strictEqual(store.hasNextMaze(), true); 42 | store._runningMazeCount = 5; 43 | assert.strictEqual(store.hasNextMaze(), false); 44 | }); 45 | 46 | it('_doesPlayerArriveGoal', function() { 47 | var store = _createGameStore(); 48 | store._prepare(); 49 | assert.strictEqual(store._doesPlayerArriveGoal(), false); 50 | store.maze.moveThing( 51 | store._things.player, 52 | [1, 1], 53 | store.maze.searchThingPos(store._things.upstairs) 54 | ); 55 | assert.strictEqual(store._doesPlayerArriveGoal(), true); 56 | }); 57 | 58 | it('_crushWallByPlayer', function() { 59 | var store = _createGameStore(); 60 | store._prepare(); 61 | store._picksCount = 1; 62 | let playerPos = store._maze.searchThingPos(store._things.player); 63 | let upperPos = [playerPos[0] - 1, playerPos[1]]; 64 | let wallAtUpper = store._maze.getCellOrError(upperPos).getThing(); 65 | assert.strictEqual(wallAtUpper.getTypeId(), 'wall'); 66 | store._crushWallByPlayer(MazeModel.DIRECTIONS.UP); 67 | let crushedThing = store._maze.getCellOrError(upperPos).getThing(); 68 | assert.strictEqual(crushedThing, null); 69 | assert.strictEqual(store._picksCount, 0); 70 | }); 71 | 72 | it('_pickThingsByPlayer', function() { 73 | var store = _createGameStore(); 74 | store._prepare(); 75 | let playerPos = store._maze.searchThingPos(store._things.player); 76 | function getThingCount() { 77 | return store._maze.getCellOrError(playerPos).getThings().length; 78 | } 79 | assert.strictEqual(getThingCount(), 1); 80 | let bonusTime5Thing = new BonusTime5ThingModel(); 81 | let penaltyTime3Thing = new PenaltyTime3ThingModel(); 82 | 83 | store._maze.addThing(bonusTime5Thing, playerPos); 84 | store._maze.addThing(penaltyTime3Thing, playerPos); 85 | 86 | assert.strictEqual(getThingCount(), 3); 87 | let baseTimeLimit = store._timeLimit; 88 | store._pickThingsByPlayer(); 89 | assert.strictEqual(getThingCount(), 1); 90 | assert(store._timeLimit > baseTimeLimit); 91 | }); 92 | 93 | it('_forwardGameTime', function() { 94 | var store = _createGameStore(); 95 | assert.strictEqual(store._forwardGameTime(999), false); 96 | assert.strictEqual(store._forwardGameTime(1), true); 97 | }); 98 | 99 | 100 | context('action subscription', function() { 101 | 102 | it('SAVE_VICTORY', function() { 103 | let store = _createGameStore(); 104 | assert.strictEqual(store.gameResult, null); 105 | GameActionCreators.saveVictory(); 106 | assert(store.gameResult instanceof GameResultModel); 107 | }); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /test/lib/apis/index.es6: -------------------------------------------------------------------------------- 1 | import assert from 'power-assert'; 2 | 3 | import conf from 'conf'; 4 | import { 5 | _formatRankingDataToText, 6 | _restructGameResultRowsForRanking, 7 | requestRanking 8 | } from 'lib/apis'; 9 | import {heading} from 'test/support/helpers'; 10 | 11 | 12 | describe(heading(__filename), function() { 13 | 14 | it('_restructGameResultRowsForRanking', function() { 15 | let rows, rankingData; 16 | 17 | rows = [ 18 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 2 }, 19 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 4 }, 20 | { created_at: 10000, stage: 'easy', name: 'Foo', score: 1 }, 21 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 3 }, 22 | { created_at: 10000, stage: 'easy', name: 'Foo', score: 1 }, 23 | { created_at: 10000, stage: 'hard', name: 'Foo', score: 1 }, 24 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 25 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 26 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 27 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 28 | { created_at: 9999, stage: 'simple', name: 'Foo', score: 1 }, 29 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 30 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 31 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 32 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 33 | { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, 34 | ]; 35 | rankingData = _restructGameResultRowsForRanking(rows); 36 | assert.deepEqual(Object.keys(rankingData).sort(), [ 37 | 'easy', 38 | 'hard', 39 | 'simple', 40 | ]); 41 | assert.strictEqual(rankingData.simple.all.length, 13); 42 | assert.strictEqual(rankingData.easy.all.length, 2); 43 | assert.strictEqual(rankingData.hard.all.length, 1); 44 | assert.deepEqual(rankingData.simple.all.slice(0, 10).map((v) => v.score), [4, 3, 2, 1, 1, 1, 1, 1, 1, 1]); 45 | assert.strictEqual(rankingData.simple.all[3].created_at, 9999, 'Be applied secondary-sort by created_at'); 46 | 47 | // validate time windows 48 | let nowTime = (new Date()).getTime(); 49 | rows = [ 50 | { created_at: nowTime, stage: 'simple', name: 'Foo', score: 1 }, 51 | { created_at: nowTime - 86400000 * 0.5, stage: 'simple', name: 'Foo', score: 1 }, 52 | { created_at: nowTime - 86400000 * 3, stage: 'simple', name: 'Foo', score: 1 }, 53 | { created_at: nowTime - 86400000 * 10, stage: 'simple', name: 'Foo', score: 1 }, 54 | { created_at: nowTime - 86400000 * 20, stage: 'simple', name: 'Foo', score: 1 }, 55 | { created_at: nowTime - 86400000 * 29, stage: 'simple', name: 'Foo', score: 1 }, 56 | { created_at: nowTime - 86400000 * 31, stage: 'simple', name: 'Foo', score: 1 }, 57 | ]; 58 | rankingData = _restructGameResultRowsForRanking(rows); 59 | assert.strictEqual(rankingData.simple.all.length, 7); 60 | assert.strictEqual(rankingData.simple.last30Days.length, 6); 61 | assert.strictEqual(rankingData.simple.last7Days.length, 3); 62 | assert.strictEqual(rankingData.simple.last1Day.length, 2); 63 | }); 64 | 65 | it('_formatRankingDataToText', function() { 66 | let nowTime = (new Date()).getTime(); 67 | let rows = [ 68 | { created_at: nowTime, stage: 'lunatic', name: 'Mr. Number One', score: 99999 }, 69 | { created_at: nowTime, stage: 'lunatic', name: 'hutarime', score: 67676 }, 70 | { created_at: nowTime - 86400000 * 2, stage: 'lunatic', name: 'sann', score: 67675 }, 71 | { created_at: nowTime - 86400000 * 2, stage: 'hard', name: 'sann', score: 999999 }, 72 | ]; 73 | let rankingData = _restructGameResultRowsForRanking(rows); 74 | let text = _formatRankingDataToText(rankingData); 75 | assert(/1\. Mr\. /.test(text)); 76 | assert(/2\. hutarime /.test(text)); 77 | assert(/3\. sann /.test(text)); 78 | assert(/1\. sann /.test(text)); 79 | }); 80 | 81 | it('requestRanking', function(done) { 82 | requestRanking(done); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /lib/apis/index.es6: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import querystring from 'querystring'; 3 | import request from 'request'; 4 | import _s from 'underscore.string'; 5 | 6 | import conf from 'conf'; 7 | import {stageList, stages} from 'lib/stages'; 8 | 9 | 10 | export function _restructGameResultRowsForRanking(gameResultRows) { 11 | let rankingData = {}; 12 | 13 | gameResultRows.forEach((row) => { 14 | let { created_at, stage, name, score } = row; 15 | if (!rankingData[stage]) { 16 | rankingData[stage] = []; 17 | } 18 | rankingData[stage].push(row); 19 | }); 20 | 21 | let nowTime = (new Date()).getTime(); 22 | Object.keys(rankingData).forEach((stageTypeId) => { 23 | let rows = rankingData[stageTypeId] 24 | .sort((a, b) => { 25 | let compared = b.score - a.score; 26 | if (compared !== 0) { 27 | return compared; 28 | }; 29 | return a.created_at - b.created_at; 30 | }) 31 | ; 32 | rankingData[stageTypeId] = { 33 | last30Days: rows.filter((v) => v.created_at >= nowTime - 86400000 * 30).slice(0, 10), 34 | last7Days: rows.filter((v) => v.created_at >= nowTime - 86400000 * 7).slice(0, 10), 35 | last1Day: rows.filter((v) => v.created_at >= nowTime - 86400000).slice(0, 10), 36 | // Don't use "all" in production, because game-results are already filtered by last 30 days in server 37 | // It is for testing 38 | all: rows, 39 | }; 40 | }); 41 | 42 | return rankingData; 43 | } 44 | 45 | export function _formatRankingDataToText(rankingData) { 46 | let lines = []; 47 | stageList 48 | .slice() 49 | .forEach((Stage) => { 50 | 51 | // title 52 | let title = chalk.magenta(Stage.getName()); 53 | ['last30Days', 'last7Days', 'last1Day'].forEach((timeWindowKey) => { 54 | 55 | // sub title 56 | let subTitle = { 57 | last30Days: 'Last 30 days', 58 | last7Days: 'Last 7 days', 59 | last1Day: 'Last day', 60 | }[timeWindowKey]; 61 | subTitle = chalk.yellow(subTitle); 62 | lines.push(title + ' - ' + subTitle); 63 | lines.push(''); 64 | 65 | if (!(Stage.typeId in rankingData)) { 66 | return; 67 | } 68 | 69 | // rows 70 | let rows = rankingData[Stage.typeId][timeWindowKey]; 71 | if (rows) { 72 | rows.forEach(({ name, score }, idx) => { 73 | let line = [ 74 | _s.lpad(idx + 1, 2, '') + '.', 75 | _s.rpad(name, 16, ' '), 76 | chalk.underline(_s.numberFormat(score)) + ' pts', 77 | ].join(' '); 78 | lines.push(' ' + line); 79 | }); 80 | lines.push(''); 81 | } 82 | }); 83 | }) 84 | ; 85 | return lines.join('\n'); 86 | } 87 | 88 | export function requestRanking(callback) { 89 | let params = { 90 | api_mode: 'get_ranking' 91 | }; 92 | let url = conf.apiUrl + '?' + querystring.stringify(params); 93 | request(url, function onRequested(err, response, body) { 94 | if (err) { 95 | return callback(err); 96 | } else if (response.statusCode !== 200) { 97 | return callback(new Error(`Returned HTTP status ${response.statusCode} from AWS API Gateway`)); 98 | } 99 | let gameResultRows = JSON.parse(body.toString()); 100 | let rankingData = _restructGameResultRowsForRanking(gameResultRows); 101 | let text = _formatRankingDataToText(rankingData); 102 | callback(null, text); 103 | }); 104 | } 105 | 106 | export function requestAddingGameResult({ stageTypeId, playerName, score }, callback = function(){}) { 107 | let url = conf.apiUrl + '?' + querystring.stringify({ 108 | api_mode: 'add_game_result', 109 | stage: stageTypeId, 110 | name: playerName, 111 | score: score 112 | }); 113 | request(url, function onRequested(err, response, body) { 114 | if (err) { 115 | return callback(err); 116 | } else if (response.statusCode !== 200) { 117 | return callback(new Error(`Returned HTTP status ${response.statusCode} from AWS API Gateway`)); 118 | } 119 | callback(); 120 | }); 121 | } 122 | -------------------------------------------------------------------------------- /dist/components/pages/WelcomePageComponent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _lodash = require('lodash'); 18 | 19 | var _lodash2 = _interopRequireDefault(_lodash); 20 | 21 | var _react = require('react'); 22 | 23 | var _react2 = _interopRequireDefault(_react); 24 | 25 | var _variables = require('../variables'); 26 | 27 | var _variables2 = _interopRequireDefault(_variables); 28 | 29 | var _consts = require('consts'); 30 | 31 | var _libStages = require('lib/stages'); 32 | 33 | var WelcomePageComponent = (function (_Component) { 34 | _inherits(WelcomePageComponent, _Component); 35 | 36 | function WelcomePageComponent() { 37 | _classCallCheck(this, WelcomePageComponent); 38 | 39 | _get(Object.getPrototypeOf(WelcomePageComponent.prototype), 'constructor', this).apply(this, arguments); 40 | } 41 | 42 | _createClass(WelcomePageComponent, [{ 43 | key: 'render', 44 | value: function render() { 45 | 46 | var content = ''; 47 | 48 | // Title 49 | content += '{magenta-fg}Escape From The Maze{/}\n\n'; 50 | 51 | // Overview 52 | content += 'The purpose of the game is to escape from the maze by operating the "{magenta-fg}@{/}" '; 53 | content += 'by [{green-fg}wasd{/}] [{green-fg}hjkl{/}] or {green-fg}arrow keys{/}. '; 54 | content += 'Futher, by using [{green-fg}space{/}], you can also break the wall by consuming a pickaxe.\n'; 55 | content += '{yellow-fg}--help{/} option shows more helps!\n\n'; 56 | 57 | // Choices of stages 58 | var invertedKeys = _lodash2['default'].invert(_consts.KEYS.STAGE_SELECTION); 59 | content += 'Push a {green-fg}key{/} for stage selection.\n\n'; 60 | content += _libStages.stageList.map(function (Stage) { 61 | return '[{green-fg}' + invertedKeys[Stage.typeId] + '{/}] ' + Stage.getName() + ': ' + Stage.description; 62 | }).join('\n'); 63 | 64 | var props = Object.assign({}, _variables2['default'].pageBoxProps); 65 | 66 | return _react2['default'].createElement( 67 | 'box', 68 | props, 69 | content 70 | ); 71 | } 72 | }]); 73 | 74 | return WelcomePageComponent; 75 | })(_react.Component); 76 | 77 | exports['default'] = WelcomePageComponent; 78 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/test/lib/apis/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _conf = require('conf'); 10 | 11 | var _conf2 = _interopRequireDefault(_conf); 12 | 13 | var _libApis = require('lib/apis'); 14 | 15 | var _testSupportHelpers = require('test/support/helpers'); 16 | 17 | describe((0, _testSupportHelpers.heading)(__filename), function () { 18 | 19 | it('_restructGameResultRowsForRanking', function () { 20 | var rows = undefined, 21 | rankingData = undefined; 22 | 23 | rows = [{ created_at: 10000, stage: 'simple', name: 'Foo', score: 2 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 4 }, { created_at: 10000, stage: 'easy', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 3 }, { created_at: 10000, stage: 'easy', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'hard', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 9999, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }, { created_at: 10000, stage: 'simple', name: 'Foo', score: 1 }]; 24 | rankingData = (0, _libApis._restructGameResultRowsForRanking)(rows); 25 | _powerAssert2['default'].deepEqual(Object.keys(rankingData).sort(), ['easy', 'hard', 'simple']); 26 | _powerAssert2['default'].strictEqual(rankingData.simple.all.length, 13); 27 | _powerAssert2['default'].strictEqual(rankingData.easy.all.length, 2); 28 | _powerAssert2['default'].strictEqual(rankingData.hard.all.length, 1); 29 | _powerAssert2['default'].deepEqual(rankingData.simple.all.slice(0, 10).map(function (v) { 30 | return v.score; 31 | }), [4, 3, 2, 1, 1, 1, 1, 1, 1, 1]); 32 | _powerAssert2['default'].strictEqual(rankingData.simple.all[3].created_at, 9999, 'Be applied secondary-sort by created_at'); 33 | 34 | // validate time windows 35 | var nowTime = new Date().getTime(); 36 | rows = [{ created_at: nowTime, stage: 'simple', name: 'Foo', score: 1 }, { created_at: nowTime - 86400000 * 0.5, stage: 'simple', name: 'Foo', score: 1 }, { created_at: nowTime - 86400000 * 3, stage: 'simple', name: 'Foo', score: 1 }, { created_at: nowTime - 86400000 * 10, stage: 'simple', name: 'Foo', score: 1 }, { created_at: nowTime - 86400000 * 20, stage: 'simple', name: 'Foo', score: 1 }, { created_at: nowTime - 86400000 * 29, stage: 'simple', name: 'Foo', score: 1 }, { created_at: nowTime - 86400000 * 31, stage: 'simple', name: 'Foo', score: 1 }]; 37 | rankingData = (0, _libApis._restructGameResultRowsForRanking)(rows); 38 | _powerAssert2['default'].strictEqual(rankingData.simple.all.length, 7); 39 | _powerAssert2['default'].strictEqual(rankingData.simple.last30Days.length, 6); 40 | _powerAssert2['default'].strictEqual(rankingData.simple.last7Days.length, 3); 41 | _powerAssert2['default'].strictEqual(rankingData.simple.last1Day.length, 2); 42 | }); 43 | 44 | it('_formatRankingDataToText', function () { 45 | var nowTime = new Date().getTime(); 46 | var rows = [{ created_at: nowTime, stage: 'lunatic', name: 'Mr. Number One', score: 99999 }, { created_at: nowTime, stage: 'lunatic', name: 'hutarime', score: 67676 }, { created_at: nowTime - 86400000 * 2, stage: 'lunatic', name: 'sann', score: 67675 }, { created_at: nowTime - 86400000 * 2, stage: 'hard', name: 'sann', score: 999999 }]; 47 | var rankingData = (0, _libApis._restructGameResultRowsForRanking)(rows); 48 | var text = (0, _libApis._formatRankingDataToText)(rankingData); 49 | (0, _powerAssert2['default'])(/1\. Mr\. /.test(text)); 50 | (0, _powerAssert2['default'])(/2\. hutarime /.test(text)); 51 | (0, _powerAssert2['default'])(/3\. sann /.test(text)); 52 | (0, _powerAssert2['default'])(/1\. sann /.test(text)); 53 | }); 54 | 55 | it('requestRanking', function (done) { 56 | (0, _libApis.requestRanking)(done); 57 | }); 58 | }); -------------------------------------------------------------------------------- /input/subscriptions/keypress.es6: -------------------------------------------------------------------------------- 1 | import GameActionCreators from 'actions/GameActionCreators'; 2 | import ScreenActionCreators from 'actions/ScreenActionCreators'; 3 | import {KEYS} from 'consts'; 4 | import MazeModel from 'models/MazeModel'; 5 | import DialogStore from 'stores/DialogStore'; 6 | import GameStore from 'stores/GameStore'; 7 | import ScreenStore from 'stores/ScreenStore'; 8 | 9 | 10 | function getDirectionByKeyName(keyName) { 11 | // [w][a][s][d] or 12 | // [h][j][k][l] or 13 | // arrow keys 14 | return { 15 | up: MazeModel.DIRECTIONS.UP, 16 | w: MazeModel.DIRECTIONS.UP, 17 | k: MazeModel.DIRECTIONS.UP, 18 | right: MazeModel.DIRECTIONS.RIGHT, 19 | d: MazeModel.DIRECTIONS.RIGHT, 20 | l: MazeModel.DIRECTIONS.RIGHT, 21 | down: MazeModel.DIRECTIONS.DOWN, 22 | s: MazeModel.DIRECTIONS.DOWN, 23 | j: MazeModel.DIRECTIONS.DOWN, 24 | left: MazeModel.DIRECTIONS.LEFT, 25 | a: MazeModel.DIRECTIONS.LEFT, 26 | h: MazeModel.DIRECTIONS.LEFT 27 | }[keyName] || null; 28 | } 29 | 30 | function acceptKeyOnWelcomePage(keyName, isControl) { 31 | let stageTypeId = KEYS.STAGE_SELECTION[keyName]; 32 | 33 | if (stageTypeId) { 34 | ScreenActionCreators.prepareGame(stageTypeId); 35 | ScreenActionCreators.changePage('game'); 36 | return true; 37 | } 38 | 39 | return false; 40 | } 41 | 42 | function acceptKeyOnGamePage(keyName, isControl) { 43 | let gameStore = GameStore.getInstance(); 44 | 45 | if (gameStore.isPlaying()) { 46 | let direction = getDirectionByKeyName(keyName); 47 | if (direction) { 48 | if (gameStore.isAssumedPicksMode) { 49 | GameActionCreators.crushWallByPlayer(direction); 50 | return true; 51 | } else { 52 | GameActionCreators.walkPlayer(direction); 53 | return true; 54 | } 55 | } else if (keyName === 'space') { 56 | if (gameStore.isAssumedPicksMode) { 57 | GameActionCreators.cancelPicksMode(); 58 | return true; 59 | } else { 60 | GameActionCreators.assumePicksMode(); 61 | return true; 62 | } 63 | } 64 | } 65 | 66 | let backToWelcomePage = () => { 67 | GameActionCreators.resetGame(); 68 | ScreenActionCreators.changePage('welcome'); 69 | }; 70 | 71 | if (gameStore.hasBeenVictory) { 72 | if (keyName === 'y' || keyName === 'enter') { 73 | ScreenActionCreators.openDialog(); 74 | return true; 75 | } else if (keyName === 'n') { 76 | backToWelcomePage(); 77 | return true; 78 | } 79 | } else if (gameStore.hasBeenDefeat) { 80 | if (keyName === 'enter') { 81 | backToWelcomePage(); 82 | return true; 83 | } 84 | } 85 | 86 | return false; 87 | } 88 | 89 | 90 | export function onKeypress({ name, ctrl, sequence }) { 91 | let screenStore = ScreenStore.getInstance(); 92 | let dialogStore = DialogStore.getInstance(); 93 | let gameStore = GameStore.getInstance(); 94 | 95 | if (dialogStore.isDialogActive) { 96 | // FIXME: Generalize dialog's action 97 | if (name === 'enter') { 98 | if (!dialogStore.isValidDialogInput) { 99 | return; 100 | } 101 | if ( 102 | screenStore.pageId === 'game' && 103 | dialogStore.isValidDialogInput && 104 | gameStore.hasBeenVictory 105 | ) { 106 | GameActionCreators.requestAddingGameResult(dialogStore.dialogInputValue); // async 107 | ScreenActionCreators.closeDialog(); 108 | GameActionCreators.resetGame(); 109 | ScreenActionCreators.changePage('welcome'); 110 | return; 111 | } 112 | ScreenActionCreators.closeDialog(); 113 | return; 114 | } else if (name === 'escape') { 115 | ScreenActionCreators.closeDialog(); 116 | return; 117 | } else if (name === 'backspace' || name === 'delete') { 118 | ScreenActionCreators.deleteLastInputFromDialog(); 119 | return; 120 | } else if (!ctrl) { 121 | ScreenActionCreators.inputKeyToDialog(sequence); 122 | return; 123 | } 124 | } 125 | 126 | if (name === 'escape' || ctrl && name === 'c') { 127 | ScreenActionCreators.exit(); 128 | return; 129 | } 130 | 131 | let acceptKeyByActivePage = { 132 | game: acceptKeyOnGamePage, 133 | welcome: acceptKeyOnWelcomePage 134 | }[screenStore.pageId]; 135 | 136 | if (!acceptKeyByActivePage) { 137 | ScreenActionCreators.throwRuntimeError( 138 | new Error(screenStore.pageId + ' is invalid pageId')); 139 | return; 140 | } 141 | 142 | if (acceptKeyByActivePage(name, ctrl)) { 143 | return; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /dist/stores/DialogStore.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 14 | 15 | var _lodash = require('lodash'); 16 | 17 | var _lodash2 = _interopRequireDefault(_lodash); 18 | 19 | var _consts = require('consts'); 20 | 21 | var _dispatcherAppDispatcher = require('dispatcher/AppDispatcher'); 22 | 23 | var _dispatcherAppDispatcher2 = _interopRequireDefault(_dispatcherAppDispatcher); 24 | 25 | var _libEventManager = require('lib/EventManager'); 26 | 27 | var _libEventManager2 = _interopRequireDefault(_libEventManager); 28 | 29 | var _storesStore = require('stores/Store'); 30 | 31 | var _storesStore2 = _interopRequireDefault(_storesStore); 32 | 33 | var DIALOG_INPUT_MATCHER = /^[a-zA-Z0-9]{1,12}$/; 34 | function validateDialogInput(input) { 35 | return DIALOG_INPUT_MATCHER.test(input); 36 | } 37 | 38 | var DialogStore = (function (_Store) { 39 | _inherits(DialogStore, _Store); 40 | 41 | function DialogStore() { 42 | var _this = this; 43 | 44 | _classCallCheck(this, DialogStore); 45 | 46 | _get(Object.getPrototypeOf(DialogStore.prototype), 'constructor', this).call(this); 47 | 48 | this._isDialogActive = false; 49 | this._dialogInputValue = ''; 50 | this._isValidDialogInput = false; 51 | 52 | Object.defineProperty(this, 'isDialogActive', { get: function get() { 53 | return this._isDialogActive; 54 | } }); 55 | Object.defineProperty(this, 'dialogInputValue', { get: function get() { 56 | return this._dialogInputValue; 57 | } }); 58 | Object.defineProperty(this, 'isValidDialogInput', { get: function get() { 59 | return this._isValidDialogInput; 60 | } }); 61 | 62 | var dispatcher = _dispatcherAppDispatcher2['default'].getInstance(); 63 | 64 | var _EventManager$getInstance = _libEventManager2['default'].getInstance(); 65 | 66 | var emitter = _EventManager$getInstance.emitter; 67 | 68 | this._dispatchToken = dispatcher.register(function (action) { 69 | switch (action.type) { 70 | case _consts.ACTIONS.CLOSE_DIALOG: 71 | _this._isDialogActive = false; 72 | _this._dialogInputValue = ''; 73 | emitter.emit(_consts.EVENTS.UPDATE_DIALOG); 74 | break; 75 | case _consts.ACTIONS.DELETE_LAST_INPUT_FROM_DIALOG: 76 | _this._dialogInputValue = _this._dialogInputValue.slice(0, -1); 77 | _this._isValidDialogInput = validateDialogInput(_this._dialogInputValue); 78 | emitter.emit(_consts.EVENTS.UPDATE_DIALOG); 79 | break; 80 | case _consts.ACTIONS.INPUT_KEY_TO_DIALOG: 81 | _this._dialogInputValue += action.keyName; 82 | _this._isValidDialogInput = validateDialogInput(_this._dialogInputValue); 83 | emitter.emit(_consts.EVENTS.UPDATE_DIALOG); 84 | break; 85 | case _consts.ACTIONS.OPEN_DIALOG: 86 | _this._isDialogActive = true; 87 | _this._dialogInputValue = ''; 88 | _this._isValidDialogInput = false; 89 | emitter.emit(_consts.EVENTS.UPDATE_DIALOG); 90 | break; 91 | } 92 | }); 93 | } 94 | 95 | return DialogStore; 96 | })(_storesStore2['default']); 97 | 98 | exports['default'] = DialogStore; 99 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/stores/ScreenStore.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _lodash = require('lodash'); 18 | 19 | var _lodash2 = _interopRequireDefault(_lodash); 20 | 21 | var _consts = require('consts'); 22 | 23 | var _dispatcherAppDispatcher = require('dispatcher/AppDispatcher'); 24 | 25 | var _dispatcherAppDispatcher2 = _interopRequireDefault(_dispatcherAppDispatcher); 26 | 27 | var _libEventManager = require('lib/EventManager'); 28 | 29 | var _libEventManager2 = _interopRequireDefault(_libEventManager); 30 | 31 | var _storesGameStore = require('stores/GameStore'); 32 | 33 | var _storesGameStore2 = _interopRequireDefault(_storesGameStore); 34 | 35 | var _storesStore = require('stores/Store'); 36 | 37 | var _storesStore2 = _interopRequireDefault(_storesStore); 38 | 39 | var DIALOG_INPUT_MATCHER = /^[a-zA-Z0-9]{1,12}$/; 40 | function validateDialogInput(input) { 41 | return DIALOG_INPUT_MATCHER.test(input); 42 | } 43 | 44 | var ScreenStore = (function (_Store) { 45 | _inherits(ScreenStore, _Store); 46 | 47 | function ScreenStore() { 48 | var _this = this; 49 | 50 | _classCallCheck(this, ScreenStore); 51 | 52 | _get(Object.getPrototypeOf(ScreenStore.prototype), 'constructor', this).call(this); 53 | 54 | this._pageId = 'welcome'; 55 | this._runtimeErrors = []; 56 | 57 | Object.defineProperty(this, 'pageId', { get: function get() { 58 | return this._pageId; 59 | } }); 60 | 61 | var dispatcher = _dispatcherAppDispatcher2['default'].getInstance(); 62 | 63 | var _EventManager$getInstance = _libEventManager2['default'].getInstance(); 64 | 65 | var emitter = _EventManager$getInstance.emitter; 66 | 67 | var gameStore = _storesGameStore2['default'].getInstance(); 68 | this._dispatchToken = dispatcher.register(function (action) { 69 | dispatcher.waitFor([gameStore.getDispatchToken()]); 70 | 71 | switch (action.type) { 72 | case _consts.ACTIONS.CHANGE_PAGE: 73 | _this._pageId = action.pageId; 74 | emitter.emit(_consts.EVENTS.CHANGE_PAGE); 75 | break; 76 | case _consts.ACTIONS.EXIT: 77 | emitter.emit(_consts.EVENTS.EXIT); 78 | break; 79 | case _consts.ACTIONS.THROW_RUNTIME_ERROR: 80 | _this._runtimeErrors.push(action.err); 81 | emitter.emit(_consts.EVENTS.UPDATE_ERRORS); 82 | break; 83 | } 84 | }); 85 | } 86 | 87 | _createClass(ScreenStore, [{ 88 | key: 'getLastRuntimeError', 89 | value: function getLastRuntimeError() { 90 | return _lodash2['default'].last(this._runtimeErrors); 91 | } 92 | }]); 93 | 94 | return ScreenStore; 95 | })(_storesStore2['default']); 96 | 97 | exports['default'] = ScreenStore; 98 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12 | 13 | var _actionsScreenActionCreators = require('actions/ScreenActionCreators'); 14 | 15 | var _actionsScreenActionCreators2 = _interopRequireDefault(_actionsScreenActionCreators); 16 | 17 | var _componentsScreen = require('components/Screen'); 18 | 19 | var _componentsScreen2 = _interopRequireDefault(_componentsScreen); 20 | 21 | var _conf = require('conf'); 22 | 23 | var _conf2 = _interopRequireDefault(_conf); 24 | 25 | var _dispatcherAppDispatcher = require('dispatcher/AppDispatcher'); 26 | 27 | var _dispatcherAppDispatcher2 = _interopRequireDefault(_dispatcherAppDispatcher); 28 | 29 | var _inputAppInput = require('input/AppInput'); 30 | 31 | var _inputAppInput2 = _interopRequireDefault(_inputAppInput); 32 | 33 | var _libEventManager = require('lib/EventManager'); 34 | 35 | var _libEventManager2 = _interopRequireDefault(_libEventManager); 36 | 37 | var _libMixinsSingletonMixin = require('lib/mixins/SingletonMixin'); 38 | 39 | var _libMixinsSingletonMixin2 = _interopRequireDefault(_libMixinsSingletonMixin); 40 | 41 | var _storesDialogStore = require('stores/DialogStore'); 42 | 43 | var _storesDialogStore2 = _interopRequireDefault(_storesDialogStore); 44 | 45 | var _storesGameStore = require('stores/GameStore'); 46 | 47 | var _storesGameStore2 = _interopRequireDefault(_storesGameStore); 48 | 49 | var _storesScreenStore = require('stores/ScreenStore'); 50 | 51 | var _storesScreenStore2 = _interopRequireDefault(_storesScreenStore); 52 | 53 | var App = (function () { 54 | _createClass(App, null, [{ 55 | key: 'initializeInstances', 56 | 57 | /* 58 | * Initialize unique instances in consideration of the order 59 | */ 60 | value: function initializeInstances() { 61 | [function () { 62 | return _libEventManager2['default'].getInstance(); 63 | }, function () { 64 | return _dispatcherAppDispatcher2['default'].getInstance(); 65 | }, function () { 66 | return _storesDialogStore2['default'].getInstance(); 67 | }, function () { 68 | return _storesGameStore2['default'].getInstance(); 69 | }, function () { 70 | return _storesScreenStore2['default'].getInstance(); 71 | }, function () { 72 | return _inputAppInput2['default'].getInstance(); 73 | }].forEach(function (task) { 74 | return task(); 75 | }); 76 | } 77 | }, { 78 | key: 'purgeInstances', 79 | value: function purgeInstances() { 80 | [function () { 81 | return _componentsScreen2['default'].clearInstance(); 82 | }, function () { 83 | return _inputAppInput2['default'].clearInstance(); 84 | }, function () { 85 | return _storesScreenStore2['default'].clearInstance(); 86 | }, function () { 87 | return _storesDialogStore2['default'].clearInstance(); 88 | }, function () { 89 | return _storesGameStore2['default'].clearInstance(); 90 | }, function () { 91 | return _dispatcherAppDispatcher2['default'].clearInstance(); 92 | }, function () { 93 | return _libEventManager2['default'].clearInstance(); 94 | }].forEach(function (task) { 95 | return task(); 96 | }); 97 | } 98 | }]); 99 | 100 | function App() { 101 | _classCallCheck(this, App); 102 | 103 | this.constructor.initializeInstances(); 104 | } 105 | 106 | _createClass(App, [{ 107 | key: 'start', 108 | value: function start() { 109 | _componentsScreen2['default'].getInstance({ componentMode: _conf2['default'].componentMode }); 110 | _actionsScreenActionCreators2['default'].changePage('welcome'); 111 | } 112 | }]); 113 | 114 | return App; 115 | })(); 116 | 117 | exports['default'] = App; 118 | 119 | Object.assign(App, _libMixinsSingletonMixin2['default']); 120 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/components/DialogComponent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _lodash = require('lodash'); 18 | 19 | var _lodash2 = _interopRequireDefault(_lodash); 20 | 21 | var _react = require('react'); 22 | 23 | var _react2 = _interopRequireDefault(_react); 24 | 25 | var _variables = require('./variables'); 26 | 27 | var _variables2 = _interopRequireDefault(_variables); 28 | 29 | var DialogComponent = (function (_Component) { 30 | _inherits(DialogComponent, _Component); 31 | 32 | function DialogComponent(props) { 33 | _classCallCheck(this, DialogComponent); 34 | 35 | _get(Object.getPrototypeOf(DialogComponent.prototype), 'constructor', this).call(this, props); 36 | } 37 | 38 | _createClass(DialogComponent, [{ 39 | key: 'render', 40 | value: function render() { 41 | 42 | var content = ''; 43 | content += '\n'; 44 | content += 'What\'s your name?\n'; 45 | content += '\n'; 46 | content += '\n'; 47 | content += '\n'; 48 | content += 'by /{green-fg}[-_a-zA-Z0-9]{open}1,12{close}{/}/\n'; 49 | content += '\n'; 50 | content += 'Submit is [{green-fg}enter{/}]\n'; 51 | content += 'Cancel is [{green-fg}escape{/}]\n'; 52 | 53 | var props = { 54 | ref: 'root', 55 | top: 'center', 56 | left: 'center', 57 | width: 33, 58 | height: 12, 59 | tags: true, 60 | border: { 61 | type: 'line' 62 | }, 63 | align: 'center', 64 | style: { 65 | fg: 'white', 66 | bg: 'black', 67 | border: { 68 | fg: 'white' 69 | } 70 | }, 71 | content: content, 72 | hidden: !this.props.isDialogActive 73 | }; 74 | if (this.props.isDialogActive) { 75 | this.refs.root.setFront(); 76 | } 77 | 78 | var inputBoxProps = { 79 | top: 3, 80 | left: 'center', 81 | width: 25, 82 | height: 1, 83 | style: { 84 | fg: this.props.isValidDialogInput ? 'black' : 'red', 85 | bg: 'white' 86 | }, 87 | content: this.props.dialogInputValue 88 | }; 89 | 90 | return _react2['default'].createElement( 91 | 'box', 92 | props, 93 | _react2['default'].createElement('box', inputBoxProps) 94 | ); 95 | } 96 | }]); 97 | 98 | return DialogComponent; 99 | })(_react.Component); 100 | 101 | exports['default'] = DialogComponent; 102 | 103 | Object.assign(DialogComponent, { 104 | 105 | propTypes: { 106 | isDialogActive: _react2['default'].PropTypes.bool.isRequired, 107 | dialogInputValue: _react2['default'].PropTypes.string.isRequired, 108 | isValidDialogInput: _react2['default'].PropTypes.bool.isRequired 109 | } 110 | }); 111 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/models/CellModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var _lodash = require('lodash'); 18 | 19 | var _lodash2 = _interopRequireDefault(_lodash); 20 | 21 | var _modelsModel = require('models/Model'); 22 | 23 | var _modelsModel2 = _interopRequireDefault(_modelsModel); 24 | 25 | var CellModel = (function (_Model) { 26 | _inherits(CellModel, _Model); 27 | 28 | function CellModel() { 29 | _classCallCheck(this, CellModel); 30 | 31 | _get(Object.getPrototypeOf(CellModel.prototype), 'constructor', this).call(this); 32 | 33 | this._things = []; 34 | } 35 | 36 | _createClass(CellModel, [{ 37 | key: 'getThings', 38 | value: function getThings() { 39 | return this._things; 40 | } 41 | }, { 42 | key: 'getThing', 43 | value: function getThing() { 44 | return this.getThings()[0] || null; 45 | } 46 | }, { 47 | key: 'getThingOrError', 48 | value: function getThingOrError() { 49 | var thing = this.getThing(); 50 | if (thing) { 51 | return thing; 52 | } else { 53 | throw new Error('Can not get a thing'); 54 | } 55 | } 56 | }, { 57 | key: 'findThing', 58 | value: function findThing(thing) { 59 | return _lodash2['default'].find(this._things, function (thing_) { 60 | return thing === thing_; 61 | }) || null; 62 | } 63 | }, { 64 | key: 'findThingOrError', 65 | value: function findThingOrError(thing) { 66 | var thing_ = this.findThing(thing); 67 | if (thing_) { 68 | return thing_; 69 | } else { 70 | throw new Error('Can not find the thing'); 71 | } 72 | } 73 | }, { 74 | key: 'hasThing', 75 | value: function hasThing(thing) { 76 | return !!this.findThing(thing); 77 | } 78 | }, { 79 | key: 'setThing', 80 | value: function setThing(thing) { 81 | if (this.hasThing(thing)) { 82 | throw new Error('The thing is duplicated'); 83 | } 84 | this._things.push(thing); 85 | } 86 | 87 | /* 88 | * @param {Thing} thing 89 | * @return {boolean} Removed or not removed 90 | */ 91 | }, { 92 | key: 'removeThing', 93 | value: function removeThing(thing) { 94 | var removed = _lodash2['default'].remove(this._things, function (thing_) { 95 | return thing === thing_; 96 | }); 97 | return removed.length > 0; 98 | } 99 | }, { 100 | key: 'isPassable', 101 | value: function isPassable() { 102 | if (this._things.length === 0) { 103 | return true; 104 | } 105 | return this._things.every(function (thing) { 106 | return thing.isPassable(); 107 | }); 108 | } 109 | }, { 110 | key: 'toContent', 111 | value: function toContent() { 112 | if (this._things.length > 0) { 113 | return this._things[0].toContent(); 114 | } else { 115 | return ' '; 116 | } 117 | } 118 | }]); 119 | 120 | return CellModel; 121 | })(_modelsModel2['default']); 122 | 123 | exports['default'] = CellModel; 124 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/lib/apis/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | exports._restructGameResultRowsForRanking = _restructGameResultRowsForRanking; 7 | exports._formatRankingDataToText = _formatRankingDataToText; 8 | exports.requestRanking = requestRanking; 9 | exports.requestAddingGameResult = requestAddingGameResult; 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12 | 13 | var _chalk = require('chalk'); 14 | 15 | var _chalk2 = _interopRequireDefault(_chalk); 16 | 17 | var _querystring = require('querystring'); 18 | 19 | var _querystring2 = _interopRequireDefault(_querystring); 20 | 21 | var _request = require('request'); 22 | 23 | var _request2 = _interopRequireDefault(_request); 24 | 25 | var _underscoreString = require('underscore.string'); 26 | 27 | var _underscoreString2 = _interopRequireDefault(_underscoreString); 28 | 29 | var _conf = require('conf'); 30 | 31 | var _conf2 = _interopRequireDefault(_conf); 32 | 33 | var _libStages = require('lib/stages'); 34 | 35 | function _restructGameResultRowsForRanking(gameResultRows) { 36 | var rankingData = {}; 37 | 38 | gameResultRows.forEach(function (row) { 39 | var created_at = row.created_at; 40 | var stage = row.stage; 41 | var name = row.name; 42 | var score = row.score; 43 | 44 | if (!rankingData[stage]) { 45 | rankingData[stage] = []; 46 | } 47 | rankingData[stage].push(row); 48 | }); 49 | 50 | var nowTime = new Date().getTime(); 51 | Object.keys(rankingData).forEach(function (stageTypeId) { 52 | var rows = rankingData[stageTypeId].sort(function (a, b) { 53 | var compared = b.score - a.score; 54 | if (compared !== 0) { 55 | return compared; 56 | }; 57 | return a.created_at - b.created_at; 58 | }); 59 | rankingData[stageTypeId] = { 60 | last30Days: rows.filter(function (v) { 61 | return v.created_at >= nowTime - 86400000 * 30; 62 | }).slice(0, 10), 63 | last7Days: rows.filter(function (v) { 64 | return v.created_at >= nowTime - 86400000 * 7; 65 | }).slice(0, 10), 66 | last1Day: rows.filter(function (v) { 67 | return v.created_at >= nowTime - 86400000; 68 | }).slice(0, 10), 69 | // Don't use "all" in production, because game-results are already filtered by last 30 days in server 70 | // It is for testing 71 | all: rows 72 | }; 73 | }); 74 | 75 | return rankingData; 76 | } 77 | 78 | function _formatRankingDataToText(rankingData) { 79 | var lines = []; 80 | _libStages.stageList.slice().forEach(function (Stage) { 81 | 82 | // title 83 | var title = _chalk2['default'].magenta(Stage.getName()); 84 | ['last30Days', 'last7Days', 'last1Day'].forEach(function (timeWindowKey) { 85 | 86 | // sub title 87 | var subTitle = ({ 88 | last30Days: 'Last 30 days', 89 | last7Days: 'Last 7 days', 90 | last1Day: 'Last day' 91 | })[timeWindowKey]; 92 | subTitle = _chalk2['default'].yellow(subTitle); 93 | lines.push(title + ' - ' + subTitle); 94 | lines.push(''); 95 | 96 | if (!(Stage.typeId in rankingData)) { 97 | return; 98 | } 99 | 100 | // rows 101 | var rows = rankingData[Stage.typeId][timeWindowKey]; 102 | if (rows) { 103 | rows.forEach(function (_ref, idx) { 104 | var name = _ref.name; 105 | var score = _ref.score; 106 | 107 | var line = [_underscoreString2['default'].lpad(idx + 1, 2, '') + '.', _underscoreString2['default'].rpad(name, 16, ' '), _chalk2['default'].underline(_underscoreString2['default'].numberFormat(score)) + ' pts'].join(' '); 108 | lines.push(' ' + line); 109 | }); 110 | lines.push(''); 111 | } 112 | }); 113 | }); 114 | return lines.join('\n'); 115 | } 116 | 117 | function requestRanking(callback) { 118 | var params = { 119 | api_mode: 'get_ranking' 120 | }; 121 | var url = _conf2['default'].apiUrl + '?' + _querystring2['default'].stringify(params); 122 | (0, _request2['default'])(url, function onRequested(err, response, body) { 123 | if (err) { 124 | return callback(err); 125 | } else if (response.statusCode !== 200) { 126 | return callback(new Error('Returned HTTP status ' + response.statusCode + ' from AWS API Gateway')); 127 | } 128 | var gameResultRows = JSON.parse(body.toString()); 129 | var rankingData = _restructGameResultRowsForRanking(gameResultRows); 130 | var text = _formatRankingDataToText(rankingData); 131 | callback(null, text); 132 | }); 133 | } 134 | 135 | function requestAddingGameResult(_ref2) { 136 | var stageTypeId = _ref2.stageTypeId; 137 | var playerName = _ref2.playerName; 138 | var score = _ref2.score; 139 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1]; 140 | 141 | var url = _conf2['default'].apiUrl + '?' + _querystring2['default'].stringify({ 142 | api_mode: 'add_game_result', 143 | stage: stageTypeId, 144 | name: playerName, 145 | score: score 146 | }); 147 | (0, _request2['default'])(url, function onRequested(err, response, body) { 148 | if (err) { 149 | return callback(err); 150 | } else if (response.statusCode !== 200) { 151 | return callback(new Error('Returned HTTP status ' + response.statusCode + ' from AWS API Gateway')); 152 | } 153 | callback(); 154 | }); 155 | } -------------------------------------------------------------------------------- /dist/test/stores/GameStore.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _powerAssert = require('power-assert'); 6 | 7 | var _powerAssert2 = _interopRequireDefault(_powerAssert); 8 | 9 | var _sinon = require('sinon'); 10 | 11 | var _sinon2 = _interopRequireDefault(_sinon); 12 | 13 | var _actionsGameActionCreators = require('actions/GameActionCreators'); 14 | 15 | var _actionsGameActionCreators2 = _interopRequireDefault(_actionsGameActionCreators); 16 | 17 | var _actionsScreenActionCreators = require('actions/ScreenActionCreators'); 18 | 19 | var _actionsScreenActionCreators2 = _interopRequireDefault(_actionsScreenActionCreators); 20 | 21 | var _app = require('app'); 22 | 23 | var _app2 = _interopRequireDefault(_app); 24 | 25 | var _libStages = require('lib/stages'); 26 | 27 | var _modelsGameResultModel = require('models/GameResultModel'); 28 | 29 | var _modelsGameResultModel2 = _interopRequireDefault(_modelsGameResultModel); 30 | 31 | var _modelsMazeModel = require('models/MazeModel'); 32 | 33 | var _modelsMazeModel2 = _interopRequireDefault(_modelsMazeModel); 34 | 35 | var _modelsThingsBonusTime5ThingModel = require('models/things/BonusTime5ThingModel'); 36 | 37 | var _modelsThingsBonusTime5ThingModel2 = _interopRequireDefault(_modelsThingsBonusTime5ThingModel); 38 | 39 | var _modelsThingsPenaltyTime3ThingModel = require('models/things/PenaltyTime3ThingModel'); 40 | 41 | var _modelsThingsPenaltyTime3ThingModel2 = _interopRequireDefault(_modelsThingsPenaltyTime3ThingModel); 42 | 43 | var _storesGameStore = require('stores/GameStore'); 44 | 45 | var _storesGameStore2 = _interopRequireDefault(_storesGameStore); 46 | 47 | var _testSupportHelpers = require('test/support/helpers'); 48 | 49 | describe((0, _testSupportHelpers.heading)(__filename), function () { 50 | 51 | function _createGameStore() { 52 | var store = new _storesGameStore2['default'](); 53 | _actionsScreenActionCreators2['default'].prepareGame('simple'); 54 | return store; 55 | } 56 | 57 | beforeEach(function () { 58 | _app2['default'].purgeInstances(); 59 | }); 60 | 61 | it('should be defined', function () { 62 | _powerAssert2['default'].strictEqual(typeof _storesGameStore2['default'], 'function'); 63 | }); 64 | 65 | it('hasNextMaze', function () { 66 | var FooStage = Object.assign({}, _libStages.Stage); 67 | FooStage.mazeCount = 5; 68 | 69 | var store = _createGameStore(); 70 | store._prepare(); 71 | store._runningMazeCount = 4; 72 | _sinon2['default'].stub(store, '_getStage', function () { 73 | return FooStage; 74 | }); 75 | 76 | _powerAssert2['default'].strictEqual(store.hasNextMaze(), true); 77 | store._runningMazeCount = 5; 78 | _powerAssert2['default'].strictEqual(store.hasNextMaze(), false); 79 | }); 80 | 81 | it('_doesPlayerArriveGoal', function () { 82 | var store = _createGameStore(); 83 | store._prepare(); 84 | _powerAssert2['default'].strictEqual(store._doesPlayerArriveGoal(), false); 85 | store.maze.moveThing(store._things.player, [1, 1], store.maze.searchThingPos(store._things.upstairs)); 86 | _powerAssert2['default'].strictEqual(store._doesPlayerArriveGoal(), true); 87 | }); 88 | 89 | it('_crushWallByPlayer', function () { 90 | var store = _createGameStore(); 91 | store._prepare(); 92 | store._picksCount = 1; 93 | var playerPos = store._maze.searchThingPos(store._things.player); 94 | var upperPos = [playerPos[0] - 1, playerPos[1]]; 95 | var wallAtUpper = store._maze.getCellOrError(upperPos).getThing(); 96 | _powerAssert2['default'].strictEqual(wallAtUpper.getTypeId(), 'wall'); 97 | store._crushWallByPlayer(_modelsMazeModel2['default'].DIRECTIONS.UP); 98 | var crushedThing = store._maze.getCellOrError(upperPos).getThing(); 99 | _powerAssert2['default'].strictEqual(crushedThing, null); 100 | _powerAssert2['default'].strictEqual(store._picksCount, 0); 101 | }); 102 | 103 | it('_pickThingsByPlayer', function () { 104 | var store = _createGameStore(); 105 | store._prepare(); 106 | var playerPos = store._maze.searchThingPos(store._things.player); 107 | function getThingCount() { 108 | return store._maze.getCellOrError(playerPos).getThings().length; 109 | } 110 | _powerAssert2['default'].strictEqual(getThingCount(), 1); 111 | var bonusTime5Thing = new _modelsThingsBonusTime5ThingModel2['default'](); 112 | var penaltyTime3Thing = new _modelsThingsPenaltyTime3ThingModel2['default'](); 113 | 114 | store._maze.addThing(bonusTime5Thing, playerPos); 115 | store._maze.addThing(penaltyTime3Thing, playerPos); 116 | 117 | _powerAssert2['default'].strictEqual(getThingCount(), 3); 118 | var baseTimeLimit = store._timeLimit; 119 | store._pickThingsByPlayer(); 120 | _powerAssert2['default'].strictEqual(getThingCount(), 1); 121 | (0, _powerAssert2['default'])(store._timeLimit > baseTimeLimit); 122 | }); 123 | 124 | it('_forwardGameTime', function () { 125 | var store = _createGameStore(); 126 | _powerAssert2['default'].strictEqual(store._forwardGameTime(999), false); 127 | _powerAssert2['default'].strictEqual(store._forwardGameTime(1), true); 128 | }); 129 | 130 | context('action subscription', function () { 131 | 132 | it('SAVE_VICTORY', function () { 133 | var store = _createGameStore(); 134 | _powerAssert2['default'].strictEqual(store.gameResult, null); 135 | _actionsGameActionCreators2['default'].saveVictory(); 136 | (0, _powerAssert2['default'])(store.gameResult instanceof _modelsGameResultModel2['default']); 137 | }); 138 | }); 139 | }); -------------------------------------------------------------------------------- /dist/input/subscriptions/keypress.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | exports.onKeypress = onKeypress; 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9 | 10 | var _actionsGameActionCreators = require('actions/GameActionCreators'); 11 | 12 | var _actionsGameActionCreators2 = _interopRequireDefault(_actionsGameActionCreators); 13 | 14 | var _actionsScreenActionCreators = require('actions/ScreenActionCreators'); 15 | 16 | var _actionsScreenActionCreators2 = _interopRequireDefault(_actionsScreenActionCreators); 17 | 18 | var _consts = require('consts'); 19 | 20 | var _modelsMazeModel = require('models/MazeModel'); 21 | 22 | var _modelsMazeModel2 = _interopRequireDefault(_modelsMazeModel); 23 | 24 | var _storesDialogStore = require('stores/DialogStore'); 25 | 26 | var _storesDialogStore2 = _interopRequireDefault(_storesDialogStore); 27 | 28 | var _storesGameStore = require('stores/GameStore'); 29 | 30 | var _storesGameStore2 = _interopRequireDefault(_storesGameStore); 31 | 32 | var _storesScreenStore = require('stores/ScreenStore'); 33 | 34 | var _storesScreenStore2 = _interopRequireDefault(_storesScreenStore); 35 | 36 | function getDirectionByKeyName(keyName) { 37 | // [w][a][s][d] or 38 | // [h][j][k][l] or 39 | // arrow keys 40 | return ({ 41 | up: _modelsMazeModel2['default'].DIRECTIONS.UP, 42 | w: _modelsMazeModel2['default'].DIRECTIONS.UP, 43 | k: _modelsMazeModel2['default'].DIRECTIONS.UP, 44 | right: _modelsMazeModel2['default'].DIRECTIONS.RIGHT, 45 | d: _modelsMazeModel2['default'].DIRECTIONS.RIGHT, 46 | l: _modelsMazeModel2['default'].DIRECTIONS.RIGHT, 47 | down: _modelsMazeModel2['default'].DIRECTIONS.DOWN, 48 | s: _modelsMazeModel2['default'].DIRECTIONS.DOWN, 49 | j: _modelsMazeModel2['default'].DIRECTIONS.DOWN, 50 | left: _modelsMazeModel2['default'].DIRECTIONS.LEFT, 51 | a: _modelsMazeModel2['default'].DIRECTIONS.LEFT, 52 | h: _modelsMazeModel2['default'].DIRECTIONS.LEFT 53 | })[keyName] || null; 54 | } 55 | 56 | function acceptKeyOnWelcomePage(keyName, isControl) { 57 | var stageTypeId = _consts.KEYS.STAGE_SELECTION[keyName]; 58 | 59 | if (stageTypeId) { 60 | _actionsScreenActionCreators2['default'].prepareGame(stageTypeId); 61 | _actionsScreenActionCreators2['default'].changePage('game'); 62 | return true; 63 | } 64 | 65 | return false; 66 | } 67 | 68 | function acceptKeyOnGamePage(keyName, isControl) { 69 | var gameStore = _storesGameStore2['default'].getInstance(); 70 | 71 | if (gameStore.isPlaying()) { 72 | var direction = getDirectionByKeyName(keyName); 73 | if (direction) { 74 | if (gameStore.isAssumedPicksMode) { 75 | _actionsGameActionCreators2['default'].crushWallByPlayer(direction); 76 | return true; 77 | } else { 78 | _actionsGameActionCreators2['default'].walkPlayer(direction); 79 | return true; 80 | } 81 | } else if (keyName === 'space') { 82 | if (gameStore.isAssumedPicksMode) { 83 | _actionsGameActionCreators2['default'].cancelPicksMode(); 84 | return true; 85 | } else { 86 | _actionsGameActionCreators2['default'].assumePicksMode(); 87 | return true; 88 | } 89 | } 90 | } 91 | 92 | var backToWelcomePage = function backToWelcomePage() { 93 | _actionsGameActionCreators2['default'].resetGame(); 94 | _actionsScreenActionCreators2['default'].changePage('welcome'); 95 | }; 96 | 97 | if (gameStore.hasBeenVictory) { 98 | if (keyName === 'y' || keyName === 'enter') { 99 | _actionsScreenActionCreators2['default'].openDialog(); 100 | return true; 101 | } else if (keyName === 'n') { 102 | backToWelcomePage(); 103 | return true; 104 | } 105 | } else if (gameStore.hasBeenDefeat) { 106 | if (keyName === 'enter') { 107 | backToWelcomePage(); 108 | return true; 109 | } 110 | } 111 | 112 | return false; 113 | } 114 | 115 | function onKeypress(_ref) { 116 | var name = _ref.name; 117 | var ctrl = _ref.ctrl; 118 | var sequence = _ref.sequence; 119 | 120 | var screenStore = _storesScreenStore2['default'].getInstance(); 121 | var dialogStore = _storesDialogStore2['default'].getInstance(); 122 | var gameStore = _storesGameStore2['default'].getInstance(); 123 | 124 | if (dialogStore.isDialogActive) { 125 | // FIXME: Generalize dialog's action 126 | if (name === 'enter') { 127 | if (!dialogStore.isValidDialogInput) { 128 | return; 129 | } 130 | if (screenStore.pageId === 'game' && dialogStore.isValidDialogInput && gameStore.hasBeenVictory) { 131 | _actionsGameActionCreators2['default'].requestAddingGameResult(dialogStore.dialogInputValue); // async 132 | _actionsScreenActionCreators2['default'].closeDialog(); 133 | _actionsGameActionCreators2['default'].resetGame(); 134 | _actionsScreenActionCreators2['default'].changePage('welcome'); 135 | return; 136 | } 137 | _actionsScreenActionCreators2['default'].closeDialog(); 138 | return; 139 | } else if (name === 'escape') { 140 | _actionsScreenActionCreators2['default'].closeDialog(); 141 | return; 142 | } else if (name === 'backspace' || name === 'delete') { 143 | _actionsScreenActionCreators2['default'].deleteLastInputFromDialog(); 144 | return; 145 | } else if (!ctrl) { 146 | _actionsScreenActionCreators2['default'].inputKeyToDialog(sequence); 147 | return; 148 | } 149 | } 150 | 151 | if (name === 'escape' || ctrl && name === 'c') { 152 | _actionsScreenActionCreators2['default'].exit(); 153 | return; 154 | } 155 | 156 | var acceptKeyByActivePage = ({ 157 | game: acceptKeyOnGamePage, 158 | welcome: acceptKeyOnWelcomePage 159 | })[screenStore.pageId]; 160 | 161 | if (!acceptKeyByActivePage) { 162 | _actionsScreenActionCreators2['default'].throwRuntimeError(new Error(screenStore.pageId + ' is invalid pageId')); 163 | return; 164 | } 165 | 166 | if (acceptKeyByActivePage(name, ctrl)) { 167 | return; 168 | } 169 | } --------------------------------------------------------------------------------