UNPKG

backgammon

Version:

a clean api for building a backgammon game

429 lines (340 loc) 12.1 kB
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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var Point = /*#__PURE__*/function () { function Point(position, checkers) { if (checkers === void 0) { checkers = []; } this.position = position; this.checkers = checkers; } // ! not in use var _proto = Point.prototype; _proto.relativePositionFromHome = function relativePositionFromHome(player) { if (player.color === PlayerColor.white) { return this.position; } else { return player.home.position - this.position; } }; _proto.isHouse = function isHouse() { return this.checkers.length > 1; }; _proto.isSingle = function isSingle() { return this.checkers.length === 1; } // todo rename includesCheckersOf ; _proto.includesCheckerOf = function includesCheckerOf(player) { if (!this.checkers.length) { return false; } return !!this.checkers.find(function (c) { return c.color === player.color; }); }; _proto.isAvailableFor = function isAvailableFor(player) { if (!this.includesCheckerOf(player) && this.isHouse()) { return false; } return true; }; Point.getPointRefByPosition = function getPointRefByPosition(position, points) { return points.find(function (p) { return p.position === position; }); }; _createClass(Point, [{ key: "oppisetPosition", get: function get() { return 25 - this.position; } }]); return Point; }(); var PlayerColor; (function (PlayerColor) { PlayerColor["black"] = "black"; PlayerColor["white"] = "white"; })(PlayerColor || (PlayerColor = {})); var PlayerHome; (function (PlayerHome) { PlayerHome[PlayerHome["white"] = 0] = "white"; PlayerHome[PlayerHome["black"] = 25] = "black"; })(PlayerHome || (PlayerHome = {})); var PlayerPrison; (function (PlayerPrison) { PlayerPrison[PlayerPrison["white"] = 25] = "white"; PlayerPrison[PlayerPrison["black"] = 0] = "black"; })(PlayerPrison || (PlayerPrison = {})); var Player = function Player(color) { this.home = new Point(PlayerHome[color]); this.prison = new Point(PlayerPrison[color]); this.color = color; }; var Players = /*#__PURE__*/function () { // todo use infer on starter, to make sure is's one of the first 2 args function Players(white, black, starter) { this.white = white; this.black = black; this._current = starter; } var _proto = Players.prototype; // todo hide from public api _proto.toggle = function toggle() { this._current = this.second; return this.current; }; _createClass(Players, [{ key: "current", get: function get() { return this._current; } }, { key: "second", get: function get() { return this.current === this.white ? this.black : this.white; } }, { key: "White", get: function get() { return this.white; } }, { key: "Black", get: function get() { return this.black; } }]); return Players; }(); var Dices = /*#__PURE__*/function () { function Dices(numbers) { this.numbers = numbers; this.isDouble = false; if (Dices.dicesAreDouble(this)) { var _this$numbers; this.isDouble = true; (_this$numbers = this.numbers).push.apply(_this$numbers, this.numbers); } } Dices.roll1Dice = function roll1Dice() { return Math.floor(Math.random() * 6 + 1); }; Dices.roll2Dices = function roll2Dices() { return new Dices([this.roll1Dice(), this.roll1Dice()]); }; Dices.dicesAreDouble = function dicesAreDouble(_ref) { var numbers = _ref.numbers; return numbers[0] === numbers[1]; } // a weird bug makes tests fail when setting the return type to [DiceResut, DiceResut] ; Dices.getStarterDices = function getStarterDices() { var dices; do { dices = new Dices([this.roll1Dice(), this.roll1Dice()]); } while (this.dicesAreDouble(dices)); return dices; }; return Dices; }(); var Checker = function Checker(color) { this.color = color; }; var initialPointsState = [/*#__PURE__*/new Point(1, /*#__PURE__*/repeatCheckers(2, PlayerColor.black)), /*#__PURE__*/new Point(2), /*#__PURE__*/new Point(3), /*#__PURE__*/new Point(4), /*#__PURE__*/new Point(5), /*#__PURE__*/new Point(6, /*#__PURE__*/repeatCheckers(5, PlayerColor.white)), /*#__PURE__*/new Point(7), /*#__PURE__*/new Point(8, /*#__PURE__*/repeatCheckers(3, PlayerColor.white)), /*#__PURE__*/new Point(9), /*#__PURE__*/new Point(10), /*#__PURE__*/new Point(11), /*#__PURE__*/new Point(12, /*#__PURE__*/repeatCheckers(5, PlayerColor.black)), /*#__PURE__*/new Point(13, /*#__PURE__*/repeatCheckers(5, PlayerColor.white)), /*#__PURE__*/new Point(14), /*#__PURE__*/new Point(15), /*#__PURE__*/new Point(16), /*#__PURE__*/new Point(17, /*#__PURE__*/repeatCheckers(3, PlayerColor.black)), /*#__PURE__*/new Point(18), /*#__PURE__*/new Point(19, /*#__PURE__*/repeatCheckers(5, PlayerColor.black)), /*#__PURE__*/new Point(20), /*#__PURE__*/new Point(21), /*#__PURE__*/new Point(22), /*#__PURE__*/new Point(23), /*#__PURE__*/new Point(24, /*#__PURE__*/repeatCheckers(2, PlayerColor.white))]; function repeatCheckers(count, color) { var list = []; for (var i = 0; i < count; i++) { list.push(new Checker(PlayerColor[color])); } return list; } // todo fix this type generator (not working) // usage example: UntilRange<25> // result: 0 | 1 | 2 ... | 24 // export type UntilRange<Max extends number> = number extends Max // ? number // : _Range<Max, []>; // type _Range<Max extends number, Arr extends number[]> // = Arr['length'] extends Max // ? Arr[number] // : _Range<Max, [...Arr, Arr['length']]>; // todo write tests function unshiftFrom(arr, item) { var index = arr.indexOf(item); if (index > -1 && index < arr.length) { var _arr$splice = arr.splice(index, 1), itemToMove = _arr$splice[0]; arr.unshift(itemToMove); } return arr; } // submittedMove: MovePath[]; // } var Board = /*#__PURE__*/function () { // private turnsHistory: CompletedTurn[] = []; function Board() { // todo make private whatever is possible this.points = initialPointsState; var white = new Player(PlayerColor.white); var black = new Player(PlayerColor.black); var dices = Dices.getStarterDices(); var starter = dices.numbers[0] > dices.numbers[1] ? white : black; this.players = new Players(white, black, starter); this.currentTurn = { player: starter, dices: dices, possibleMoves: this.getAllMovePaths(dices, starter) }; } var _proto = Board.prototype; _proto.submitMove = function submitMove(submittedMove) { this.generateNextMove(); }; _proto.generateNextMove = function generateNextMove() { var dices = Dices.roll2Dices(); var player = this.players.toggle(); var possibleMoves = this.getAllMovePaths(dices, player); this.currentTurn = { dices: dices, player: player, possibleMoves: possibleMoves }; // todo test the logic // if (possibleMoves.length === 0) { // this.submitMove([]); // } }; _proto.PlayerInPrison = function PlayerInPrison(player) { if (player === void 0) { player = this.players.current; } return player.prison.checkers.length > 0; }; _proto.currentPlayerCanBearOff = function currentPlayerCanBearOff() { var _this = this; if (this.PlayerInPrison()) { return false; } var points = this.getPlayersPoints(); return points.every(function (point) { return point.relativePositionFromHome(_this.players.current) <= 6; }); }; _proto.getPlayersPoints = function getPlayersPoints(player) { if (player === void 0) { player = this.players.current; } return this.points.filter(function (point) { return point.includesCheckerOf(player); }); }; _proto.score = function score(player) { var playersPoints = this.getPlayersPoints(player); if (this.PlayerInPrison(player)) { playersPoints.push(player.prison); } var totalScore = 0; for (var _iterator = _createForOfIteratorHelperLoose(playersPoints), _step; !(_step = _iterator()).done;) { var point = _step.value; totalScore += point.relativePositionFromHome(player) * point.checkers.length; } return totalScore; }; _proto.getTargetPoint = function getTargetPoint(point, dice, player) { var position = player.color === PlayerColor.white ? Math.max(point.position - dice, player.home.position) : Math.min(point.position + dice, player.home.position); return Point.getPointRefByPosition(position, this.points); }; _proto.getMovePathsForPoint = function getMovePathsForPoint(point, dices, player) { var _this2 = this; var pointPaths = []; var LoopDices = function LoopDices(dices) { var movePath = []; var distance = 0; var lastPoint = point; for (var _iterator2 = _createForOfIteratorHelperLoose(dices), _step2; !(_step2 = _iterator2()).done;) { var dice = _step2.value; var target = _this2.getTargetPoint(point, distance + dice, player); if (!target || !target.isAvailableFor(player)) { break; } movePath.push({ from: lastPoint, to: target, uses: dice }); distance += dice; lastPoint = target; } if (movePath.length > 0) { pointPaths.push(movePath); } }; dices.numbers.forEach(function (dice) { LoopDices(unshiftFrom(dices.numbers, dice)); }); return pointPaths; }; _proto.getAllMovePaths = function getAllMovePaths(dices, player) { if (player === void 0) { player = this.players.current; } // todo check if in prison var allMovePaths = []; var points = this.getPlayersPoints(player); for (var _iterator3 = _createForOfIteratorHelperLoose(points), _step3; !(_step3 = _iterator3()).done;) { var point = _step3.value; var moves = this.getMovePathsForPoint(point, dices, player); if (moves.length > 0) { allMovePaths.push.apply(allMovePaths, moves); } } return allMovePaths; }; return Board; }(); export { Board }; //# sourceMappingURL=backgammon.esm.js.map