react-memory-game
Version:
A memory game engine.
429 lines (377 loc) • 14.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MemoryGame = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
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; }; }();
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _lodash = require('lodash');
require('regenerator-runtime/runtime');
var _MemoryGrid = require('./MemoryGrid');
var _MemoryGrid2 = _interopRequireDefault(_MemoryGrid);
var _MemoryCard = require('./MemoryCard');
var _MemoryCard2 = _interopRequireDefault(_MemoryCard);
var _Counter = require('./Counter');
var _Counter2 = _interopRequireDefault(_Counter);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
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; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var MEMORY_GAME_CONTEXT = '__memory_game_context__';
var BOARD_SIZE = 16;
var ResetButton = function ResetButton(_ref, context) {
var _ref$children = _ref.children,
children = _ref$children === undefined ? 'Reset Game' : _ref$children;
var resetGame = context[MEMORY_GAME_CONTEXT].resetGame;
return _react2.default.createElement(
'button',
{ className: 'memory-game--reset', onClick: resetGame },
children
);
};
ResetButton.contextTypes = _defineProperty({}, MEMORY_GAME_CONTEXT, _propTypes2.default.object.isRequired);
var Board = function Board(props, context) {
var cards = context[MEMORY_GAME_CONTEXT].cards;
return _react2.default.createElement(
_MemoryGrid2.default,
null,
cards
);
};
Board.contextTypes = _defineProperty({}, MEMORY_GAME_CONTEXT, _propTypes2.default.object.isRequired);
var MovesCounter = function MovesCounter(props, context) {
var movesCounter = context[MEMORY_GAME_CONTEXT].movesCounter;
return _react2.default.createElement(_Counter2.default, { counter: movesCounter });
};
MovesCounter.contextTypes = _defineProperty({}, MEMORY_GAME_CONTEXT, _propTypes2.default.object.isRequired);
var PairsFoundCounter = function PairsFoundCounter(props, context) {
var pairsFoundCounter = context[MEMORY_GAME_CONTEXT].pairsFoundCounter;
return _react2.default.createElement(_Counter2.default, { counter: pairsFoundCounter });
};
PairsFoundCounter.contextTypes = _defineProperty({}, MEMORY_GAME_CONTEXT, _propTypes2.default.object.isRequired);
var MemoryGame = exports.MemoryGame = function (_Component) {
_inherits(MemoryGame, _Component);
function MemoryGame(props) {
var _this2 = this;
_classCallCheck(this, MemoryGame);
var _this = _possibleConstructorReturn(this, (MemoryGame.__proto__ || Object.getPrototypeOf(MemoryGame)).call(this, props));
Object.defineProperty(_this, 'getPreparedCard', {
enumerable: true,
writable: true,
value: function value(display, _value) {
return {
value: _value,
display: display,
state: _MemoryCard.CARD_STATE.CLOSED
};
}
});
Object.defineProperty(_this, 'prepareCardPairs', {
enumerable: true,
writable: true,
value: function value(pairs) {
return pairs.map(function (pair, index) {
return pair.map(function (card) {
return _this.getPreparedCard(card, index);
});
}).reduce(function (prev, curr) {
return prev.concat(curr);
});
}
});
Object.defineProperty(_this, 'prepareSingleCards', {
enumerable: true,
writable: true,
value: function value(cards) {
var preparedCards = cards.map(_this.getPreparedCard);
return preparedCards.concat((0, _lodash.cloneDeep)(preparedCards));
}
});
Object.defineProperty(_this, 'getInitialState', {
enumerable: true,
writable: true,
value: function value(cards) {
var randomise = _this.props.dryRun ? _lodash.identity : _lodash.shuffle;
var prepareCards = Array.isArray(cards[0]) ? _this.prepareCardPairs : _this.prepareSingleCards;
return {
moves: 0,
pairsFound: 0,
glimpse: false,
cards: randomise(prepareCards(cards))
};
}
});
Object.defineProperty(_this, 'resetGame', {
enumerable: true,
writable: true,
value: function value(cards) {
clearTimeout(_this.timeout);
_this.setState(_this.getInitialState(cards), function () {
if (_this.props.glimpse) {
_this.startGlimpse();
}
});
}
});
Object.defineProperty(_this, 'startGlimpse', {
enumerable: true,
writable: true,
value: function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var cards;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
cards = (0, _lodash.cloneDeep)(_this.state.cards).map(function (card) {
return _extends({}, card, {
state: _MemoryCard.CARD_STATE.OPEN
});
});
_this.setState({
cards: cards,
glimpse: true
});
_this.timeout = setTimeout(function () {
_this.closeOpenCards();
_this.setState({
glimpse: false
});
}, _this.props.glimpse);
case 3:
case 'end':
return _context.stop();
}
}
}, _callee, _this2);
}));
return function value() {
return _ref2.apply(this, arguments);
};
}()
});
Object.defineProperty(_this, 'getOpenCards', {
enumerable: true,
writable: true,
value: function value() {
return (0, _lodash.cloneDeep)(_this.state.cards).filter(function (card) {
return card.state === _MemoryCard.CARD_STATE.OPEN;
});
}
});
Object.defineProperty(_this, 'openCard', {
enumerable: true,
writable: true,
value: function value(position) {
var cards = (0, _lodash.cloneDeep)(_this.state.cards);
cards[position].state = cards[position].state === _MemoryCard.CARD_STATE.CLOSED ? _MemoryCard.CARD_STATE.OPEN : cards[position].state;
_this.setState({ cards: cards }, _this.checkForPair);
}
});
Object.defineProperty(_this, 'closeOpenCards', {
enumerable: true,
writable: true,
value: function value() {
clearTimeout(_this.timeout);
var cards = (0, _lodash.cloneDeep)(_this.state.cards).map(function (card) {
return _extends({}, card, {
state: card.state === _MemoryCard.CARD_STATE.OPEN ? _MemoryCard.CARD_STATE.CLOSED : card.state
});
});
_this.setState({ cards: cards });
}
});
Object.defineProperty(_this, 'findCardPair', {
enumerable: true,
writable: true,
value: function value() {
var cards = (0, _lodash.cloneDeep)(_this.state.cards).map(function (card) {
return _extends({}, card, {
state: card.state === _MemoryCard.CARD_STATE.OPEN ? _MemoryCard.CARD_STATE.FOUND : card.state
});
});
_this.setState({ cards: cards });
}
});
Object.defineProperty(_this, 'hasGameEnded', {
enumerable: true,
writable: true,
value: function value() {
(0, _lodash.cloneDeep)(_this.state.cards).some(function (card) {
return card.state !== _MemoryCard.CARD_STATE.FOUND;
});
}
});
Object.defineProperty(_this, 'scheduleCloseCards', {
enumerable: true,
writable: true,
value: function value() {
var delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 700;
_this.timeout = setTimeout(_this.closeOpenCards, delay);
}
});
Object.defineProperty(_this, 'incrementCounter', {
enumerable: true,
writable: true,
value: function value() {
_this.setState({
moves: _this.state.moves + 1
});
}
});
Object.defineProperty(_this, 'incrementFoundPairsCounter', {
enumerable: true,
writable: true,
value: function value() {
_this.setState({
pairsFound: _this.state.pairsFound + 1
});
}
});
Object.defineProperty(_this, 'checkForPair', {
enumerable: true,
writable: true,
value: function value() {
var openCards = _this.getOpenCards();
if (openCards.length !== 2) {
return;
}
_this.incrementCounter();
if (openCards[0].value === openCards[1].value) {
_this.findCardPair();
_this.incrementFoundPairsCounter();
} else {
_this.scheduleCloseCards();
}
}
});
Object.defineProperty(_this, 'handleCardClick', {
enumerable: true,
writable: true,
value: function value(position) {
return function () {
if (_this.state.glimpse) {
return;
}
var openCards = _this.getOpenCards(_this.state);
switch (openCards.length) {
case 0:
{
_this.openCard(position);
break;
}
case 1:
{
_this.openCard(position);
break;
}
default:
{
break;
}
}
};
}
});
if (props.cards.length !== BOARD_SIZE / 2) {
throw new Error('Wrong card set size: <MemoryGame /> expects ' + BOARD_SIZE / 2 + ' cards or pairs');
}
_this.state = _this.getInitialState(props.cards);
return _this;
}
_createClass(MemoryGame, [{
key: 'componentWillMount',
value: function componentWillMount() {
var _props = this.props,
glimpse = _props.glimpse,
glimpseOnMount = _props.glimpseOnMount;
if (glimpse && glimpseOnMount) {
this.startGlimpse();
}
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (nextProps.cards !== this.props.cards) {
this.resetGame(nextProps.cards);
}
}
}, {
key: 'getChildContext',
value: function getChildContext() {
return _defineProperty({}, MEMORY_GAME_CONTEXT, {
cards: this.getMemoryCards(),
resetGame: this.resetGame.bind(this, this.props.cards),
movesCounter: this.state.moves,
pairsFoundCounter: this.state.pairsFound
});
}
}, {
key: 'getMemoryCards',
value: function getMemoryCards() {
var _this3 = this;
return (0, _lodash.cloneDeep)(this.state.cards).map(function (card, position) {
return _react2.default.createElement(
_MemoryCard2.default,
{
onClick: _this3.handleCardClick(position),
key: position,
state: card.state
},
card.display
);
});
}
}, {
key: 'render',
value: function render() {
return _react2.default.createElement(
'div',
{ className: 'memory-game' },
this.props.children
);
}
}]);
return MemoryGame;
}(_react.Component);
Object.defineProperty(MemoryGame, 'propTypes', {
enumerable: true,
writable: true,
value: {
cards: _propTypes2.default.arrayOf(_propTypes2.default.any).isRequired,
glimpse: _propTypes2.default.number,
glimpseOnMount: _propTypes2.default.bool
}
});
Object.defineProperty(MemoryGame, 'Reset', {
enumerable: true,
writable: true,
value: ResetButton
});
Object.defineProperty(MemoryGame, 'Board', {
enumerable: true,
writable: true,
value: Board
});
Object.defineProperty(MemoryGame, 'MovesCounter', {
enumerable: true,
writable: true,
value: MovesCounter
});
Object.defineProperty(MemoryGame, 'PairsFoundCounter', {
enumerable: true,
writable: true,
value: PairsFoundCounter
});
Object.defineProperty(MemoryGame, 'childContextTypes', {
enumerable: true,
writable: true,
value: _defineProperty({}, MEMORY_GAME_CONTEXT, _propTypes2.default.object.isRequired)
});
exports.default = MemoryGame;