From dc0ac9a49c5fd215e626920832852d30de7be5e9 Mon Sep 17 00:00:00 2001 From: Leonardo Val Date: Sat, 10 May 2014 11:58:10 -0300 Subject: [PATCH] Added utils.Cache. Cache is meant to implement transposition tables and similar data structures designed to prevent duplicates in game tree searches. --- Gruntfile.js | 30 +++-- build/ludorum.js | 275 ++++++++++++++++++++++++++++---------- build/ludorum.js.map | 3 +- build/ludorum.min.js | 4 +- build/ludorum.min.js.map | 2 +- src/utils/Cache.js | 131 ++++++++++++++++++ src/utils/Checkerboard.js | 20 ++- tests/specs/cache.test.js | 36 +++++ 8 files changed, 406 insertions(+), 95 deletions(-) create mode 100644 src/utils/Cache.js create mode 100644 tests/specs/cache.test.js diff --git a/Gruntfile.js b/Gruntfile.js index b87557e..6a5b8b0 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,6 +17,7 @@ var sourceFiles = [ 'src/__prologue__.js', 'src/utils/Checkerboard.js', 'src/utils/CheckerboardFromString.js', 'src/utils/Scanner.js', + 'src/utils/Cache.js', // games. 'src/games/Predefined.js', 'src/games/Choose2Win.js', 'src/games/ConnectionGame.js', @@ -46,15 +47,11 @@ module.exports = function(grunt) { } }, }, - karma: { /////////////////////////////////////////////////////////////// - options: { - configFile: 'tests/karma.conf.js' + jshint: { ////////////////////////////////////////////////////////////// + build: { + options: { }, + src: ['build/<%= pkg.name %>.js'], }, - build: { browsers: ['PhantomJS'] }, - chrome: { browsers: ['Chrome'] }, - firefox: { browsers: ['Firefox'] }, - opera: { browsers: ['Opera'] }, - iexplore: { browsers: ['IE'] } }, uglify: { ////////////////////////////////////////////////////////////// build: { @@ -69,7 +66,17 @@ module.exports = function(grunt) { } } }, - docker: { //////////////////////////////////////////////////////////////// + karma: { /////////////////////////////////////////////////////////////// + options: { + configFile: 'tests/karma.conf.js' + }, + build: { browsers: ['PhantomJS'] }, + chrome: { browsers: ['Chrome'] }, + firefox: { browsers: ['Firefox'] }, + opera: { browsers: ['Opera'] }, + iexplore: { browsers: ['IE'] } + }, + docker: { ////////////////////////////////////////////////////////////// build: { src: ["src/**/*.js", "README.md"], dest: "docs/docker", @@ -104,6 +111,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-docker'); grunt.loadNpmTasks('grunt-bowercopy'); + grunt.loadNpmTasks('grunt-contrib-jshint'); // Custom tasks. /////////////////////////////////////////////////////////////// grunt.registerTask('bower-json', 'Writes based on .', function() { @@ -135,8 +143,8 @@ module.exports = function(grunt) { // Register tasks. ///////////////////////////////////////////////////////////// grunt.registerTask('compile', ['concat_sourcemap:build', 'uglify:build']); - grunt.registerTask('build', ['concat_sourcemap:build', - 'karma:build', 'uglify:build', 'docker:build']); + grunt.registerTask('build', ['concat_sourcemap:build', 'uglify:build', + 'karma:build', 'docker:build']); grunt.registerTask('default', ['build']); grunt.registerTask('test', ['concat_sourcemap:build', 'karma:build', 'karma:chrome', 'karma:firefox', 'karma:opera', 'karma:iexplore']); diff --git a/build/ludorum.js b/build/ludorum.js index f291e3d..77adc6a 100644 --- a/build/ludorum.js +++ b/build/ludorum.js @@ -52,35 +52,33 @@ var Game = exports.Game = declare({ (!Array.isArray(activePlayers) ? [activePlayers] : activePlayers); }, - /** The game's name at `Game.name` is used mainly for displaying purposes. + /** The game's `name` is used mainly for displaying purposes. */ name: '?', - /** The game players are specified in the class property `Game.players`, an - array of role names (strings), that the players can assume in a match of - this game. For example: `"Xs"` and `"Os"` in TicTacToe, or `"Whites"` and - `"Blacks"` in Chess. + /** The game `players` are specified in an array of role names (strings), + that the players can assume in a match of this game. For example: `"Xs"` + and `"Os"` in TicTacToe, or `"Whites"` and `"Blacks"` in Chess. */ players: [], - /** The moves of each active player are calculated by `Game.moves()`. This - method returns an object with every active player related to the moves each - can make in this turn. For example: + /** The moves of each active player are calculated by `moves()`. This method + returns an object with every active player related to the moves each can + make in this turn. For example: - { Player1: ['Rock', 'Paper', 'Scissors'], - Player2: ['Rock', 'Paper', 'Scissors'] } + + `{ Player1: ['Rock', 'Paper', 'Scissors'], Player2: ['Rock', 'Paper', 'Scissors'] }` - If the game has finished then a falsy value must be returned (`null` is + If the game has finished then a _falsy_ value must be returned (`null` is recommended). */ moves: unimplemented("Game", "moves"), - /** Once the players have chosen their moves, the method `Game.next(moves)` - is used to perform the given moves. It returns a new game instance with the + /** Once the players have chosen their moves, the method `next(moves)` is + used to perform the given moves. It returns a new game instance with the resulting state. The moves object should have a move for each active player. For example: - { Player1: 'Rock', Player2: 'Paper' } + + `{ Player1: 'Rock', Player2: 'Paper' }` There isn't a default implementation, so it must be overriden. It is strongly advised to check if the moves argument has valid moves. @@ -88,14 +86,14 @@ var Game = exports.Game = declare({ next: unimplemented("Game", "next"), /** If the game is finished the result of the game is calculated with - `Game.result()`. It returns an object with every player in the game related - to a number. This number must be positive if the player wins, negative if - the player loses or zero if the game is a tie. For example: + `result()`. It returns an object with every player in the game related to a + number. This number must be positive if the player wins, negative if the + player loses or zero if the game is a tie. For example: - { Player1: -1, Player2: +1 } + + `{ Player1: -1, Player2: +1 }` - If the game is not finished, this function must return a falsy value (`null` - is recommended). + If the game is not finished, this function must return a _falsy_ value + (`null` is recommended). */ result: unimplemented("Game", "result"), @@ -103,18 +101,18 @@ var Game = exports.Game = declare({ differ from the result, since the score sign doesn't have to indicate victory or defeat. For example: - result: { Player1: -1, Player2: +1 } - scores: { Player1: 4, Player2: 15 } + + result: `{ Player1: -1, Player2: +1 }` + + scores: `{ Player1: 4, Player2: 15 }` - The method `Game.scores()` returns the scores if such is the case. By - default, it return the same that `Game.result()` does. + The method `scores()` returns the scores if such is the case. By default, it + return the same that `result()` does. */ scores: function scores() { return this.results(); }, /** In incomplete or imperfect information games all players have different - access to the game state data. `Game.view(player)` returns a modified + access to the game state data. The method `view(player)` returns a modified version of this game, that shows only the information from the perspective of the given player. The other information is modelled as aleatory variables. @@ -129,7 +127,7 @@ var Game = exports.Game = declare({ // ### Player information ################################################## - /** `Game.isActive(player...)` checks if the given players are all active. + /** Method `isActive(player...)` checks if the given players are all active. */ isActive: function isActive() { for (var i = 0; i < arguments.length; i++) { @@ -141,8 +139,8 @@ var Game = exports.Game = declare({ }, /** In most games there is only one active player per turn. The method - `Game.activePlayer()` returns that active player's role if there is one and - only one, else it raises an error. + `activePlayer()` returns that active player's role if there is one and only + one, else it raises an error. */ activePlayer: function activePlayer() { var len = this.activePlayers.length; @@ -152,8 +150,8 @@ var Game = exports.Game = declare({ }, /** All players in a game are assumed to be opponents. The method - `Game.opponents(players=activePlayers)` returns an array with the opponent - roles of the given players, or of the active players by default. If not all + `opponents(players=activePlayers)` returns an array with the opponent roles + of the given players, or of the active players by default. If not all players are opponents this method can be overriden. */ opponents: function opponents(players) { @@ -164,8 +162,8 @@ var Game = exports.Game = declare({ }, /** Since most games have only two players, the method - `Game.opponent(player=activePlayer)` conveniently returns the opponent of - the given player, or the active player by default. + `opponent(player=activePlayer)` conveniently returns the opponent of the + given player, or the active player by default. */ opponent: function opponent(player) { var playerIndex = this.players.indexOf(player || this.activePlayer()); @@ -174,10 +172,10 @@ var Game = exports.Game = declare({ // ### Game flow ########################################################### - /** Since `Game.next()` expects a moves object, the method - `Game.perform(move, player=activePlayer, ...)` pretends to simplify simpler - game mechanics. It performs the given moves for the given players - (activePlayer by default) and returns the next game state. + /** Since `next()` expects a moves object, the method + `perform(move, player=activePlayer, ...)` pretends to simplify simpler game + mechanics. It performs the given moves for the given players (activePlayer + by default) and returns the next game state. */ perform: function perform() { var moves = {}, move, player; @@ -199,7 +197,7 @@ var Game = exports.Game = declare({ The method `possibleMoves(moves=this.moves())` calculates all possible `moves` objects based on the result of `moves()`. For example, if `moves()` - returns `{A: [1,2], B: [3,4]}`, `possibleMoves()` would return + returns `{A: [1,2], B: [3,4]}`, then `possibleMoves()` would return `[{A:1,B:3}, {A:1,B:4}, {A:2,B:3}, {A:2,B:4}]`. */ possibleMoves: function possibleMoves(moves) { @@ -229,8 +227,8 @@ var Game = exports.Game = declare({ // ### Result functions #################################################### /** The maximum and minimum results may be useful and even required by some - game search algorithm. To expose these values, `Game.resultBounds()` returns - an array with first the minimum and then the maximum. Most game have one type + game search algorithm. To expose these values, `resultBounds()` returns an + array with first the minimum and then the maximum. Most game have one type of victory (+1) and one type of defeat (-1). That's why `resultBounds()` returns [-1,+1] by default. Yet some games can define different bounds by overriding it. @@ -257,11 +255,10 @@ var Game = exports.Game = declare({ /** Most games have victory and defeat results that cancel each other. It is said that all the victors wins the defeated player loses. Those games are - called _zerosum games_. The method - `Game.zerosumResult(score, players=activePlayers)` builds a game result - object for a zerosum game. The given score is split between the given - players (the active players by default), and (-score) is split between their - opponents. + called _zerosum games_. The method + `zerosumResult(score, players=activePlayers)` builds a game result object + for a zerosum game. The given score is split between the given players (the + active players by default), and (-score) is split between their opponents. */ zerosumResult: function zerosumResult(score, players) { players = !players ? this.activePlayers : (!Array.isArray(players) ? [players] : players); @@ -275,27 +272,27 @@ var Game = exports.Game = declare({ return result; }, - /** `Game.zerosumResult()` has two shorcuts. - `Game.victory(players=activePlayers, score=1)` returns the zerosum game - result with the given players (or the active players by default) as winners, - and their opponents as losers. + /** There are two shortcuts for `zerosumResult()`. First + `victory(players=activePlayers, score=1)` returns the zero-sum game result + with the given players (or the active players by default) as winners, and + their opponents as losers. */ victory: function victory(players, score) { return this.zerosumResult(score || 1, players); }, - /** `Game.defeat(players=activePlayers, score=-1)` returns the zerosum game - result with the given players (or the active players by default) as losers, - and their opponents as winners. + /** Second `defeat(players=activePlayers, score=-1)` returns the zero-sum + game result with the given players (or the active players by default) as + losers, and their opponents as winners. */ defeat: function defeat(players, score) { return this.zerosumResult(score || -1, players); }, - /** A tied game must always have the same result for all players. - `Game.draw(players=this.players, score=0)` returns the game result of a tied - game with the given players (or the active players by default) all with the - same score (zero by default). + /** Finally `draw(players=this.players, score=0)` returns the game result of + a tied game with the given players (or the active players by default) all + with the same score (zero by default). A tied game must always have the same + result for all players. */ draw: function draw(players, score) { score = +(score || 0); @@ -310,14 +307,14 @@ var Game = exports.Game = declare({ // ### Conversions & presentations ######################################### /** Many methods are based in the serialization of the game instances. The - abstract method `Game.__serialize__()` should returns an array, where the - first element should be the name of the game, and the rest are the arguments - to call the game's constructor in order to rebuild this game's state. + abstract method `__serialize__()` should returns an array, where the first + element should be the name of the game, and the rest are the arguments to + call the game's constructor in order to rebuild this game's state. */ __serialize__: unimplemented("Game", "__serialize__"), - /** Based on the game's serialization, `Game.clone()` creates a copy of this - game state. + /** Based on the game's serialization, `clone()` creates a copy of this game + state. */ clone: function clone() { var args = this.__serialize__(); @@ -325,8 +322,8 @@ var Game = exports.Game = declare({ return new (this.constructor.bind.apply(this.constructor, args))(); }, - /** Some algorithms require an identifier for each game state, in order to - store them in caches or hashes. `Game.identifier()` calculates a string that + /** Some algorithms require an `identifier()` for each game state, in order + to store them in caches or hashes. This method calculates a string that uniquely identifies this game state, based on the game's serialization. */ identifier: function identifier() { @@ -334,26 +331,25 @@ var Game = exports.Game = declare({ return args.shift() + args.map(JSON.stringify).join(''); }, - /** The default string representation of a Game (i.e. `Game.toString()`) is - also based on the serialization. Changing this is not recommended. + /** The default string representation of a game is also based on the + serialization. Changing this is not recommended. */ toString: function toString() { var args = this.__serialize__(); return args.shift() +'('+ args.map(JSON.stringify).join(',') +')'; }, - /** The default JSON representation (i.e. `Game.toJSON()`) is a straight - JSON stringification of the serialization. It may be used to transfer the - game state between server and client, frames or workers. + /** The default JSON representation (i.e. `toJSON()`) is a straight JSON + stringification of the serialization. It may be used to transfer the game + state between server and client, frames or workers. */ toJSON: function toJSON() { return JSON.stringify(this.__serialize__()); }, - /** The static counterpart of `Game.toJSON` is `Game.fromJSON(data)`, which - creates a new instance of this game from the given JSON. The function in the - Game abstract class finds the proper constructor with the game name and - calls it. + /** The static counterpart of `toJSON()` is `fromJSON()`, which creates a + new instance of this game from the given JSON. The function in `Game` + abstract class finds the proper constructor with the game name and calls it. */ "static fromJSON": function fromJSON(data) { if (typeof data === 'string') { @@ -374,7 +370,7 @@ var Game = exports.Game = declare({ } }); // declare Game. -/** The namespace `ludorum.games` contains all game implementations (as Game +/** The namespace `ludorum.games` contains all game implementations (as `Game` subclasses) provided by this library. */ var games = exports.games = {}; @@ -1406,7 +1402,7 @@ players.MonteCarloPlayer = declare(HeuristicPlayer, { game = game.next(move); } } - //return { game: game, result: game.result(), plies: plies }; + return { game: game, result: game.result(), plies: plies }; }, toString: function toString() { @@ -2231,6 +2227,139 @@ exports.utils.Scanner = declare({ }); // declare utils.Scanner. +/** ## Class Cache. + +A game cache contains a part of a game tree, avoiding redundancies. It can be +used to implement a [transposition table](http://en.wikipedia.org/wiki/Transposition_table) +or similar data structures. +*/ +utils.Cache = declare({ + /** The Cache constructor may take a game to define as `root`. + */ + constructor: function Cache(game) { + this.clear(); + game && this.root(game); + }, + + /** The `stateIdentifier(state)` of every game state is used as the key in + the cache's entries. By default is calculated with the `Game.identifier()` + method. + */ + stateIdentifier: function stateIdentifier(state) { + return state.identifier(); + }, + + /** + */ + moveIdentifier: function moveIdentifier(move) { + return JSON.stringify(move); + }, + + /** The `has(state|id)` returns if the given state or state identifier has + an entry in this cache. + */ + has: function has(state) { + var stateId = typeof state === 'string' ? state : this.stateIdentifier(state); + return this.__entries__.hasOwnProperty(stateId); + }, + + /** If the given state or state identifier has en entry in this cache, + `get(state)` returns that entry. Else it returns `undefined`. + */ + get: function get(state) { + var stateId = typeof state === 'string' ? state : this.stateIdentifier(state); + return this.__entries__[stateId]; + }, + + /** If the given state has no entry in this cache, `entry(state, id)` builds + a new entry, adds it to this cache and returns it. If the state is already + cached, its entry is returned. + Every entry has the game `state`, its `id`, the states that may come before + (the `precursors`) and the states that may follow (the `descendants`). + */ + entry: function entry(state, id) { + id = id || this.stateIdentifier(state); + if (this.has(id)) { + return this.get(id); + } else { + var _entry = { id: id, state: state, precursors: [], descendants: {} }; + this.__entries__[id] = _entry; + return _entry; + } + }, + + /** An entry's `descendant(entry, moves)` is the entry of the game state + following the given entry's game state with the given moves. The method not + only returns the entry is this state, it creates and caches that entry if + not present. + */ + descendant: function descendant(entry, moves) { + var movesId = this.moveIdentifier(moves), + descendants = entry.descendants; + if (descendants.hasOwnProperty(movesId)) { // Already expanded. + return descendants[movesId][1]; + } else { + var nextState = entry.state.next(moves), + nextStateId = this.stateIdentifier(nextState), + nextEntry = this.get(nextStateId) // Reuse entry in cache if it exists. + || this.entry(nextState, nextStateId); // Else add new entry. + descendants[movesId] = [moves, nextEntry]; + nextEntry.precursors.push([moves, entry]); + return nextEntry; + } + }, + + /** An entry `descendants(entry)` + */ + descendants: function descendants(entry) { + var descendant = this.descendant.bind(this, entry); + if (arguments.length > 1) { + return Array.prototype.slice.call(arguments, 1).map(descendant); + } else { // if (arguments.length == 0) + return entry.state.possibleMoves().map(descendant); + } + }, + + /** A clear cache has no entries and of course no root. + */ + clear: function clear() { + this.__entries__ = {}; + this.__root__ = null; + }, + + /** If `root()` is called without arguments, it returns the current root. + If a state is given, that state is assigned as the new root, and the whole + cache is pruned. + */ + root: function root(state) { + if (arguments.length > 0) { // Called with argument means setter. + var stateId = this.stateIdentifier(state); + this.__root__ = this.get(stateId) || this.entry(state, stateId); + this.prune(stateId); + } + return this.__root__; + }, + + /** Deletes all nodes except the one with the given id and its descendants. + */ + prune: function prune(id) { + var pending = [id || this.__root__.id], + pruned = {}, + entry; + while (id = pending.shift()) { + if (!pruned.hasOwnProperty(id)) { + entry = this.get(id); + pruned[id] = entry; + pending.push.apply(pending, iterable(entry.descendants).mapApply(function (id, pair) { + return pair[1].id; + }).toArray()); + } + } + return this.__entries__ = pruned; + } +}); // declare Cache + + /** Simple reference games with a predefined outcome, mostly for testing purposes. */ diff --git a/build/ludorum.js.map b/build/ludorum.js.map index 354c22b..3c45087 100644 --- a/build/ludorum.js.map +++ b/build/ludorum.js.map @@ -21,6 +21,7 @@ "src/utils/Checkerboard.js", "src/utils/CheckerboardFromString.js", "src/utils/Scanner.js", + "src/utils/Cache.js", "src/games/Predefined.js", "src/games/Choose2Win.js", "src/games/ConnectionGame.js", @@ -39,5 +40,5 @@ "src/__epilogue__.js" ], "names": [], - "mappings": "AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mC;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2C;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yC;;ACvDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC7FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8B;;AC/DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACzIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8B;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC5RA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2B;;ACzFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uB;;ACvFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uB;;AChGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC5CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpFA;AACA;AACA,G" + "mappings": "AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9aA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mC;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2C;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yC;;ACvDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC7FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8B;;AC/DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACzIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8B;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC5RA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2B;;ACzFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uB;;ACvFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uB;;AChGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC5CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpFA;AACA;AACA,G" } \ No newline at end of file diff --git a/build/ludorum.min.js b/build/ludorum.min.js index 81d9501..220d70d 100644 --- a/build/ludorum.min.js +++ b/build/ludorum.min.js @@ -1,5 +1,5 @@ //! ludorum 0.1.2 -"use strict";!function(a,b){"function"==typeof define&&define.amd?define(["creatartis-base"],b):"object"==typeof module&&module.exports?module.exports=b(require("creatartis-base")):a.ludorum=b(a.base)}(this,function __init__(base){var declare=base.declare,unimplemented=base.objects.unimplemented,obj=base.obj,copy=base.copy,raiseIf=base.raiseIf,Iterable=base.Iterable,iterable=base.iterable,Future=base.Future,Randomness=base.Randomness,initialize=base.initialize,Statistics=base.Statistics,Events=base.Events,exports={__name__:"ludorum",__init__:__init__};__init__.dependencies={"creatartis-base":base};var utils=exports.utils={},Game=exports.Game=declare({constructor:function(a){this.activePlayers=a?Array.isArray(a)?a:[a]:[this.players[0]]},name:"?",players:[],moves:unimplemented("Game","moves"),next:unimplemented("Game","next"),result:unimplemented("Game","result"),scores:function(){return this.results()},view:function(){return this},isActive:function(){for(var a=0;aa,"There is no active player."),raiseIf(a>1,"More than one player is active."),this.activePlayers[0]},opponents:function(a){return a=a||this.activePlayers,this.players.filter(function(b){return a.indexOf(b)<0})},opponent:function(a){var b=this.players.indexOf(a||this.activePlayer());return this.players[(b+1)%this.players.length]},perform:function(){for(var a,b={},c=0;c+a?this.ply()+ +a:+a,this.history[0|a]},result:function(){return this.state().result()},decisions:function(a){a=a||this.state();var b=this,c=this.players,d=a.activePlayers;return Future.all(d.map(function(b){return c[b].decision(a,b)})).then(function(c){var e=iterable(d).zip(c).toObject();return b.onMove(a,e),e})},run:function(a){if(a=isNaN(a)?1/0:+a,1>a)return Future.when(this);var b,c=this.ply(),d=this.state();if(1>c&&this.onBegin(d),d=this.__advanceAleatories__(d),b=d.result())return this.onEnd(d,b),Future.when(this);var e=this;return this.decisions(d).then(function(b){return e.__advance__(d,b)?e.run(a-1):e})},__advanceAleatories__:function(a){for(var b;a instanceof Aleatory;a=b)b=a.next(),this.history.push(b),this.onNext(a,b);return a},__advance__:function(a,b){var c=this,d=a.activePlayers.filter(function(a){return b[a]instanceof Match.CommandQuit});if(d.length>0)return c.onQuit(a,d[0]),!1;var e=a.next(b);return this.history.push(e),this.onNext(a,e),!0},"static CommandQuit":function(){},onBegin:function(a){this.events.emit("begin",a,this),this.logger&&this.logger.info("Match begins with ",iterable(this.players).map(function(a){return a[1]+" as "+a[0]}).join(", "),"; for ",a,".")},onMove:function(a,b){this.events.emit("move",a,b,this),this.logger&&this.logger.info("Players move: ",JSON.stringify(b)," in ",a)},onNext:function(a,b){this.events.emit("next",a,b,this),this.logger&&this.logger.info("Match advances from ",a," to ",b)},onEnd:function(a,b){this.events.emit("end",a,b,this),this.logger&&this.logger.info("Match for ",a,"ends with ",JSON.stringify(b))},onQuit:function(a,b){this.events.emit("quit",a,b,this),this.logger&&this.logger.info("Match for ",a," aborted because player "+b+" quitted.")},toString:function(){return"Match("+this.game+", "+JSON.stringify(this.players)+")"}}),Tournament=exports.Tournament=declare({constructor:function(a,b){this.game=a,this.players=Array.isArray(b)?b:iterables.iterable(b).toArray(),this.statistics=new Statistics,this.events=new Events({events:["begin","beforeMatch","afterMatch","end"]})},__advance__:unimplemented("Tournament","__advance__"),run:function(){this.onBegin();var a=this;return Future.doWhile(function(){return Future.then(a.__advance__(),function(b){return b?(a.beforeMatch(b),a.__runMatch__(b).then(function(b){return a.account(b),a.afterMatch(b),b})):null})}).then(this.onEnd.bind(this))},__runMatch__:function(a){return a.run()},account:function(a){var b=this.game,c=a.result(),d=this.statistics;raiseIf(!c,"Match doesn't have results. Has it finished?"),iterable(a.players).forEach(function(e){var f=e[0],g=e[1],h=c[e[0]];d.add({key:"results",game:b.name,role:f,player:g.name},h),d.add({key:h>0?"victories":0>h?"defeats":"draws",game:b.name,role:f,player:g.name},h),d.add({key:"length",game:b.name,role:f,player:g.name},a.ply()),a.history.forEach(function(a){if("function"==typeof a.moves){var c=a.moves();c&&c.hasOwnProperty(f)&&c[f].length>0&&d.add({key:"width",game:b.name,role:f,player:g.name},c[f].length)}})})},onBegin:function(){this.events.emit("begin",this),this.logger&&this.logger.info("Tournament begins for game ",game.name,".")},beforeMatch:function(a){this.events.emit("beforeMatch",a,this),this.logger&&this.logger.debug("Beginning match with ",JSON.stringify(a.players),".")},afterMatch:function(a){this.events.emit("afterMatch",a,this),this.logger&&this.logger.debug("Finishing match with ",JSON.stringify(a.players),".")},onEnd:function(){this.events.emit("end",this.statistics,this),this.logger&&this.logger.info("Tournament ends for game ",game.name,":\n",this.statistics,"\n")}}),tournaments=exports.tournaments={},Aleatory=exports.Aleatory=declare({constructor:function(a,b){this.random=b||Randomness.DEFAULT,"function"==typeof a&&(this.next=a)},value:function a(){var a,b=random.random();if(iterable(this.distribution()).forEach(function(c){if(b-=c[1],0>=b)throw a=c[0],Iterable.STOP_ITERATION}),"undefined"==typeof a)throw new Error("Random value could not be obtained.");return a},next:unimplemented("Aleatory","next"),distribution:unimplemented("Aleatory","distribution")}),aleatories=exports.aleatories={};players.RandomPlayer=declare(Player,{constructor:function(a){Player.call(this,a),initialize(this,a).object("random",{defaultValue:Randomness.DEFAULT})},decision:function(a,b){return this.random.choice(this.__moves__(a,b))}}),players.TracePlayer=declare(Player,{constructor:function(a){Player.call(this,a),this.trace=iterable(a.trace),this.__iterator__=this.trace.__iter__(),this.__decision__=this.__iterator__()},decision:function(){try{this.__decision__=this.__iterator__()}catch(a){Iterable.prototype.catchStop(a)}return this.__decision__},__serialize__:function(){return["TracePlayer",{name:this.name,trace:this.trace.toArray()}]}});var HeuristicPlayer=players.HeuristicPlayer=declare(Player,{constructor:function(a){Player.call(this,a),initialize(this,a).object("random",{defaultValue:Randomness.DEFAULT}).func("heuristic",{ignore:!0})},moveEvaluation:function(a,b,c){return this.stateEvaluation(b.next(obj(c,a)),c)},stateEvaluation:function(a,b){var c=a.result();return c?c[b]:this.heuristic(a,b)},heuristic:function(){return this.random.random(-.5,.5)},bestMoves:function(a){return iterable(a).greater(function(a){return a[1]}).map(function(a){return a[0]})},selectMoves:function(a,b,c){var d=this,e=!1,f=a.map(function(a){var f=d.moveEvaluation(a,b,c);return f instanceof Future?(e=e||!0,f.then(function(b){return[a,b]})):[a,f]});return e?Future.all(f).then(this.bestMoves):this.bestMoves(f)},decision:function(a,b){var c=this,d=c.selectMoves(c.__moves__(a,b),a,b);return Future.then(d,function(a){return c.random.choice(a)})}}),MaxNPlayer=players.MaxNPlayer=declare(HeuristicPlayer,{constructor:function(a){HeuristicPlayer.call(this,a),initialize(this,a).integer("horizon",{defaultValue:3,coerce:!0})},stateEvaluation:function(a,b){return this.maxN(a,b,0)[b]},heuristics:function(a){var b={},c=this;return a.players.forEach(function(d){b[d]=c.heuristic(a,d)}),b},quiescence:function(a,b,c){var d=a.result();return d?d:c>=this.horizon?this.heuristics(a):null},maxN:function(a,b,c){var d=this.quiescence(a,b,c);if(!d){var e,f,g=a.activePlayer(),h=this.__moves__(a,g),d={};if(h.length<1)throw new Error("No moves for unfinished game "+a+".");for(var i=0;i(d[g]||-1/0)&&(d=e)}return d},toString:function(){return(this.constructor.name||"MaxNPlayer")+"("+JSON.stringify({name:this.name,horizon:this.horizon})+")"}}),MiniMaxPlayer=players.MiniMaxPlayer=declare(HeuristicPlayer,{constructor:function(a){HeuristicPlayer.call(this,a),initialize(this,a).integer("horizon",{defaultValue:4,coerce:!0})},stateEvaluation:function(a,b){return this.minimax(a,b,0)},quiescence:function(a,b,c){var d=a.result();return d?d[b]:c>=this.horizon?this.heuristic(a,b):0/0},minimax:function(a,b,c){var d=this.quiescence(a,b,c);if(isNaN(d)){var e,f,g=a.activePlayer(),h=this.__moves__(a,g);if(h.length<1)throw new Error("No moves for unfinished game "+a+".");g==b?(d=-1/0,e=Math.max):(d=+1/0,e=Math.min);for(var i=0;id&&(d=f):e>f&&(e=f),!(d>=e));k++);return i?d:e}}),players.MonteCarloPlayer=declare(HeuristicPlayer,{constructor:function(a){HeuristicPlayer.call(this,a),initialize(this,a).number("simulationCount",{defaultValue:30,coerce:!0}).number("timeCap",{defaultValue:1e3,coerce:!0}).object("agent",{defaultValue:null})},selectMoves:function(a,b,c){for(var d=this,e=Date.now()+this.timeCap,f=a.map(function(a){return{move:a,next:b.next(obj(c,a)),isFinal:!1,sum:0,count:0}}),g=0;g0?a.sum/a.count:0}).map(function(a){return a.move})},stateEvaluation:function(a,b){for(var c,d=0,e=this.simulationCount,f=0;e>f&&(c=this.simulation(a,b),d+=c.result[b],!(c.plies<1));++f);return e>0?d/e:0},simulation:function(a){var b,c,d,e=this;for(b=0;!0;++b)if(a instanceof Aleatory)a=a.next();else{if(d=a.moves(),!d)return{game:a,result:a.result(),plies:b};c={},a.activePlayers.forEach(function(b){c[b]=e.agent?e.agent.decision(a,b):e.random.choice(d[b])}),a=a.next(c)}},toString:function(){return(this.constructor.name||"MonteCarloPlayer")+"("+JSON.stringify({name:this.name,simulationCount:this.simulationCount,timeCap:this.timeCap})+")"}});var UserInterfacePlayer=players.UserInterfacePlayer=declare(Player,{constructor:function(a){Player.call(this,a)},participate:function(a,b){return this.role=b,this},decision:function(){return this.__future__&&this.__future__.isPending()&&this.__future__.resolve(new Match.CommandQuit),this.__future__=new Future},perform:function(a){var b=this.__future__;return b&&(this.__future__=null,b.resolve(a)),!!b}}),UserInterface=players.UserInterface=declare({constructor:function(a){this.onBegin=this.onBegin.bind(this),this.onNext=this.onNext.bind(this),this.onEnd=this.onEnd.bind(this),a.match&&this.show(a.match)},show:function(a){this.match&&(a.events.off("begin",this.onBegin),a.events.off("next",this.onNext),a.events.off("end",this.onEnd)),this.match=a,a.events.on("begin",this.onBegin),a.events.on("next",this.onNext),a.events.on("end",this.onEnd)},onBegin:function(a){this.display(a)},onNext:function(a,b){this.display(b)},onEnd:function(a,b){this.results=b,this.display(a)},display:function(){throw new Error("UserInterface.display is not defined. Please override.")},perform:function(a,b){iterable(this.match.players).forEach(function(c){var d=(c[0],c[1]);d instanceof UserInterfacePlayer&&(!b||d.role===b)&&d.perform(a)})}});UserInterface.BasicHTMLInterface=declare(UserInterface,{constructor:function(a){UserInterface.call(this,a),this.container=a.container,"string"==typeof this.container&&(this.container=document.getElementById(this.container))},display:function display(game){var ui=this,container=this.container;container.innerHTML=game.toHTML(),Array.prototype.slice.call(container.querySelectorAll("[data-ludorum]")).forEach(function(elem){var data=eval("({"+elem.getAttribute("data-ludorum")+"})");data.hasOwnProperty("move")&&(elem.onclick=ui.perform.bind(ui,data.move,data.activePlayer))})}});var WebWorkerPlayer=players.WebWorkerPlayer=declare(Player,{constructor:function(a){Player.call(this,a),initialize(this,a).object("worker"),this.worker.onmessage=base.Parallel.prototype.__onmessage__.bind(this)},"static createWorker":function(a){raiseIf("string function".indexOf(typeof a)<0,"Invalid player builder: "+a+"!");var b=new base.Parallel;return b.run("self.ludorum = ("+exports.__init__+')(self.base), "OK"').then(function(){return b.run("self.PLAYER = ("+a+').call(self), "OK"')}).then(function(){return b.worker})},"static create":function(a){var b=this;return b.createWorker(a.playerBuilder).then(function(a){return new b({name:name,worker:a})})},decision:function(a,b){return this.__future__&&this.__future__.isPending()&&this.__future__.resolve(Match.commandQuit),this.__future__=new Future,this.worker.postMessage("PLAYER.decision(ludorum.Game.fromJSON("+a.toJSON()+"), "+JSON.stringify(b)+")"),this.__future__}});aleatories.Dice=declare(Aleatory,{constructor:function(a,b,c){Aleatory.call(this,a,c),this.base=isNaN(b)?6:Math.max(2,+b)},value:function(){return this.random.randomInt(1,this.base+1)},distribution:function(){return this.__distribution__||(this.__distribution__=function(a){return Iterable.range(1,a+1).map(function(b){return[b,1/a]}).toArray()}(this.base))}});var Checkerboard=utils.Checkerboard=declare({constructor:function(a,b){isNaN(a)||(this.height=0|a),isNaN(b)||(this.width=0|b)},emptySquare:null,isValidCoord:function(a){return Array.isArray(a)&&!isNaN(a[0])&&!isNaN(a[1])&&a[0]>=0&&a[0]=0&&a[1]=b}).map(function(a){return Iterable.range(0,a.length-b+1).map(function(c){return a.slice(c,c+b)})}).flatten()},walk:function(a,b){var c=this;return new Iterable(function(){var d=a.slice();return function(){if(c.isValidCoord(d)){var a=d.slice();return d[0]+=b[0],d[1]+=b[1],a}throw Iterable.STOP_ITERATION}})},walks:function(a,b){var c=this;return b.map(function(b){return c.walk(a,b)})},"static DIRECTIONS":{HORIZONTAL:[[0,-1],[0,1]],VERTICAL:[[-1,0],[1,0]],ORTHOGONAL:[[0,-1],[0,1],[-1,0],[1,0]],DIAGONAL:[[-1,-1],[-1,1],[1,-1],[1,1]],EVERY:[[0,-1],[0,1],[-1,0],[1,0],[-1,-1],[-1,1],[1,-1],[1,1]]},clone:unimplemented("utils.Checkerboard","clone"),__place__:unimplemented("utils.Checkerboard","place"),place:function(a,b){return this.clone().__place__(a,b)},__move__:function(a,b,c){return this.__place__(b,this.square(a)).__place__(a,"undefined"==typeof c?this.emptySquare:c)},move:function(a,b,c){return this.clone().__move__(a,b,c)},__swap__:function(a,b){var c=this.square(b);return this.__place__(b,this.square(a)).__place__(a,c)},swap:function(a,b){return this.clone().__swap__(a,b)},asHTMLTable:function(a,b,c){var d=a.createElement("table");board.horizontals().reverse().foeEach(function(b){var e=a.createElement("tr");d.appendChild(e),b.forEach(function(b){var d=board.square(b),f=c(d,b),g=a.createElement("td");td_content=a.createTextNode(f.hasOwnProperty("content")?f.content:d),e.appendChild(g),g.id=f.id||"ludorum-square-"+b.join("-"),g.className=f.className||"ludorum-square",g.data_ludorum=f})})}}),CheckerboardFromString=utils.CheckerboardFromString=declare(Checkerboard,{constructor:function(a,b,c,d){if(Checkerboard.call(this,a,b),d&&(this.emptySquare=(d+this.emptySquare).charAt(0)),c&&c.length!==a*b)throw new Error("Given string "+JSON.stringify(c)+" does not match board dimensions.");this.string=c||this.emptySquare.repeat(a*b)},emptySquare:".",toString:function(){var a=this.string,b=this.height,c=this.width;return Iterable.range(b).map(function(d){return a.substr((b-d-1)*c,c)}).join("\n")},square:function(a,b){var c=a[0],d=a[1],e=this.width;return c>=0&&c=0&&e>d?this.string.charAt(c*e+d):b},asString:function(a){var b=this;return a.map(function(a){return b.square(a)}).join("")},asStrings:function(a){var b=this;return a.map(function(a){return b.asString(a)})},asRegExp:function(a,b,c){c=c||".";var d=this.width,e=Iterable.repeat(!1,d*this.height).toArray();a.forEach(function(a){e[a[0]*d+a[1]]=!0});for(var f,g="",h=0,i=0;ih?f?b:c:(f?b:c)+"{"+h+"}"}return g},asRegExps:function(a,b,c){var d=this;return a.map(function(a){return d.asRegExp(a,b,c)}).join("|")},clone:function(){return new this.constructor(this.height,this.width,this.string,this.hasOwnProperty("emptySquare")?this.emptySquare:void 0)},__place__:function(a,b){raiseIf(!this.isValidCoord(a),"Invalid coordinate ",a,"."),b=(b+this.emptySquare).charAt(0);var c=a[0]*this.width+a[1];return this.string=this.string.substr(0,c)+b+this.string.substr(c+1),this}});return exports.utils.Scanner=declare({constructor:function(a){initialize(this,a).object("game",{ignore:!0}).integer("maxWidth",{defaultValue:1e3,coerce:!0}).integer("maxLength",{defaultValue:50,coerce:!0}).object("random",{defaultValue:Randomness.DEFAULT}).object("statistics",{defaultValue:new Statistics})},scan:function(a){var b=this,c=arguments.length<2?this.game?[this.game]:[]:Array.prototype.slice.call(arguments,1),d=0;return Future.whileDo(function(){return c.length>0&&dg?(e.add({key:"defeat.result",game:b.name,role:f,player:h},g,b),e.add({key:"defeat.length",game:b.name,role:f,player:h},c,b)):g>0?(e.add({key:"victory.result",game:b.name,role:f,player:h},g,b),e.add({key:"victory.length",game:b.name,role:f,player:h},c,b)):e.add({key:"draw.length",game:b.name,role:f,player:h},c,b)}),!0;var f=b.moves();return iterable(b.activePlayers).forEach(function(a){e.add({key:"game.width",game:b.name,role:a},f[a].length)}),!1}}),games.Predefined=declare(Game,{constructor:function(a,b,c,d){b&&(this.__results__=b,this.players=Object.keys(b)),Game.call(this,a),this.height=isNaN(c)?5:+c,this.width=isNaN(d)?5:+d},name:"Predefined",players:["A","B"],__results__:{A:0,B:0},moves:function(){return this.height>0?obj(this.activePlayer(),Iterable.range(1,this.width+1).toArray()):void 0},result:function(){return this.height>0?null:this.__results__},next:function(){return new this.constructor(this.opponent(),this.__results__,this.height-1,this.width)},__serialize__:function(){return[this.name,this.activePlayer(),this.results,this.height,this.width]}}),games.Choose2Win=declare(Game,{constructor:function(a,b,c){Game.call(this,b),this.__turns__=isNaN(a)?1/0:+a,this.__winner__=c},name:"Choose2Win",players:["This","That"],moves:function(){return!this.__winner__&&this.__turns__>0?obj(this.activePlayer(),["win","lose","pass"]):void 0},result:function(){return this.__winner__?this.victory(this.__winner__):this.__turns__<1?this.draw():null},next:function(a){var b=this.activePlayer(),c=this.opponent(b);switch(a[b]){case"win":return new this.constructor(this.__turns__-1,c,b);case"lose":return new this.constructor(this.__turns__-1,c,c);case"pass":return new this.constructor(this.__turns__-1,c)}throw new Error("Invalid move "+a[b]+" for player "+b+".")},__serialize__:function(){return[this.name,this.__turns__,this.activePlayer(),this.__winner__]}}),games.ConnectionGame=declare(Game,{height:9,width:9,lineLength:5,constructor:function(a,b){Game.call(this,a),this.board=b instanceof CheckerboardFromString?b:new CheckerboardFromString(this.height,this.width,(b||".".repeat(this.height*this.width))+"")},name:"ConnectionGame",players:["First","Second"],__lines__:function(){function a(a,c,d){var e=a+"x"+c+"/"+d;if(!b.hasOwnProperty(e)){var f=new CheckerboardFromString(a,c,".".repeat(a*c));b[e]=f.lines().map(function(a){return a.toArray()},function(a){return a.length>=d}).toArray()}return b[e]}var b={};return a.CACHE=b,a}(),result:function(){if(this.hasOwnProperty("__result__"))return this.__result__;for(var a=this.lineLength,b=this.board.asStrings(this.__lines__(this.height,this.width,a)).join(" "),c=0;c=0)return this.__result__=this.victory([this.players[c]]);return this.__result__=b.indexOf(".")<0?this.draw():null},moves:function(){return this.hasOwnProperty("__moves__")?this.__moves__:this.__moves__=this.result()?null:obj(this.activePlayer(),iterable(this.board.string).filter(function(a){return"."===a},function(a,b){return b}).toArray())},next:function(a){var b=this.activePlayer(),c=this.players.indexOf(b),d=+a[b],e=d/this.width>>0,f=d%this.width;return new this.constructor((c+1)%this.players.length,this.board.place([e,f],c.toString(36)))},toHTML:function(){var a=this.moves(),b=this.activePlayer(),c=this.board,d=this.width;return a=a&&a[b],""+c.horizontals().reverse().map(function(e){return""+e.map(function(e){var f="",g=c.square(e),h=e[0]*d+e[1];return a&&a.indexOf(h)>=0&&(f=' data-ludorum="move: '+h+", activePlayer: '"+b+"'\""),"."===g?"":'"}).join("")+""}).join("")+"
 
"},__serialize__:function(){return[this.name,this.activePlayer(),this.board.string]}}),games.OddsAndEvens=declare(Game,{constructor:function(a,b){Game.call(this,this.players),this.turns=isNaN(a)?1:+a,this.points=b||{Evens:0,Odds:0}},name:"OddsAndEvens",players:["Evens","Odds"],moves:function(){return this.turns<1?null:{Evens:[1,2],Odds:[1,2]}},result:function(){var a=this.points.Evens-this.points.Odds;return this.turns>0?null:{Evens:+a,Odds:-a}},next:function(a){var b=!((a.Evens+a.Odds)%2);return new this.constructor(this.turns-1,{Evens:this.points.Evens+(b?1:0),Odds:this.points.Odds+(b?0:1)})},__serialize__:function(){return[this.name,this.turns,this.points]}}),games.TicTacToe=declare(Game,{constructor:function(a,b){Game.call(this,a),this.board=b||"_________"},name:"TicTacToe",players:["Xs","Os"],result:function(){return function(){return this.board.match(this.WIN_X)?this.victory(["Xs"]):this.board.match(this.WIN_O)?this.victory(["Os"]):this.board.indexOf("_")<0?this.draw():null}}(),moves:function(){if(this.result())return null;var a={};return a[this.activePlayer()]=iterable(this.board).filter(function(a){return"_"===a},function(a,b){return b}).toArray(),a},next:function(a){var b=this.activePlayer(),c=+a[b];if("_"!==this.board.charAt(c))throw new Error("Invalid move "+JSON.stringify(a)+" for board "+this.board+" (moves= "+JSON.stringify(a)+").");var d=this.board.substring(0,c)+b.charAt(0)+this.board.substring(c+1);return new this.constructor(this.opponent(b),d)},toString:function(){var a=this.board;return[a.substr(0,3).split("").join("|"),"-+-+-",a.substr(3,3).split("").join("|"),"-+-+-",a.substr(6,3).split("").join("|")].join("\n")},toHTML:function(){var a=this.activePlayer(),b=this.board.split("").map(function(b,c){return"_"===b?' ":""+b+""});return""+[b.slice(0,3).join(""),b.slice(3,6).join(""),b.slice(6,9).join("")].join("")+"
"},__serialize__:function(){return[this.name,this.activePlayer(),this.board]},"static heuristics":{heuristicFromWeights:function(a){function b(b,d){var e=d.charAt(0);return iterable(b.board).map(function(b,c){return"_"===b?0:a[c]*(b===e?1:-1)}).sum()/c}var c=iterable(a).map(Math.abs).sum();return b.weights=a,b}},"":function(){var a=new CheckerboardFromString(3,3,"_".repeat(9)),b=a.sublines(a.lines(),3);this.prototype.WIN_X=new RegExp(a.asRegExps(b,"X",".")),this.prototype.WIN_O=new RegExp(a.asRegExps(b,"O","."))}}),games.TicTacToe.heuristics.defaultHeuristic=games.TicTacToe.heuristics.heuristicFromWeights([2,1,2,1,5,1,2,1,2]),games.ToadsAndFrogs=declare(Game,{constructor:function b(a,c){Game.call(this,a),this.board=c||b.board()},"static board":function(a,b){return a=isNaN(a)?3:+a,b=isNaN(b)?2:+b,"T".repeat(a)+"_".repeat(b)+"F".repeat(a)},name:"ToadsAndFrogs",players:["Toads","Frogs"],result:function(){return this.moves()?null:this.defeat()},moves:function(){var a=this.activePlayer(),b={},c=b[a]=[];return this.board.replace(a==this.players[0]?/TF?_/g:/_T?F/g,function(a,b){return c.push(b),a}),c.length>0?b:null},next:function(a){var b=this.activePlayer(),c=a[b],d=(b.charAt(0),this.board);if("T_"==d.substr(c,2))d=d.substring(0,c)+"_T"+d.substring(c+2);else if("_F"==d.substr(c,2))d=d.substring(0,c)+"F_"+d.substring(c+2);else if("TF_"==d.substr(c,3))d=d.substring(0,c)+"_FT"+d.substring(c+3);else{if("_TF"!=d.substr(c,3))throw new Error("Invalid move ",c," for board <",d,">.");d=d.substring(0,c)+"FT_"+d.substring(c+3)}return new this.constructor(this.opponent(),d)},__serialize__:function(){return[this.name,this.activePlayer,this.board]}}),games.Mancala=declare(Game,{constructor:function(a,b){Game.call(this,a),this.board=b||this.makeBoard()},makeBoard:function(a,b){a=isNaN(a)?4:+a,b=isNaN(b)?6:+b;for(var c=[],d=0;2>d;d++){for(var e=0;b>e;e++)c.push(a);c.push(0)}return c},name:"Mancala",players:["North","South"],emptyCapture:!1,countRemainingSeeds:!0,store:function(a){switch(this.players.indexOf(a)){case 0:return this.board.length/2-1;case 1:return this.board.length-1;default:throw new Error("Invalid player "+a+".")}},houses:function(a){switch(this.players.indexOf(a)){case 0:return Iterable.range(0,this.board.length/2-1).toArray();case 1:return Iterable.range(this.board.length/2,this.board.length-1).toArray();default:throw new Error("Invalid player "+a+".")}},oppositeHouse:function(a,b){var c=this.houses(a),d=this.houses(this.opponent(a)),e=c.indexOf(b); -return 0>e?e:d.reverse()[e]},nextSquare:function(a,b){do b=(b+1)%this.board.length;while(b===this.store(this.opponent(a)));return b},moves:function(){if(this.result())return null;var a=this.board,b={},c=this.activePlayer();return b[c]=this.houses(c).filter(function(b){return a[b]>0}),b[c].length>0?b:null},scores:function(){var a=this,b=this.board,c=this.players.map(function(c){return iterable(a.houses(c)).map(function(a){return b[a]}).sum()});if(c[0]>0&&c[1]>0)return null;var d={};return this.players.forEach(function(e,f){d[e]=b[a.store(e)]+a.countRemainingSeeds*c[f]}),d},result:function(){var a=this.scores(),b=this.players;return a&&this.zerosumResult(a[b[0]]-a[b[1]],b[0])},next:function(a){var b,c,d=this.activePlayer(),e=+a[d],f=this.board.slice(0),g=f[e],h=!1;for(raiseIf(1>g,"Invalid move ",e," for game ",this),f[e]=0;g>0;g--)e=this.nextSquare(d,e),f[e]++;return h=e==this.store(d),h||(c=this.oppositeHouse(d,e),c>=0&&1==f[e]&&f[c]>0&&(b=this.store(d),f[b]++,f[e]=0,this.emptyCapture||(f[b]+=f[c],f[c]=0))),new this.constructor(h?d:this.opponent(),f)},resultBounds:function(){var a=iterable(this.board).sum();return[-a,+a]},__serialize__:function(){return[this.name,this.activePlayer(),this.board.slice()]},identifier:function(){return this.activePlayer().charAt(0)+this.board.map(function(a){return("00"+a.toString(36)).substr(-2)}).join("")},toString:function(){var a=this,b=base.Text.lpad,c=this.players[0],d=this.houses(c).map(function(c){return b(""+a.board[c],2,"0")}).reverse(),e=b(""+this.board[this.store(c)],2,"0"),f=this.players[1],g=this.houses(f).map(function(c){return b(""+a.board[c],2,"0")}),h=b(""+this.board[this.store(f)],2,"0");return" "+d.join(" | ")+" \n"+e+" ".repeat(2*d.length+3*(d.length-1)+2)+h+"\n "+g.join(" | ")+" "},toHTML:function(){function a(a,c){return!b||!b[a]||!b[a].indexOf(c)<0?""+this.board[c]+"":'"+this.board[c]+""}var b=this.moves(),c=this.players[0],d=this.players[1];return'"+this.houses(c).map(a.bind(this,c)).reverse().join("")+'"+this.houses(d).map(a.bind(this,d)).join("")+"
'+this.board[this.store(c)]+"'+this.board[this.store(d)]+"
"},"static heuristics":{heuristicFromWeights:function(a){function b(b,d){var e,f=0;switch(b.players.indexOf(d)){case 0:e=1;break;case 1:e=-1;break;default:throw new Error("Invalid player "+d+".")}return iterable(b.board).map(function(b,c){return f+=b,b*a[c]}).sum()/c/f*e}var c=iterable(a).map(Math.abs).sum();return b.weights=a,b}},"":function(){this.makeBoard=this.prototype.makeBoard,this.heuristics.defaultHeuristic=this.heuristics.heuristicFromWeights([1,1,1,1,1,1,5,-1,-1,-1,-1,-1,-1,-5])}}),games.Pig=declare(Game,{constructor:function(a,b,c,d){Game.call(this,a),this.goal=isNaN(b)?100:+b,this.__scores__=c||iterable(this.players).zip([0,0]).toObject(),this.__rolls__=d||[]},name:"Pig",players:["One","Two"],moves:function(){if(!this.result()){var a=this.activePlayer(),b=this.__scores__[a]+iterable(this.__rolls__).sum();return obj(a,b=this.goal||b>=this.goal){var c={};return c[this.players[0]]=a-b,c[this.players[1]]=-c[this.players[0]],c}},next:function(a){var b=this.activePlayer(),c=a[b];if("hold"===c){var d=copy(this.__scores__);return d[b]+=iterable(this.__rolls__).sum(),new this.constructor(this.opponent(),this.goal,d,[])}if("roll"===c){var e=this;return new aleatories.Dice(function(a){return a=isNaN(a)?this.value():+a,a>1?new e.constructor(b,e.goal,e.__scores__,e.__rolls__.concat(a)):new e.constructor(e.opponent(),e.goal,e.__scores__,[])})}throw new Error("Invalid moves: "+JSON.stringify(a))},__serialize__:function(){return[this.name,this.activePlayer(),this.goal,this.__scores__,this.__rolls__]}}),games.ConnectFour=declare(games.ConnectionGame,{height:6,width:7,lineLength:4,name:"ConnectFour",players:["Yellow","Red"],moves:function(){var a=null;if(!this.result()){for(var b=[],c=this.board.string,d=(this.height-1)*this.width,e=0;e0&&(a={},a[this.activePlayer()]=b)}return a},next:function(a){for(var b=this.activePlayer(),c=this.board.string,d=+a[b],e=this.height,f=this.width,g=0;e>g;++g)if("."===c.charAt(g*f+d))return new this.constructor(this.opponent(),this.board.place([g,d],b===this.players[0]?"0":"1"));throw new Error("Invalid move "+JSON.stringify(a)+"!")},toHTML:function(){var a=this.moves(),b=this.activePlayer(),c=this.board;return a=a&&a[b],""+"".repeat(this.board.width)+""+c.horizontals().reverse().map(function(d){return""+d.map(function(d){var e="",f=c.square(d);return a&&a.indexOf(d[1])>=0&&(e=' data-ludorum="move: '+d[1]+", activePlayer: '"+b+"'\""),"."===f?"":'"}).join("")+""}).join("")+"
 
"},__serialize__:function(){return[this.name,this.activePlayer(),this.board.string]}}),games.Mutropas=declare(Game,{allPieces:Iterable.range(9).toArray(),name:"Mutropas",players:["Left","Right"],constructor:function(a){Game.call(this,this.players),a=a||{},this._pieces=a.pieces||this.dealtPieces(a.random),this._scores=a.scores||obj(this.players[0],0,this.players[1],0)},result:function(){var a=this.players[0];return this._pieces[a].length<1?copy({},this._scores):null},moves:function(){var a=this.players[0],b=this.players[1];return this.result()?null:obj(a,this._pieces[a].slice(),b,this._pieces[b].slice())},next:function(a){var b=this.players[0],c=this.players[1],d=a[b],e=a[c];raiseIf(this._pieces[b].indexOf(d)<0,"Invalid move "+JSON.stringify(d)+" for player "+b+"! (moves= "+JSON.stringify(a)+")"),raiseIf(this._pieces[c].indexOf(e)<0,"Invalid move "+JSON.stringify(e)+" for player "+c+"! (moves= "+JSON.stringify(a)+")");var f=this.moveResult(d,e),g=this._pieces[b].slice(),h=this._pieces[c].slice();return g.splice(g.indexOf(d),1),h.splice(h.indexOf(e),1),new this.constructor({pieces:obj(b,g,c,h),scores:obj(b,this._scores[b]+f,c,this._scores[c]-f)})},__serialize__:function(){return[this.name,{pieces:this._pieces,scores:this._scores}]},dealtPieces:function(a){var a=a||Randomness.DEFAULT,b=this.allPieces.length>>1,c=a.split(b,this.allPieces),d=a.split(b,c[1]);return obj(this.players[0],c[0],this.players[1],d[0])},moveResult:function(a,b){var c=iterable(this.allPieces).max(0)+1;return b>a?c>>1>=b-a?1:-1:a>b?a-b>=(c>>1)+1?1:-1:0}}),games.Othello=declare(Game,{constructor:function(a,b){if(Game.call(this,a),this.board=this.makeBoard.apply(this,b||[]),!this.moves()){var c=this.opponent();this.moves(c)&&(this.activePlayers=[c])}},makeBoard:function(a,b,c){return a=isNaN(a)?8:+a,b=isNaN(b)?8:+b,raiseIf(4>a||4>b||a%2||b%2,"An Othello board must have even dimensions greater than 3."),"string"==typeof c?new CheckerboardFromString(a,b,c):new CheckerboardFromString(a,b).__place__([a/2,b/2-1],"W").__place__([a/2-1,b/2],"W").__place__([a/2,b/2],"B").__place__([a/2-1,b/2-1],"B")},name:"Othello",players:["Black","White"],lines:new utils.Checkerboard(8,8).lines().map(function(a){return a.toArray()},function(a){return a.length>2}).toArray(),__MOVE_REGEXPS__:{Black:[/\.W+B/g,/BW+\./g],White:[/\.B+W/g,/WB+\./g]},moves:function(a){if(!a&&this.__moves__)return this.__moves__;a=a||this.activePlayer();var b=this.board,c={},d=this.__MOVE_REGEXPS__[a];this.lines.forEach(function(a){d.forEach(function(d){b.asString(a).replace(d,function(b,d){var e="."===b.charAt(0)?a[d]:a[b.length-1+d];return c[e]=e,b})})});var e=[];for(var f in c)e.push(c[f]);return this.__moves__=e.length>0?obj(a,e):null},result:function(){if(this.moves())return null;var a={W:-1,B:1},b=iterable(this.board.string).map(function(b){return a[b]||0}).sum();return this.zerosumResult(b,"Black")},next:function(a){var b,c,d=this.board.clone(),e=this.activePlayer();if(!a.hasOwnProperty(e)||!d.isValidCoord(a[e]))throw new Error("Invalid moves "+JSON.stringify(a)+"!");return e==this.players[0]?(b="B",c=/^W+B/):(b="W",c=/^B+W/),d.walks(a[e],Checkerboard.DIRECTIONS.EVERY).forEach(function(a){var e=c.exec(d.asString(a).substr(1));e&&a.toArray().slice(0,e[0].length).forEach(function(a){d.__place__(a,b)})}),new this.constructor(this.opponent(),[d.height,d.width,d.string])},__serialize__:function(){var a=this.board;return[this.name,this.activePlayer(),[a.height,a.width,a.string]]},toHTML:function(){var a=this.moves(),b=this.activePlayer(),c=this.board;return a=a&&a[b].map(JSON.stringify),""+c.horizontals().reverse().map(function(d){return""+d.map(function(d){switch(c.square(d)){case"B":return'';case"W":return'';default:var e=JSON.stringify(d);return a&&a.indexOf(e)>=0?'":''}}).join("")+""}).join("")+"
    
"}}),games.Othello.makeBoard=games.Othello.prototype.makeBoard,games.Othello.heuristics={},games.Bahab=declare(Game,{initialBoard:["BBABB","BBBBB",".....","bbbbb","bbabb"].join(""),name:"Bahab",players:["Uppercase","Lowercase"],constructor:function(a,b){Game.call(this,a),this.board=b instanceof CheckerboardFromString?b:new CheckerboardFromString(5,5,b||this.initialBoard)},__PLAYER_PIECES_RE__:{Uppercase:/[AB]/g,Lowercase:/[ab]/g},result:function(){var a=this.board.string;return a.match(/^[.bAB]+$|[A].{0,4}$/)?this.defeat(this.players[1]):a.match(/^[.Bab]+$|^.{0,4}[a]/)?this.defeat(this.players[0]):null},moves:function(){var a=this.activePlayer(),b=this.__PLAYER_PIECES_RE__[a],c=this.board,d=[];return c.string.replace(b,function(a,e){var f,g=[e/5|0,e%5];switch(a){case"A":f=[[1,-1],[1,0],[1,1]];break;case"B":f=[[1,-1],[1,1]];break;case"a":f=[[-1,-1],[-1,0],[-1,1]];break;case"b":f=[[-1,-1],[-1,1]]}return iterable(f).forEachApply(function(e,f){var h=[g[0]+e,g[1]+f],i=c.square(h);!c.isValidCoord(h)||i.match(b)||"b"==a.toLowerCase()&&"a"==i.toLowerCase()||d.push([g,h])}),a}),d.length>0?obj(a,d):null},next:function(a){if(!a)throw new Error("Invalid moves "+a+"!");var b=this.activePlayer(),c=a[b];if(!Array.isArray(a[b]))throw new Error("Invalid moves "+JSON.stringify(a)+"!");return new this.constructor(this.opponent(),this.board.move(c[0],c[1]))},__serialize__:function(){return[this.name,this.activePlayer(),this.board.string]},toHTML:function(){var a=(this.moves(),this.activePlayer(),this.board);return""+a.horizontals().reverse().map(function(b){return""+b.map(function(b){var c=a.square(b);switch(c){case"A":case"B":return'";case"a":case"b":return'";default:return''}}).join("")+""}).join("")+"
'+c+"'+c+" 
"}}),tournaments.RoundRobin=declare(Tournament,{constructor:function(a,b,c){Tournament.call(this,a,b),this.matchCount=isNaN(c)?a.players.length:+c,this.__advance__=this.__matches__().chain(Iterable.repeat(null)).__iter__()},__matches__:function(){var a=this.game,b=iterable(this.players);return b=b.product.apply(b,Iterable.repeat(this.players,a.players.length-1).toArray()),b.filter(function(a){for(var b=1;bc;c++)if(a[b]===a[c])return!1;return!0}).product(Iterable.range(this.matchCount)).map(function(b){return new Match(a,b[0])})}}),tournaments.Measurement=declare(Tournament,{constructor:function(a,b,c,d){Tournament.call(this,a,Array.isArray(b)?b:[b]),this.opponents=Array.isArray(c)?c:[c],raiseIf(this.opponents.length2?c.product.apply(c,Iterable.repeat(this.opponents,b-2).toArray()):c.map(function(a){return[a]}),iterable(this.players).product(Iterable.range(b),c,Iterable.range(this.matchCount)).map(function(b){var c=b[2].slice(0);return c.splice(b[1],0,b[0]),new Match(a,c)})}}),tournaments.Elimination=declare(Tournament,{constructor:function(a,b,c){Tournament.call(this,a,b),this.matchCount=isNaN(c)?1:+c>>0},__bracket__:function(a){var b=this.game,c=this.matchCount,d=this.game.players.length;return a=a||this.players,a.lengtha,"There is no active player."),raiseIf(a>1,"More than one player is active."),this.activePlayers[0]},opponents:function(a){return a=a||this.activePlayers,this.players.filter(function(b){return a.indexOf(b)<0})},opponent:function(a){var b=this.players.indexOf(a||this.activePlayer());return this.players[(b+1)%this.players.length]},perform:function(){for(var a,b={},c=0;c+a?this.ply()+ +a:+a,this.history[0|a]},result:function(){return this.state().result()},decisions:function(a){a=a||this.state();var b=this,c=this.players,d=a.activePlayers;return Future.all(d.map(function(b){return c[b].decision(a,b)})).then(function(c){var e=iterable(d).zip(c).toObject();return b.onMove(a,e),e})},run:function(a){if(a=isNaN(a)?1/0:+a,1>a)return Future.when(this);var b,c=this.ply(),d=this.state();if(1>c&&this.onBegin(d),d=this.__advanceAleatories__(d),b=d.result())return this.onEnd(d,b),Future.when(this);var e=this;return this.decisions(d).then(function(b){return e.__advance__(d,b)?e.run(a-1):e})},__advanceAleatories__:function(a){for(var b;a instanceof Aleatory;a=b)b=a.next(),this.history.push(b),this.onNext(a,b);return a},__advance__:function(a,b){var c=this,d=a.activePlayers.filter(function(a){return b[a]instanceof Match.CommandQuit});if(d.length>0)return c.onQuit(a,d[0]),!1;var e=a.next(b);return this.history.push(e),this.onNext(a,e),!0},"static CommandQuit":function(){},onBegin:function(a){this.events.emit("begin",a,this),this.logger&&this.logger.info("Match begins with ",iterable(this.players).map(function(a){return a[1]+" as "+a[0]}).join(", "),"; for ",a,".")},onMove:function(a,b){this.events.emit("move",a,b,this),this.logger&&this.logger.info("Players move: ",JSON.stringify(b)," in ",a)},onNext:function(a,b){this.events.emit("next",a,b,this),this.logger&&this.logger.info("Match advances from ",a," to ",b)},onEnd:function(a,b){this.events.emit("end",a,b,this),this.logger&&this.logger.info("Match for ",a,"ends with ",JSON.stringify(b))},onQuit:function(a,b){this.events.emit("quit",a,b,this),this.logger&&this.logger.info("Match for ",a," aborted because player "+b+" quitted.")},toString:function(){return"Match("+this.game+", "+JSON.stringify(this.players)+")"}}),Tournament=exports.Tournament=declare({constructor:function(a,b){this.game=a,this.players=Array.isArray(b)?b:iterables.iterable(b).toArray(),this.statistics=new Statistics,this.events=new Events({events:["begin","beforeMatch","afterMatch","end"]})},__advance__:unimplemented("Tournament","__advance__"),run:function(){this.onBegin();var a=this;return Future.doWhile(function(){return Future.then(a.__advance__(),function(b){return b?(a.beforeMatch(b),a.__runMatch__(b).then(function(b){return a.account(b),a.afterMatch(b),b})):null})}).then(this.onEnd.bind(this))},__runMatch__:function(a){return a.run()},account:function(a){var b=this.game,c=a.result(),d=this.statistics;raiseIf(!c,"Match doesn't have results. Has it finished?"),iterable(a.players).forEach(function(e){var f=e[0],g=e[1],h=c[e[0]];d.add({key:"results",game:b.name,role:f,player:g.name},h),d.add({key:h>0?"victories":0>h?"defeats":"draws",game:b.name,role:f,player:g.name},h),d.add({key:"length",game:b.name,role:f,player:g.name},a.ply()),a.history.forEach(function(a){if("function"==typeof a.moves){var c=a.moves();c&&c.hasOwnProperty(f)&&c[f].length>0&&d.add({key:"width",game:b.name,role:f,player:g.name},c[f].length)}})})},onBegin:function(){this.events.emit("begin",this),this.logger&&this.logger.info("Tournament begins for game ",game.name,".")},beforeMatch:function(a){this.events.emit("beforeMatch",a,this),this.logger&&this.logger.debug("Beginning match with ",JSON.stringify(a.players),".")},afterMatch:function(a){this.events.emit("afterMatch",a,this),this.logger&&this.logger.debug("Finishing match with ",JSON.stringify(a.players),".")},onEnd:function(){this.events.emit("end",this.statistics,this),this.logger&&this.logger.info("Tournament ends for game ",game.name,":\n",this.statistics,"\n")}}),tournaments=exports.tournaments={},Aleatory=exports.Aleatory=declare({constructor:function(a,b){this.random=b||Randomness.DEFAULT,"function"==typeof a&&(this.next=a)},value:function a(){var a,b=random.random();if(iterable(this.distribution()).forEach(function(c){if(b-=c[1],0>=b)throw a=c[0],Iterable.STOP_ITERATION}),"undefined"==typeof a)throw new Error("Random value could not be obtained.");return a},next:unimplemented("Aleatory","next"),distribution:unimplemented("Aleatory","distribution")}),aleatories=exports.aleatories={};players.RandomPlayer=declare(Player,{constructor:function(a){Player.call(this,a),initialize(this,a).object("random",{defaultValue:Randomness.DEFAULT})},decision:function(a,b){return this.random.choice(this.__moves__(a,b))}}),players.TracePlayer=declare(Player,{constructor:function(a){Player.call(this,a),this.trace=iterable(a.trace),this.__iterator__=this.trace.__iter__(),this.__decision__=this.__iterator__()},decision:function(){try{this.__decision__=this.__iterator__()}catch(a){Iterable.prototype.catchStop(a)}return this.__decision__},__serialize__:function(){return["TracePlayer",{name:this.name,trace:this.trace.toArray()}]}});var HeuristicPlayer=players.HeuristicPlayer=declare(Player,{constructor:function(a){Player.call(this,a),initialize(this,a).object("random",{defaultValue:Randomness.DEFAULT}).func("heuristic",{ignore:!0})},moveEvaluation:function(a,b,c){return this.stateEvaluation(b.next(obj(c,a)),c)},stateEvaluation:function(a,b){var c=a.result();return c?c[b]:this.heuristic(a,b)},heuristic:function(){return this.random.random(-.5,.5)},bestMoves:function(a){return iterable(a).greater(function(a){return a[1]}).map(function(a){return a[0]})},selectMoves:function(a,b,c){var d=this,e=!1,f=a.map(function(a){var f=d.moveEvaluation(a,b,c);return f instanceof Future?(e=e||!0,f.then(function(b){return[a,b]})):[a,f]});return e?Future.all(f).then(this.bestMoves):this.bestMoves(f)},decision:function(a,b){var c=this,d=c.selectMoves(c.__moves__(a,b),a,b);return Future.then(d,function(a){return c.random.choice(a)})}}),MaxNPlayer=players.MaxNPlayer=declare(HeuristicPlayer,{constructor:function(a){HeuristicPlayer.call(this,a),initialize(this,a).integer("horizon",{defaultValue:3,coerce:!0})},stateEvaluation:function(a,b){return this.maxN(a,b,0)[b]},heuristics:function(a){var b={},c=this;return a.players.forEach(function(d){b[d]=c.heuristic(a,d)}),b},quiescence:function(a,b,c){var d=a.result();return d?d:c>=this.horizon?this.heuristics(a):null},maxN:function(a,b,c){var d=this.quiescence(a,b,c);if(!d){var e,f,g=a.activePlayer(),h=this.__moves__(a,g),d={};if(h.length<1)throw new Error("No moves for unfinished game "+a+".");for(var i=0;i(d[g]||-1/0)&&(d=e)}return d},toString:function(){return(this.constructor.name||"MaxNPlayer")+"("+JSON.stringify({name:this.name,horizon:this.horizon})+")"}}),MiniMaxPlayer=players.MiniMaxPlayer=declare(HeuristicPlayer,{constructor:function(a){HeuristicPlayer.call(this,a),initialize(this,a).integer("horizon",{defaultValue:4,coerce:!0})},stateEvaluation:function(a,b){return this.minimax(a,b,0)},quiescence:function(a,b,c){var d=a.result();return d?d[b]:c>=this.horizon?this.heuristic(a,b):0/0},minimax:function(a,b,c){var d=this.quiescence(a,b,c);if(isNaN(d)){var e,f,g=a.activePlayer(),h=this.__moves__(a,g);if(h.length<1)throw new Error("No moves for unfinished game "+a+".");g==b?(d=-1/0,e=Math.max):(d=+1/0,e=Math.min);for(var i=0;id&&(d=f):e>f&&(e=f),!(d>=e));k++);return i?d:e}}),players.MonteCarloPlayer=declare(HeuristicPlayer,{constructor:function(a){HeuristicPlayer.call(this,a),initialize(this,a).number("simulationCount",{defaultValue:30,coerce:!0}).number("timeCap",{defaultValue:1e3,coerce:!0}).object("agent",{defaultValue:null})},selectMoves:function(a,b,c){for(var d=this,e=Date.now()+this.timeCap,f=a.map(function(a){return{move:a,next:b.next(obj(c,a)),isFinal:!1,sum:0,count:0}}),g=0;g0?a.sum/a.count:0}).map(function(a){return a.move})},stateEvaluation:function(a,b){for(var c,d=0,e=this.simulationCount,f=0;e>f&&(c=this.simulation(a,b),d+=c.result[b],!(c.plies<1));++f);return e>0?d/e:0},simulation:function(a){var b,c,d,e=this;for(b=0;!0;++b)if(a instanceof Aleatory)a=a.next();else{if(d=a.moves(),!d)return{game:a,result:a.result(),plies:b};c={},a.activePlayers.forEach(function(b){c[b]=e.agent?e.agent.decision(a,b):e.random.choice(d[b])}),a=a.next(c)}return{game:a,result:a.result(),plies:b}},toString:function(){return(this.constructor.name||"MonteCarloPlayer")+"("+JSON.stringify({name:this.name,simulationCount:this.simulationCount,timeCap:this.timeCap})+")"}});var UserInterfacePlayer=players.UserInterfacePlayer=declare(Player,{constructor:function(a){Player.call(this,a)},participate:function(a,b){return this.role=b,this},decision:function(){return this.__future__&&this.__future__.isPending()&&this.__future__.resolve(new Match.CommandQuit),this.__future__=new Future},perform:function(a){var b=this.__future__;return b&&(this.__future__=null,b.resolve(a)),!!b}}),UserInterface=players.UserInterface=declare({constructor:function(a){this.onBegin=this.onBegin.bind(this),this.onNext=this.onNext.bind(this),this.onEnd=this.onEnd.bind(this),a.match&&this.show(a.match)},show:function(a){this.match&&(a.events.off("begin",this.onBegin),a.events.off("next",this.onNext),a.events.off("end",this.onEnd)),this.match=a,a.events.on("begin",this.onBegin),a.events.on("next",this.onNext),a.events.on("end",this.onEnd)},onBegin:function(a){this.display(a)},onNext:function(a,b){this.display(b)},onEnd:function(a,b){this.results=b,this.display(a)},display:function(){throw new Error("UserInterface.display is not defined. Please override.")},perform:function(a,b){iterable(this.match.players).forEach(function(c){var d=(c[0],c[1]);d instanceof UserInterfacePlayer&&(!b||d.role===b)&&d.perform(a)})}});UserInterface.BasicHTMLInterface=declare(UserInterface,{constructor:function(a){UserInterface.call(this,a),this.container=a.container,"string"==typeof this.container&&(this.container=document.getElementById(this.container))},display:function display(game){var ui=this,container=this.container;container.innerHTML=game.toHTML(),Array.prototype.slice.call(container.querySelectorAll("[data-ludorum]")).forEach(function(elem){var data=eval("({"+elem.getAttribute("data-ludorum")+"})");data.hasOwnProperty("move")&&(elem.onclick=ui.perform.bind(ui,data.move,data.activePlayer))})}});var WebWorkerPlayer=players.WebWorkerPlayer=declare(Player,{constructor:function(a){Player.call(this,a),initialize(this,a).object("worker"),this.worker.onmessage=base.Parallel.prototype.__onmessage__.bind(this)},"static createWorker":function(a){raiseIf("string function".indexOf(typeof a)<0,"Invalid player builder: "+a+"!");var b=new base.Parallel;return b.run("self.ludorum = ("+exports.__init__+')(self.base), "OK"').then(function(){return b.run("self.PLAYER = ("+a+').call(self), "OK"')}).then(function(){return b.worker})},"static create":function(a){var b=this;return b.createWorker(a.playerBuilder).then(function(a){return new b({name:name,worker:a})})},decision:function(a,b){return this.__future__&&this.__future__.isPending()&&this.__future__.resolve(Match.commandQuit),this.__future__=new Future,this.worker.postMessage("PLAYER.decision(ludorum.Game.fromJSON("+a.toJSON()+"), "+JSON.stringify(b)+")"),this.__future__}});aleatories.Dice=declare(Aleatory,{constructor:function(a,b,c){Aleatory.call(this,a,c),this.base=isNaN(b)?6:Math.max(2,+b)},value:function(){return this.random.randomInt(1,this.base+1)},distribution:function(){return this.__distribution__||(this.__distribution__=function(a){return Iterable.range(1,a+1).map(function(b){return[b,1/a]}).toArray()}(this.base))}});var Checkerboard=utils.Checkerboard=declare({constructor:function(a,b){isNaN(a)||(this.height=0|a),isNaN(b)||(this.width=0|b)},emptySquare:null,isValidCoord:function(a){return Array.isArray(a)&&!isNaN(a[0])&&!isNaN(a[1])&&a[0]>=0&&a[0]=0&&a[1]=b}).map(function(a){return Iterable.range(0,a.length-b+1).map(function(c){return a.slice(c,c+b)})}).flatten()},walk:function(a,b){var c=this;return new Iterable(function(){var d=a.slice();return function(){if(c.isValidCoord(d)){var a=d.slice();return d[0]+=b[0],d[1]+=b[1],a}throw Iterable.STOP_ITERATION}})},walks:function(a,b){var c=this;return b.map(function(b){return c.walk(a,b)})},"static DIRECTIONS":{HORIZONTAL:[[0,-1],[0,1]],VERTICAL:[[-1,0],[1,0]],ORTHOGONAL:[[0,-1],[0,1],[-1,0],[1,0]],DIAGONAL:[[-1,-1],[-1,1],[1,-1],[1,1]],EVERY:[[0,-1],[0,1],[-1,0],[1,0],[-1,-1],[-1,1],[1,-1],[1,1]]},clone:unimplemented("utils.Checkerboard","clone"),__place__:unimplemented("utils.Checkerboard","place"),place:function(a,b){return this.clone().__place__(a,b)},__move__:function(a,b,c){return this.__place__(b,this.square(a)).__place__(a,"undefined"==typeof c?this.emptySquare:c)},move:function(a,b,c){return this.clone().__move__(a,b,c)},__swap__:function(a,b){var c=this.square(b);return this.__place__(b,this.square(a)).__place__(a,c)},swap:function(a,b){return this.clone().__swap__(a,b)},asHTMLTable:function(a,b,c){var d=a.createElement("table");board.horizontals().reverse().foeEach(function(b){var e=a.createElement("tr");d.appendChild(e),b.forEach(function(b){var d=board.square(b),f=c(d,b),g=a.createElement("td");td_content=a.createTextNode(f.hasOwnProperty("content")?f.content:d),e.appendChild(g),g.id=f.id||"ludorum-square-"+b.join("-"),g.className=f.className||"ludorum-square",g.data_ludorum=f})})}}),CheckerboardFromString=utils.CheckerboardFromString=declare(Checkerboard,{constructor:function(a,b,c,d){if(Checkerboard.call(this,a,b),d&&(this.emptySquare=(d+this.emptySquare).charAt(0)),c&&c.length!==a*b)throw new Error("Given string "+JSON.stringify(c)+" does not match board dimensions.");this.string=c||this.emptySquare.repeat(a*b)},emptySquare:".",toString:function(){var a=this.string,b=this.height,c=this.width;return Iterable.range(b).map(function(d){return a.substr((b-d-1)*c,c)}).join("\n")},square:function(a,b){var c=a[0],d=a[1],e=this.width;return c>=0&&c=0&&e>d?this.string.charAt(c*e+d):b},asString:function(a){var b=this;return a.map(function(a){return b.square(a)}).join("")},asStrings:function(a){var b=this;return a.map(function(a){return b.asString(a)})},asRegExp:function(a,b,c){c=c||".";var d=this.width,e=Iterable.repeat(!1,d*this.height).toArray();a.forEach(function(a){e[a[0]*d+a[1]]=!0});for(var f,g="",h=0,i=0;ih?f?b:c:(f?b:c)+"{"+h+"}"}return g},asRegExps:function(a,b,c){var d=this;return a.map(function(a){return d.asRegExp(a,b,c)}).join("|")},clone:function(){return new this.constructor(this.height,this.width,this.string,this.hasOwnProperty("emptySquare")?this.emptySquare:void 0)},__place__:function(a,b){raiseIf(!this.isValidCoord(a),"Invalid coordinate ",a,"."),b=(b+this.emptySquare).charAt(0);var c=a[0]*this.width+a[1];return this.string=this.string.substr(0,c)+b+this.string.substr(c+1),this}});return exports.utils.Scanner=declare({constructor:function(a){initialize(this,a).object("game",{ignore:!0}).integer("maxWidth",{defaultValue:1e3,coerce:!0}).integer("maxLength",{defaultValue:50,coerce:!0}).object("random",{defaultValue:Randomness.DEFAULT}).object("statistics",{defaultValue:new Statistics})},scan:function(a){var b=this,c=arguments.length<2?this.game?[this.game]:[]:Array.prototype.slice.call(arguments,1),d=0;return Future.whileDo(function(){return c.length>0&&dg?(e.add({key:"defeat.result",game:b.name,role:f,player:h},g,b),e.add({key:"defeat.length",game:b.name,role:f,player:h},c,b)):g>0?(e.add({key:"victory.result",game:b.name,role:f,player:h},g,b),e.add({key:"victory.length",game:b.name,role:f,player:h},c,b)):e.add({key:"draw.length",game:b.name,role:f,player:h},c,b)}),!0;var f=b.moves();return iterable(b.activePlayers).forEach(function(a){e.add({key:"game.width",game:b.name,role:a},f[a].length)}),!1}}),utils.Cache=declare({constructor:function(a){this.clear(),a&&this.root(a)},stateIdentifier:function(a){return a.identifier()},moveIdentifier:function(a){return JSON.stringify(a)},has:function(a){var b="string"==typeof a?a:this.stateIdentifier(a);return this.__entries__.hasOwnProperty(b)},get:function(a){var b="string"==typeof a?a:this.stateIdentifier(a);return this.__entries__[b]},entry:function(a,b){if(b=b||this.stateIdentifier(a),this.has(b))return this.get(b);var c={id:b,state:a,precursors:[],descendants:{}};return this.__entries__[b]=c,c},descendant:function(a,b){var c=this.moveIdentifier(b),d=a.descendants;if(d.hasOwnProperty(c))return d[c][1];var e=a.state.next(b),f=this.stateIdentifier(e),g=this.get(f)||this.entry(e,f);return d[c]=[b,g],g.precursors.push([b,a]),g},descendants:function(a){var b=this.descendant.bind(this,a);return arguments.length>1?Array.prototype.slice.call(arguments,1).map(b):a.state.possibleMoves().map(b)},clear:function(){this.__entries__={},this.__root__=null},root:function(a){if(arguments.length>0){var b=this.stateIdentifier(a);this.__root__=this.get(b)||this.entry(a,b),this.prune(b)}return this.__root__},prune:function(a){for(var b,c=[a||this.__root__.id],d={};a=c.shift();)d.hasOwnProperty(a)||(b=this.get(a),d[a]=b,c.push.apply(c,iterable(b.descendants).mapApply(function(a,b){return b[1].id}).toArray()));return this.__entries__=d}}),games.Predefined=declare(Game,{constructor:function(a,b,c,d){b&&(this.__results__=b,this.players=Object.keys(b)),Game.call(this,a),this.height=isNaN(c)?5:+c,this.width=isNaN(d)?5:+d},name:"Predefined",players:["A","B"],__results__:{A:0,B:0},moves:function(){return this.height>0?obj(this.activePlayer(),Iterable.range(1,this.width+1).toArray()):void 0},result:function(){return this.height>0?null:this.__results__},next:function(){return new this.constructor(this.opponent(),this.__results__,this.height-1,this.width)},__serialize__:function(){return[this.name,this.activePlayer(),this.results,this.height,this.width]}}),games.Choose2Win=declare(Game,{constructor:function(a,b,c){Game.call(this,b),this.__turns__=isNaN(a)?1/0:+a,this.__winner__=c},name:"Choose2Win",players:["This","That"],moves:function(){return!this.__winner__&&this.__turns__>0?obj(this.activePlayer(),["win","lose","pass"]):void 0},result:function(){return this.__winner__?this.victory(this.__winner__):this.__turns__<1?this.draw():null},next:function(a){var b=this.activePlayer(),c=this.opponent(b);switch(a[b]){case"win":return new this.constructor(this.__turns__-1,c,b);case"lose":return new this.constructor(this.__turns__-1,c,c);case"pass":return new this.constructor(this.__turns__-1,c)}throw new Error("Invalid move "+a[b]+" for player "+b+".")},__serialize__:function(){return[this.name,this.__turns__,this.activePlayer(),this.__winner__]}}),games.ConnectionGame=declare(Game,{height:9,width:9,lineLength:5,constructor:function(a,b){Game.call(this,a),this.board=b instanceof CheckerboardFromString?b:new CheckerboardFromString(this.height,this.width,(b||".".repeat(this.height*this.width))+"")},name:"ConnectionGame",players:["First","Second"],__lines__:function(){function a(a,c,d){var e=a+"x"+c+"/"+d;if(!b.hasOwnProperty(e)){var f=new CheckerboardFromString(a,c,".".repeat(a*c));b[e]=f.lines().map(function(a){return a.toArray()},function(a){return a.length>=d}).toArray()}return b[e]}var b={};return a.CACHE=b,a}(),result:function(){if(this.hasOwnProperty("__result__"))return this.__result__;for(var a=this.lineLength,b=this.board.asStrings(this.__lines__(this.height,this.width,a)).join(" "),c=0;c=0)return this.__result__=this.victory([this.players[c]]);return this.__result__=b.indexOf(".")<0?this.draw():null},moves:function(){return this.hasOwnProperty("__moves__")?this.__moves__:this.__moves__=this.result()?null:obj(this.activePlayer(),iterable(this.board.string).filter(function(a){return"."===a},function(a,b){return b}).toArray())},next:function(a){var b=this.activePlayer(),c=this.players.indexOf(b),d=+a[b],e=d/this.width>>0,f=d%this.width;return new this.constructor((c+1)%this.players.length,this.board.place([e,f],c.toString(36)))},toHTML:function(){var a=this.moves(),b=this.activePlayer(),c=this.board,d=this.width;return a=a&&a[b],""+c.horizontals().reverse().map(function(e){return""+e.map(function(e){var f="",g=c.square(e),h=e[0]*d+e[1];return a&&a.indexOf(h)>=0&&(f=' data-ludorum="move: '+h+", activePlayer: '"+b+"'\""),"."===g?"":'"}).join("")+""}).join("")+"
 
"},__serialize__:function(){return[this.name,this.activePlayer(),this.board.string]}}),games.OddsAndEvens=declare(Game,{constructor:function(a,b){Game.call(this,this.players),this.turns=isNaN(a)?1:+a,this.points=b||{Evens:0,Odds:0}},name:"OddsAndEvens",players:["Evens","Odds"],moves:function(){return this.turns<1?null:{Evens:[1,2],Odds:[1,2]}},result:function(){var a=this.points.Evens-this.points.Odds;return this.turns>0?null:{Evens:+a,Odds:-a}},next:function(a){var b=!((a.Evens+a.Odds)%2);return new this.constructor(this.turns-1,{Evens:this.points.Evens+(b?1:0),Odds:this.points.Odds+(b?0:1)})},__serialize__:function(){return[this.name,this.turns,this.points]}}),games.TicTacToe=declare(Game,{constructor:function(a,b){Game.call(this,a),this.board=b||"_________"},name:"TicTacToe",players:["Xs","Os"],result:function(){return function(){return this.board.match(this.WIN_X)?this.victory(["Xs"]):this.board.match(this.WIN_O)?this.victory(["Os"]):this.board.indexOf("_")<0?this.draw():null}}(),moves:function(){if(this.result())return null;var a={};return a[this.activePlayer()]=iterable(this.board).filter(function(a){return"_"===a},function(a,b){return b}).toArray(),a},next:function(a){var b=this.activePlayer(),c=+a[b];if("_"!==this.board.charAt(c))throw new Error("Invalid move "+JSON.stringify(a)+" for board "+this.board+" (moves= "+JSON.stringify(a)+").");var d=this.board.substring(0,c)+b.charAt(0)+this.board.substring(c+1);return new this.constructor(this.opponent(b),d)},toString:function(){var a=this.board;return[a.substr(0,3).split("").join("|"),"-+-+-",a.substr(3,3).split("").join("|"),"-+-+-",a.substr(6,3).split("").join("|")].join("\n")},toHTML:function(){var a=this.activePlayer(),b=this.board.split("").map(function(b,c){return"_"===b?' ":""+b+""});return""+[b.slice(0,3).join(""),b.slice(3,6).join(""),b.slice(6,9).join("")].join("")+"
"},__serialize__:function(){return[this.name,this.activePlayer(),this.board]},"static heuristics":{heuristicFromWeights:function(a){function b(b,d){var e=d.charAt(0);return iterable(b.board).map(function(b,c){return"_"===b?0:a[c]*(b===e?1:-1)}).sum()/c}var c=iterable(a).map(Math.abs).sum();return b.weights=a,b}},"":function(){var a=new CheckerboardFromString(3,3,"_".repeat(9)),b=a.sublines(a.lines(),3);this.prototype.WIN_X=new RegExp(a.asRegExps(b,"X",".")),this.prototype.WIN_O=new RegExp(a.asRegExps(b,"O","."))}}),games.TicTacToe.heuristics.defaultHeuristic=games.TicTacToe.heuristics.heuristicFromWeights([2,1,2,1,5,1,2,1,2]),games.ToadsAndFrogs=declare(Game,{constructor:function b(a,c){Game.call(this,a),this.board=c||b.board()},"static board":function(a,b){return a=isNaN(a)?3:+a,b=isNaN(b)?2:+b,"T".repeat(a)+"_".repeat(b)+"F".repeat(a)},name:"ToadsAndFrogs",players:["Toads","Frogs"],result:function(){return this.moves()?null:this.defeat()},moves:function(){var a=this.activePlayer(),b={},c=b[a]=[];return this.board.replace(a==this.players[0]?/TF?_/g:/_T?F/g,function(a,b){return c.push(b),a +}),c.length>0?b:null},next:function(a){var b=this.activePlayer(),c=a[b],d=(b.charAt(0),this.board);if("T_"==d.substr(c,2))d=d.substring(0,c)+"_T"+d.substring(c+2);else if("_F"==d.substr(c,2))d=d.substring(0,c)+"F_"+d.substring(c+2);else if("TF_"==d.substr(c,3))d=d.substring(0,c)+"_FT"+d.substring(c+3);else{if("_TF"!=d.substr(c,3))throw new Error("Invalid move ",c," for board <",d,">.");d=d.substring(0,c)+"FT_"+d.substring(c+3)}return new this.constructor(this.opponent(),d)},__serialize__:function(){return[this.name,this.activePlayer,this.board]}}),games.Mancala=declare(Game,{constructor:function(a,b){Game.call(this,a),this.board=b||this.makeBoard()},makeBoard:function(a,b){a=isNaN(a)?4:+a,b=isNaN(b)?6:+b;for(var c=[],d=0;2>d;d++){for(var e=0;b>e;e++)c.push(a);c.push(0)}return c},name:"Mancala",players:["North","South"],emptyCapture:!1,countRemainingSeeds:!0,store:function(a){switch(this.players.indexOf(a)){case 0:return this.board.length/2-1;case 1:return this.board.length-1;default:throw new Error("Invalid player "+a+".")}},houses:function(a){switch(this.players.indexOf(a)){case 0:return Iterable.range(0,this.board.length/2-1).toArray();case 1:return Iterable.range(this.board.length/2,this.board.length-1).toArray();default:throw new Error("Invalid player "+a+".")}},oppositeHouse:function(a,b){var c=this.houses(a),d=this.houses(this.opponent(a)),e=c.indexOf(b);return 0>e?e:d.reverse()[e]},nextSquare:function(a,b){do b=(b+1)%this.board.length;while(b===this.store(this.opponent(a)));return b},moves:function(){if(this.result())return null;var a=this.board,b={},c=this.activePlayer();return b[c]=this.houses(c).filter(function(b){return a[b]>0}),b[c].length>0?b:null},scores:function(){var a=this,b=this.board,c=this.players.map(function(c){return iterable(a.houses(c)).map(function(a){return b[a]}).sum()});if(c[0]>0&&c[1]>0)return null;var d={};return this.players.forEach(function(e,f){d[e]=b[a.store(e)]+a.countRemainingSeeds*c[f]}),d},result:function(){var a=this.scores(),b=this.players;return a&&this.zerosumResult(a[b[0]]-a[b[1]],b[0])},next:function(a){var b,c,d=this.activePlayer(),e=+a[d],f=this.board.slice(0),g=f[e],h=!1;for(raiseIf(1>g,"Invalid move ",e," for game ",this),f[e]=0;g>0;g--)e=this.nextSquare(d,e),f[e]++;return h=e==this.store(d),h||(c=this.oppositeHouse(d,e),c>=0&&1==f[e]&&f[c]>0&&(b=this.store(d),f[b]++,f[e]=0,this.emptyCapture||(f[b]+=f[c],f[c]=0))),new this.constructor(h?d:this.opponent(),f)},resultBounds:function(){var a=iterable(this.board).sum();return[-a,+a]},__serialize__:function(){return[this.name,this.activePlayer(),this.board.slice()]},identifier:function(){return this.activePlayer().charAt(0)+this.board.map(function(a){return("00"+a.toString(36)).substr(-2)}).join("")},toString:function(){var a=this,b=base.Text.lpad,c=this.players[0],d=this.houses(c).map(function(c){return b(""+a.board[c],2,"0")}).reverse(),e=b(""+this.board[this.store(c)],2,"0"),f=this.players[1],g=this.houses(f).map(function(c){return b(""+a.board[c],2,"0")}),h=b(""+this.board[this.store(f)],2,"0");return" "+d.join(" | ")+" \n"+e+" ".repeat(2*d.length+3*(d.length-1)+2)+h+"\n "+g.join(" | ")+" "},toHTML:function(){function a(a,c){return!b||!b[a]||!b[a].indexOf(c)<0?""+this.board[c]+"":'"+this.board[c]+""}var b=this.moves(),c=this.players[0],d=this.players[1];return'"+this.houses(c).map(a.bind(this,c)).reverse().join("")+'"+this.houses(d).map(a.bind(this,d)).join("")+"
'+this.board[this.store(c)]+"'+this.board[this.store(d)]+"
"},"static heuristics":{heuristicFromWeights:function(a){function b(b,d){var e,f=0;switch(b.players.indexOf(d)){case 0:e=1;break;case 1:e=-1;break;default:throw new Error("Invalid player "+d+".")}return iterable(b.board).map(function(b,c){return f+=b,b*a[c]}).sum()/c/f*e}var c=iterable(a).map(Math.abs).sum();return b.weights=a,b}},"":function(){this.makeBoard=this.prototype.makeBoard,this.heuristics.defaultHeuristic=this.heuristics.heuristicFromWeights([1,1,1,1,1,1,5,-1,-1,-1,-1,-1,-1,-5])}}),games.Pig=declare(Game,{constructor:function(a,b,c,d){Game.call(this,a),this.goal=isNaN(b)?100:+b,this.__scores__=c||iterable(this.players).zip([0,0]).toObject(),this.__rolls__=d||[]},name:"Pig",players:["One","Two"],moves:function(){if(!this.result()){var a=this.activePlayer(),b=this.__scores__[a]+iterable(this.__rolls__).sum();return obj(a,b=this.goal||b>=this.goal){var c={};return c[this.players[0]]=a-b,c[this.players[1]]=-c[this.players[0]],c}},next:function(a){var b=this.activePlayer(),c=a[b];if("hold"===c){var d=copy(this.__scores__);return d[b]+=iterable(this.__rolls__).sum(),new this.constructor(this.opponent(),this.goal,d,[])}if("roll"===c){var e=this;return new aleatories.Dice(function(a){return a=isNaN(a)?this.value():+a,a>1?new e.constructor(b,e.goal,e.__scores__,e.__rolls__.concat(a)):new e.constructor(e.opponent(),e.goal,e.__scores__,[])})}throw new Error("Invalid moves: "+JSON.stringify(a))},__serialize__:function(){return[this.name,this.activePlayer(),this.goal,this.__scores__,this.__rolls__]}}),games.ConnectFour=declare(games.ConnectionGame,{height:6,width:7,lineLength:4,name:"ConnectFour",players:["Yellow","Red"],moves:function(){var a=null;if(!this.result()){for(var b=[],c=this.board.string,d=(this.height-1)*this.width,e=0;e0&&(a={},a[this.activePlayer()]=b)}return a},next:function(a){for(var b=this.activePlayer(),c=this.board.string,d=+a[b],e=this.height,f=this.width,g=0;e>g;++g)if("."===c.charAt(g*f+d))return new this.constructor(this.opponent(),this.board.place([g,d],b===this.players[0]?"0":"1"));throw new Error("Invalid move "+JSON.stringify(a)+"!")},toHTML:function(){var a=this.moves(),b=this.activePlayer(),c=this.board;return a=a&&a[b],""+"".repeat(this.board.width)+""+c.horizontals().reverse().map(function(d){return""+d.map(function(d){var e="",f=c.square(d);return a&&a.indexOf(d[1])>=0&&(e=' data-ludorum="move: '+d[1]+", activePlayer: '"+b+"'\""),"."===f?"":'"}).join("")+""}).join("")+"
 
"},__serialize__:function(){return[this.name,this.activePlayer(),this.board.string]}}),games.Mutropas=declare(Game,{allPieces:Iterable.range(9).toArray(),name:"Mutropas",players:["Left","Right"],constructor:function(a){Game.call(this,this.players),a=a||{},this._pieces=a.pieces||this.dealtPieces(a.random),this._scores=a.scores||obj(this.players[0],0,this.players[1],0)},result:function(){var a=this.players[0];return this._pieces[a].length<1?copy({},this._scores):null},moves:function(){var a=this.players[0],b=this.players[1];return this.result()?null:obj(a,this._pieces[a].slice(),b,this._pieces[b].slice())},next:function(a){var b=this.players[0],c=this.players[1],d=a[b],e=a[c];raiseIf(this._pieces[b].indexOf(d)<0,"Invalid move "+JSON.stringify(d)+" for player "+b+"! (moves= "+JSON.stringify(a)+")"),raiseIf(this._pieces[c].indexOf(e)<0,"Invalid move "+JSON.stringify(e)+" for player "+c+"! (moves= "+JSON.stringify(a)+")");var f=this.moveResult(d,e),g=this._pieces[b].slice(),h=this._pieces[c].slice();return g.splice(g.indexOf(d),1),h.splice(h.indexOf(e),1),new this.constructor({pieces:obj(b,g,c,h),scores:obj(b,this._scores[b]+f,c,this._scores[c]-f)})},__serialize__:function(){return[this.name,{pieces:this._pieces,scores:this._scores}]},dealtPieces:function(a){var a=a||Randomness.DEFAULT,b=this.allPieces.length>>1,c=a.split(b,this.allPieces),d=a.split(b,c[1]);return obj(this.players[0],c[0],this.players[1],d[0])},moveResult:function(a,b){var c=iterable(this.allPieces).max(0)+1;return b>a?c>>1>=b-a?1:-1:a>b?a-b>=(c>>1)+1?1:-1:0}}),games.Othello=declare(Game,{constructor:function(a,b){if(Game.call(this,a),this.board=this.makeBoard.apply(this,b||[]),!this.moves()){var c=this.opponent();this.moves(c)&&(this.activePlayers=[c])}},makeBoard:function(a,b,c){return a=isNaN(a)?8:+a,b=isNaN(b)?8:+b,raiseIf(4>a||4>b||a%2||b%2,"An Othello board must have even dimensions greater than 3."),"string"==typeof c?new CheckerboardFromString(a,b,c):new CheckerboardFromString(a,b).__place__([a/2,b/2-1],"W").__place__([a/2-1,b/2],"W").__place__([a/2,b/2],"B").__place__([a/2-1,b/2-1],"B")},name:"Othello",players:["Black","White"],lines:new utils.Checkerboard(8,8).lines().map(function(a){return a.toArray()},function(a){return a.length>2}).toArray(),__MOVE_REGEXPS__:{Black:[/\.W+B/g,/BW+\./g],White:[/\.B+W/g,/WB+\./g]},moves:function(a){if(!a&&this.__moves__)return this.__moves__;a=a||this.activePlayer();var b=this.board,c={},d=this.__MOVE_REGEXPS__[a];this.lines.forEach(function(a){d.forEach(function(d){b.asString(a).replace(d,function(b,d){var e="."===b.charAt(0)?a[d]:a[b.length-1+d];return c[e]=e,b})})});var e=[];for(var f in c)e.push(c[f]);return this.__moves__=e.length>0?obj(a,e):null},result:function(){if(this.moves())return null;var a={W:-1,B:1},b=iterable(this.board.string).map(function(b){return a[b]||0}).sum();return this.zerosumResult(b,"Black")},next:function(a){var b,c,d=this.board.clone(),e=this.activePlayer();if(!a.hasOwnProperty(e)||!d.isValidCoord(a[e]))throw new Error("Invalid moves "+JSON.stringify(a)+"!");return e==this.players[0]?(b="B",c=/^W+B/):(b="W",c=/^B+W/),d.walks(a[e],Checkerboard.DIRECTIONS.EVERY).forEach(function(a){var e=c.exec(d.asString(a).substr(1));e&&a.toArray().slice(0,e[0].length).forEach(function(a){d.__place__(a,b)})}),new this.constructor(this.opponent(),[d.height,d.width,d.string])},__serialize__:function(){var a=this.board;return[this.name,this.activePlayer(),[a.height,a.width,a.string]]},toHTML:function(){var a=this.moves(),b=this.activePlayer(),c=this.board;return a=a&&a[b].map(JSON.stringify),""+c.horizontals().reverse().map(function(d){return""+d.map(function(d){switch(c.square(d)){case"B":return'';case"W":return'';default:var e=JSON.stringify(d);return a&&a.indexOf(e)>=0?'":''}}).join("")+""}).join("")+"
    
"}}),games.Othello.makeBoard=games.Othello.prototype.makeBoard,games.Othello.heuristics={},games.Bahab=declare(Game,{initialBoard:["BBABB","BBBBB",".....","bbbbb","bbabb"].join(""),name:"Bahab",players:["Uppercase","Lowercase"],constructor:function(a,b){Game.call(this,a),this.board=b instanceof CheckerboardFromString?b:new CheckerboardFromString(5,5,b||this.initialBoard)},__PLAYER_PIECES_RE__:{Uppercase:/[AB]/g,Lowercase:/[ab]/g},result:function(){var a=this.board.string;return a.match(/^[.bAB]+$|[A].{0,4}$/)?this.defeat(this.players[1]):a.match(/^[.Bab]+$|^.{0,4}[a]/)?this.defeat(this.players[0]):null},moves:function(){var a=this.activePlayer(),b=this.__PLAYER_PIECES_RE__[a],c=this.board,d=[];return c.string.replace(b,function(a,e){var f,g=[e/5|0,e%5];switch(a){case"A":f=[[1,-1],[1,0],[1,1]];break;case"B":f=[[1,-1],[1,1]];break;case"a":f=[[-1,-1],[-1,0],[-1,1]];break;case"b":f=[[-1,-1],[-1,1]]}return iterable(f).forEachApply(function(e,f){var h=[g[0]+e,g[1]+f],i=c.square(h);!c.isValidCoord(h)||i.match(b)||"b"==a.toLowerCase()&&"a"==i.toLowerCase()||d.push([g,h])}),a}),d.length>0?obj(a,d):null},next:function(a){if(!a)throw new Error("Invalid moves "+a+"!");var b=this.activePlayer(),c=a[b];if(!Array.isArray(a[b]))throw new Error("Invalid moves "+JSON.stringify(a)+"!");return new this.constructor(this.opponent(),this.board.move(c[0],c[1]))},__serialize__:function(){return[this.name,this.activePlayer(),this.board.string]},toHTML:function(){var a=(this.moves(),this.activePlayer(),this.board);return""+a.horizontals().reverse().map(function(b){return""+b.map(function(b){var c=a.square(b);switch(c){case"A":case"B":return'";case"a":case"b":return'";default:return''}}).join("")+""}).join("")+"
'+c+"'+c+" 
"}}),tournaments.RoundRobin=declare(Tournament,{constructor:function(a,b,c){Tournament.call(this,a,b),this.matchCount=isNaN(c)?a.players.length:+c,this.__advance__=this.__matches__().chain(Iterable.repeat(null)).__iter__()},__matches__:function(){var a=this.game,b=iterable(this.players);return b=b.product.apply(b,Iterable.repeat(this.players,a.players.length-1).toArray()),b.filter(function(a){for(var b=1;bc;c++)if(a[b]===a[c])return!1;return!0}).product(Iterable.range(this.matchCount)).map(function(b){return new Match(a,b[0])})}}),tournaments.Measurement=declare(Tournament,{constructor:function(a,b,c,d){Tournament.call(this,a,Array.isArray(b)?b:[b]),this.opponents=Array.isArray(c)?c:[c],raiseIf(this.opponents.length2?c.product.apply(c,Iterable.repeat(this.opponents,b-2).toArray()):c.map(function(a){return[a]}),iterable(this.players).product(Iterable.range(b),c,Iterable.range(this.matchCount)).map(function(b){var c=b[2].slice(0);return c.splice(b[1],0,b[0]),new Match(a,c)})}}),tournaments.Elimination=declare(Tournament,{constructor:function(a,b,c){Tournament.call(this,a,b),this.matchCount=isNaN(c)?1:+c>>0},__bracket__:function(a){var b=this.game,c=this.matchCount,d=this.game.players.length;return a=a||this.players,a.length 1) { + return Array.prototype.slice.call(arguments, 1).map(descendant); + } else { // if (arguments.length == 0) + return entry.state.possibleMoves().map(descendant); + } + }, + + /** A clear cache has no entries and of course no root. + */ + clear: function clear() { + this.__entries__ = {}; + this.__root__ = null; + }, + + /** If `root()` is called without arguments, it returns the current root. + If a state is given, that state is assigned as the new root, and the whole + cache is pruned. + */ + root: function root(state) { + if (arguments.length > 0) { // Called with argument means setter. + var stateId = this.stateIdentifier(state); + this.__root__ = this.get(stateId) || this.entry(state, stateId); + this.prune(stateId); + } + return this.__root__; + }, + + /** Deletes all nodes except the one with the given id and its descendants. + */ + prune: function prune(id) { + var pending = [id || this.__root__.id], + pruned = {}, + entry; + while (id = pending.shift()) { + if (!pruned.hasOwnProperty(id)) { + entry = this.get(id); + pruned[id] = entry; + pending.push.apply(pending, iterable(entry.descendants).mapApply(function (id, pair) { + return pair[1].id; + }).toArray()); + } + } + return this.__entries__ = pruned; + } +}); // declare Cache diff --git a/src/utils/Checkerboard.js b/src/utils/Checkerboard.js index f64c76d..44b12aa 100644 --- a/src/utils/Checkerboard.js +++ b/src/utils/Checkerboard.js @@ -257,18 +257,24 @@ var Checkerboard = utils.Checkerboard = declare({ */ asHTMLTable: function (document, parent, callback) { //TODO var table = document.createElement('table'); - board.horizontals().reverse().foeEach(function (line) { + board.horizontals().reverse().forEach(function (line) { var tr = document.createElement('tr'); table.appendChild(tr); line.forEach(function (coord) { var square = board.square(coord), - data = callback(square, coord), - td = document.createElement('td'); - td_content = document.createTextNode(data.hasOwnProperty('content') ? data.content : square); + td = document.createElement('td'), + data = callback(square, coord); tr.appendChild(td); - td.id = data.id || "ludorum-square-"+ coord.join('-'); - td.className = data.className || "ludorum-square"; - td.data_ludorum = data; + td.ludorum_data = base.copy({}, data, { + id: "ludorum-square-"+ coord.join('-'), + className: || "ludorum-square", + innerHTML: base.Text.escapeXML(square), + game: this, + coord: coord + }); + td.id = data.id; + td.className = data.className; + td.innerHTML = data.innerHTML; }); }); } diff --git a/tests/specs/cache.test.js b/tests/specs/cache.test.js new file mode 100644 index 0000000..067dd99 --- /dev/null +++ b/tests/specs/cache.test.js @@ -0,0 +1,36 @@ +define(['creatartis-base', 'ludorum'], function (base, ludorum) { + + describe("utils.Cache (basics)", function () { ///////////////////////////// + it("with Mancala", function () { + var game = new ludorum.games.Mancala(), + cache = new ludorum.utils.Cache(game), + root = cache.root(); + expect(root).toBeDefined(); + expect(root.state).toBe(game); + expect(root.id).toBe(game.identifier()); + expect(cache.__entries__[root.id]).toBe(root); + expect(Object.keys(cache.__entries__).length).toBe(1); + + var descendants = cache.descendants(cache.root()); + expect(descendants.length).toBe(6); + descendants.forEach(function (d, i) { + expect(cache.__entries__[d.id]).toBe(d); + expect(d.precursors.length).toBe(1); + expect(d.precursors[0].length).toBe(2); + expect(d.precursors[0][1]).toBe(root); + var move = d.precursors[0][0], + moveIdentifier = cache.moveIdentifier(move); + expect(root.descendants[moveIdentifier].length).toBe(2); + expect(root.descendants[moveIdentifier][0]).toBe(move); + expect(root.descendants[moveIdentifier][1]).toBe(d); + }); + expect(Object.keys(cache.__entries__).length).toBe(7); + + root = cache.root(descendants[3].state); + expect(root).toBe(descendants[3]); + expect(cache.__entries__[root.id]).toBe(root); + expect(Object.keys(cache.__entries__).length).toBe(1); + }); + }); //// utils.Cache (basics) + +}); //// define. \ No newline at end of file