From 8ab2019000003ea29720f1a847ef020a7d6ed82b Mon Sep 17 00:00:00 2001 From: ecrucru Date: Sun, 25 Dec 2016 09:12:26 +0100 Subject: [PATCH] Initial commit --- LICENSE | 18 + README.md | 383 ++++++ anticrux.css | 125 ++ anticrux.js | 2244 +++++++++++++++++++++++++++++++++++ anticrux.min.js | 22 + build_jshint.bat | 2 + build_min.bat | 3 + build_prototype.bat | 2 + images/agplv3.png | Bin 0 -> 3552 bytes images/ajax-loader.gif | Bin 0 -> 19110 bytes images/mate_-1.png | Bin 0 -> 159 bytes images/mate_1.png | Bin 0 -> 163 bytes images/piece_-11.png | Bin 0 -> 561 bytes images/piece_-12.png | Bin 0 -> 607 bytes images/piece_-13.png | Bin 0 -> 1239 bytes images/piece_-14.png | Bin 0 -> 905 bytes images/piece_-15.png | Bin 0 -> 1797 bytes images/piece_-16.png | Bin 0 -> 1955 bytes images/piece_11.png | Bin 0 -> 988 bytes images/piece_12.png | Bin 0 -> 814 bytes images/piece_13.png | Bin 0 -> 1508 bytes images/piece_14.png | Bin 0 -> 1499 bytes images/piece_15.png | Bin 0 -> 2288 bytes images/piece_16.png | Bin 0 -> 1910 bytes index.html | 676 +++++++++++ jquery-1.11.1.min.js | 5 + jquery-1.5.0.mobile.min.css | 3 + jquery-1.5.0.mobile.min.js | 10 + 28 files changed, 3493 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 anticrux.css create mode 100644 anticrux.js create mode 100644 anticrux.min.js create mode 100644 build_jshint.bat create mode 100644 build_min.bat create mode 100644 build_prototype.bat create mode 100644 images/agplv3.png create mode 100644 images/ajax-loader.gif create mode 100644 images/mate_-1.png create mode 100644 images/mate_1.png create mode 100644 images/piece_-11.png create mode 100644 images/piece_-12.png create mode 100644 images/piece_-13.png create mode 100644 images/piece_-14.png create mode 100644 images/piece_-15.png create mode 100644 images/piece_-16.png create mode 100644 images/piece_11.png create mode 100644 images/piece_12.png create mode 100644 images/piece_13.png create mode 100644 images/piece_14.png create mode 100644 images/piece_15.png create mode 100644 images/piece_16.png create mode 100644 index.html create mode 100644 jquery-1.11.1.min.js create mode 100644 jquery-1.5.0.mobile.min.css create mode 100644 jquery-1.5.0.mobile.min.js diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..84879a4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +AntiCrux - Artificial intelligence playing AntiChess and AntiChess960 with jQuery Mobile +Copyright (C) 2016-2017, ecrucru + + https://github.com/ecrucru/anticrux/ + http://ecrucru.free.fr/?page=anticrux + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..99c9d65 --- /dev/null +++ b/README.md @@ -0,0 +1,383 @@ +# AntiCrux + +> Artificial intelligence playing AntiChess and AntiChess960 with jQuery Mobile + +**Test it online at http://ecrucru.free.fr/?page=anticrux !** + + + +## Quick summary + +- [Presentation](#presentation) +- [Features](#features) +- [Gameplay](#gameplay) +- [Options](#options) + - [Some theory](#some-theory) + - [For the intelligence](#for-the-intelligence) + - [For the board](#for-the-board) +- [Programming interface](#programming-interface) +- [Information](#information) + - [Change log](#change-log) + - [License](#license) + + + +## Presentation + +AntiChess is a variant of the classical chess which consists in losing to win. The rules are very simple : + +- there are no check, no mate and no castling, +- the winner has no more piece on the board or cannot move, +- when you can take an opponent's piece, you **must** take it, +- when you can take several opponent's pieces, you may choose which one to take, +- you can promote a king. + +The logic of loosing all one's pieces leads to a really different way of thinking. On contrary to the classical chess, when you start to lose, you can still expect to win at the end. The programming of such an algorithm is easier than the classical chess because the nodes are generally reduced to the forced moves causing a maximal damage. That's why it is generally called a "forced-move game" or "suicide game". + +AntiChess is rapidely repetitive. That's why AntiCrux also plays AntiChess960. The concept is to shuffle the pieces of the first line and there are 960 different positions. The rules are the same and will change your habits ! + +The game is written in JavaScript and requires preferably a powerful desktop computer, else it will use a classical technique. Indeed, the JavaScript interpreter consumes a lot of memory depending on the current settings. The game works slightly better with the JavaScript implemented by Google compared to Mozilla. + +AntiCrux is neither UCI-compatible, nor working as a Worker (which would allow an asynchronous execution). + + + +## Features + +- Client-side +- Based on HTML5 and jQuery Mobile +- 1 player (human vs. AI) or 2 local players (human vs. human) +- Initial or advanced position for AntiChess and AntiChess 960 +- Several levels for the AI +- Informative or detailed hints +- History of the moves +- Undo +- Import from FEN, Lichess +- Export to FEN, PGN, Chess fonts + + + +## Gameplay + +It mainly depends on the settings you set for the analysis of the decision tree. The default application is shipped along with several possible levels : + +- Oyster : random play +- Handicaped player : restricted classical play +- Classical player : maximal damage at low depth +- Advanced classical player : deeper maximal damage +- Tactical player : set of techniques +- Champion 512 MB : full set of techniques +- Champion 1 GB : deeper full set of techniques +- Champion 2 GB : deepest full set of techniques + +"Champion" is a very relative term as it has never won any competition at all and will certainly never succeed in that task. It just means that AntiCrux will use its maximal optimized capabilities. The number followed by MB or GB is the recommended memory to be available else the browser will crash. + +The final release of AntiCrux has competed with StockFish Antichess available at [www.lichess.org](https://lichess.org). Following the [calculation rules](http://www.fide.com/component/handbook/?id=172&view=article), the maximal rating of AntiCrux with no time limit is estimated at **1980** (with no guarantee of accuracy). + + + +## Options + +### Some theory + +The options influence how the choice of a move is done by AntiCrux. Therefore, it is needed to know a little how it works. + +Schematically, AntiCrux plays all the possible moves to find a better situation. The problem is that it becomes rapidely exponential and exploring more than 4 half-moves is complicated, at least in JavaScript. Thanks to the rules of AntiChess which insist on the forced moves, their quantity can be reduced a lot and it allows the algorithm to explore deeper. Then its efficiency is higher. + +Basically, playing one piece is an **half-move** and it generates a new position called **node**. This node leads to new nodes if there are available moves for the next player. The nodes are linked to each other and the player is alternate between each turn. This is modelled with a tree with plenty of leaves and we have to cut the branches to discover its hidden treasure : the right move to play ! + +The positions are valuated at the lowest level. Then by use of rules of aggregations, the upper levels are weighted with some formulas based on the number of moves, the strength of the remaining pieces, etc... Once the first level is reached, we can pick the move with the best score. This score is a collection of hypothesis which should help the artificial intelligence to win. It is up to you to beat it. Have fun ! + +The algorithm implements some randomness in order to never play the same games. With the level "Champion", the randomness is rather reduced. + +### For the intelligence + +- **AntiCrux.options.ai.version** + +It is the version of the algorithm implemented for AntiCrux. + +- **AntiCrux.options.ai.maxDepth** + +The maximal depth is the number of half-moves which can be explored. The value is restricted to the amount of available memory on your computer. Mathematically, there are more possible positions at the beginning of the game, so it is normal to be less restricted by the depth at the end of the game. + +The value can be increased drastically if you enable *minimizeLiberty*. But the game will always play the forced moves even if it is not the best move. This is especially true at the beginning of the game. + +If you don't want that, you should reach the maximal depth dynamically at any moment. So you can set the maximal depth to 99, define a maximal number of nodes relevant with the size of your memory (*maxNodes*) and ask to reach this limit all the time (*wholeNodes*). + +- **AntiCrux.options.ai.maxNodes** + +The number of positions to be analyzed impacts the consumption of memory. When there is not enough memory, the browser will crash and your game will be lost. + +If you put the value to zero, the maximal number of nodes is defined by the depth to be reached. The risk of crash is then very high. So this option is more relevant at the end of the game where the possibilities are reduced. + +The number of nodes is a known restriction to allow AntiCrux to finish a game properly. If a node is not evaluated because of this limit, AntiCrux may play inaccurately and it will rely on your own arbitration. Make a challenge "Rook vs. King" to see how undeterministic the situation is despite the fact that the rook can win if it has the right initial position. + +- **AntiCrux.options.ai.minimizeLiberty** + +The simplification consists in playing the forced moves all the time even if is not the best move from a general point of view. It also contributes to a reduced variety of the game. + +When multiple moves are possible, the other options will help to decide how to pick the best one. + +In the following table issued from a game, the number of nodes is really reduced when the feature is enabled : + +| Depth | Normal nodes | Reduced nodes | +|:-----:|:-------------:|:-------------:| +| 2 | 146 | 21 | +| 3 | 1898 | 40 | +| 4 | 35883 | 73 | +| 5 | 461749 | 147 | +| 6 | 5449480 (?) | 322 | +| 7 | 70712349 (?) | 648 | +| 8 | 917562070 (?) | 1506 | + +- **AntiCrux.options.ai.noStatOnForcedMove** + +To play faster when the moves are forced, you can choose to not perform a deep analysis to evaluate the position of the artificial intelligence. + +The statistics will be updated the next time several moves are possible. So this option accelerates the game play. + +- **AntiCrux.options.ai.wholeNodes** + +The exploration is done depth by depth to permit an homogeneous evaluation of all the possible moves. When you reach a next depth, the number of nodes increases exponentially. Their number is approximately given by the relation "Nodes=A\*exp(B\*Depth)" where A and B are two constants to be determined with an [exponential regression](http://keisan.casio.com/exec/system/14059930754231). + +If the option is set to true, you are exposed to a partial exploration of the deepest level while the previous one have been entirely explored. This is generally not an issue because it is often good to explore a maximal number of nodes even if some are not totally processed. + +If you don't use the option, the number of nodes is first estimated for each depth. If the prediction is lower than the defined maximal number of nodes (*maxNodes*), the next level is explored and there is great chance that it will be entirely explored and still in the limit of the maximal number of nodes. The advantage of this option is that it reduces the thinking time dynamically. The game is quicker and never a constant. + +- **AntiCrux.options.ai.randomizedSearch** + +When you scan the nodes at the deepest level, the processing order is always the same. To bring some randomness in the game, the randomization of the moves at each level is a good option. + +- **AntiCrux.options.ai.pessimisticScenario** + +When it is not up to you to play, you can expect your opponent to play his best move. Assuming that you can't rely on the mistake of your opponent to reach a good position, the algorithm consider a very defensive approach by being pessimistic. + +If your opponent is weak, you can turn off this option and you will be able to make higher damages if the chance is on your side. + +Concluding the game with this option is particularly hard. That's why the option is silently turned off in some cases. + +- **AntiCrux.options.ai.bestStaticScore** + +When the algorithm has to choose between several positions having the same deep valuation, this option picks the move having the best immediate valuation. + +The opponent may be discouraged in the short term by this killing move, even if it doesn't change a lot for the next turns. + +The option reduces the randoness of the game. + +- **AntiCrux.options.ai.opportunistic** + +Sometimes a winning position is hidden by counter moves of the opponent. However, it will not necessary play one of these moves. So when we have equivalent positions, the option will favor the ones leading to a potential win. + +The option reduces the randomness of the game. + +- **AntiCrux.options.ai.handicap** + +This option weakens the algorithm by removing randomly some possible moves above a minimal number of moves. + +The number is expressed as a percentage between 0 and 100. + +- **AntiCrux.options.ai.acceleratedEndGame** + +When the artificial intelligence is sure to win, the move is chosen to put an end to the game as fast as possible. Else the game may never finish. Indeed, this option is recommended all the time. + +It is up to the human player to declare a draw by stopping the game. + +- **AntiCrux.options.ai.oyster** + +This option activates the worst play ever. It just picks randomly among the possible moves. + +Mechanically, it deactivates the other options based on the decision tree. + + +### For the board + +- **AntiCrux.options.board.rotated** + +When you play Black, the board must be rotated at 180°. + +- **AntiCrux.options.board.symbols** + +When the symbols are activated, some nice Unicode characters will replace the standard letters : + +- R : rook +- N : knight +- B : bishop +- Q : queen +- K : king + +If the unicode characters are not displayed (example: ♛ and ♕), you have to turn off the option. + +- **AntiCrux.options.board.fisher** + +The option is a number between 1 and 960. It defines a position where the pieces of the first line are shuffled is a precise order. + +The classical position is equal to 519. You can read more on [Wikipedia](https://en.wikipedia.org/wiki/Chess960). + +- **AntiCrux.options.board.coordinates** + +The option activates the coordinates all around the board. + +When the option is disabled, the board is more compact. + +- **AntiCrux.options.board.noStatOnOwnMove** + +To not interfere with your thinking, the statistics are not generated when you play. You can use a hint on demand from the general user interface. + +- **AntiCrux.options.board.fullDecisionTree** + +The decision tree is the basic structure of nodes helping to find the best move. In practice, the player needs to read the deepest level, not every level. + +Essentially for debugging purposes, you can ask to show all the levels. In any case, the depth is restricted to a certain level. + +- **AntiCrux.options.board.debugCellId** + +This option is used for debugging purposes in the process of developing AntiCrux. + + +### For the gameplay + +- **AntiCrux.options.variant.promoteQueen** + +With this option, you immediately promote paws as queen. You cannot choose for another piece. + +- **AntiCrux.options.variant.activePawns** + +The option gives the pawn a higher static valuation when it has left its initial position. + +The impact is on the valuation, not on the performances. + +- **AntiCrux.options.variant.whiteBoard** + +This human-related option renders the board with white pieces only. It may be used to reduce the readability of the game but the players must still follow the basic rules. + +The export to FEN and PGN is not impacted. + + + +## Programming interface + +The board is a mono-dimensional array of 64 cells. Black is at the top. White is at the bottom. + +| | A | B | C | . | H | +|-----|----|----|----|---|----| +|**8**| 0 | 1 | 2 | . | 7 | +|**7**| 8 | 9 | 10 | . | 15 | +|**.**| . | . | . | . | . | +|**1**| 56 | 57 | 58 | . | 63 | + +The pieces are represented with an arbitrary internal identifier : + +- AntiCrux.constants.piece.none +- AntiCrux.constants.piece.pawn +- AntiCrux.constants.piece.rook +- AntiCrux.constants.piece.knight +- AntiCrux.constants.piece.bishop +- AntiCrux.constants.piece.queen +- AntiCrux.constants.piece.king + +The pieces are owned by a player : + +- AntiCrux.constants.owner.black +- AntiCrux.constants.owner.none +- AntiCrux.constants.owner.white + +The moves are identified by 3 notation systems : + +- Algebraic notation : e3, Ra6, Nfxe5, h8=Q... This classical notation is practical for the human players but necessitates a complex processing to convert it into X/Y coordinates. It is used to register the moves and to show their history. +- Index-based notation : 0=A8 and 63=H1 as seen above. When looping an the mono-dimensional array of the board, the analysis is very simple to mark cells. It is then used internally to highlight the cells. +- XY notation : massively used internally for the processing of the moves, X and Y are concatenated. The first figure is X from 0 to 7. The second figure is Y from 0 to 7. For example, 56=G3. You can combine up to 5 figures to build a move : the first one is the promotion based on *AntiCrux.constants.piece*, the following 2 figures describe the source position, the following 2 figures describe the target position. For example, 51201=(cxb8=Q). + +A **node** is a position defined by pieces and their owner : + +```javascript +node = { + piece : [ /* 64 cells */ ], + owner : [ /* 64 cells */ ] +}; +``` + +A node is enriched with attributes when you call the API below. Any field or method beginning with an underscore is a private member which is not expected to be called directly by a third-party application. + +- AntiCrux.clearBoard(pNode) +- AntiCrux.defaultBoard(pFisher, pNode) +- AntiCrux.freeMemory() +- AntiCrux.getDecisionTreeHtml(pNode) +- AntiCrux.getHistory(pNode) +- AntiCrux.getMoveAI(pPlayer, pNode) +- AntiCrux.getMoves(pPlayer, pNode) +- AntiCrux.getNumNodes() +- AntiCrux.getPieceSymbol(pPiece, pPlayer, pSymbol) +- AntiCrux.getPlayer(pNode) +- AntiCrux.getReachedDepth() +- AntiCrux.getScore(pNode) +- AntiCrux.getWinner(pNode) +- AntiCrux.hasPendingPromotion(pNode) +- AntiCrux.hasSetUp(pNode) +- AntiCrux.highlight(pReset, pPosition) +- AntiCrux.highlightMoves() +- AntiCrux.isDraw(pNode) +- AntiCrux.isEndGame(pNode) +- AntiCrux.loadFen(pFen, pNode) +- AntiCrux.loadLichess(pKey, pNode) +- AntiCrux.logMove(pMove, pNode) +- AntiCrux.movePiece(pMove, pCheckLegit, pPlayerIndication, pNode) +- AntiCrux.moveToString(pMove, pNode) +- AntiCrux.promote(pPiece, pNode) +- AntiCrux.setPlayer(pPlayer, pNode) +- AntiCrux.toFen(pNode) +- AntiCrux.toHtml(pNode) +- AntiCrux.toPgn(pNode) +- AntiCrux.toText(pNode) +- AntiCrux.undoMove(pNode) + +The parameter *pNode* is generally optional. When you omit it, the internal root node is automatically picked. + +Your instance is AntiCrux and embeds by default a "root" node representing the current board. The same instance will apply on any node provided in the argument. Consequently : a node is minimalist and an instance of AntiCrux is unique. + +Once a node is evaluated, you get 2 attributes among others : + +- node.valuation : the static score based on the weight of every piece +- node.valuationSolver : the deep valuation after a certain exploration of the depths and based on the settings of the instance + +The valuation is based on a deep static score known as [centipawn](http://chess.wikia.com/wiki/Centipawn). A queen has a high score, not a pawn. Black and White are added and the valuation is changed to a percentage for a better understanding. This score varies between -100% (bad score for Black) and +100% (bad score for white). + +⚠ The score shows the strength of the player, so its ability to lose AntiChess. Your objective is then to modify the score in favor of your opponent. + + + +## Information + +### Change log + +- November 11th 2016 - Creation of the project +- December 25th 2016 - Completion of the first version (v0.1) + + +### License + +AntiCrux is released under the terms of the **GNU Affero General Public License version 3**. + +- https://www.gnu.org/licenses/agpl-3.0.html + +```javascript +/* + AntiCrux - Artificial intelligence playing AntiChess and AntiChess960 with jQuery Mobile + Copyright (C) 2016-2017, ecrucru + + https://github.com/ecrucru/anticrux/ + http://ecrucru.free.fr/?page=anticrux + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +``` \ No newline at end of file diff --git a/anticrux.css b/anticrux.css new file mode 100644 index 0000000..9fa7f4f --- /dev/null +++ b/anticrux.css @@ -0,0 +1,125 @@ +/* + AntiCrux - Artificial intelligence playing AntiChess and AntiChess960 with jQuery Mobile + Copyright (C) 2016-2017, ecrucru + + https://github.com/ecrucru/anticrux/ + http://ecrucru.free.fr/?page=anticrux + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/*===== General styles =====*/ + +.AntiCrux-hSizer { + overflow:hidden; +} + +.AntiCrux-hSizer DIV.AntiCrux-vSizer { + float:left; + padding:5px; +} + +.AntiCrux-leftMargin { + margin-left:15px; +} + +.AntiCrux-big { + font-size:20pt; +} + + +/*===== Particular styles =====*/ + +.AntiCrux-table TH { + border-bottom:1px solid #D6D6D6; +} + +.AntiCrux-table TR:nth-child(even) { + background:#E9E9E9; +} + + +/*===== Board =====*/ + +.AntiCrux-board-promotion { + font-size:24pt; +} + +.AntiCrux-board { + display:block; +} + +.AntiCrux-board-coordinates-vertical { + float:left; + height:50px; + width:15px; + font-weight:bold; +} +.AntiCrux-board-coordinates-horizontal { + float:left; + height:15px; + width:50px; + font-weight:bold; + text-align:center; +} +.AntiCrux-board-coordinates-corner { + float:left; + height:15px; + width:15px; +} + +.AntiCrux-board-line { + overflow:hidden; +} + +.AntiCrux-board-cell-0 { + float:left; + background-color:#A6ABD6; + width:50px; + height:50px; + text-align:center; + font-weight:bold; + color:yellow; +} +.AntiCrux-board-cell-1 { + float:left; + background-color:#F0F0F0; + width:50px; + height:50px; + text-align:center; + vertical-align:middle; + font-weight:bold; + color:red; +} +.AntiCrux-board-cell-hl { + float:left; + background-color:#00FF00; + width:50px; + height:50px; + text-align:center; + vertical-align:middle; +} + +.AntiCrux-board-piece-11 { background-image:url(images/piece_11.png); } +.AntiCrux-board-piece-12 { background-image:url(images/piece_12.png); } +.AntiCrux-board-piece-13 { background-image:url(images/piece_13.png); } +.AntiCrux-board-piece-14 { background-image:url(images/piece_14.png); } +.AntiCrux-board-piece-15 { background-image:url(images/piece_15.png); } +.AntiCrux-board-piece-16 { background-image:url(images/piece_16.png); } +.AntiCrux-board-piece--11 { background-image:url(images/piece_-11.png); } +.AntiCrux-board-piece--12 { background-image:url(images/piece_-12.png); } +.AntiCrux-board-piece--13 { background-image:url(images/piece_-13.png); } +.AntiCrux-board-piece--14 { background-image:url(images/piece_-14.png); } +.AntiCrux-board-piece--15 { background-image:url(images/piece_-15.png); } +.AntiCrux-board-piece--16 { background-image:url(images/piece_-16.png); } diff --git a/anticrux.js b/anticrux.js new file mode 100644 index 0000000..6e5d066 --- /dev/null +++ b/anticrux.js @@ -0,0 +1,2244 @@ +/* + AntiCrux - Artificial intelligence playing AntiChess and AntiChess960 with jQuery Mobile + Copyright (C) 2016-2017, ecrucru + + https://github.com/ecrucru/anticrux/ + http://ecrucru.free.fr/?page=anticrux + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + + "use strict"; + + +// Interesting positions for playing with AntiCrux : +// r1bqk1nr/p2npp1p/1p4p1/8/4P3/6P1/P4b1P/5BR1 w - - Uncertain game +// 3q1b2/4p1pr/4P3/8/6b1/8/5P2/8 w - - Quick win or deep loss +// 8/6k1/3p3p/1p5P/1P6/5p2/1p3P2/8 b - - Pawn game +// 1r6/4npb1/n4k2/7P/P6R/P4K2/2P2P2/2R5 w - - Mate in 6 to be found +// 2r1k1nr/p1pp1ppp/8/8/P7/1R3P2/2PP2PP/1NB1K1NR b - - Mate in 9 to be found +// 1n1qk1n1/r1pp1p1r/1p6/8/8/1P4P1/2PK1P1P/1N3BNR w - - Mate in 10 to be found +// rnb4r/p1pk3p/5P2/8/1p6/1P3P2/P1PNP1P1/R3KBN1 b - - Mate in 10 to be found +// rn2k2r/ppp2p1p/5p2/8/8/N6P/PPPKPP1P/R1B2BNR b - - Mate in 11 to be found +// rnb1kb1r/p1pp1ppp/7n/4P3/1p5R/1P6/P1P1PPP1/RNBQKBN1 w - - Mate in 15 to be found + +// Interesting positions which illustrate the implemented features : +// 8/5k2/8/3P4/8/8/8/8 b - - Accelerated end of game +// 8/P7/1p6/8/8/8/8/8 w - - Accelerated end of game +// k7/1p6/1P6/8/8/8/8/8 w - - Accelerated end of game +// 5R2/8/2k5/8/8/8/8/8 w - - Accelerated end of game (Rc8 and Rf6 are forbidden) +// 8/5P2/8/8/4k1p1/8/8/8 w - - Promotion +// 8/2p5/8/3P4/8/8/8/8 w - - En passant is a forced move +// 7r/7p/8/8/8/5R2/8/8 b - - En passant if no impact on the other pieces +// 2Rn1b1r/1ppppppq/1k3n1p/8/1P6/6P1/2PPPPNP/1KBN1BQR w - - Minimization of the liberty (Rxc7=no minimization, Rxd8=minimization) +// 3R4/8/8/8/8/8/2p5/8 w - - Effect of the option "No statistic on forced moves" +// 6R1/8/8/8/8/2k5/8/8 w - - Hard to finish (maximal number of nodes, no game strategy) +// 8/6p1/4K3/8/7r/8/8/8 b - - Hard to finish (maximal number of nodes) +// k7/8/8/2R5/8/8/8/8 w - - Exploration level by level +// 1n1k4/8/5n2/5p2/3P1P2/1P6/8/8 b - - Nfd7 is the move of 1 knight only + + + +//======== Main class +var AntiCrux = function() { + this._root_node = { + piece : [], + owner : [] + }; + this._init(); + this.clearBoard(); +}; + + +//---- Public members + +AntiCrux.prototype.clearBoard = function(pNode) { + var i; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + if (!this._has(pNode, 'piece', false)) + pNode.piece = []; + if (!this._has(pNode, 'owner', false)) + pNode.owner = []; + + //-- Clears the board + this.freeMemory(); + pNode.player = this.constants.owner.white; + this._buffer = ''; + this._highlight = []; + pNode._history = []; + pNode._history_fen0 = ''; + for (i=0 ; i<64 ; i++) + { + pNode.piece[i] = this.constants.piece.none; + pNode.owner[i] = this.constants.owner.none; + } + pNode = { + piece : pNode.piece, + owner : pNode.owner, + _pendingPromotion : null, + enpassant : null + }; +}; + +AntiCrux.prototype.defaultBoard = function(pFisher, pNode) { + var fisher, i, z, p, krn, pieces; + + //-- Self + if (pFisher === undefined) + pFisher = 519; + if (pNode === undefined) + pNode = this._root_node; + + //-- Clears the board + this.clearBoard(pNode); + if ((pFisher < 1) || (pFisher > 960)) + return false; + this.fisher = pFisher; + fisher = pFisher-1; + + //-- Defines the main line of pieces with the help of Chess960 + // https://en.wikipedia.org/wiki/Chess960 + pieces = [ this.constants.piece.none, + this.constants.piece.none, + this.constants.piece.none, + this.constants.piece.none, + this.constants.piece.none, + this.constants.piece.none, + this.constants.piece.none, + this.constants.piece.none + ]; + //Bishop on a white cell + pieces[Math.floor(0.08*(Math.floor(25*fisher) % 100)+1.5)] = this.constants.piece.bishop; + //Bishop on a black cell + pieces[Math.floor(0.08*(Math.floor(25*Math.floor(fisher/4)) % 100) + 0.5)] = this.constants.piece.bishop; + //Queen + z = Math.floor(Math.floor(fisher/4)/4)/6; + p = Math.floor(6*(z-Math.floor(z)) + 0.5); + for (i=0 ; i<8 ; i++) + { + if (pieces[i] != this.constants.piece.none) + continue; + if (p === 0) + { + pieces[i] = this.constants.piece.queen; + break; + } + p--; + } + //KRN + krn = ['NNRKR', 'NRNKR', 'NRKNR', 'NRKRN', 'RNNKR', 'RNKNR', 'RNKRN', 'RKNNR', 'RKNRN', 'RKRNN'][Math.floor(z)]; + for (i=0 ; i<8 ; i++) + { + if (pieces[i] != this.constants.piece.none) + continue; + + pieces[i] = this.constants.piece.mapping[krn.charAt(0)]; + krn = krn.substring(1); + } + + //-- Sets the pieces + for (i=0 ; i<8 ; i++) + { + pNode.piece[8*0+i] = pieces[i]; + pNode.piece[8*1+i] = this.constants.piece.pawn; + pNode.piece[8*6+i] = this.constants.piece.pawn; + pNode.piece[8*7+i] = pieces[i]; + + pNode.owner[8*0+i] = this.constants.owner.black; + pNode.owner[8*1+i] = this.constants.owner.black; + pNode.owner[8*6+i] = this.constants.owner.white; + pNode.owner[8*7+i] = this.constants.owner.white; + } + pNode._history_fen0 = this.toFen(); + return true; +}; + +AntiCrux.prototype.loadFen = function(pFen, pNode) { + var list, x, y, i, car; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Checks + if (pFen.length === 0) + return false; + + //-- Clears the board + this.clearBoard(pNode); + + //-- Splits the input parameter + list = pFen.split(' '); + + //-- Loads the FEN + x = 0; + y = 0; + for (i=0 ; i 0) + { + if (!that.loadFen(fen, node)) + return false; + } + else + { + moves = moves.split(' '); + if ((player == that.constants.owner.white) && (moves.length % 2 == 1)) //Who was the first player... + playerIndication = that.constants.owner.black; + else + playerIndication = that.constants.owner.white; + for (i=0 ; i 1) + move_promotion = this.constants.piece.mapping[regex[6].substring(1)]; + else + move_promotion = 0; + + //- Move to + move_toX = 'abcdefgh'.indexOf(regex[5].charAt(0)); + move_toY = 8 - parseInt(regex[5].charAt(1)); + + //- Move from : establishes the possible moves + node = this._ai_nodeCopy(pNode, false); + moves = []; + if (pPlayerIndication == this.constants.owner.none) + { + node.player = this.constants.owner.black; + this._ai_nodeMoves(node); + moves = moves.concat(node.moves); + node.player = this.constants.owner.white; + this._ai_nodeMoves(node); + node.moves = moves.concat(node.moves); + } + else + { + node.player = pPlayerIndication; + this._ai_nodeMoves(node); + } + moves = []; + + //- Move from : validates the originating positions + for (i=0 ; i 7) || + (move_fromY < 0) || (move_fromY > 7) || + (move_toX < 0) || (move_toX > 7) || + (move_toY < 0) || (move_toY > 7) || + (move_promotion > this.constants.piece.king) + ) + return false; + pMove = move_promotion*10000 + move_fromY*1000 + move_fromX*100 + move_toY*10 + move_toX; + + //-- Finds the player + player = pNode.owner[8*move_fromY+move_fromX]; + if (player == this.constants.owner.none) + return false; + pNode.player = player; + pNode.lastMove = pMove; + + //-- Verifies if the move is legit + if (pCheckLegit) + { + node = this._ai_nodeCopy(pNode, false); + node.player = player; + this._ai_nodeMoves(node); + valid = false; + for (i=0 ; i=0) && (tX<=7) && (tY>=0) && (tY<=7) && //Assumed to be always true + (pNode.piece[8*tY+tX] == this.constants.piece.pawn) && //Kill an en passant pawn + (pNode.owner[8*tY+tX] != pNode.owner[8*move_fromY+move_fromX]) //Black vs. White + ) { + pNode.piece[8*tY+tX] = this.constants.piece.none; + pNode.owner[8*tY+tX] = this.constants.owner.none; + pNode.enpassant = null; + } + } + //- Marks the cell + else if ( (pNode.piece[8*move_fromY+move_fromX] == this.constants.piece.pawn) && + (Math.abs(move_toY-move_fromY) == 2) + ) + pNode.enpassant = 4*(move_toY+move_fromY) + move_toX; + //- Removes the cell + else + pNode.enpassant = null; + + //-- Performs the move + pNode.piece[8*move_toY+move_toX] = pNode.piece[8*move_fromY+move_fromX]; + pNode.piece[8*move_fromY+move_fromX] = this.constants.piece.none; + pNode.owner[8*move_toY+move_toX] = pNode.owner[8*move_fromY+move_fromX]; + pNode.owner[8*move_fromY+move_fromX] = this.constants.owner.none; + + //-- Promotes the pawn immediately or not + if ((move_toY === 0) || (move_toY === 7)) + { + if (pNode.piece[8*move_toY+move_toX] == this.constants.piece.pawn) + { + //- Forced promotion + if (this.options.variant.promoteQueen) + move_promotion = this.constants.piece.queen; + + //- Effective promotion + if (move_promotion != this.constants.piece.none) + pNode.piece[8*move_toY+move_toX] = move_promotion; + else + pNode._pendingPromotion = 8*move_toY+move_toX; + } + } + + //-- Result + this._highlight = []; + return true; +}; + +AntiCrux.prototype.getMoveAI = function(pPlayer, pNode) { + var i, + maxDepth, curDepth, reg_x, reg_y, reg_mean_x, reg_mean_y, reg_sxx, reg_sxy, reg_a, reg_b, reg_estimate, + val, threshold, better, same, flag, moves; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + if ((pPlayer != this.constants.owner.black) && (pPlayer != this.constants.owner.white)) + return null; + this._buffer = ''; + + //-- Pre-conditions + if (this.hasPendingPromotion(pNode)) + return null; + if (this.options.ai.maxDepth < 3) + this.options.ai.maxDepth = 3; //At depth 2, the algorithm doesn't attack... + this._ai_nodeFreeMemory(pNode); //Should be done by the calling program in any case + pNode.player = pPlayer; + maxDepth = this.options.ai.maxDepth; + + //-- End of game ? + this._ai_nodeMoves(pNode); + if (pNode.moves.length === 0) + return null; + + //-- Oyster : you can't lose against this level + if (this.options.ai.oyster) + { + this._numNodes = 0; + this._reachedDepth = 0; + return pNode.moves[Math.floor(Math.random() * (pNode.moves.length-1) + 0.5)]; + } + + //-- Builds the decision tree level by level + reg_x = []; + reg_y = []; + for (curDepth=3 ; curDepth<=maxDepth ; curDepth++) + { + //- Explores to the temporary lowest level + this._numNodes = 0; + this.options.ai.maxDepth = curDepth; + this._ai_nodeRecurseTree(pPlayer, 0, pNode); + this._reachedDepth = curDepth; + + //- Estimates the number of nodes for the next level + // The mathematical background is at http://keisan.casio.com/exec/system/14059930754231 + if (this._numNodes === 0) + throw 'Internal error - Report any error (#001)'; + // Input data + reg_x.push(curDepth); + reg_y.push(this._numNodes); + // Average + reg_mean_x = 0; + reg_mean_y = 0; + for (i=0 ; i= maxDepth) || //Max depth reached + ( !this.options.ai.wholeNodes && //Exceeded projection with 5% of tolerance + (this.options.ai.maxNodes !== 0) && + (reg_estimate > this.options.ai.maxNodes) + ) || + ( this.options.ai.wholeNodes && + (this.options.ai.maxNodes !== 0) && //Max nodes reached + (this._numNodes >= this.options.ai.maxNodes) + ) + ) + break; + } + this.options.ai.maxDepth = maxDepth; //Restores the initial setting + + //-- Valuates the decision tree entirely + this._ai_nodeSolve(pPlayer, pNode); + + //-- Keeps the moves which lead to fast end of game + if (this.options.ai.acceleratedEndGame && pNode._forced && (pNode.valuationSolver == pNode.player * -this.constants.score.infinite)) + { + threshold = this.constants.score.infinite; + for (i=0 ; i 0) && (pNode.nodes[i]._sequence < threshold)) + threshold = pNode.nodes[i]._sequence; + } + if (threshold == this.constants.score.infinite) + throw 'Internal error - Report any error (#006)'; + for (i=0 ; i 1)) + { + threshold = pPlayer * this.constants.score.infinite; + + //- Finds the corresponding valuation + for (i=0 ; i threshold)) + ) + threshold = pNode.nodes[i].valuationSolver; + } + + //- Removes the weak moves + for (i=0 ; i 1)) + { + flag = false; + for (i=0 ; i threshold)); + same = ((pPlayer == this.constants.owner.white) && (val == threshold)) || + ((pPlayer == this.constants.owner.black) && (val == threshold)); + + //- Selects the move + if (better) + { + moves = []; + threshold = val; + } + if (same || better) + moves.push(pNode.moves[i]); + } + + //-- Final move + switch (moves.length) + { + case 0 : throw 'Internal error - Report any error (#002)'; + case 1 : return moves[0]; + default: return moves[Math.floor(Math.random() * (moves.length-1) + 0.5)]; + } +}; + +AntiCrux.prototype.logMove = function(pMove, pNode) { + //-- Self + if (pNode === undefined) + pNode = this._root_node; + if (pMove === undefined) + { + if (this._has(pNode, 'lastMove', false)) + pMove = pNode.lastMove; + else + return false; + } + + //-- Logs the move + if (typeof pMove !== 'number') + return false; + else + { + pNode._history.push(pMove); + return true; + } +}; + +AntiCrux.prototype.undoMove = function(pNode) { + var i, hist; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Checks + if (!this._has(pNode, '_history', true) || !this._has(pNode, '_history_fen0', true)) + return ''; + + //-- Prepares the board + hist = pNode._history.slice(0, pNode._history.length-1); + this.loadFen(pNode._history_fen0, pNode); + + //-- Builds the new board + for (i=0 ; i'+output+''); + } +}; + +AntiCrux.prototype.moveToString = function(pMove, pNode) { + var move, move_promo, move_fromY, move_fromX, move_toY, move_toX, + buffer, taken, output; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Elements + move = parseInt(pMove); + move_promo = Math.floor(move/10000) % 10; + move_fromY = Math.floor(move/1000 ) % 10; + move_fromX = Math.floor(move/100 ) % 10; + move_toY = Math.floor(move/10 ) % 10; + move_toX = move % 10; + + //-- Piece + output = this.getPieceSymbol( pNode.piece[8*move_fromY+move_fromX], + pNode.owner[8*move_fromY+move_fromX], + this.options.board.symbols + ); + + //-- Taken piece + taken = (pNode.owner[8*move_toY+move_toX] != pNode.owner[8*move_fromY+move_fromX]) && + (pNode.owner[8*move_toY+move_toX] != this.constants.owner.none); + if (this._has(pNode, 'enpassant', false)) + taken = taken || ( (pNode.piece[8*move_fromY+move_fromX] == this.constants.piece.pawn) && + (8*move_toY+move_toX == pNode.enpassant) + ); + + //-- Initial position + if ((this._ai_nodeInventory(pNode.owner[8*move_fromY+move_fromX], pNode.piece[8*move_fromY+move_fromX], undefined, pNode) > 1) || + (taken && (pNode.piece[8*move_fromY+move_fromX] == this.constants.piece.pawn)) + ) { + buffer = 'abcdefgh'.charAt(move_fromX); + if (this._ai_nodeInventory(pNode.owner[8*move_fromY+move_fromX], pNode.piece[8*move_fromY+move_fromX], move_fromX, pNode) > 1) + buffer += 8-move_fromY; + } + else + buffer = ''; + + //-- Simplified notation + if (!taken && (pNode.piece[8*move_fromY+move_fromX] == this.constants.piece.pawn) && (move_fromX == move_toX)) + buffer = ''; + if (!taken && (this._ai_nodeInventory(pNode.owner[8*move_fromY+move_fromX], pNode.piece[8*move_fromY+move_fromX], undefined, pNode) == 1)) + buffer = ''; + if (taken) + buffer += 'x'; + output += buffer; + + //-- Final position + output += 'abcdefgh'.charAt(move_toX); + output += 8-move_toY; + + //-- Promotion + if (move_promo != this.constants.piece.none) + output += '=' + this.getPieceSymbol( move_promo, + pNode.owner[8*move_fromY+move_fromX], + this.options.board.symbols + ); + + //-- Result + return output; +}; + +AntiCrux.prototype.getScore = function(pNode) { + var i, val, valD, valW, valB; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Gets the score per player + valW = 0; + valB = 0; + for (i=0 ; i<64 ; i++) + { + val = this.options.ai.valuation[pNode.piece[i]]; + switch (pNode.owner[i]) + { + case this.constants.owner.black: + valB += val; + break; + case this.constants.owner.white: + valW += val; + break; + } + } + + //-- Final score + valD = (valB > valW ? valB : valW); + if (valD === 0) + return 0; + else + { + if (this._has(pNode, 'valuationSolver', false)) + val = pNode.valuationSolver; + else + { + if (!this._has(pNode, 'valuation', false)) + this._ai_nodeValuate(pNode); + val = pNode.valuation; + } + val = 2*(Math.round(100*(val+valD)/(2*valD))-50); + + //- Adjust the boundaries to correct the effects of the big weights representing a defeat/victory + if (val < -100) + val = -100; + if (val > 100) + val = 100; + return val; + } +}; + +AntiCrux.prototype.getWinner = function(pNode) { + var node = this._ai_nodeCopy((pNode === undefined ? this._root_node : pNode), true); + + //-- Tests for White + node.player = this.constants.owner.white; + this._ai_nodeMoves(node); + if (!this._has(node, 'moves', true)) + return this.constants.owner.white; + + //-- Tests for Black + node.player = this.constants.owner.black; + this._ai_nodeMoves(node); + if (!this._has(node, 'moves', true)) + return this.constants.owner.black; + + //-- No winner + return this.constants.owner.none; +}; + +AntiCrux.prototype.isDraw = function(pNode) { + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Checks + if (!this._has(this, '_reachedDepth', false) || !this._has(pNode, 'valuation', false) || !this._has(pNode, 'valuationSolver', false)) + return false; + + //-- Possible draw + return ( (this._reachedDepth >= 5) && //Sufficient depth for the valuation + (pNode.valuation === 0) && //Equal game on both side + (pNode.valuationSolver === 0) && //No deep opportunity + (this._ai_nodeInventory(this.constants.owner.black, null, undefined, pNode) <= 5) && //Few remaining pieces + (this._ai_nodeInventory(this.constants.owner.white, null, undefined, pNode) <= 5) //Few remaining pieces + ); +}; + +AntiCrux.prototype.isEndGame = function(pNode) { + var node = this._ai_nodeCopy(pNode === undefined ? this._root_node : pNode, false); + this._ai_nodeSwitchPlayer(node); + this._ai_nodeMoves(node); + return !this._has(node, 'moves', true); +}; + +AntiCrux.prototype.highlight = function(pReset, pPosition) { + //-- Clears the highlighted cells + if (pPosition === undefined) + pPosition = null; + if (pReset || (pPosition === null)) + this._highlight = []; + + //-- Applies the highlighted cells (no check of unicity) + if (pPosition === null) + ; //Nothing + else + if (Array.isArray(pPosition)) + this._highlight = this._highlight.concat(pPosition); + else + if (typeof pPosition != 'string') + this._highlight.push(parseInt(pPosition)); + else + if (pPosition.length === 0) + ; //Nothing + else + if (pPosition.match(/^[a-h][1-8]$/)) + this._highlight.push((8-parseInt(pPosition.charAt(1)))*8 + 'abcdefgh'.indexOf(pPosition.charAt(0))); + else + if (pPosition.match(/^[0-7]{2}$/)) + this._highlight.push(parseInt(pPosition)); + else + return false; + return true; +}; + +AntiCrux.prototype.highlightMoves = function() { + var node, i, position; + + //-- Resets the current board + this._highlight = []; + + //-- Gets the possible moves + node = this._ai_nodeCopy(this._root_node, false); + this._ai_nodeMoves(node); + for (i=0 ; i'; + output += '' + this.moveToString(pNode._history[i], node) + ''; + if (!this.movePiece(pNode._history[i], true, this.constants.owner.none, node)) + throw 'Internal error - Report any error (#010)'; + if (i%2 == 1) + output += ''; + } + if (i%2 == 1) + output += ''; + return output + ''; +}; + +AntiCrux.prototype.getDecisionTreeHtml = function(pNode) { + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Extracts the data + this._buffer = ''; + this._ai_nodeTreeHtml(0, '', pNode); + if (this._buffer.length === 0) + this._buffer = 'No data'; + return '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + this._buffer + + ' ' + + '
StaticDeepMoves
'; +}; + +AntiCrux.prototype.getMoves = function(pPlayer, pNode) { + var i, node, maxVal, output; + + //-- Fetches the result of the last calculation of the AI + node = (pNode === undefined ? this._root_node : pNode); + if (!this._has(node, 'nodes', false) || !this._has(node, 'moves', false)) + { + node = this._ai_nodeCopy(node, false); + node.player = pPlayer; + this._ai_nodeMoves(node); + } + + //-- Output + output = ''; + if (this._has(node, 'nodes', true) && this._has(node, 'moves', true)) + { + maxVal = this._ai_getMaxValuation(node); + if (maxVal === 0) + maxVal = 1; + for (i=0 ; i'; + if (node.nodes[i].hasOwnProperty('valuation')) + { + if (node.nodes[i].hasOwnProperty('valuationSolver')) + { + output += '' + this._ai_formatScore(100*node.nodes[i].valuationSolver/maxVal, true); + if (this._has(node.nodes[i], '_win', false) && + (Math.abs(node.nodes[i].valuationSolver) != this.constants.score.infinite) + ) + output += ' *'; + output += ''; + } + else + output += ''; + output += '' + this._ai_formatScore(100*node.nodes[i].valuation/maxVal, true) + ''; + } + else + output += ''; + output += ''; + } + } + return (output.length === 0 ? '' : + '' + + '' + + '' + + '' + + output + + '
Evaluation
MoveDeepStatic
'); +}; + +AntiCrux.prototype.toHtml = function(pNode) { + var x, y, rotated, color, abc, output; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Builds the output + rotated = this.options.board.rotated; //Shortened syntax + output = ''; + color = 1; + abc = 'abcdefgh'; + for (y=(rotated?7:0) ; (!rotated&&(y<8)) || (rotated&&(y>=0)) ; (rotated?y--:y++)) + { + color = 1 - color; + output += '
'; + if (this.options.board.coordinates) + output += '
' + (8-y) + '
'; + for (x=(rotated?7:0) ; (!rotated&&(x<8)) || (rotated&&(x>=0)) ; (rotated?x--:x++)) + { + color = 1 - color; + output += '
'; + if (this.options.board.debugCellId) + output += y + '/' + x + '
' + (8*y+x); + output += '
'; + } + output += '
'; + } + + //-- Coordinates + if (this.options.board.coordinates) + { + abc = abc.toUpperCase(); + output += '
'; + output += '
'; + for (x=0 ; x'; + output += '
'; + } + + //-- Result + return '
' + output + '
'; +}; + +AntiCrux.prototype.toFen = function(pNode) { + // https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation + // https://www.chessclub.com/user/help/PGN-spec + + var i, output, empty, piece; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + if (!this._has(pNode, 'piece', true) || !this._has(pNode, 'owner', true)) + return ''; + + //-- Builds the FEN code for the main board + output = ''; + empty = 0; + for (i=0 ; i<64 ; i++) + { + //Piece + if (pNode.owner[i] == this.constants.owner.none) + empty++; + else + { + if (empty > 0) + { + output += empty; + empty = 0; + } + + //Identifies a piece + piece = this.constants.piece.mapping_rev[pNode.piece[i]]; + if (pNode.owner[i] == this.constants.owner.black) + piece = piece.toLowerCase(); + output += piece; + } + + //Separator + if ((i+1) % 8 === 0) + { + if (empty > 0) + { + output += empty; + empty = 0; + } + if (i < 63) + output += '/'; + } + } + + //-- Player + if (pNode.player == this.constants.owner.black) + output += ' b'; + else + output += ' w'; + + //-- Castling doesnt exist for AntiChess + output += ' -'; + + //-- En passant + if (this._has(pNode, 'enpassant', false)) + output += ' ' + ('abcdefgh'[pNode.enpassant%8]); + else + output += ' -'; + + //-- Halfmove clock: count of ply since the last pawn advance or capturing move (not supported) + output += ' 0'; + + //-- Fullmove number + if (!this._has(pNode, '_history', true)) + output += ' 0'; + else + output += ' ' + Math.ceil(pNode._history.length/2); + + //-- Result + return output; +}; + +AntiCrux.prototype.toText = function(pNode) { + // Use one of the fonts "Chess" available at www.dafont.com + + var x, y, rotated, i, b, car, buffer; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Builds the board + rotated = this.options.board.rotated; //Shortened syntax + buffer = ''; + for (y=(rotated?7:0) ; (!rotated&&(y<8)) || (rotated&&(y>=0)) ; (rotated?y--:y++)) + for (x=(rotated?7:0) ; (!rotated&&(x<8)) || (rotated&&(x>=0)) ; (rotated?x--:x++)) + { + i = 8*y+x; + b = ((x+y)%2 == 1); + + //- Left margin + if (x === (rotated?7:0)) + { + if (this.options.board.coordinates) + buffer += 'àáâãäåæç'[7-y]; + else + buffer += '$'; + } + + //- Nature of the position + switch (this.options.variant.whiteBoard && (pNode.owner[i] != this.constants.owner.none) ? this.constants.owner.white : pNode.owner[i]) + { + case this.constants.owner.none: + car = (b ? '+' : '*'); + break; + case this.constants.owner.white: + car = ' prnbqk'[pNode.piece[i]]; + break; + case this.constants.owner.black: + car = ' otmvwl'[pNode.piece[i]]; + break; + default: + throw 'Internal error - Report any error (#009)'; + } + if (b) + car = car.toUpperCase(); + buffer += car; + + //- Right margin + if (x === (rotated?0:7)) + buffer += '%' + "\n"; + } + + //-- Result + return 'A""""""""S' + "\n" + + buffer + + (this.options.board.coordinates ? (rotated?'DïîíìëêéèF':'DèéêëìíîïF') : 'D((((((((F'); +}; + +AntiCrux.prototype.toPgn = function(pNode) { + // https://www.chessclub.com/user/help/PGN-spec + + var pgn, i, turn, fen0, hist, move, symbols; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Checks + if (!this._has(pNode, '_history', true) || !this._has(pNode, '_history_fen0', true)) + return ''; + + //-- Header + pgn = '[Event "Game"]' + "\n"; + pgn += '[Site "https://github.com/ecrucru/anticrux/"]' + "\n"; + pgn += '[Date "' + (new Date().toISOString().slice(0, 10)) + '"]' + "\n"; + if (this.options.board.rotated) + pgn += '[White "AntiCrux '+this.options.ai.version+'"]' + "\n" + + '[Black "You"]' + "\n"; + else + pgn += '[White "You"]' + "\n" + + '[Black "AntiCrux '+this.options.ai.version+'"]' + "\n"; + pgn += '[Result "?"]' + "\n"; + if (this.hasSetUp(pNode)) + { + pgn += '[SetUp "1"]' + "\n"; + pgn += '[FEN "' + pNode._history_fen0 + '"]' + "\n"; + } + pgn += '[PlyCount "' + (pNode._history.length) +'"]' + "\n"; + pgn += '[Variant "Antichess"]' + "\n"; + pgn += '[TimeControl "-"]' + "\n\n"; + + //-- Deactivates the symbols + symbols = this.options.board.symbols; + this.options.board.symbols = false; + + //-- Loads the initial position + fen0 = pNode._history_fen0; + hist = pNode._history.slice(0); + this.loadFen(pNode._history_fen0, pNode); + pNode._history = hist; + pNode._history_fen0 = fen0; + + //-- Moves + turn = 0; + for (i=0 ; i0 ? ' ' : '') + (++turn) + '.'; + + //- Move + move = this.moveToString(pNode._history[i], pNode); + if (!this.movePiece(pNode._history[i], true, this.constants.owner.none, pNode)) + throw 'Internal error - Report any error (#011)'; + else + { + pgn += ' ' + move; + this._ai_nodeSwitchPlayer(pNode); + } + } + + //-- Final position + switch (this.getWinner(pNode)) + { + case this.constants.owner.white: + pgn += '# 1-0'; + pgn = pgn.replace('[Result "?"]', '[Result "1-0"]'); + break; + case this.constants.owner.black: + pgn += '# 0-1'; + pgn = pgn.replace('[Result "?"]', '[Result "0-1"]'); + break; + } + + //-- Restores the symbols + this.options.board.symbols = symbols; + + //-- Result + return pgn; +}; + +AntiCrux.prototype.freeMemory = function() { + this._ai_nodeFreeMemory(this._root_node); +}; + + +//---- Private members + +AntiCrux.prototype._init = function() { + //-- Constants + this.constants = { + piece : { + none : 0, //Must be zero + pawn : 1, + rook : 2, + knight : 3, + bishop : 4, + queen : 5, + king : 6 //Must be the highest ID + }, + owner : { + black : -1, //Negative points are black + none : 0, + white : 1 //Positive points are white + }, + score : { + infinite : 16777217, //8^8+1 + neutral : 0 + } + }; + this.constants.piece.mapping = { + '' : this.constants.piece.none, + 'p' : this.constants.piece.pawn, + 'P' : this.constants.piece.pawn, + 'r' : this.constants.piece.rook, + 'R' : this.constants.piece.rook, + 'n' : this.constants.piece.knight, + 'N' : this.constants.piece.knight, + 'b' : this.constants.piece.bishop, + 'B' : this.constants.piece.bishop, + 'q' : this.constants.piece.queen, + 'Q' : this.constants.piece.queen, + 'k' : this.constants.piece.king, + 'K' : this.constants.piece.king + }; + this.constants.piece.mapping_rev = []; + this.constants.piece.mapping_rev[this.constants.piece.none] = ''; + this.constants.piece.mapping_rev[this.constants.piece.pawn] = 'P'; + this.constants.piece.mapping_rev[this.constants.piece.rook] = 'R'; + this.constants.piece.mapping_rev[this.constants.piece.knight] = 'N'; + this.constants.piece.mapping_rev[this.constants.piece.bishop] = 'B'; + this.constants.piece.mapping_rev[this.constants.piece.queen] = 'Q'; + this.constants.piece.mapping_rev[this.constants.piece.king] = 'K'; + + //-- Options + this.options = { + ai : { + version : 'v0.1', //Version of AntiCrux + valuation : [], //Valuation of each piece + maxDepth : 12, //Maximal depth for the search dependant on the simplification of the tree + maxNodes : 100000, //Maximal number of nodes before the game exhausts your memory (0=Dangerously infinite) + minimizeLiberty : true, //TRUE allows a deeper inspection by forcing the moves, FALSE does a complete evaluation + noStatOnForcedMove : true, //TRUE plays faster but the player won't be able to check the situation + wholeNodes : false, //TRUE evaluates the depths until the limit is reached and makes the analysis stronger + randomizedSearch : true, //TRUE helps the game to not played the same pieces + pessimisticScenario : true, //TRUE makes the algorithm stronger, FALSE is more random + bestStaticScore : true, //TRUE makes the algorithm stronger, FALSE is more random for low determined situations + opportunistic : false, //TRUE helps to find a winning position + handicap : 0, //To weaken the algorithm, remove between 0% and 100% of the moves above a fixed number of moves + acceleratedEndGame : true, //TRUE makes more direct kills but doesn't change the output + oyster : false //TRUE is a full random play + }, + variant : { + promoteQueen : false, //TRUE only promotes pawns as queen + activePawns : true, //TRUE makes the pawns stronger for the valuation once they are moved + whiteBoard : false //TRUE makes the board fully white + }, + board : { + rotated : false, //TRUE rotates the board at 180° + symbols : true, //Symbols in Unicode for the display + fisher : Math.floor(Math.random()*960)+1, //Default layout (519=classical) + coordinates : true, //TRUE displays the coordinates around the board + noStatOnOwnMove : true, //TRUE plays faster but the player won't be able to know if he played the right wove + fullDecisionTree : false, //TRUE displays the full decision tree in the user interface and this may represent too much data. The option is essentially used for debugging purposes + debugCellId : false //TRUE display the internal identifier of every cell of the board when there is no piece on it + } + }; + this.options.ai.valuation[ this.constants.piece.none ] = 0; + this.options.ai.valuation[ this.constants.piece.pawn ] = 100; + this.options.ai.valuation[-this.constants.piece.pawn ] = 180; //A pawn is more active when it is released + this.options.ai.valuation[ this.constants.piece.rook ] = 500; + this.options.ai.valuation[ this.constants.piece.knight] = 300; + this.options.ai.valuation[ this.constants.piece.bishop] = 300; + this.options.ai.valuation[ this.constants.piece.queen ] = 900; + this.options.ai.valuation[ this.constants.piece.king ] = 250; +}; + +AntiCrux.prototype._has = function(pNode, pField, pLengthCheck) { + var b = ((pNode !== undefined) && (pNode !== null)); + if (b) + { + b = pNode.hasOwnProperty(pField); + if (b && (pNode[pField] === null)) + return false; + if (b && pLengthCheck) + b = (pNode[pField].length > 0); + } + return b; +}; + +AntiCrux.prototype._ai_nodeCopy = function(pNode, pFull) { + //-- Clones the node + var newNode = { + player : pNode.player, + piece : pNode.piece.slice(0), + owner : pNode.owner.slice(0), + enpassant : (pNode.hasOwnProperty('enpassant') ? pNode.enpassant : null) + }; + + //-- Extended copy + if (pFull) + { + if (this._has(pNode, 'valuation', false)) + newNode.valuation = pNode.valuation; + if (this._has(pNode, 'valuationSolver', false)) + newNode.valuationSolver = pNode.valuationSolver; + if (this._has(pNode, 'moves', false)) + newNode.moves = pNode.moves.slice(0); + if (this._has(pNode, '_pendingPromotion', false)) + newNode._pendingPromotion = pNode._pendingPromotion; + } + + //-- Result + return newNode; +}; + +AntiCrux.prototype._ai_nodeSwitchPlayer = function(pNode) { + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Switches the players + if (pNode.player == this.constants.owner.white) + pNode.player = this.constants.owner.black; + else + pNode.player = this.constants.owner.white; +}; + +AntiCrux.prototype._ai_nodeInventory = function(pPlayer, pPiece, pColumn, pNode) { + var i, counter; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Counts + counter = 0; + for (i=0 ; i<64 ; i++) + if ( ((pNode.owner[i] == pPlayer) || (pPlayer === null)) && + ((pNode.piece[i] == pPiece ) || (pPiece === null)) + ) { + if (pColumn !== undefined) + if (i%8 != pColumn) + continue; + counter++; + } + return counter; +}; + +AntiCrux.prototype._ai_nodeLocatePiece = function(pPlayer, pPiece, pNode) { + var x, y; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Locates the piece + for (y=0 ; y<8 ; y++) + for (x=0 ; x<8 ; x++) + if ( ((pNode.owner[8*y+x] == pPlayer) || (pPlayer === null)) && + ((pNode.piece[8*y+x] == pPiece ) || (pPiece === null)) + ) + return {x:x, y:y}; + return null; +}; + +AntiCrux.prototype._ai_nodeMoves = function(pNode) { + var i, x, y, t, epX, epY, tX, tY, + move_base, moves, forced, + directionX, directionY, directionXY; + + //-- Local functions (macros) + var that = this; + var moveLegit = function(pY, pX, pKill, pRestricted) { + var target_type, opponent, promo_move, promoted; + + //- Boundaries + if ((pX<0) || (pX>7) || (pY<0) || (pY>7)) + return false; + + //- Validity + target_type = pNode.owner[8*pY+pX]; + opponent = (target_type != pNode.player) && + (target_type != that.constants.owner.none); //Target is opponent + if ((target_type == pNode.player) || (opponent && !pKill)) //Impossible move + return false; + + //- Forced move + if (opponent && !forced) + { + moves = []; + forced = true; + } + + //- Logs the move + if (opponent || (!opponent && !forced && !pRestricted)) + { + //Promotes a pawn + promoted = false; + if (pNode.piece[8*y+x] == that.constants.piece.pawn) + { + if ( ((pY === 0) && (pNode.owner[8*y+x] == that.constants.owner.white)) || + ((pY === 7) && (pNode.owner[8*y+x] == that.constants.owner.black)) + ) + { + promo_move = move_base + 10*pY + pX; + moves.push(promo_move + 10000*that.constants.piece.queen); //All the promotions will be analyzed later to eliminate the wrong one + if (!that.options.variant.promoteQueen) + { + moves.push(promo_move + 10000*that.constants.piece.rook); + moves.push(promo_move + 10000*that.constants.piece.knight); + moves.push(promo_move + 10000*that.constants.piece.bishop); + moves.push(promo_move + 10000*that.constants.piece.king); + } + promoted = true; + } + } + + //Normal move + if (!promoted) + moves.push(move_base + 10*pY + pX); + } + + //- Result + return !opponent; + }; + + //-- Checks + if ((pNode === undefined) || (pNode === null)) + return; + + //-- Scans every position + forced = false; + moves = []; + for (y=0 ; y<8 ; y++) + { + for (x=0 ; x<8 ; x++) + { + i = 8*y + x; + + //- Initialization for the piece + if (pNode.owner[i] != pNode.player) + continue; + move_base = y*1000 + x*100; + + //- Processing of the piece + switch (pNode.piece[i]) + { + case this.constants.piece.none: + continue; + + case this.constants.piece.pawn: + directionY = -pNode.player; + + // Straight and by side + if (moveLegit(y+directionY, x, false, false)) + { + if (((directionY==-1) && (y==6)) || + ((directionY== 1) && (y==1)) + ) + moveLegit(y+2*directionY, x, false, false); + } + moveLegit(y+directionY, x-1, true, true); + moveLegit(y+directionY, x+1, true, true); + + // En passant + if (this._has(pNode, 'enpassant', false)) + { + //Source pawn at y/x + //Mid position at epX/epY + epX = pNode.enpassant % 8; + epY = Math.floor(pNode.enpassant / 8); + //Target pawn at tY/tX + tX = epX; + tY = epY-directionY; + //Check + if ((epX>=0) && (epX<=7) && (epY>=0) && (epY<=7) && //Assumed to be always true + ( tX>=0) && ( tX<=7) && ( tY>=0) && ( tY<=7) && //Assumed to be always true + (Math.abs(epX-x) == 1) && (epY-y == directionY) && //Right distance + (pNode.piece[i ] == this.constants.piece.pawn) && //Right exchanged pieces + (pNode.piece[8*epY+epX] == this.constants.piece.none) && + (pNode.piece[8* tY+ tX] == this.constants.piece.pawn) && + (pNode.owner[8*epY+epX] != pNode.owner[8*tY+tX]) + ) { + if (!forced) + moves = []; + forced = true; + moves.push(move_base + 10*epY + epX); + } + } + break; + + case this.constants.piece.queen: + case this.constants.piece.rook: + // Moves + for (directionX=1 ; directionX<8 ; directionX++) + if (!moveLegit(y, x+directionX, true, false)) + break; + for (directionX=1 ; directionX<8 ; directionX++) + if (!moveLegit(y, x-directionX, true, false)) + break; + for (directionY=1 ; directionY<8 ; directionY++) + if (!moveLegit(y+directionY, x, true, false)) + break; + for (directionY=1 ; directionY<8 ; directionY++) + if (!moveLegit(y-directionY, x, true, false)) + break; + if (pNode.piece[i] == this.constants.piece.rook) // Queen = Rook + Bishop + break; + //else no break, yes ! + + case this.constants.piece.bishop: + for (directionXY=1 ; directionXY<8 ; directionXY++) + if (!moveLegit(y+directionXY, x+directionXY, true, false)) + break; + for (directionXY=1 ; directionXY<8 ; directionXY++) + if (!moveLegit(y+directionXY, x-directionXY, true, false)) + break; + for (directionXY=1 ; directionXY<8 ; directionXY++) + if (!moveLegit(y-directionXY, x+directionXY, true, false)) + break; + for (directionXY=1 ; directionXY<8 ; directionXY++) + if (!moveLegit(y-directionXY, x-directionXY, true, false)) + break; + break; + + case this.constants.piece.king: + for (directionX=-1 ; directionX<=1 ; directionX++) + { + for (directionY=-1 ; directionY<=1 ; directionY++) + { + if ((directionX === 0) && (directionY === 0)) + continue; + moveLegit(y+directionY, x+directionX, true, false); + } + } + break; + + case this.constants.piece.knight: + moveLegit(y-2, x-1, true, false); + moveLegit(y-2, x+1, true, false); + moveLegit(y+2, x-1, true, false); + moveLegit(y+2, x+1, true, false); + moveLegit(y-1, x-2, true, false); + moveLegit(y-1, x+2, true, false); + moveLegit(y+1, x-2, true, false); + moveLegit(y+1, x+2, true, false); + break; + + default: + throw 'Internal error - Report any error (#003)'; + } + } + } + + //-- Randomized search + // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + if (this.options.ai.randomizedSearch) + { + for (x=moves.length-1 ; x>=0 ; x--) + { + y = Math.floor(Math.random() * x + 0.5); + t = moves[y]; + moves[y] = moves[x]; + moves[x] = t; + } + } + + //-- Results + pNode.moves = moves; +}; + +AntiCrux.prototype._ai_nodeCreateNodes = function(pNode) { + var i, node; + + //-- Checks + if (!pNode.hasOwnProperty('moves')) + return; + + //-- Builds the new sub-nodes + pNode.nodes = []; + for (i=0 ; i 0) && (pNode.player == pPlayer)) + { + //- Number of moves to remove (simulation of an handicap) + if (pNode.moves.length > 4) + min_moves = Math.floor((pNode.moves.length-4) * this.options.ai.handicap / 100); + else + min_moves = 0; + //- Removes random valid moves + for (i=min_moves ; i>0 ; i--) + pNode.moves.splice(Math.floor(Math.random() * pNode.moves.length), 1); + } + if (!this._has(pNode, 'nodes', true) || + (pNode.nodes.length != pNode.moves.length) + ) + this._ai_nodeCreateNodes(pNode); + + //-- Kills the bad sub-levels to constraint the opponent + min_moves = this.constants.score.infinite; + for (i=0 ; i 0) && (pNode.nodes[i].moves.length < min_moves)) + min_moves = pNode.nodes[i].moves.length; + } + killed = false; + for (i=0 ; i min_moves)) + { + pNode.moves[i] = 0; + pNode.nodes[i] = null; + killed = true; + } + else + { + this._numNodes++; + this._ai_nodeValuate(pNode.nodes[i]); + if ( (pDepth >= this.options.ai.maxDepth) || + ((this.options.ai.maxNodes !== 0) && (this._numNodes >= this.options.ai.maxNodes)) + ) + ; //No recursive search + else + { + if ( !this.options.ai.noStatOnForcedMove || + (this.options.ai.noStatOnForcedMove && (pNode.moves.length > 1)) + ) + this._ai_nodeRecurseTree(pPlayer, pDepth+1, pNode.nodes[i]); + } + } + } + + //-- Compacts the arrays + if (killed) + { + for (i=pNode.moves.length-1 ; i>=0 ; i--) + if (pNode.moves[i] === 0) + pNode.moves.splice(i, 1); + for (i=pNode.nodes.length-1 ; i>=0 ; i--) + if (pNode.nodes[i] === null) + pNode.nodes.splice(i, 1); + if (pNode.moves.length != pNode.nodes.length) + throw 'Internal error - Report any error (#005)'; + } +}; + +AntiCrux.prototype._ai_nodeValuate = function(pNode) { + var i, val, valB, valW; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Gets the score per player + valB = 0; + valW = 0; + for (i=0 ; i<64 ; i++) + { + //- Determines the value of the piece + if ( this.options.variant.activePawns && + (pNode.piece[i] == this.constants.piece.pawn) && + ( ((pNode.owner[i] == this.constants.owner.black) && (Math.floor(i/8) != 1)) || + ((pNode.owner[i] == this.constants.owner.white) && (Math.floor(i/8) != 6)) + ) + ) + val = this.options.ai.valuation[-pNode.piece[i]]; + else + val = this.options.ai.valuation[pNode.piece[i]]; + + //- Assigns the value to the right player + switch (pNode.owner[i]) + { + case this.constants.owner.black: + valB += val; + break; + case this.constants.owner.white: + valW += val; + break; + } + } + + //-- Valuates the position + if (valB === 0) + pNode.valuation = this.constants.score.infinite; //No more piece for Black + else if (valW === 0) + pNode.valuation = -this.constants.score.infinite; //No more piece for White + else + pNode.valuation = this.constants.owner.black*valB + //Normal case + this.constants.owner.white*valW; + + //-- No move possible anymore + if (this._has(pNode, 'moves', false)) + if (pNode.moves.length === 0) + pNode.valuation = pNode.player * -this.constants.score.infinite; +}; + +AntiCrux.prototype._ai_getMaxValuation = function(pNode) { + var i, val, valW, valB; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Valuates the position + valW = 0; + valB = 0; + for (i=0 ; i<64 ; i++) + { + val = this.options.ai.valuation[pNode.piece[i]]; + switch (pNode.owner[i]) + { + case this.constants.owner.black: + valB += val; + break; + case this.constants.owner.white: + valW += val; + break; + } + } + return (valB > valW ? valB : valW); +}; + +AntiCrux.prototype._ai_nodeSolve = function(pPlayer, pNode) { + var i, allForced, hasForced, condition, threshold, val, counter; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Checks the maximal depth + if (!this._has(pNode, 'nodes', true)) + { + //- Applies the valuation for the solver + pNode.valuationSolver = pNode.valuation; + pNode._forced = true; //All the lowest levels are defined as forced moves + pNode._sequence = (pNode.valuationSolver==pPlayer*-this.constants.score.infinite ? 1 : 0); //Will help for quicker ends of game + if (this.options.ai.opportunistic && (pNode._sequence == 1)) + pNode._win = true; + return; + } + + //-- Sets the flag of forced moves + Updates the lowest valuations recursively + allForced = true; + hasForced = false; + for (i=0 ; i threshold)) + ) + threshold = pNode.nodes[i].valuationSolver; + } + + //- Remove the weak moves + for (i=0 ; i val)) || + ((pPlayer == this.constants.owner.black) && (pNode.nodes[i].valuationSolver < val)) + ) + val = pNode.nodes[i].valuationSolver; + } + pNode.valuationSolver = val; + } + + //-- Calculates the sequence which leads to faster end of game + if (!this.options.ai.acceleratedEndGame) + pNode._sequence = 0; + else + { + val = this.constants.score.infinite; + for (i=0 ; i 0) && (pNode.nodes[i]._sequence < val)) + val = pNode.nodes[i]._sequence; + } + pNode._sequence = (pNode._forced && (pNode.valuationSolver==pPlayer*-this.constants.score.infinite) ? val+1 : 0); + } +}; + +AntiCrux.prototype._ai_formatScore = function(pValue, pPercent) { + if ((pPercent && (pValue < -100)) || (pValue == -this.constants.score.infinite)) + return '-∞'; + if ((pPercent && (pValue > 100)) || (pValue == this.constants.score.infinite)) + return '+∞'; + return pValue.toFixed(0) + (pPercent ? '%' : ''); +}; + +AntiCrux.prototype._ai_nodeTreeHtml = function(pDepth, pHTML, pNode) { + var i, j, subHTML, writeMode; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Checks + if (!this._has(pNode, 'nodes', false)) + return; + + //-- Formats + for (i=0 ; i= 3) + ); + + //- Valuation + if (writeMode) + { + this._buffer += ''; + if (pNode.nodes[i].hasOwnProperty('valuation')) + { + this._buffer += '' + this._ai_formatScore(pNode.nodes[i].valuation, false) + ''; + if (pNode.nodes[i].hasOwnProperty('valuationSolver')) + this._buffer += '' + this._ai_formatScore(pNode.nodes[i].valuationSolver, false) + ''; + else + this._buffer += ' '; + } + else + this._buffer += '  '; + } + + //- New move + subHTML += '' + this.moveToString(pNode.moves[i], pNode) + ''; + if (writeMode) + { + this._buffer += subHTML; + for (j=pDepth ; j<4 ; j++) + this._buffer += ' '; + this._buffer += ''; + } + + //- Next level + if (pNode.nodes[i].hasOwnProperty('nodes') && (pDepth < 4)) + this._ai_nodeTreeHtml(pDepth+1, subHTML, pNode.nodes[i]); + } +}; + +AntiCrux.prototype._ai_nodeFreeMemory = function(pNode) { + var i; + + //-- Self + if (pNode === undefined) + pNode = this._root_node; + + //-- Checks + if (!pNode.hasOwnProperty('nodes')) + return; + if (pNode.nodes === null) + return; + + //-- Removes the links between the objects to help the garbage collector to remove the unused objects + for (i=0 ; i. +*/ +"use strict";var AntiCrux=function(){this._root_node={piece:[],owner:[]},this._init(),this.clearBoard()};AntiCrux.prototype.clearBoard=function(t){var e;for(void 0===t&&(t=this._root_node),this._has(t,"piece",!1)||(t.piece=[]),this._has(t,"owner",!1)||(t.owner=[]),this.freeMemory(),t.player=this.constants.owner.white,this._buffer="",this._highlight=[],t._history=[],t._history_fen0="",e=0;e<64;e++)t.piece[e]=this.constants.piece.none,t.owner[e]=this.constants.owner.none;t={piece:t.piece,owner:t.owner,_pendingPromotion:null,enpassant:null}},AntiCrux.prototype.defaultBoard=function(t,e){var n,o,s,i,a,r;if(void 0===t&&(t=519),void 0===e&&(e=this._root_node),this.clearBoard(e),t<1||t>960)return!1;for(this.fisher=t,n=t-1,r=[this.constants.piece.none,this.constants.piece.none,this.constants.piece.none,this.constants.piece.none,this.constants.piece.none,this.constants.piece.none,this.constants.piece.none,this.constants.piece.none],r[Math.floor(.08*(Math.floor(25*n)%100)+1.5)]=this.constants.piece.bishop,r[Math.floor(.08*(Math.floor(25*Math.floor(n/4))%100)+.5)]=this.constants.piece.bishop,s=Math.floor(Math.floor(n/4)/4)/6,i=Math.floor(6*(s-Math.floor(s))+.5),o=0;o<8;o++)if(r[o]==this.constants.piece.none){if(0===i){r[o]=this.constants.piece.queen;break}i--}for(a=["NNRKR","NRNKR","NRKNR","NRKRN","RNNKR","RNKNR","RNKRN","RKNNR","RKNRN","RKRNN"][Math.floor(s)],o=0;o<8;o++)r[o]==this.constants.piece.none&&(r[o]=this.constants.piece.mapping[a.charAt(0)],a=a.substring(1));for(o=0;o<8;o++)e.piece[0+o]=r[o],e.piece[8+o]=this.constants.piece.pawn,e.piece[48+o]=this.constants.piece.pawn,e.piece[56+o]=r[o],e.owner[0+o]=this.constants.owner.black,e.owner[8+o]=this.constants.owner.black,e.owner[48+o]=this.constants.owner.white,e.owner[56+o]=this.constants.owner.white;return e._history_fen0=this.toFen(),!0},AntiCrux.prototype.loadFen=function(t,e){var n,o,s,i,a;if(void 0===e&&(e=this._root_node),0===t.length)return!1;for(this.clearBoard(e),n=t.split(" "),o=0,s=0,i=0;i0){if(!n.loadFen(o,r))return!1}else for(s=s.split(" "),a=i==n.constants.owner.white&&s.length%2==1?n.constants.owner.black:n.constants.owner.white,h=0;h1?this.constants.piece.mapping[s[6].substring(1)]:0,g="abcdefgh".indexOf(s[5].charAt(0)),w=8-parseInt(s[5].charAt(1)),a=this._ai_nodeCopy(o,!1),r=[],n==this.constants.owner.none?(a.player=this.constants.owner.black,this._ai_nodeMoves(a),r=r.concat(a.moves),a.player=this.constants.owner.white,this._ai_nodeMoves(a),a.moves=r.concat(a.moves)):(a.player=n,this._ai_nodeMoves(a)),r=[],h=0;h7||f<0||f>7||g<0||g>7||w<0||w>7||_>this.constants.piece.king)return!1;if(t=1e4*_+1e3*f+100*v+10*w+g,i=o.owner[8*f+v],i==this.constants.owner.none)return!1;if(o.player=i,o.lastMove=t,e){for(a=this._ai_nodeCopy(o,!1),a.player=i,this._ai_nodeMoves(a),u=!1,h=0;h=0&&l<=7&&d>=0&&d<=7&&o.piece[8*d+l]==this.constants.piece.pawn&&o.owner[8*d+l]!=o.owner[8*f+v]&&(o.piece[8*d+l]=this.constants.piece.none,o.owner[8*d+l]=this.constants.owner.none,o.enpassant=null)):o.piece[8*f+v]==this.constants.piece.pawn&&2==Math.abs(w-f)?o.enpassant=4*(w+f)+g:o.enpassant=null,o.piece[8*w+g]=o.piece[8*f+v],o.piece[8*f+v]=this.constants.piece.none,o.owner[8*w+g]=o.owner[8*f+v],o.owner[8*f+v]=this.constants.owner.none,0!==w&&7!==w||o.piece[8*w+g]==this.constants.piece.pawn&&(this.options.variant.promoteQueen&&(_=this.constants.piece.queen),_!=this.constants.piece.none?o.piece[8*w+g]=_:o._pendingPromotion=8*w+g),this._highlight=[],!0},AntiCrux.prototype.getMoveAI=function(t,e){var n,o,s,i,a,r,h,c,p,l,d,u,_,f,v,w,g,y;if(void 0===e&&(e=this._root_node),t!=this.constants.owner.black&&t!=this.constants.owner.white)return null;if(this._buffer="",this.hasPendingPromotion(e))return null;if(this.options.ai.maxDepth<3&&(this.options.ai.maxDepth=3),this._ai_nodeFreeMemory(e),e.player=t,o=this.options.ai.maxDepth,this._ai_nodeMoves(e),0===e.moves.length)return null;if(this.options.ai.oyster)return this._numNodes=0,this._reachedDepth=0,e.moves[Math.floor(Math.random()*(e.moves.length-1)+.5)];for(i=[],a=[],s=3;s<=o;s++){if(this._numNodes=0,this.options.ai.maxDepth=s,this._ai_nodeRecurseTree(t,0,e),this._reachedDepth=s,0===this._numNodes)throw"Internal error - Report any error (#001)";for(i.push(s),a.push(this._numNodes),r=0,h=0,n=0;n=o||!this.options.ai.wholeNodes&&0!==this.options.ai.maxNodes&&u>this.options.ai.maxNodes||this.options.ai.wholeNodes&&0!==this.options.ai.maxNodes&&this._numNodes>=this.options.ai.maxNodes)break}if(this.options.ai.maxDepth=o,this._ai_nodeSolve(t,e),this.options.ai.acceleratedEndGame&&e._forced&&e.valuationSolver==e.player*-this.constants.score.infinite){for(f=this.constants.score.infinite,n=0;n0&&e.nodes[n]._sequence1){for(f=t*this.constants.score.infinite,n=0;nf)&&(f=e.nodes[n].valuationSolver);for(n=0;n1)for(g=!1,n=0;nf,w=t==this.constants.owner.white&&_==f||t==this.constants.owner.black&&_==f,v&&(y=[],f=_),(w||v)&&y.push(e.moves[n]));switch(y.length){case 0:throw"Internal error - Report any error (#002)";case 1:return y[0];default:return y[Math.floor(Math.random()*(y.length-1)+.5)]}},AntiCrux.prototype.logMove=function(t,e){if(void 0===e&&(e=this._root_node),void 0===t){if(!this._has(e,"lastMove",!1))return!1;t=e.lastMove}return"number"==typeof t&&(e._history.push(t),!0)},AntiCrux.prototype.undoMove=function(t){var e,n;if(void 0===t&&(t=this._root_node),!this._has(t,"_history",!0)||!this._has(t,"_history_fen0",!0))return"";for(n=t._history.slice(0,t._history.length-1),this.loadFen(t._history_fen0,t),e=0;e'+o+""}return t==this.constants.piece.pawn?"":this.constants.piece.mapping_rev[t].toUpperCase()},AntiCrux.prototype.moveToString=function(t,e){var n,o,s,i,a,r,h,c,p;return void 0===e&&(e=this._root_node),n=parseInt(t),o=Math.floor(n/1e4)%10,s=Math.floor(n/1e3)%10,i=Math.floor(n/100)%10,a=Math.floor(n/10)%10,r=n%10,p=this.getPieceSymbol(e.piece[8*s+i],e.owner[8*s+i],this.options.board.symbols),c=e.owner[8*a+r]!=e.owner[8*s+i]&&e.owner[8*a+r]!=this.constants.owner.none,this._has(e,"enpassant",!1)&&(c=c||e.piece[8*s+i]==this.constants.piece.pawn&&8*a+r==e.enpassant),this._ai_nodeInventory(e.owner[8*s+i],e.piece[8*s+i],void 0,e)>1||c&&e.piece[8*s+i]==this.constants.piece.pawn?(h="abcdefgh".charAt(i),this._ai_nodeInventory(e.owner[8*s+i],e.piece[8*s+i],i,e)>1&&(h+=8-s)):h="",c||e.piece[8*s+i]!=this.constants.piece.pawn||i!=r||(h=""),c||1!=this._ai_nodeInventory(e.owner[8*s+i],e.piece[8*s+i],void 0,e)||(h=""),c&&(h+="x"),p+=h,p+="abcdefgh".charAt(r),p+=8-a,o!=this.constants.piece.none&&(p+="="+this.getPieceSymbol(o,e.owner[8*s+i],this.options.board.symbols)),p},AntiCrux.prototype.getScore=function(t){var e,n,o,s,i;for(void 0===t&&(t=this._root_node),s=0,i=0,e=0;e<64;e++)switch(n=this.options.ai.valuation[t.piece[e]],t.owner[e]){case this.constants.owner.black:i+=n;break;case this.constants.owner.white:s+=n}return o=i>s?i:s,0===o?0:(this._has(t,"valuationSolver",!1)?n=t.valuationSolver:(this._has(t,"valuation",!1)||this._ai_nodeValuate(t),n=t.valuation),n=2*(Math.round(100*(n+o)/(2*o))-50),n<-100&&(n=-100),n>100&&(n=100),n)},AntiCrux.prototype.getWinner=function(t){var e=this._ai_nodeCopy(void 0===t?this._root_node:t,!0);return e.player=this.constants.owner.white,this._ai_nodeMoves(e),this._has(e,"moves",!0)?(e.player=this.constants.owner.black,this._ai_nodeMoves(e),this._has(e,"moves",!0)?this.constants.owner.none:this.constants.owner.black):this.constants.owner.white},AntiCrux.prototype.isDraw=function(t){return void 0===t&&(t=this._root_node),!!(this._has(this,"_reachedDepth",!1)&&this._has(t,"valuation",!1)&&this._has(t,"valuationSolver",!1))&&(this._reachedDepth>=5&&0===t.valuation&&0===t.valuationSolver&&this._ai_nodeInventory(this.constants.owner.black,null,void 0,t)<=5&&this._ai_nodeInventory(this.constants.owner.white,null,void 0,t)<=5)},AntiCrux.prototype.isEndGame=function(t){var e=this._ai_nodeCopy(void 0===t?this._root_node:t,!1);return this._ai_nodeSwitchPlayer(e),this._ai_nodeMoves(e),!this._has(e,"moves",!0)},AntiCrux.prototype.highlight=function(t,e){if(void 0===e&&(e=null),(t||null===e)&&(this._highlight=[]),null===e);else if(Array.isArray(e))this._highlight=this._highlight.concat(e);else if("string"!=typeof e)this._highlight.push(parseInt(e));else if(0===e.length);else if(e.match(/^[a-h][1-8]$/))this._highlight.push(8*(8-parseInt(e.charAt(1)))+"abcdefgh".indexOf(e.charAt(0)));else{if(!e.match(/^[0-7]{2}$/))return!1;this._highlight.push(parseInt(e))}return!0},AntiCrux.prototype.highlightMoves=function(){var t,e,n;for(this._highlight=[],t=this._ai_nodeCopy(this._root_node,!1),this._ai_nodeMoves(t),e=0;e',n=0;n"+Math.floor((n+2)/2)+""),o+=""+this.moveToString(t._history[n],e)+"",!this.movePiece(t._history[n],!0,this.constants.owner.none,e))throw"Internal error - Report any error (#010)";n%2==1&&(o+="")}return n%2==1&&(o+=""),o+""},AntiCrux.prototype.getDecisionTreeHtml=function(t){return void 0===t&&(t=this._root_node),this._buffer="",this._ai_nodeTreeHtml(0,"",t),0===this._buffer.length&&(this._buffer='No data'),'\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'+this._buffer+"\t
StaticDeepMoves
"},AntiCrux.prototype.getMoves=function(t,e){var n,o,s,i;if(o=void 0===e?this._root_node:e,this._has(o,"nodes",!1)&&this._has(o,"moves",!1)||(o=this._ai_nodeCopy(o,!1),o.player=t,this._ai_nodeMoves(o)),i="",this._has(o,"nodes",!0)&&this._has(o,"moves",!0))for(s=this._ai_getMaxValuation(o),0===s&&(s=1),n=0;n"+this.moveToString(o.moves[n],o)+"",o.nodes[n].hasOwnProperty("valuation")?(o.nodes[n].hasOwnProperty("valuationSolver")?(i+=""+this._ai_formatScore(100*o.nodes[n].valuationSolver/s,!0),this._has(o.nodes[n],"_win",!1)&&Math.abs(o.nodes[n].valuationSolver)!=this.constants.score.infinite&&(i+=" *"),i+=""):i+="",i+=""+this._ai_formatScore(100*o.nodes[n].valuation/s,!0)+""):i+="",i+="");return 0===i.length?"":''+i+"
Evaluation
MoveDeepStatic
"},AntiCrux.prototype.toHtml=function(t){var e,n,o,s,i,a;for(void 0===t&&(t=this._root_node),o=this.options.board.rotated,a="",s=1,i="abcdefgh",n=o?7:0;!o&&n<8||o&&n>=0;o?n--:n++){for(s=1-s,a+='
',this.options.board.coordinates&&(a+='
'+(8-n)+"
"),e=o?7:0;!o&&e<8||o&&e>=0;o?e--:e++)s=1-s,a+='
',this.options.board.debugCellId&&(a+=n+"/"+e+"
"+(8*n+e)),a+="
";a+="
"}if(this.options.board.coordinates){for(i=i.toUpperCase(),a+='
',a+='
',e=0;e'+i[o?7-e:e]+"
";a+=""}return'
'+a+"
"},AntiCrux.prototype.toFen=function(t){var e,n,o,s;if(void 0===t&&(t=this._root_node),!this._has(t,"piece",!0)||!this._has(t,"owner",!0))return"";for(n="",o=0,e=0;e<64;e++)t.owner[e]==this.constants.owner.none?o++:(o>0&&(n+=o,o=0),s=this.constants.piece.mapping_rev[t.piece[e]],t.owner[e]==this.constants.owner.black&&(s=s.toLowerCase()),n+=s),(e+1)%8===0&&(o>0&&(n+=o,o=0),e<63&&(n+="/"));return n+=t.player==this.constants.owner.black?" b":" w",n+=" -",n+=this._has(t,"enpassant",!1)?" "+"abcdefgh"[t.enpassant%8]:" -",n+=" 0",n+=this._has(t,"_history",!0)?" "+Math.ceil(t._history.length/2):" 0"},AntiCrux.prototype.toText=function(t){var e,n,o,s,i,a,r;for(void 0===t&&(t=this._root_node),o=this.options.board.rotated,r="",n=o?7:0;!o&&n<8||o&&n>=0;o?n--:n++)for(e=o?7:0;!o&&e<8||o&&e>=0;o?e--:e++){switch(s=8*n+e,i=(e+n)%2==1,e===(o?7:0)&&(r+=this.options.board.coordinates?"àáâãäåæç"[7-n]:"$"),this.options.variant.whiteBoard&&t.owner[s]!=this.constants.owner.none?this.constants.owner.white:t.owner[s]){case this.constants.owner.none:a=i?"+":"*";break;case this.constants.owner.white:a=" prnbqk"[t.piece[s]];break;case this.constants.owner.black:a=" otmvwl"[t.piece[s]];break;default:throw"Internal error - Report any error (#009)"}i&&(a=a.toUpperCase()),r+=a,e===(o?0:7)&&(r+="%\n")}return'A""""""""S\n'+r+(this.options.board.coordinates?o?"DïîíìëêéèF":"DèéêëìíîïF":"D((((((((F")},AntiCrux.prototype.toPgn=function(t){var e,n,o,s,i,a,r;if(void 0===t&&(t=this._root_node),!this._has(t,"_history",!0)||!this._has(t,"_history_fen0",!0))return"";for(e='[Event "Game"]\n',e+='[Site "https://github.com/ecrucru/anticrux/"]\n',e+='[Date "'+(new Date).toISOString().slice(0,10)+'"]\n',e+=this.options.board.rotated?'[White "AntiCrux '+this.options.ai.version+'"]\n[Black "You"]\n':'[White "You"]\n[Black "AntiCrux '+this.options.ai.version+'"]\n',e+='[Result "?"]\n',this.hasSetUp(t)&&(e+='[SetUp "1"]\n',e+='[FEN "'+t._history_fen0+'"]\n'),e+='[PlyCount "'+t._history.length+'"]\n',e+='[Variant "Antichess"]\n',e+='[TimeControl "-"]\n\n',r=this.options.board.symbols,this.options.board.symbols=!1,s=t._history_fen0,i=t._history.slice(0),this.loadFen(t._history_fen0,t),t._history=i,t._history_fen0=s,o=0,n=0;n0?" ":"")+ ++o+"."),a=this.moveToString(t._history[n],t),!this.movePiece(t._history[n],!0,this.constants.owner.none,t))throw"Internal error - Report any error (#011)";e+=" "+a,this._ai_nodeSwitchPlayer(t)}switch(this.getWinner(t)){case this.constants.owner.white:e+="# 1-0",e=e.replace('[Result "?"]','[Result "1-0"]');break;case this.constants.owner.black:e+="# 0-1",e=e.replace('[Result "?"]','[Result "0-1"]')}return this.options.board.symbols=r,e},AntiCrux.prototype.freeMemory=function(){this._ai_nodeFreeMemory(this._root_node)},AntiCrux.prototype._init=function(){this.constants={piece:{none:0,pawn:1,rook:2,knight:3,bishop:4,queen:5,king:6},owner:{black:-1,none:0,white:1},score:{infinite:16777217,neutral:0}},this.constants.piece.mapping={"":this.constants.piece.none,p:this.constants.piece.pawn,P:this.constants.piece.pawn,r:this.constants.piece.rook,R:this.constants.piece.rook,n:this.constants.piece.knight,N:this.constants.piece.knight,b:this.constants.piece.bishop,B:this.constants.piece.bishop,q:this.constants.piece.queen,Q:this.constants.piece.queen,k:this.constants.piece.king,K:this.constants.piece.king},this.constants.piece.mapping_rev=[],this.constants.piece.mapping_rev[this.constants.piece.none]="",this.constants.piece.mapping_rev[this.constants.piece.pawn]="P",this.constants.piece.mapping_rev[this.constants.piece.rook]="R",this.constants.piece.mapping_rev[this.constants.piece.knight]="N",this.constants.piece.mapping_rev[this.constants.piece.bishop]="B",this.constants.piece.mapping_rev[this.constants.piece.queen]="Q",this.constants.piece.mapping_rev[this.constants.piece.king]="K",this.options={ai:{version:"v0.1",valuation:[],maxDepth:12,maxNodes:1e5,minimizeLiberty:!0,noStatOnForcedMove:!0,wholeNodes:!1,randomizedSearch:!0,pessimisticScenario:!0,bestStaticScore:!0,opportunistic:!1,handicap:0,acceleratedEndGame:!0,oyster:!1},variant:{promoteQueen:!1,activePawns:!0,whiteBoard:!1},board:{rotated:!1,symbols:!0,fisher:Math.floor(960*Math.random())+1,coordinates:!0,noStatOnOwnMove:!0,fullDecisionTree:!1,debugCellId:!1}},this.options.ai.valuation[this.constants.piece.none]=0,this.options.ai.valuation[this.constants.piece.pawn]=100,this.options.ai.valuation[-this.constants.piece.pawn]=180,this.options.ai.valuation[this.constants.piece.rook]=500,this.options.ai.valuation[this.constants.piece.knight]=300,this.options.ai.valuation[this.constants.piece.bishop]=300,this.options.ai.valuation[this.constants.piece.queen]=900,this.options.ai.valuation[this.constants.piece.king]=250},AntiCrux.prototype._has=function(t,e,n){var o=void 0!==t&&null!==t;if(o){if(o=t.hasOwnProperty(e),o&&null===t[e])return!1;o&&n&&(o=t[e].length>0)}return o},AntiCrux.prototype._ai_nodeCopy=function(t,e){var n={player:t.player,piece:t.piece.slice(0),owner:t.owner.slice(0),enpassant:t.hasOwnProperty("enpassant")?t.enpassant:null};return e&&(this._has(t,"valuation",!1)&&(n.valuation=t.valuation),this._has(t,"valuationSolver",!1)&&(n.valuationSolver=t.valuationSolver),this._has(t,"moves",!1)&&(n.moves=t.moves.slice(0)),this._has(t,"_pendingPromotion",!1)&&(n._pendingPromotion=t._pendingPromotion)),n},AntiCrux.prototype._ai_nodeSwitchPlayer=function(t){void 0===t&&(t=this._root_node),t.player==this.constants.owner.white?t.player=this.constants.owner.black:t.player=this.constants.owner.white},AntiCrux.prototype._ai_nodeInventory=function(t,e,n,o){var s,i;for(void 0===o&&(o=this._root_node),i=0,s=0;s<64;s++)if(!(o.owner[s]!=t&&null!==t||o.piece[s]!=e&&null!==e)){if(void 0!==n&&s%8!=n)continue;i++}return i},AntiCrux.prototype._ai_nodeLocatePiece=function(t,e,n){var o,s;for(void 0===n&&(n=this._root_node),s=0;s<8;s++)for(o=0;o<8;o++)if(!(n.owner[8*s+o]!=t&&null!==t||n.piece[8*s+o]!=e&&null!==e))return{x:o,y:s};return null},AntiCrux.prototype._ai_nodeMoves=function(t){var e,n,o,s,i,a,r,h,c,p,l,d,u,_,f=this,v=function(e,s,i,a){var r,h,d,u;return!(s<0||s>7||e<0||e>7)&&(r=t.owner[8*e+s],h=r!=t.player&&r!=f.constants.owner.none,!(r==t.player||h&&!i)&&(h&&!l&&(p=[],l=!0),!h&&(h||l||a)||(u=!1,t.piece[8*o+n]==f.constants.piece.pawn&&(0===e&&t.owner[8*o+n]==f.constants.owner.white||7===e&&t.owner[8*o+n]==f.constants.owner.black)&&(d=c+10*e+s,p.push(d+1e4*f.constants.piece.queen),f.options.variant.promoteQueen||(p.push(d+1e4*f.constants.piece.rook),p.push(d+1e4*f.constants.piece.knight),p.push(d+1e4*f.constants.piece.bishop),p.push(d+1e4*f.constants.piece.king)),u=!0),u||p.push(c+10*e+s)),!h))};if(void 0!==t&&null!==t){for(l=!1,p=[],o=0;o<8;o++)for(n=0;n<8;n++)if(e=8*o+n,t.owner[e]==t.player)switch(c=1e3*o+100*n,t.piece[e]){case this.constants.piece.none:continue;case this.constants.piece.pawn:u=-t.player,v(o+u,n,!1,!1)&&(u==-1&&6==o||1==u&&1==o)&&v(o+2*u,n,!1,!1),v(o+u,n-1,!0,!0),v(o+u,n+1,!0,!0),this._has(t,"enpassant",!1)&&(i=t.enpassant%8,a=Math.floor(t.enpassant/8),r=i,h=a-u,i>=0&&i<=7&&a>=0&&a<=7&&r>=0&&r<=7&&h>=0&&h<=7&&1==Math.abs(i-n)&&a-o==u&&t.piece[e]==this.constants.piece.pawn&&t.piece[8*a+i]==this.constants.piece.none&&t.piece[8*h+r]==this.constants.piece.pawn&&t.owner[8*a+i]!=t.owner[8*h+r]&&(l||(p=[]),l=!0,p.push(c+10*a+i)));break;case this.constants.piece.queen:case this.constants.piece.rook:for(d=1;d<8&&v(o,n+d,!0,!1);d++);for(d=1;d<8&&v(o,n-d,!0,!1);d++);for(u=1;u<8&&v(o+u,n,!0,!1);u++);for(u=1;u<8&&v(o-u,n,!0,!1);u++);if(t.piece[e]==this.constants.piece.rook)break;case this.constants.piece.bishop:for(_=1;_<8&&v(o+_,n+_,!0,!1);_++);for(_=1;_<8&&v(o+_,n-_,!0,!1);_++);for(_=1;_<8&&v(o-_,n+_,!0,!1);_++);for(_=1;_<8&&v(o-_,n-_,!0,!1);_++);break;case this.constants.piece.king:for(d=-1;d<=1;d++)for(u=-1;u<=1;u++)0===d&&0===u||v(o+u,n+d,!0,!1);break;case this.constants.piece.knight:v(o-2,n-1,!0,!1),v(o-2,n+1,!0,!1),v(o+2,n-1,!0,!1),v(o+2,n+1,!0,!1),v(o-1,n-2,!0,!1),v(o-1,n+2,!0,!1),v(o+1,n-2,!0,!1),v(o+1,n+2,!0,!1);break;default:throw"Internal error - Report any error (#003)"}if(this.options.ai.randomizedSearch)for(n=p.length-1;n>=0;n--)o=Math.floor(Math.random()*n+.5),s=p[o],p[o]=p[n],p[n]=s;t.moves=p}},AntiCrux.prototype._ai_nodeCreateNodes=function(t){var e,n;if(t.hasOwnProperty("moves"))for(t.nodes=[],e=0;e0&&n.player==t)for(s=n.moves.length>4?Math.floor((n.moves.length-4)*this.options.ai.handicap/100):0,o=s;o>0;o--)n.moves.splice(Math.floor(Math.random()*n.moves.length),1);for(this._has(n,"nodes",!0)&&n.nodes.length==n.moves.length||this._ai_nodeCreateNodes(n),s=this.constants.score.infinite,o=0;o0&&n.nodes[o].moves.lengths?(n.moves[o]=0,n.nodes[o]=null,i=!0):(this._numNodes++,this._ai_nodeValuate(n.nodes[o]),e>=this.options.ai.maxDepth||0!==this.options.ai.maxNodes&&this._numNodes>=this.options.ai.maxNodes||(!this.options.ai.noStatOnForcedMove||this.options.ai.noStatOnForcedMove&&n.moves.length>1)&&this._ai_nodeRecurseTree(t,e+1,n.nodes[o]));if(i){for(o=n.moves.length-1;o>=0;o--)0===n.moves[o]&&n.moves.splice(o,1);for(o=n.nodes.length-1;o>=0;o--)null===n.nodes[o]&&n.nodes.splice(o,1);if(n.moves.length!=n.nodes.length)throw"Internal error - Report any error (#005)"}}},AntiCrux.prototype._ai_nodeValuate=function(t){var e,n,o,s;for(void 0===t&&(t=this._root_node),o=0,s=0,e=0;e<64;e++)switch(n=this.options.variant.activePawns&&t.piece[e]==this.constants.piece.pawn&&(t.owner[e]==this.constants.owner.black&&1!=Math.floor(e/8)||t.owner[e]==this.constants.owner.white&&6!=Math.floor(e/8))?this.options.ai.valuation[-t.piece[e]]:this.options.ai.valuation[t.piece[e]],t.owner[e]){case this.constants.owner.black:o+=n;break;case this.constants.owner.white:s+=n}0===o?t.valuation=this.constants.score.infinite:0===s?t.valuation=-this.constants.score.infinite:t.valuation=this.constants.owner.black*o+this.constants.owner.white*s,this._has(t,"moves",!1)&&0===t.moves.length&&(t.valuation=t.player*-this.constants.score.infinite)},AntiCrux.prototype._ai_getMaxValuation=function(t){var e,n,o,s;for(void 0===t&&(t=this._root_node),o=0,s=0,e=0;e<64;e++)switch(n=this.options.ai.valuation[t.piece[e]],t.owner[e]){case this.constants.owner.black:s+=n;break;case this.constants.owner.white:o+=n}return s>o?s:o},AntiCrux.prototype._ai_nodeSolve=function(t,e){var n,o,s,i,a,r,h;if(void 0===e&&(e=this._root_node),!this._has(e,"nodes",!0))return e.valuationSolver=e.valuation,e._forced=!0,e._sequence=e.valuationSolver==t*-this.constants.score.infinite?1:0,void(this.options.ai.opportunistic&&1==e._sequence&&(e._win=!0));for(o=!0,s=!1,n=0;na)&&(a=e.nodes[n].valuationSolver):e.nodes[n]=null);for(n=0;nr||t==this.constants.owner.black&&e.nodes[n].valuationSolver0&&e.nodes[n]._sequence':e&&t>100||t==this.constants.score.infinite?'+∞':t.toFixed(0)+(e?"%":"")},AntiCrux.prototype._ai_nodeTreeHtml=function(t,e,n){var o,s,i,a;if(void 0===n&&(n=this._root_node),this._has(n,"nodes",!1))for(o=0;o=3,a&&(this._buffer+='',n.nodes[o].hasOwnProperty("valuation")?(this._buffer+=""+this._ai_formatScore(n.nodes[o].valuation,!1)+"",n.nodes[o].hasOwnProperty("valuationSolver")?this._buffer+=""+this._ai_formatScore(n.nodes[o].valuationSolver,!1)+"":this._buffer+=" "):this._buffer+="  "),i+=""+this.moveToString(n.moves[o],n)+"",a){for(this._buffer+=i,s=t;s<4;s++)this._buffer+=" ";this._buffer+=""}n.nodes[o].hasOwnProperty("nodes")&&t<4&&this._ai_nodeTreeHtml(t+1,i,n.nodes[o])}},AntiCrux.prototype._ai_nodeFreeMemory=function(t){ +var e;if(void 0===t&&(t=this._root_node),t.hasOwnProperty("nodes")&&null!==t.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 z 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 literal 0 HcmV?d00001 diff --git a/images/piece_-12.png b/images/piece_-12.png new file mode 100644 index 0000000000000000000000000000000000000000..e18bd6ace7867e0bfa67c72558cd05bd967c250a GIT binary patch literal 607 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 KMNUMnLSTZ5x!o54 literal 0 HcmV?d00001 diff --git a/images/piece_12.png b/images/piece_12.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0fea9a79826d6ea15986fb30ffeaf27a318341 GIT binary patch literal 814 zcmV+}1JV46P)Km4q~#@cGGjIm_-U5baBvsp%fg% zt&1Q|BGSS2#Hmm+7ag2Bv=o;PS#oqrkU|s5)TD4NA;tV0+S(+wP43=RgWLxmj}{I5eA04h{~^T(fOkrBbKiQ>hfST1^E(a7H^eHby#~Hc2J4k!t|!>+4vS zWi;@4?Cx*1Da~=Or%k`MhYY+gj@#U?OZ%VQ1uo+gj@l+qN^=Y_>fzG7>S&5r>C| zR4Nr61VOdkZqESUjRJ;b9uUv-jAz61ypwe?A2k_mV5DZyH};q&Muv*S$gq(Z88#9l z!$x9c*!XXZ80`=N>h(JHdfhmNDJDklDy3LnUS?%w#VCm&2vABPB6onVM!`ZdqLeD9 z(`nh>-ZuXCTPPF+5T#TZh_ok&G9#maCnA%%T#izyM5$DYGIkd;Gc#;#Y)k?lffqo_ zIA|YUa{2r9g|JCQnGqXcc6Qdd7S&6&T4il*4d6zsfzRO;9hJd2>8M=351Z6~^Bozq z`0xgJdi?t)kU1$j$4N&~yarT{Pk#a4_Uk*Sks{zuPfrsB0hLMx5s8#+--MJRo6Ta| zHibd~zz6Qd6~E}ZZtQEKAFk^PM>nxA1HZL=-)C`gG4h>=g75pW$6V#_)qH!~>L3XY sx<;-7w+7V4%@3gYkH$_&NEkML0VW#S17sBPZvX%Q07*qoM6N<$f`wsrLjV8( literal 0 HcmV?d00001 diff --git a/images/piece_13.png b/images/piece_13.png new file mode 100644 index 0000000000000000000000000000000000000000..c3fed79fc30c948c834f0e2866e855e7aa1bde81 GIT binary patch literal 1508 zcmVDDgd9YIBx*(W8fO4lw;cvTSSaxWMnWuKVJzUGyvs+^GyJF=FAy7ole3p zv}e1542J=$)v65*4bf;cYVZgAD*zT16)B(3N0-Z`i*y5U0C*RGar;6J&Nl#f7xf`9ys1Na2nD6~gPIlq7Zeih1sq_+CR%aK_vi>|INy@S5p42cvW#Hh(+(mWmyNpfOhf)_4apx5gS8Qk359IL9T*w@z= zmP}1e4TTU(0P^B3;sn6+=g&vg%lGcxBLKQwuCVSO85yC$U{CeML)2EH|3B3}aF)vH&dk{BBsquFex)oP8X+~DA#K32YnheU>y zayl4_>EB-!8JuV>`bXgUHyhyk0;rcF;zlO(-f@A6-)y}g~IqodrpbEhVR zm<3Q3q>6kg!?Hk)C1sw0|)4GxoEfBmqpxeH;apl^=+VF z5}87X(H%Q>sDXijs3mlgl9CksJ26qyEQFZX1@z<4p+oxbvq8$F0q6t3%aV5py6=j$Pr2@U&K>nJp}w~2Ra;%xC!VSJ$jTvh=r{XaR8v*ZjWmw zbWWT&p^wQ;C0$B6vv==awYV5^vm`1`o;<0GnAZy;9$S?kE2UoR=;%Ola&jE1TZ_@S zyzjm4vLj{@A;j_ByLYR~%F1p1Iu&c}x`QyPSL;<|02S^z`F(QBuJ3p|IEL;XNHF^SLt#90000< KMNUMnLSTXiD$bq& literal 0 HcmV?d00001 diff --git a/images/piece_14.png b/images/piece_14.png new file mode 100644 index 0000000000000000000000000000000000000000..3779342f21585bbdec50cfb47ba9284945d38679 GIT binary patch literal 1499 zcmV<11tj{3P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D00v@9M??Vs0RI60 zpuMM)000GENklfA#B`HQpj~Jel`8ncq*1AXAWBk1A)xrcDq?+$+9u9D{l0V0O{D6m zGbWRv^Mh~B|DJR1x##^F5grcny-3 zm6dX3Wkso?qQWZ7MMm%!zJlcV__(wf8ym9-PAxwzhJM&(`q1 zM!X;i19>q#Jltq#Xpmc5TRMA(!?^YJ^)fUxlxxT$(n>Uw^o*0Z4tfz8X~sJ60w1EH zq7I#<5Lc|NttlI=aUbP+6XvM$@Q{8>juZVJTa(IsC+2mC-DIbE2^qe_!#x*rHrL%Z+CMPFlL_~xO zY5b;>^B8ZtmK|EbAxTtK@pkn1G&eVkp`js~QP4UKU+@-WEoR<|1Kwl2ZISn(>({Pb z6D1`jrq40CapQ)lsi~p)9`q9pU%+j*#FQ(0dwV6e^}6>T4&(Op^vJVk&sr_wWP+Y@ z64P%T2J2!zD~`M)6+mX{HKL4QIg0{0s4K!2bM@S}Tb zcR!)u8)ao>^6J&A>WYZsUJU1Zt{c{U)}hkh`~}K}+~Tf9qELffsKLC*$VekAE6bLV zks&Y+M07M8LI*Bqt|}xVShKPO#c5m*Ex*3kzaqW=8$(z;Jv+ z9ndy6H&r&xkS;AP zJ<1#l!NOQ@Kyx3(@6OK7is9j5(cjOZAVfhyfp9vVsv@|l3<(JlXgL)|SP1L1$wJ4( z#0X9rq_(zJ+`M^{W-s(Q#DX0OuCl6mu?gh#dguV&PpAy8)EpCcwY_gVcjC8si@D2> zV{s4ex>f-`{yAJ;6W)h=2O5Mp2+ch>S`LadO@+FNhgk4gh;etriGmXb#~#1^xWAd( z6TU}Sk&OEal#6`u&!KzB2dC-VP=Ejd0{AsT{0p%Bl+)oWXJ7yT002ovPDHLkV1h$Z B#_|9F literal 0 HcmV?d00001 diff --git a/images/piece_15.png b/images/piece_15.png new file mode 100644 index 0000000000000000000000000000000000000000..933f3d29642e6f2e02bb0efb127079150102e47d GIT binary patch literal 2288 zcmVAF{jI4-`FYp1WQ^S}vgak=}wyHXHtqSbJBp7V_KnSX~jwmmE z%UXv<crWzXLWphTq`Rp6ULZ-Wr(-c7&8PUMC4Q82iILe3iklo)zzire$$r zE#zgllZbri^ZBe7UU)(G?AfC}pU)DJ^cvX%=qI0iqN=Lzz4x9St7{>MdVwC`0Pqq} znP%Sz=+>=U^~8x2x^w4FJ9&GW-z~hX9ipg)7}78l7|vc!AZ<@0nFpCvAzEg9?wJRXk~ zkH=M2_3gLcwtXMCnve<+iLYI|*6Q!?*Zc0f&z{tsL&z&x;=SSWc_WKYXAU7ffNtBi zP5b-%wW+De5|J2i)769kJRu@+S8yeBaXCUn*W@-UUBoZMKiP*VX(tLIS zJoZ@nR0n0L+@!d?1Dws|m`#X{KLc2nwUV?A&qir!DciSi7vK)yJ1$cMptZG?*4EZ} zV=1f?FpNVedeuHjY@Ash}94u=sD znBOuVR@K0+UAwa7z8iQrmD}Nx4Y`C20`&Cs5C{Y;W6XXaknXf;(qBp3`*TU)Cl;?#qPbT41N+-h%6KM(*AFvjc;1Oir1PtQCq*D7QPU}|cL zy?gf>%d*yx+z97EMCj`363enyk=)>xs_M;=NW|GFBaw)^;5Vr1+8sM~n39r`OnG}P z%UZK{?_M)CH8qdRwFlIH|y80R}p!J47+MaM+Y8{$1ZxO&|O08d@aB( z5#jO2ztKe@xg?)izka=TcXu;1G=wqc0&wx$2*I+f!NI{n%j5Cz+H0?g$Kw$Zd7b&k zamvff*|KGe06zq_0rQI3_5B_ZY1_DQBTY?B>FJ6@RdqjqdOu&40?=c}j;X5Z%*>27G&IakA+?>+6%^;^b+^&Pk4r1^K;2xdHfh zdwV;mF470PdBoYZOU%m{$^5x6%csvvr7gJJF zf`||d2J!iPtXj3oS%Lu1KmRgFDw(0PesJK>#n~w#7e!aOMiaJibCK0HUeJ&Qdd_;U0ofkSFfh5tPH>3PcRq+ z{#)clMMX~GPfbm6<;oReu^3-}{WSoSlatKN%`q`C!MStiIDPswUw-+eo$I^6sRH>G zgkJ#K*Vnh;b+Lc{e)|snv`|v{b}ctf0$jRu$r(6z?i^!dW6m!;Jw5GQ?Uw5E`J6ko zWXTfe4pvrHvU>Gu04`p1wu%q0fmgx!EuhWK&01eyuYSM(Ti1u*@7MbJdTnlQw#QyC zlvJTL(gOSqkWeVZnl)>vs;Z*8x|-_hYJ$O_)0Ny;Rb_5&&go|MH5!dFIy%b8$cS@w z-RWvzv`|5LK}1gY{r<%J@4vs`^b7`Q>#HL9%1%jvYI$n+O{zA(wLSnTLE% zzczj>B0TiaLxse@CWOOb3kZ=sEartmgw&Oklvs6jbp;bE6rG)&Hm~pHJExFhzgI*K ztEvfwLRLjZg|S;_RaF%?-gqNkuh(gk60|`6uI4+&!1;>bku3#2AGV!#A2228PtMJ!?wx$qwi)=X0c>DNR60000< KMNUMnLSTYz({Pdi literal 0 HcmV?d00001 diff --git a/images/piece_16.png b/images/piece_16.png new file mode 100644 index 0000000000000000000000000000000000000000..685abbf012a7d60f6bb566137313853486a9ade3 GIT binary patch literal 1910 zcmV-+2Z{KJP)g*n} zV6~TXAS2FxiXfs^B3o!#3Poz&TBsz5jLv=tKiHZS6;`xj?t(e3)>!CT?)Wl|ra8~G zALa#1Jf#S}jgF~0P(=O4ZlQKBO40GRU`d_;_I zfgZpKjQWz(_w3t9IE++_JOds92H-2-vws2}-@BhB&At>-v`9PnTtr&PTwsF(|pi^bwmN;!e)Uph#DL?9WMG0FR_fSf*kT0W$rqC)Vt%5NtqX9DKqT|h$~yTKNi z2mD#nGzZ>=?HSF|( z2d)9@02NGt!7PY-lu{LdF)J%eva_=>o6Yp}^w8AQl+x7H^u37uUMY1~L=FLNfPsO5 zafbT(`uw*>pjs)lRYa84YL)ElY&B=j97aY)Xm4+yaqHHt-wX~8exsCX5Rsk0e}WM- z8AX7krlxuxJa{m!tB8nnc6LfhNr}Y9#(Dr9xDH5FRn@q>7cX8EKr~Hzt7)3-*|SGl zTU#fz>vFl|$dMyrFc@@A)BXo!hAZNiN~yt=loZdaSFa{?HkKDJUPyj^zJIEf!otFF zd9t&!1(5mk=j#m(4Ii~BB2rURBSxc9*EH<~Ff$w>e+A^mjT=EZ6cO=wJaXvJAps;R zDoVyyz}d5B1(2mnmr7SxSI{;^M9!Z-@1G?85~>K3QtHi$6)Qq==%=)_Q~S5pvU~ULPpU-`3AD(kpzFHWY&MUk zX&nT)K#t{y=;&yDvU&b<3aP59^4kfkS%0OJ@+@1nOn1B8Urb1IbF-LCCSB9CPA1>q zeUyWMY~H+C1_uW}yAZqGE_3J3^(dv@^8S8q93Sg%3iuoFU0z-u)z#HlESC2&csw2& z8yjh8XyD0{C)n+F91aIAmy5x{L0m2uF)=YDCMFUW7e`7;3RbI?#fuk{o105UMg~fa z598jwdu-XVMeptH6%pA1Tn@heCl~W4Ku=0a@?5%fN#4DCCs(gtm4bo-nK^T2pw!0*yLPRdIB`Pm+_@vKU%w8j%XD^jN_~C396fqe zR<2wr27^KHZcb(1ym>m_{aPci_@@@(Ck0mkohVVyLNj*e1ZUe1*( zS9tjFAs&w>5NLXOI{Eqe#Ky)F7Z-=gWMXJ&i2nY5+-^7R?d@E@ew}OAt^r^)8p+AY zp|G&fZ(a{4rcj9o0$m^}DM@zi+9j7RU6SX|pZ{q0`LNqPefm_+ojWJnwr!L6_;~T# z^-Z-AC&BOV!i5X+_U+pV1MTVQk+!xrX=-YcM~@y!b91w_wY5oKU*ClJ2L=YDqM|~k zPoFM$54O#ZB1eHMgfRt&BgBsp_%-m2rfFa6x*j;HnKo^j#Kpx) zLPCN{NJvn. +--> + + + + + + + + + AntiCrux - AI for AntiChess + + + + + + + + + + + + +
+
+

AntiCrux - AI for AntiChess

+
+ +
+ +
+ + +
+
+

Board

+ + +

Load from input

+ +
+ +
+ +

Miscellaneous

+ +
+
+ +
+ + +
+ +
+
+
+
+
+
+ +
+
+
+ +
+ +
+ +
+

+

+

+

+
+ +
+

+

Download PGN

+
+
+
+
+ + + +
+ +
+
+
+

Artificial intelligence

+

+ + +

+

+

+

+

+

+

+

+

+

+

+

+

+
+ +
+

Board

+

+

+

+

+

+

+

+

+
+ +
+

Variant

+

+

+

+
+
+
+ +
+
+
+ +
+

AntiCrux

+

Artificial intelligence playing AntiChess and AntiChess960 with jQuery Mobile.

+

Copyright © 2016-2017, ecrucru

+ +

This application is released under the terms of the GNU Affero General Public License v3 :

+ +
+
+ + + +
+
+

Promotion of the pawn

+
+
+ + + + + +
+
+ + + +
+
+

Information

+
+
+

+ OK +
+
+ + + +
+
+ + \ No newline at end of file diff --git a/jquery-1.11.1.min.js b/jquery-1.11.1.min.js new file mode 100644 index 0000000..ebbcf41 --- /dev/null +++ b/jquery-1.11.1.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("