js-chess-engine 0.11.2 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,34 @@
1
+ ## [1.0.2](https://github.com/josefjadrny/js-chess-engine/compare/v1.0.1...v1.0.2) (2021-10-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Fixed FEN parsing ([#23](https://github.com/josefjadrny/js-chess-engine/issues/23)) ([14ebe50](https://github.com/josefjadrny/js-chess-engine/commit/14ebe506e300e2a22fed81696f76ef117c00c2d7))
7
+
8
+
9
+
10
+ ## [1.0.1](https://github.com/josefjadrny/js-chess-engine/compare/v0.11.3...v1.0.1) (2021-10-16)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * fixed array sort in firefox ([#21](https://github.com/josefjadrny/js-chess-engine/issues/21)) ([42c5913](https://github.com/josefjadrny/js-chess-engine/commit/42c5913a46faa5eaccf142dfd34cf83adf538435))
16
+
17
+
18
+
19
+ # [1.0.0](https://github.com/josefjadrny/js-chess-engine/compare/v0.11.3...v1.0.0) (2021-10-13)
20
+
21
+
22
+
23
+ ## [0.11.3](https://github.com/josefjadrny/js-chess-engine/compare/v0.11.2...v0.11.3) (2021-03-29)
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * **AI:** AI configuration and logic improved. Add new level (4) for testing. Add new Example ([bd2261b](https://github.com/josefjadrny/js-chess-engine/commit/bd2261be6b99df8f4de8d5a5326398e33d3015d4))
29
+
30
+
31
+
1
32
  ## [0.11.2](https://github.com/josefjadrny/js-chess-engine/compare/v0.11.1...v0.11.2) (2021-03-27)
2
33
 
3
34
 
package/README.md CHANGED
@@ -32,6 +32,7 @@ more about [importing](#import) this library.
32
32
  **More examples**<BR/>
33
33
  [Simple Fastify server](example/server.mjs) <BR/>
34
34
  [Console](example/console.mjs) <BR/>
35
+ [PC vs PC match](example/aiMatch.mjs) <BR/>
35
36
 
36
37
  ## Documentation
37
38
  ### Import
@@ -285,14 +286,15 @@ console.log(newFen)
285
286
 
286
287
  ### Computer AI
287
288
 
288
- This engine includes configurable AI computer logic based on Minimax algorithm. There are four possible levels at this time.
289
+ This engine includes configurable AI computer logic based on Minimax algorithm. There are five possible levels at this time.
289
290
 
290
291
  |Level|Alias|Moves to the future|HW requirements|Approx. time to move (s)*|
291
292
  | :-: | :-:| :-:| :-:| :-:|
292
- | 0 |Well-trained monkey| 1 | None | <0.1 |
293
- | 1 |Beginner| 2 | Very low | 0.11 |
294
- | 2 |Intermediate| 3 | Low | 1.50 |
295
- | 3 |Intermediate+| 3-4 | Medium | 2.82 |
293
+ | 0 |Well-trained monkey| 1-2 | None | <0.01 |
294
+ | 1 |Beginner| 2-4 | Very low | <0.1 |
295
+ | 2 |Intermediate| 2-4 | Low | 0.7 |
296
+ | 3 |Advanced| 3-5 | Medium | 4.6 |
297
+ | 4 |Experienced| 4-5 | High | 9.5 |
296
298
 
297
299
  ***Approx. time to move (s)** - This number represent the average amount of seconds needed for one move during a chess game on t3.nano AWS instance.
298
300
  T3.nano is a low-cost machine with 0.5 GiB RAM and basic CPU performance. Please note, amount of time needed for calculations heavily depends on in-game situation (number of chess pieces still on a chessboard).
@@ -310,6 +312,14 @@ When a move is recognized as a castling - played with a king across two chess fi
310
312
 
311
313
  <BR/>
312
314
 
315
+ ## Collaboration
316
+
317
+ **Collaborators are welcome.** Please do not forget to check ESLint and run tests before submitting a new pull request (`npm run test`).
318
+
319
+ If it is possible, also use commit message prefixes like `feat: ` or `fix: ` - changelog is generated from this.
320
+
321
+ <BR/>
322
+
313
323
  ## TODO
314
324
  - Calculation and result caching
315
325
  - Forsyth–Edwards Notation (FEN) validation
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("js-chess-engine",[],e):"object"==typeof exports?exports["js-chess-engine"]=e():t["js-chess-engine"]=e()}(this,(function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)i.d(n,o,function(e){return t[e]}.bind(null,o));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,i){"use strict";i.r(e),i.d(e,"Game",(function(){return x})),i.d(e,"moves",(function(){return q})),i.d(e,"status",(function(){return $})),i.d(e,"getFen",(function(){return J})),i.d(e,"move",(function(){return V})),i.d(e,"aiMove",(function(){return Y}));const n=["A","B","C","D","E","F","G","H"],o=["1","2","3","4","5","6","7","8"],s={KING_W:"K",QUEEN_W:"Q",ROOK_W:"R",BISHOP_W:"B",KNIGHT_W:"N",PAWN_W:"P",KING_B:"k",QUEEN_B:"q",ROOK_B:"r",BISHOP_B:"b",KNIGHT_B:"n",PAWN_B:"p"},r="black",c="white",l=[0,1,2,3],a={fullMove:1,halfMove:0,enPassant:null,isFinished:!1,checkMate:!1,check:!1,turn:c},u=Object.assign({pieces:{E1:"K",D1:"Q",A1:"R",H1:"R",C1:"B",F1:"B",B1:"N",G1:"N",A2:"P",B2:"P",C2:"P",D2:"P",E2:"P",F2:"P",G2:"P",H2:"P",E8:"k",D8:"q",A8:"r",H8:"r",C8:"b",F8:"b",B8:"n",G8:"n",A7:"p",B7:"p",C7:"p",D7:"p",E7:"p",F7:"p",G7:"p",H7:"p"},castling:{whiteShort:!0,blackShort:!0,whiteLong:!0,blackLong:!0}},a),h={UP:{A1:"A2",A2:"A3",A3:"A4",A4:"A5",A5:"A6",A6:"A7",A7:"A8",A8:null,B1:"B2",B2:"B3",B3:"B4",B4:"B5",B5:"B6",B6:"B7",B7:"B8",B8:null,C1:"C2",C2:"C3",C3:"C4",C4:"C5",C5:"C6",C6:"C7",C7:"C8",C8:null,D1:"D2",D2:"D3",D3:"D4",D4:"D5",D5:"D6",D6:"D7",D7:"D8",D8:null,E1:"E2",E2:"E3",E3:"E4",E4:"E5",E5:"E6",E6:"E7",E7:"E8",E8:null,F1:"F2",F2:"F3",F3:"F4",F4:"F5",F5:"F6",F6:"F7",F7:"F8",F8:null,G1:"G2",G2:"G3",G3:"G4",G4:"G5",G5:"G6",G6:"G7",G7:"G8",G8:null,H1:"H2",H2:"H3",H3:"H4",H4:"H5",H5:"H6",H6:"H7",H7:"H8",H8:null},DOWN:{A1:null,A2:"A1",A3:"A2",A4:"A3",A5:"A4",A6:"A5",A7:"A6",A8:"A7",B1:null,B2:"B1",B3:"B2",B4:"B3",B5:"B4",B6:"B5",B7:"B6",B8:"B7",C1:null,C2:"C1",C3:"C2",C4:"C3",C5:"C4",C6:"C5",C7:"C6",C8:"C7",D1:null,D2:"D1",D3:"D2",D4:"D3",D5:"D4",D6:"D5",D7:"D6",D8:"D7",E1:null,E2:"E1",E3:"E2",E4:"E3",E5:"E4",E6:"E5",E7:"E6",E8:"E7",F1:null,F2:"F1",F3:"F2",F4:"F3",F5:"F4",F6:"F5",F7:"F6",F8:"F7",G1:null,G2:"G1",G3:"G2",G4:"G3",G5:"G4",G6:"G5",G7:"G6",G8:"G7",H1:null,H2:"H1",H3:"H2",H4:"H3",H5:"H4",H6:"H5",H7:"H6",H8:"H7"},LEFT:{A1:null,A2:null,A3:null,A4:null,A5:null,A6:null,A7:null,A8:null,B1:"A1",B2:"A2",B3:"A3",B4:"A4",B5:"A5",B6:"A6",B7:"A7",B8:"A8",C1:"B1",C2:"B2",C3:"B3",C4:"B4",C5:"B5",C6:"B6",C7:"B7",C8:"B8",D1:"C1",D2:"C2",D3:"C3",D4:"C4",D5:"C5",D6:"C6",D7:"C7",D8:"C8",E1:"D1",E2:"D2",E3:"D3",E4:"D4",E5:"D5",E6:"D6",E7:"D7",E8:"D8",F1:"E1",F2:"E2",F3:"E3",F4:"E4",F5:"E5",F6:"E6",F7:"E7",F8:"E8",G1:"F1",G2:"F2",G3:"F3",G4:"F4",G5:"F5",G6:"F6",G7:"F7",G8:"F8",H1:"G1",H2:"G2",H3:"G3",H4:"G4",H5:"G5",H6:"G6",H7:"G7",H8:"G8"},RIGHT:{A1:"B1",A2:"B2",A3:"B3",A4:"B4",A5:"B5",A6:"B6",A7:"B7",A8:"B8",B1:"C1",B2:"C2",B3:"C3",B4:"C4",B5:"C5",B6:"C6",B7:"C7",B8:"C8",C1:"D1",C2:"D2",C3:"D3",C4:"D4",C5:"D5",C6:"D6",C7:"D7",C8:"D8",D1:"E1",D2:"E2",D3:"E3",D4:"E4",D5:"E5",D6:"E6",D7:"E7",D8:"E8",E1:"F1",E2:"F2",E3:"F3",E4:"F4",E5:"F5",E6:"F6",E7:"F7",E8:"F8",F1:"G1",F2:"G2",F3:"G3",F4:"G4",F5:"G5",F6:"G6",F7:"G7",F8:"G8",G1:"H1",G2:"H2",G3:"H3",G4:"H4",G5:"H5",G6:"H6",G7:"H7",G8:"H8",H1:null,H2:null,H3:null,H4:null,H5:null,H6:null,H7:null,H8:null},UP_LEFT:{A1:null,A2:null,A3:null,A4:null,A5:null,A6:null,A7:null,A8:null,B1:"A2",B2:"A3",B3:"A4",B4:"A5",B5:"A6",B6:"A7",B7:"A8",B8:null,C1:"B2",C2:"B3",C3:"B4",C4:"B5",C5:"B6",C6:"B7",C7:"B8",C8:null,D1:"C2",D2:"C3",D3:"C4",D4:"C5",D5:"C6",D6:"C7",D7:"C8",D8:null,E1:"D2",E2:"D3",E3:"D4",E4:"D5",E5:"D6",E6:"D7",E7:"D8",E8:null,F1:"E2",F2:"E3",F3:"E4",F4:"E5",F5:"E6",F6:"E7",F7:"E8",F8:null,G1:"F2",G2:"F3",G3:"F4",G4:"F5",G5:"F6",G6:"F7",G7:"F8",G8:null,H1:"G2",H2:"G3",H3:"G4",H4:"G5",H5:"G6",H6:"G7",H7:"G8",H8:null},DOWN_RIGHT:{A1:null,A2:"B1",A3:"B2",A4:"B3",A5:"B4",A6:"B5",A7:"B6",A8:"B7",B1:null,B2:"C1",B3:"C2",B4:"C3",B5:"C4",B6:"C5",B7:"C6",B8:"C7",C1:null,C2:"D1",C3:"D2",C4:"D3",C5:"D4",C6:"D5",C7:"D6",C8:"D7",D1:null,D2:"E1",D3:"E2",D4:"E3",D5:"E4",D6:"E5",D7:"E6",D8:"E7",E1:null,E2:"F1",E3:"F2",E4:"F3",E5:"F4",E6:"F5",E7:"F6",E8:"F7",F1:null,F2:"G1",F3:"G2",F4:"G3",F5:"G4",F6:"G5",F7:"G6",F8:"G7",G1:null,G2:"H1",G3:"H2",G4:"H3",G5:"H4",G6:"H5",G7:"H6",G8:"H7",H1:null,H2:null,H3:null,H4:null,H5:null,H6:null,H7:null,H8:null},UP_RIGHT:{A1:"B2",A2:"B3",A3:"B4",A4:"B5",A5:"B6",A6:"B7",A7:"B8",A8:null,B1:"C2",B2:"C3",B3:"C4",B4:"C5",B5:"C6",B6:"C7",B7:"C8",B8:null,C1:"D2",C2:"D3",C3:"D4",C4:"D5",C5:"D6",C6:"D7",C7:"D8",C8:null,D1:"E2",D2:"E3",D3:"E4",D4:"E5",D5:"E6",D6:"E7",D7:"E8",D8:null,E1:"F2",E2:"F3",E3:"F4",E4:"F5",E5:"F6",E6:"F7",E7:"F8",E8:null,F1:"G2",F2:"G3",F3:"G4",F4:"G5",F5:"G6",F6:"G7",F7:"G8",F8:null,G1:"H2",G2:"H3",G3:"H4",G4:"H5",G5:"H6",G6:"H7",G7:"H8",G8:null,H1:null,H2:null,H3:null,H4:null,H5:null,H6:null,H7:null,H8:null},DOWN_LEFT:{A1:null,A2:null,A3:null,A4:null,A5:null,A6:null,A7:null,A8:null,B1:null,B2:"A1",B3:"A2",B4:"A3",B5:"A4",B6:"A5",B7:"A6",B8:"A7",C1:null,C2:"B1",C3:"B2",C4:"B3",C5:"B4",C6:"B5",C7:"B6",C8:"B7",D1:null,D2:"C1",D3:"C2",D4:"C3",D5:"C4",D6:"C5",D7:"C6",D8:"C7",E1:null,E2:"D1",E3:"D2",E4:"D3",E5:"D4",E6:"D5",E7:"D6",E8:"D7",F1:null,F2:"E1",F3:"E2",F4:"E3",F5:"E4",F6:"E5",F7:"E6",F8:"E7",G1:null,G2:"F1",G3:"F2",G4:"F3",G5:"F4",G6:"F5",G7:"F6",G8:"F7",H1:null,H2:"G1",H3:"G2",H4:"G3",H5:"G4",H6:"G5",H7:"G6",H8:"G7"}},g=[[0,0,0,0,0,0,0,0],[5,5,5,5,5,5,5,5],[1,1,2,3,3,2,1,1],[.5,.5,1,2.5,2.5,1,.5,.5],[0,0,0,2,2,0,0,0],[.5,0,1,0,0,1,0,.5],[.5,0,0,-2,-2,0,0,.5],[0,0,0,0,0,0,0,0]],f=[[-4,-3,-2,-2,-2,-2,-3,-4],[-3,-2,0,0,0,0,-2,-3],[-2,0,1,1.5,1.5,1,0,-2],[-2,.5,1.5,2,2,1.5,.5,-2],[-2,0,1.5,2,2,1.5,0,-2],[-2,.5,1,1.5,1.5,1,.5,-2],[-3,-2,0,.5,.5,0,-2,-3],[-4,-3,-2,-2,-2,-2,-3,-4]],C=[[-2,-1,-1,-1,-1,-1,-1,-2],[-1,0,0,0,0,0,0,-1],[-1,0,.5,1,1,.5,0,-1],[-1,.5,.5,1,1,.5,.5,-1],[-1,0,1,1,1,1,0,-1],[-1,1,1,1,1,1,1,-1],[-1,.5,0,0,0,0,.5,-1],[-2,-1,-1,-1,-1,-1,-1,-2]],P=[[0,0,0,0,0,0,0,0],[.5,1,1,1,1,1,1,.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[0,0,0,.5,.5,0,0,0]],p=[[-3,-4,-4,-5,-5,-4,-4,-3],[-3,-4,-4,-5,-5,-4,-4,-3],[-3,-4,-4,-5,-5,-4,-4,-3],[-3,-4,-4,-5,-5,-4,-4,-3],[-2,-3,-3,-4,-4,-3,-3,-2],[-1,-2,-2,-2,-2,-2,-2,-1],[2,2,0,0,0,0,2,2],[2,3,1,0,0,1,3,2]],E=[[-2,-1,-1,-.5,-.5,-1,-1,-2],[-1,0,0,0,0,0,0,-1],[-1,0,.5,.5,.5,.5,0,-1],[-.5,0,.5,.5,.5,.5,0,-.5],[0,0,.5,.5,.5,.5,0,-.5],[-1,.5,.5,.5,.5,.5,0,-1],[-1,0,.5,0,0,0,0,-1],[-2,-1,-1,-.5,-.5,-1,-1,-2]],B={P:g.slice().reverse(),p:g,N:f.slice().reverse(),n:f,B:C.slice().reverse(),b:C,R:P.slice().reverse(),r:P,K:p.slice().reverse(),k:p,Q:E.slice().reverse(),q:E};function F(t){return h.UP[t]}function G(t){return h.DOWN[t]}function D(t){return h.LEFT[t]}function A(t){return h.RIGHT[t]}function H(t){return h.UP_LEFT[t]}function b(t){return h.UP_RIGHT[t]}function d(t){return h.DOWN_LEFT[t]}function k(t){return h.DOWN_RIGHT[t]}function v(t){const e=H(t);return e?F(e):null}function y(t){const e=H(t);return e?D(e):null}function w(t){const e=b(t);return e?F(e):null}function O(t){const e=b(t);return e?A(e):null}function L(t){const e=d(t);return e?G(e):null}function M(t){const e=d(t);return e?D(e):null}function m(t){const e=k(t);return e?G(e):null}function K(t){const e=k(t);return e?A(e):null}function N(t,e){return e===c?h.UP[t]:h.DOWN[t]}function S(t,e){return e===c?h.UP_LEFT[t]:h.DOWN_RIGHT[t]}function j(t,e){return e===c?h.UP_RIGHT[t]:h.DOWN_LEFT[t]}function _(t,e){return e===c?h.DOWN_LEFT[t]:h.UP_RIGHT[t]}function R(t,e){return e===c?h.DOWN_RIGHT[t]:h.UP_LEFT[t]}function U(t){let e=0;switch(t){case"K":e=10;break;case"Q":e=9;break;case"R":e=5;break;case"B":case"N":e=3;break;case"P":e=1;break;case"k":e=10;break;case"q":e=9;break;case"r":e=5;break;case"b":case"n":e=3;break;case"p":e=1}return e}function W(t){return"string"==typeof t&&t.match("^[a-hA-H]{1}[1-8]{1}$")}const T=-1e3,I=1e3;class Q{constructor(t=JSON.parse(JSON.stringify(u))){if("object"==typeof t)this.configuration=Object.assign({},a,t);else{if("string"!=typeof t)throw new Error(`Unknown configuration type ${typeof config}.`);this.configuration=Object.assign({},a,function(t=""){const e={pieces:{}},i=t.split(" "),s=i[0],l=i[1],a=i[2],u=i[3],h=i[4],g=i[5];let f=0,C=o.length-1;for(let t=0;t<s.length;t++)["K","Q","R","B","N","P","k","q","r","b","n","p"].includes(s[t])?(e.pieces[`${n[f]}${o[C]}`]=s[t],f++):["1","2","3","4","5","6","7","8"].includes(s[t])?f+=parseInt(s[t]):"/"===s[t]&&(C--,f=0);return e.turn="b"===l?r:c,e.castling={whiteLong:!1,whiteShort:!1,blackLong:!1,blackShort:!1},a.includes("K")&&(e.castling.whiteShort=!0),a.includes("k")&&(e.castling.blackShort=!0),a.includes("Q")&&(e.castling.whiteLong=!0),a.includes("q")&&(e.castling.blackLong=!0),W(u)&&(e.enPassant=u.toUpperCase()),e.halfMove=parseInt(h),e.fullMove=parseInt(g),e}(t))}this.configuration.castling||(this.configuration.castling={whiteShort:!0,blackShort:!0,whiteLong:!0,blackLong:!0}),this.history=[]}getAttackingFields(t=this.getPlayingColor()){let e=[];for(const i in this.configuration.pieces){const n=this.getPiece(i);this.getPieceColor(n)===t&&(e=[...e,...this.getPieceMoves(n,i)])}return e}isAttackingKing(t=this.getPlayingColor()){let e=null;for(const i in this.configuration.pieces){const n=this.getPiece(i);if(this.isKing(n)&&this.getPieceColor(n)!==t){e=i;break}}return this.isPieceUnderAttack(e)}isPieceUnderAttack(t){const e=this.getPieceOnLocationColor(t),i=this.getEnemyColor(e);let n=!1,o=t,s=0;for(;F(o)&&!n;){o=F(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;G(o)&&!n;){o=G(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;D(o)&&!n;){o=D(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;A(o)&&!n;){o=A(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;j(o,e)&&!n;){o=j(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||1===s&&(this.isKing(t)||this.isPawn(t)))&&(n=!0),t)break}for(o=t,s=0;S(o,e)&&!n;){o=S(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||1===s&&(this.isKing(t)||this.isPawn(t)))&&(n=!0),t)break}for(o=t,s=0;R(o,e)&&!n;){o=R(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;_(o,e)&&!n;){o=_(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}o=w(t);let r=this.getPiece(o);return r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=O(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=y(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=v(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=L(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=M(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=m(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=K(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),n}hasPlayingPlayerCheck(){return this.isAttackingKing(this.getNonPlayingColor())}hasNonPlayingPlayerCheck(){return this.isAttackingKing(this.getPlayingColor())}getLowestValuePieceAttackingLocation(t,e=this.getPlayingColor()){let i=null;for(const n in this.configuration.pieces){const o=this.getPiece(n);this.getPieceColor(o)===e&&this.getPieceMoves(o,n).map(e=>{e===t&&(null===i||U(o)<i)&&(i=U(o))})}return i}getMoves(t=this.getPlayingColor(),e=null){const i={};let n=0;for(const e in this.configuration.pieces){const o=this.getPiece(e);if(this.getPieceColor(o)===t){const t=this.getPieceMoves(o,e);t.length&&n++,Object.assign(i,{[e]:t})}}const o=this.getAttackingFields(this.getNonPlayingColor());if(this.isLeftCastlingPossible(o)&&(this.isPlayingWhite()&&i.E1.push("C1"),this.isPlayingBlack()&&i.E8.push("C8")),this.isRightCastlingPossible(o)&&(this.isPlayingWhite()&&i.E1.push("G1"),this.isPlayingBlack()&&i.E8.push("G8")),e&&n>e)return i;const s={};for(const t in i)i[t].map(e=>{const i={pieces:Object.assign({},this.configuration.pieces),castling:Object.assign({},this.configuration.castling)},n=new Q(i);n.move(t,e),(this.isPlayingWhite()&&!n.isAttackingKing(r)||this.isPlayingBlack()&&!n.isAttackingKing(c))&&(s[t]||(s[t]=[]),s[t].push(e))});return Object.keys(s).length||(this.configuration.isFinished=!0,this.hasPlayingPlayerCheck()&&(this.configuration.checkMate=!0)),s}isLeftCastlingPossible(t){if(this.isPlayingWhite()&&!this.configuration.castling.whiteLong)return!1;if(this.isPlayingBlack()&&!this.configuration.castling.blackLong)return!1;let e=null;if(this.isPlayingWhite()&&"K"===this.getPiece("E1")&&"R"===this.getPiece("A1")&&!t.includes("E1")?e="E1":this.isPlayingBlack()&&"k"===this.getPiece("E8")&&"r"===this.getPiece("A8")&&!t.includes("E8")&&(e="E8"),!e)return!1;let i=D(e);return!this.getPiece(i)&&!t.includes(i)&&(i=D(i),!this.getPiece(i)&&!t.includes(i)&&(i=D(i),!this.getPiece(i)))}isRightCastlingPossible(t){if(this.isPlayingWhite()&&!this.configuration.castling.whiteShort)return!1;if(this.isPlayingBlack()&&!this.configuration.castling.blackShort)return!1;let e=null;if(this.isPlayingWhite()&&"K"===this.getPiece("E1")&&"R"===this.getPiece("H1")&&!t.includes("E1")?e="E1":this.isPlayingBlack()&&"k"===this.getPiece("E8")&&"r"===this.getPiece("H8")&&!t.includes("E8")&&(e="E8"),!e)return!1;let i=A(e);return!this.getPiece(i)&&!t.includes(i)&&(i=A(i),!this.getPiece(i)&&!t.includes(i))}getPieceMoves(t,e){return this.isPawn(t)?this.getPawnMoves(t,e):this.isKnight(t)?this.getKnightMoves(t,e):this.isRook(t)?this.getRookMoves(t,e):this.isBishop(t)?this.getBishopMoves(t,e):this.isQueen(t)?this.getQueenMoves(t,e):this.isKing(t)?this.getKingMoves(t,e):[]}isPawn(t){return"P"===t.toUpperCase()}isKnight(t){return"N"===t.toUpperCase()}isRook(t){return"R"===t.toUpperCase()}isBishop(t){return"B"===t.toUpperCase()}isQueen(t){return"Q"===t.toUpperCase()}isKing(t){return"K"===t.toUpperCase()}getPawnMoves(t,e){const i=[],n=this.getPieceColor(t);let o=N(e,n);return o&&!this.getPiece(o)&&(i.push(o),o=N(o,n),function(t,e){if(t===c&&"2"===e[1])return!0;if(t===r&&"7"===e[1])return!0;return!1}(n,e)&&o&&!this.getPiece(o)&&i.push(o)),o=S(e,n),o&&(this.getPiece(o)&&this.getPieceOnLocationColor(o)!==n||o===this.configuration.enPassant)&&i.push(o),o=j(e,n),o&&(this.getPiece(o)&&this.getPieceOnLocationColor(o)!==n||o===this.configuration.enPassant)&&i.push(o),i}getKnightMoves(t,e){const i=[],n=this.getPieceColor(t);let o=w(e);return o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=O(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=v(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=y(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=M(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=L(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=K(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=m(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),i}getRookMoves(t,e){const i=[],n=this.getPieceColor(t);let o=e;for(;F(o);){o=F(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;G(o);){o=G(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;A(o);){o=A(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;D(o);){o=D(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}return i}getBishopMoves(t,e){const i=[],n=this.getPieceColor(t);let o=e;for(;H(o);){o=H(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;b(o);){o=b(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;d(o);){o=d(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;k(o);){o=k(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}return i}getQueenMoves(t,e){return[...this.getRookMoves(t,e),...this.getBishopMoves(t,e)]}getKingMoves(t,e){const i=[],n=this.getPieceColor(t);let o=e;return o=F(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=A(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=G(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=D(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=H(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=b(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=d(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=k(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),i}getPieceColor(t){return t.toUpperCase()===t?c:r}getPieceOnLocationColor(t){const e=this.getPiece(t);return e?e.toUpperCase()===e?c:r:null}getPiece(t){return this.configuration.pieces[t]}setPiece(t,e){if(!function(t){return Object.values(s).includes(t)}(e))throw new Error("Invalid piece "+e);if(!W(t))throw new Error("Invalid location "+t);this.configuration.pieces[t.toUpperCase()]=e}removePiece(t){if(!W(t))throw new Error("Invalid location "+t);delete this.configuration.pieces[t.toUpperCase()]}isEmpty(t){if(!W(t))throw new Error("Invalid location "+t);return!this.configuration.pieces[t.toUpperCase()]}getEnemyColor(t){return t===c?r:c}getPlayingColor(){return this.configuration.turn}getNonPlayingColor(){return this.isPlayingWhite()?r:c}isPlayingWhite(){return this.configuration.turn===c}isPlayingBlack(){return this.configuration.turn===r}addMoveToHistory(t,e){this.history.push({from:t,to:e,configuration:JSON.parse(JSON.stringify(this.configuration))})}move(t,e){const i=this.getPiece(t),n=this.getPiece(e);if(!i)throw new Error("There is no piece at "+t);var o,s;if(Object.assign(this.configuration.pieces,{[e]:i}),delete this.configuration.pieces[t],this.isPlayingWhite()&&this.isPawn(i)&&"8"===e[1]&&Object.assign(this.configuration.pieces,{[e]:"Q"}),this.isPlayingBlack()&&this.isPawn(i)&&"1"===e[1]&&Object.assign(this.configuration.pieces,{[e]:"q"}),this.isPawn(i)&&e===this.configuration.enPassant&&delete this.configuration.pieces[(o=e,s=this.getPlayingColor(),s===c?h.DOWN[o]:h.UP[o])],this.isPawn(i)&&this.isPlayingWhite()&&"2"===t[1]&&"4"===e[1]?this.configuration.enPassant=t[0]+"3":this.isPawn(i)&&this.isPlayingBlack()&&"7"===t[1]&&"5"===e[1]?this.configuration.enPassant=t[0]+"6":this.configuration.enPassant=null,"E1"===t&&Object.assign(this.configuration.castling,{whiteLong:!1,whiteShort:!1}),"E8"===t&&Object.assign(this.configuration.castling,{blackLong:!1,blackShort:!1}),"A1"===t&&Object.assign(this.configuration.castling,{whiteLong:!1}),"H1"===t&&Object.assign(this.configuration.castling,{whiteShort:!1}),"A8"===t&&Object.assign(this.configuration.castling,{blackLong:!1}),"H8"===t&&Object.assign(this.configuration.castling,{blackShort:!1}),this.isKing(i)){if("E1"===t&&"C1"===e)return this.move("A1","D1");if("E8"===t&&"C8"===e)return this.move("A8","D8");if("E1"===t&&"G1"===e)return this.move("H1","F1");if("E8"===t&&"G8"===e)return this.move("H8","F8")}this.configuration.turn=this.isPlayingWhite()?r:c,this.isPlayingWhite()&&this.configuration.fullMove++,this.configuration.halfMove++,(n||this.isPawn(i))&&(this.configuration.halfMove=0)}exportJson(){return{moves:this.getMoves(),pieces:this.configuration.pieces,turn:this.configuration.turn,isFinished:this.configuration.isFinished,check:this.hasPlayingPlayerCheck(),checkMate:this.configuration.checkMate,castling:this.configuration.castling,enPassant:this.configuration.enPassant,halfMove:this.configuration.halfMove,fullMove:this.configuration.fullMove}}calculateAiMove(t){return this.calculateAiMoves(t)[0]}calculateAiMoves(t){if(t=parseInt(t),!l.includes(t))throw new Error(`Invalid level ${t}. You can choose ${l.join(",")}`);const e=[],i=this.calculateScore(this.getPlayingColor()),n=this.getMoves();for(const o in n)n[o].map(n=>{const s=this.getTestBoard(),r=Boolean(s.getPiece(n));s.move(o,n),e.push({from:o,to:n,score:s.testMoveScores(this.getPlayingColor(),t,r?s.calculateScore(this.getPlayingColor()):i,n).score+s.calculateScoreByPiecesLocation(this.getPlayingColor())+Math.floor(10*Math.random())/10})});return e.sort((t,e)=>t.score<e.score?0:-1),e}getIngamePiecesValue(){let t=0;for(const e in this.configuration.pieces){t+=U(this.getPiece(e))}return t}getTestBoard(){const t={pieces:Object.assign({},this.configuration.pieces),castling:Object.assign({},this.configuration.castling),turn:this.configuration.turn,enPassant:this.configuration.enPassant};return new Q(t)}testMoveScores(t,e,i,n,o=1){let s={};if(this.hasPlayingPlayerCheck()?s=this.getMoves(this.getPlayingColor()):o<3&&(s=this.getMoves(this.getPlayingColor(),5)),this.configuration.isFinished)return{score:this.calculateScore(t)+(this.getPlayingColor()===t?o:-o),max:!0};if(o>=3){if(null!==i)return{score:i,max:!1};let o=this.calculateScore(t);return e>=3&&this.isPieceUnderAttack(n)&&(o-=10*U(this.getPiece(n))),{score:o,max:!1}}let r=this.getPlayingColor()===t?T:I,c=!1;for(const n in s)c||s[n].map(s=>{if(c)return;const l=this.getTestBoard(),a=Boolean(l.getPiece(s));if(l.move(n,s),l.hasNonPlayingPlayerCheck())return;const u=l.testMoveScores(t,e,a?l.calculateScore(t):i,s,o+1);u.max&&(c=!0),r=this.getPlayingColor()===t?Math.max(r,u.score):Math.min(r,u.score)});return{score:r,max:!1}}calculateScoreByPiecesLocation(t=this.getPlayingColor()){const e={A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7};let i=0;for(const n in this.configuration.pieces){const o=this.getPiece(n);if(B[o]){const s=B[o][n[1]-1][e[n[0]]];i+=.5*(this.getPieceColor(o)===t?s:-s)}}return i}calculateScore(t=this.getPlayingColor()){let e=0;if(this.configuration.checkMate)return this.getPlayingColor()===t?T:I;if(this.configuration.isFinished)return this.getPlayingColor()===t?I:T;for(const i in this.configuration.pieces){const n=this.getPiece(i);this.getPieceColor(n)===t?e+=10*U(n):e-=10*U(n)}return e}}class x{constructor(t){this.board=new Q(t)}move(t,e){t=t.toUpperCase(),e=e.toUpperCase();const i=this.board.getMoves();if(!i[t]||!i[t].includes(e))throw new Error(`Invalid move from ${t} to ${e} for ${this.board.getPlayingColor()}`);return this.board.addMoveToHistory(t,e),this.board.move(t,e),{[t]:e}}moves(t=null){return(t?this.board.getMoves()[t.toUpperCase()]:this.board.getMoves())||[]}setPiece(t,e){this.board.setPiece(t,e)}removePiece(t){this.board.removePiece(t)}aiMove(t=2){const e=this.board.calculateAiMove(t);return this.move(e.from,e.to)}getHistory(t=!1){return t?this.board.history.reverse():this.board.history}printToConsole(){!function(t){process.stdout.write("\n");let e=c;Object.assign([],o).reverse().map(i=>{process.stdout.write(""+i),n.map(n=>{switch(t.pieces[`${n}${i}`]){case"K":process.stdout.write("♚");break;case"Q":process.stdout.write("♛");break;case"R":process.stdout.write("♜");break;case"B":process.stdout.write("♝");break;case"N":process.stdout.write("♞");break;case"P":process.stdout.write("♟");break;case"k":process.stdout.write("♔");break;case"q":process.stdout.write("♕");break;case"r":process.stdout.write("♖");break;case"b":process.stdout.write("♗");break;case"n":process.stdout.write("♘");break;case"p":process.stdout.write("♙");break;default:process.stdout.write(e===c?"█":"░")}e=e===c?r:c}),e=e===c?r:c,process.stdout.write("\n")}),process.stdout.write(" "),n.map(t=>{process.stdout.write(""+t)}),process.stdout.write("\n")}(this.board.configuration)}exportJson(){return this.board.exportJson()}exportFEN(){return function(t){let e="";Object.assign([],o).reverse().map(i=>{let o=0;i<8&&(e+="/"),n.map(n=>{const s=t.pieces[`${n}${i}`];s?(o&&(e+=o.toString(),o=0),e+=s):o++}),e+=""+(o||"")}),e+=t.turn===c?" w ":" b ";const{whiteShort:i,whiteLong:s,blackLong:r,blackShort:l}=t.castling;return s||i||r||l?(i&&(e+="K"),s&&(e+="Q"),l&&(e+="k"),r&&(e+="q")):e+="-",e+=" "+(t.enPassant?t.enPassant.toLowerCase():"-"),e+=" "+t.halfMove,e+=" "+t.fullMove,e}(this.board.configuration)}}function q(t){if(!t)throw new Error("Configuration param required.");return new x(t).moves()}function $(t){if(!t)throw new Error("Configuration param required.");return new x(t).exportJson()}function J(t){if(!t)throw new Error("Configuration param required.");return new x(t).exportFEN()}function V(t,e,i){if(!t)throw new Error("Configuration param required.");const n=new x(t);return n.move(e,i),"object"==typeof t?n.exportJson():n.exportFEN()}function Y(t,e=2){if(!t)throw new Error("Configuration param required.");const i=new x(t).board.calculateAiMove(e);return{[i.from]:i.to}}}])}));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("js-chess-engine",[],e):"object"==typeof exports?exports["js-chess-engine"]=e():t["js-chess-engine"]=e()}(this,(function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)i.d(n,o,function(e){return t[e]}.bind(null,o));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,i){"use strict";i.r(e),i.d(e,"Game",(function(){return $})),i.d(e,"moves",(function(){return J})),i.d(e,"status",(function(){return V})),i.d(e,"getFen",(function(){return Y})),i.d(e,"move",(function(){return z})),i.d(e,"aiMove",(function(){return X}));const n=["A","B","C","D","E","F","G","H"],o=["1","2","3","4","5","6","7","8"],s={KING_W:"K",QUEEN_W:"Q",ROOK_W:"R",BISHOP_W:"B",KNIGHT_W:"N",PAWN_W:"P",KING_B:"k",QUEEN_B:"q",ROOK_B:"r",BISHOP_B:"b",KNIGHT_B:"n",PAWN_B:"p"},r="black",c="white",l=[0,1,2,3,4],a={0:1,1:2,2:2,3:3,4:3,5:4},u={0:2,1:2,2:4,3:4,4:5,5:5},h={fullMove:1,halfMove:0,enPassant:null,isFinished:!1,checkMate:!1,check:!1,turn:c},g=Object.assign({pieces:{E1:"K",D1:"Q",A1:"R",H1:"R",C1:"B",F1:"B",B1:"N",G1:"N",A2:"P",B2:"P",C2:"P",D2:"P",E2:"P",F2:"P",G2:"P",H2:"P",E8:"k",D8:"q",A8:"r",H8:"r",C8:"b",F8:"b",B8:"n",G8:"n",A7:"p",B7:"p",C7:"p",D7:"p",E7:"p",F7:"p",G7:"p",H7:"p"},castling:{whiteShort:!0,blackShort:!0,whiteLong:!0,blackLong:!0}},h),f={UP:{A1:"A2",A2:"A3",A3:"A4",A4:"A5",A5:"A6",A6:"A7",A7:"A8",A8:null,B1:"B2",B2:"B3",B3:"B4",B4:"B5",B5:"B6",B6:"B7",B7:"B8",B8:null,C1:"C2",C2:"C3",C3:"C4",C4:"C5",C5:"C6",C6:"C7",C7:"C8",C8:null,D1:"D2",D2:"D3",D3:"D4",D4:"D5",D5:"D6",D6:"D7",D7:"D8",D8:null,E1:"E2",E2:"E3",E3:"E4",E4:"E5",E5:"E6",E6:"E7",E7:"E8",E8:null,F1:"F2",F2:"F3",F3:"F4",F4:"F5",F5:"F6",F6:"F7",F7:"F8",F8:null,G1:"G2",G2:"G3",G3:"G4",G4:"G5",G5:"G6",G6:"G7",G7:"G8",G8:null,H1:"H2",H2:"H3",H3:"H4",H4:"H5",H5:"H6",H6:"H7",H7:"H8",H8:null},DOWN:{A1:null,A2:"A1",A3:"A2",A4:"A3",A5:"A4",A6:"A5",A7:"A6",A8:"A7",B1:null,B2:"B1",B3:"B2",B4:"B3",B5:"B4",B6:"B5",B7:"B6",B8:"B7",C1:null,C2:"C1",C3:"C2",C4:"C3",C5:"C4",C6:"C5",C7:"C6",C8:"C7",D1:null,D2:"D1",D3:"D2",D4:"D3",D5:"D4",D6:"D5",D7:"D6",D8:"D7",E1:null,E2:"E1",E3:"E2",E4:"E3",E5:"E4",E6:"E5",E7:"E6",E8:"E7",F1:null,F2:"F1",F3:"F2",F4:"F3",F5:"F4",F6:"F5",F7:"F6",F8:"F7",G1:null,G2:"G1",G3:"G2",G4:"G3",G5:"G4",G6:"G5",G7:"G6",G8:"G7",H1:null,H2:"H1",H3:"H2",H4:"H3",H5:"H4",H6:"H5",H7:"H6",H8:"H7"},LEFT:{A1:null,A2:null,A3:null,A4:null,A5:null,A6:null,A7:null,A8:null,B1:"A1",B2:"A2",B3:"A3",B4:"A4",B5:"A5",B6:"A6",B7:"A7",B8:"A8",C1:"B1",C2:"B2",C3:"B3",C4:"B4",C5:"B5",C6:"B6",C7:"B7",C8:"B8",D1:"C1",D2:"C2",D3:"C3",D4:"C4",D5:"C5",D6:"C6",D7:"C7",D8:"C8",E1:"D1",E2:"D2",E3:"D3",E4:"D4",E5:"D5",E6:"D6",E7:"D7",E8:"D8",F1:"E1",F2:"E2",F3:"E3",F4:"E4",F5:"E5",F6:"E6",F7:"E7",F8:"E8",G1:"F1",G2:"F2",G3:"F3",G4:"F4",G5:"F5",G6:"F6",G7:"F7",G8:"F8",H1:"G1",H2:"G2",H3:"G3",H4:"G4",H5:"G5",H6:"G6",H7:"G7",H8:"G8"},RIGHT:{A1:"B1",A2:"B2",A3:"B3",A4:"B4",A5:"B5",A6:"B6",A7:"B7",A8:"B8",B1:"C1",B2:"C2",B3:"C3",B4:"C4",B5:"C5",B6:"C6",B7:"C7",B8:"C8",C1:"D1",C2:"D2",C3:"D3",C4:"D4",C5:"D5",C6:"D6",C7:"D7",C8:"D8",D1:"E1",D2:"E2",D3:"E3",D4:"E4",D5:"E5",D6:"E6",D7:"E7",D8:"E8",E1:"F1",E2:"F2",E3:"F3",E4:"F4",E5:"F5",E6:"F6",E7:"F7",E8:"F8",F1:"G1",F2:"G2",F3:"G3",F4:"G4",F5:"G5",F6:"G6",F7:"G7",F8:"G8",G1:"H1",G2:"H2",G3:"H3",G4:"H4",G5:"H5",G6:"H6",G7:"H7",G8:"H8",H1:null,H2:null,H3:null,H4:null,H5:null,H6:null,H7:null,H8:null},UP_LEFT:{A1:null,A2:null,A3:null,A4:null,A5:null,A6:null,A7:null,A8:null,B1:"A2",B2:"A3",B3:"A4",B4:"A5",B5:"A6",B6:"A7",B7:"A8",B8:null,C1:"B2",C2:"B3",C3:"B4",C4:"B5",C5:"B6",C6:"B7",C7:"B8",C8:null,D1:"C2",D2:"C3",D3:"C4",D4:"C5",D5:"C6",D6:"C7",D7:"C8",D8:null,E1:"D2",E2:"D3",E3:"D4",E4:"D5",E5:"D6",E6:"D7",E7:"D8",E8:null,F1:"E2",F2:"E3",F3:"E4",F4:"E5",F5:"E6",F6:"E7",F7:"E8",F8:null,G1:"F2",G2:"F3",G3:"F4",G4:"F5",G5:"F6",G6:"F7",G7:"F8",G8:null,H1:"G2",H2:"G3",H3:"G4",H4:"G5",H5:"G6",H6:"G7",H7:"G8",H8:null},DOWN_RIGHT:{A1:null,A2:"B1",A3:"B2",A4:"B3",A5:"B4",A6:"B5",A7:"B6",A8:"B7",B1:null,B2:"C1",B3:"C2",B4:"C3",B5:"C4",B6:"C5",B7:"C6",B8:"C7",C1:null,C2:"D1",C3:"D2",C4:"D3",C5:"D4",C6:"D5",C7:"D6",C8:"D7",D1:null,D2:"E1",D3:"E2",D4:"E3",D5:"E4",D6:"E5",D7:"E6",D8:"E7",E1:null,E2:"F1",E3:"F2",E4:"F3",E5:"F4",E6:"F5",E7:"F6",E8:"F7",F1:null,F2:"G1",F3:"G2",F4:"G3",F5:"G4",F6:"G5",F7:"G6",F8:"G7",G1:null,G2:"H1",G3:"H2",G4:"H3",G5:"H4",G6:"H5",G7:"H6",G8:"H7",H1:null,H2:null,H3:null,H4:null,H5:null,H6:null,H7:null,H8:null},UP_RIGHT:{A1:"B2",A2:"B3",A3:"B4",A4:"B5",A5:"B6",A6:"B7",A7:"B8",A8:null,B1:"C2",B2:"C3",B3:"C4",B4:"C5",B5:"C6",B6:"C7",B7:"C8",B8:null,C1:"D2",C2:"D3",C3:"D4",C4:"D5",C5:"D6",C6:"D7",C7:"D8",C8:null,D1:"E2",D2:"E3",D3:"E4",D4:"E5",D5:"E6",D6:"E7",D7:"E8",D8:null,E1:"F2",E2:"F3",E3:"F4",E4:"F5",E5:"F6",E6:"F7",E7:"F8",E8:null,F1:"G2",F2:"G3",F3:"G4",F4:"G5",F5:"G6",F6:"G7",F7:"G8",F8:null,G1:"H2",G2:"H3",G3:"H4",G4:"H5",G5:"H6",G6:"H7",G7:"H8",G8:null,H1:null,H2:null,H3:null,H4:null,H5:null,H6:null,H7:null,H8:null},DOWN_LEFT:{A1:null,A2:null,A3:null,A4:null,A5:null,A6:null,A7:null,A8:null,B1:null,B2:"A1",B3:"A2",B4:"A3",B5:"A4",B6:"A5",B7:"A6",B8:"A7",C1:null,C2:"B1",C3:"B2",C4:"B3",C5:"B4",C6:"B5",C7:"B6",C8:"B7",D1:null,D2:"C1",D3:"C2",D4:"C3",D5:"C4",D6:"C5",D7:"C6",D8:"C7",E1:null,E2:"D1",E3:"D2",E4:"D3",E5:"D4",E6:"D5",E7:"D6",E8:"D7",F1:null,F2:"E1",F3:"E2",F4:"E3",F5:"E4",F6:"E5",F7:"E6",F8:"E7",G1:null,G2:"F1",G3:"F2",G4:"F3",G5:"F4",G6:"F5",G7:"F6",G8:"F7",H1:null,H2:"G1",H3:"G2",H4:"G3",H5:"G4",H6:"G5",H7:"G6",H8:"G7"}},C=[[0,0,0,0,0,0,0,0],[5,5,5,5,5,5,5,5],[1,1,2,3,3,2,1,1],[.5,.5,1,2.5,2.5,1,.5,.5],[0,0,0,2,2,0,0,0],[.5,0,1,0,0,1,0,.5],[.5,0,0,-2,-2,0,0,.5],[0,0,0,0,0,0,0,0]],P=[[-4,-3,-2,-2,-2,-2,-3,-4],[-3,-2,0,0,0,0,-2,-3],[-2,0,1,1.5,1.5,1,0,-2],[-2,.5,1.5,2,2,1.5,.5,-2],[-2,0,1.5,2,2,1.5,0,-2],[-2,.5,1,1.5,1.5,1,.5,-2],[-3,-2,0,.5,.5,0,-2,-3],[-4,-3,-2,-2,-2,-2,-3,-4]],p=[[-2,-1,-1,-1,-1,-1,-1,-2],[-1,0,0,0,0,0,0,-1],[-1,0,.5,1,1,.5,0,-1],[-1,.5,.5,1,1,.5,.5,-1],[-1,0,1,1,1,1,0,-1],[-1,1,1,1,1,1,1,-1],[-1,.5,0,0,0,0,.5,-1],[-2,-1,-1,-1,-1,-1,-1,-2]],E=[[0,0,0,0,0,0,0,0],[.5,1,1,1,1,1,1,.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[-.5,0,0,0,0,0,0,-.5],[0,0,0,.5,.5,0,0,0]],B=[[-3,-4,-4,-5,-5,-4,-4,-3],[-3,-4,-4,-5,-5,-4,-4,-3],[-3,-4,-4,-5,-5,-4,-4,-3],[-3,-4,-4,-5,-5,-4,-4,-3],[-2,-3,-3,-4,-4,-3,-3,-2],[-1,-2,-2,-2,-2,-2,-2,-1],[2,2,0,0,0,0,2,2],[2,3,1,0,0,1,3,2]],F=[[-2,-1,-1,-.5,-.5,-1,-1,-2],[-1,0,0,0,0,0,0,-1],[-1,0,.5,.5,.5,.5,0,-1],[-.5,0,.5,.5,.5,.5,0,-.5],[0,0,.5,.5,.5,.5,0,-.5],[-1,.5,.5,.5,.5,.5,0,-1],[-1,0,.5,0,0,0,0,-1],[-2,-1,-1,-.5,-.5,-1,-1,-2]],G={P:C.slice().reverse(),p:C,N:P.slice().reverse(),n:P,B:p.slice().reverse(),b:p,R:E.slice().reverse(),r:E,K:B.slice().reverse(),k:B,Q:F.slice().reverse(),q:F};function D(t){return f.UP[t]}function A(t){return f.DOWN[t]}function H(t){return f.LEFT[t]}function b(t){return f.RIGHT[t]}function d(t){return f.UP_LEFT[t]}function v(t){return f.UP_RIGHT[t]}function k(t){return f.DOWN_LEFT[t]}function y(t){return f.DOWN_RIGHT[t]}function w(t){const e=d(t);return e?D(e):null}function O(t){const e=d(t);return e?H(e):null}function L(t){const e=v(t);return e?D(e):null}function m(t){const e=v(t);return e?b(e):null}function M(t){const e=k(t);return e?A(e):null}function K(t){const e=k(t);return e?H(e):null}function N(t){const e=y(t);return e?A(e):null}function S(t){const e=y(t);return e?b(e):null}function j(t,e){return e===c?f.UP[t]:f.DOWN[t]}function _(t,e){return e===c?f.UP_LEFT[t]:f.DOWN_RIGHT[t]}function W(t,e){return e===c?f.UP_RIGHT[t]:f.DOWN_LEFT[t]}function U(t,e){return e===c?f.DOWN_LEFT[t]:f.UP_RIGHT[t]}function R(t,e){return e===c?f.DOWN_RIGHT[t]:f.UP_LEFT[t]}function T(t){return{k:10,q:9,r:5,b:3,n:3,p:1}[t.toLowerCase()]||0}function I(t){return"string"==typeof t&&t.match("^[a-hA-H]{1}[1-8]{1}$")}const x=-1e3,Q=1e3;class q{constructor(t=JSON.parse(JSON.stringify(g))){if("object"==typeof t)this.configuration=Object.assign({},h,t);else{if("string"!=typeof t)throw new Error(`Unknown configuration type ${typeof config}.`);this.configuration=Object.assign({},h,function(t=""){const[e,i,s,l,a,u]=t.split(" "),h={pieces:Object.fromEntries(e.split("/").flatMap((t,e)=>{let i=0;return t.split("").reduce((t,s)=>{const r=s.match(/k|b|q|n|p|r/i);r&&(t.push([`${n[i]}${o[7-e]}`,r[0]]),i+=1);const c=s.match(/[1-8]/);return c&&(i+=Number(c)),t},[])}))};return h.turn="b"===i?r:c,h.castling={whiteLong:!1,whiteShort:!1,blackLong:!1,blackShort:!1},s.includes("K")&&(h.castling.whiteShort=!0),s.includes("k")&&(h.castling.blackShort=!0),s.includes("Q")&&(h.castling.whiteLong=!0),s.includes("q")&&(h.castling.blackLong=!0),I(l)&&(h.enPassant=l.toUpperCase()),h.halfMove=parseInt(a),h.fullMove=parseInt(u),h}(t))}this.configuration.castling||(this.configuration.castling={whiteShort:!0,blackShort:!0,whiteLong:!0,blackLong:!0}),this.history=[]}getAttackingFields(t=this.getPlayingColor()){let e=[];for(const i in this.configuration.pieces){const n=this.getPiece(i);this.getPieceColor(n)===t&&(e=[...e,...this.getPieceMoves(n,i)])}return e}isAttackingKing(t=this.getPlayingColor()){let e=null;for(const i in this.configuration.pieces){const n=this.getPiece(i);if(this.isKing(n)&&this.getPieceColor(n)!==t){e=i;break}}return this.isPieceUnderAttack(e)}isPieceUnderAttack(t){const e=this.getPieceOnLocationColor(t),i=this.getEnemyColor(e);let n=!1,o=t,s=0;for(;D(o)&&!n;){o=D(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;A(o)&&!n;){o=A(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;H(o)&&!n;){o=H(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;b(o)&&!n;){o=b(o),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isRook(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;W(o,e)&&!n;){o=W(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||1===s&&(this.isKing(t)||this.isPawn(t)))&&(n=!0),t)break}for(o=t,s=0;_(o,e)&&!n;){o=_(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||1===s&&(this.isKing(t)||this.isPawn(t)))&&(n=!0),t)break}for(o=t,s=0;R(o,e)&&!n;){o=R(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}for(o=t,s=0;U(o,e)&&!n;){o=U(o,e),s++;const t=this.getPiece(o);if(t&&this.getPieceColor(t)===i&&(this.isBishop(t)||this.isQueen(t)||this.isKing(t)&&1===s)&&(n=!0),t)break}o=L(t);let r=this.getPiece(o);return r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=m(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=O(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=w(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=M(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=K(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=N(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),o=S(t),r=this.getPiece(o),r&&this.getPieceColor(r)===i&&this.isKnight(r)&&(n=!0),n}hasPlayingPlayerCheck(){return this.isAttackingKing(this.getNonPlayingColor())}hasNonPlayingPlayerCheck(){return this.isAttackingKing(this.getPlayingColor())}getLowestValuePieceAttackingLocation(t,e=this.getPlayingColor()){let i=null;for(const n in this.configuration.pieces){const o=this.getPiece(n);this.getPieceColor(o)===e&&this.getPieceMoves(o,n).map(e=>{e===t&&(null===i||T(o)<i)&&(i=T(o))})}return i}getMoves(t=this.getPlayingColor(),e=null){const i={};let n=0;for(const e in this.configuration.pieces){const o=this.getPiece(e);if(this.getPieceColor(o)===t){const t=this.getPieceMoves(o,e);t.length&&n++,Object.assign(i,{[e]:t})}}const o=this.getAttackingFields(this.getNonPlayingColor());if(this.isLeftCastlingPossible(o)&&(this.isPlayingWhite()&&i.E1.push("C1"),this.isPlayingBlack()&&i.E8.push("C8")),this.isRightCastlingPossible(o)&&(this.isPlayingWhite()&&i.E1.push("G1"),this.isPlayingBlack()&&i.E8.push("G8")),e&&n>e)return i;const s={};for(const t in i)i[t].map(e=>{const i={pieces:Object.assign({},this.configuration.pieces),castling:Object.assign({},this.configuration.castling)},n=new q(i);n.move(t,e),(this.isPlayingWhite()&&!n.isAttackingKing(r)||this.isPlayingBlack()&&!n.isAttackingKing(c))&&(s[t]||(s[t]=[]),s[t].push(e))});return Object.keys(s).length||(this.configuration.isFinished=!0,this.hasPlayingPlayerCheck()&&(this.configuration.checkMate=!0)),s}isLeftCastlingPossible(t){if(this.isPlayingWhite()&&!this.configuration.castling.whiteLong)return!1;if(this.isPlayingBlack()&&!this.configuration.castling.blackLong)return!1;let e=null;if(this.isPlayingWhite()&&"K"===this.getPiece("E1")&&"R"===this.getPiece("A1")&&!t.includes("E1")?e="E1":this.isPlayingBlack()&&"k"===this.getPiece("E8")&&"r"===this.getPiece("A8")&&!t.includes("E8")&&(e="E8"),!e)return!1;let i=H(e);return!this.getPiece(i)&&!t.includes(i)&&(i=H(i),!this.getPiece(i)&&!t.includes(i)&&(i=H(i),!this.getPiece(i)))}isRightCastlingPossible(t){if(this.isPlayingWhite()&&!this.configuration.castling.whiteShort)return!1;if(this.isPlayingBlack()&&!this.configuration.castling.blackShort)return!1;let e=null;if(this.isPlayingWhite()&&"K"===this.getPiece("E1")&&"R"===this.getPiece("H1")&&!t.includes("E1")?e="E1":this.isPlayingBlack()&&"k"===this.getPiece("E8")&&"r"===this.getPiece("H8")&&!t.includes("E8")&&(e="E8"),!e)return!1;let i=b(e);return!this.getPiece(i)&&!t.includes(i)&&(i=b(i),!this.getPiece(i)&&!t.includes(i))}getPieceMoves(t,e){return this.isPawn(t)?this.getPawnMoves(t,e):this.isKnight(t)?this.getKnightMoves(t,e):this.isRook(t)?this.getRookMoves(t,e):this.isBishop(t)?this.getBishopMoves(t,e):this.isQueen(t)?this.getQueenMoves(t,e):this.isKing(t)?this.getKingMoves(t,e):[]}isPawn(t){return"P"===t.toUpperCase()}isKnight(t){return"N"===t.toUpperCase()}isRook(t){return"R"===t.toUpperCase()}isBishop(t){return"B"===t.toUpperCase()}isQueen(t){return"Q"===t.toUpperCase()}isKing(t){return"K"===t.toUpperCase()}getPawnMoves(t,e){const i=[],n=this.getPieceColor(t);let o=j(e,n);return o&&!this.getPiece(o)&&(i.push(o),o=j(o,n),function(t,e){if(t===c&&"2"===e[1])return!0;if(t===r&&"7"===e[1])return!0;return!1}(n,e)&&o&&!this.getPiece(o)&&i.push(o)),o=_(e,n),o&&(this.getPiece(o)&&this.getPieceOnLocationColor(o)!==n||o===this.configuration.enPassant)&&i.push(o),o=W(e,n),o&&(this.getPiece(o)&&this.getPieceOnLocationColor(o)!==n||o===this.configuration.enPassant)&&i.push(o),i}getKnightMoves(t,e){const i=[],n=this.getPieceColor(t);let o=L(e);return o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=m(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=w(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=O(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=K(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=M(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=S(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=N(e),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),i}getRookMoves(t,e){const i=[],n=this.getPieceColor(t);let o=e;for(;D(o);){o=D(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;A(o);){o=A(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;b(o);){o=b(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;H(o);){o=H(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}return i}getBishopMoves(t,e){const i=[],n=this.getPieceColor(t);let o=e;for(;d(o);){o=d(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;v(o);){o=v(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;k(o);){o=k(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}for(o=e;y(o);){o=y(o);const t=this.getPieceOnLocationColor(o);if(this.getPieceOnLocationColor(o)!==n&&i.push(o),t)break}return i}getQueenMoves(t,e){return[...this.getRookMoves(t,e),...this.getBishopMoves(t,e)]}getKingMoves(t,e){const i=[],n=this.getPieceColor(t);let o=e;return o=D(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=b(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=A(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=H(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=d(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=v(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=k(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),o=e,o=y(o),o&&this.getPieceOnLocationColor(o)!==n&&i.push(o),i}getPieceColor(t){return t.toUpperCase()===t?c:r}getPieceOnLocationColor(t){const e=this.getPiece(t);return e?e.toUpperCase()===e?c:r:null}getPiece(t){return this.configuration.pieces[t]}setPiece(t,e){if(!function(t){return Object.values(s).includes(t)}(e))throw new Error("Invalid piece "+e);if(!I(t))throw new Error("Invalid location "+t);this.configuration.pieces[t.toUpperCase()]=e}removePiece(t){if(!I(t))throw new Error("Invalid location "+t);delete this.configuration.pieces[t.toUpperCase()]}isEmpty(t){if(!I(t))throw new Error("Invalid location "+t);return!this.configuration.pieces[t.toUpperCase()]}getEnemyColor(t){return t===c?r:c}getPlayingColor(){return this.configuration.turn}getNonPlayingColor(){return this.isPlayingWhite()?r:c}isPlayingWhite(){return this.configuration.turn===c}isPlayingBlack(){return this.configuration.turn===r}addMoveToHistory(t,e){this.history.push({from:t,to:e,configuration:JSON.parse(JSON.stringify(this.configuration))})}move(t,e){const i=this.getPiece(t),n=this.getPiece(e);if(!i)throw new Error("There is no piece at "+t);var o,s;if(Object.assign(this.configuration.pieces,{[e]:i}),delete this.configuration.pieces[t],this.isPlayingWhite()&&this.isPawn(i)&&"8"===e[1]&&Object.assign(this.configuration.pieces,{[e]:"Q"}),this.isPlayingBlack()&&this.isPawn(i)&&"1"===e[1]&&Object.assign(this.configuration.pieces,{[e]:"q"}),this.isPawn(i)&&e===this.configuration.enPassant&&delete this.configuration.pieces[(o=e,s=this.getPlayingColor(),s===c?f.DOWN[o]:f.UP[o])],this.isPawn(i)&&this.isPlayingWhite()&&"2"===t[1]&&"4"===e[1]?this.configuration.enPassant=t[0]+"3":this.isPawn(i)&&this.isPlayingBlack()&&"7"===t[1]&&"5"===e[1]?this.configuration.enPassant=t[0]+"6":this.configuration.enPassant=null,"E1"===t&&Object.assign(this.configuration.castling,{whiteLong:!1,whiteShort:!1}),"E8"===t&&Object.assign(this.configuration.castling,{blackLong:!1,blackShort:!1}),"A1"===t&&Object.assign(this.configuration.castling,{whiteLong:!1}),"H1"===t&&Object.assign(this.configuration.castling,{whiteShort:!1}),"A8"===t&&Object.assign(this.configuration.castling,{blackLong:!1}),"H8"===t&&Object.assign(this.configuration.castling,{blackShort:!1}),this.isKing(i)){if("E1"===t&&"C1"===e)return this.move("A1","D1");if("E8"===t&&"C8"===e)return this.move("A8","D8");if("E1"===t&&"G1"===e)return this.move("H1","F1");if("E8"===t&&"G8"===e)return this.move("H8","F8")}this.configuration.turn=this.isPlayingWhite()?r:c,this.isPlayingWhite()&&this.configuration.fullMove++,this.configuration.halfMove++,(n||this.isPawn(i))&&(this.configuration.halfMove=0)}exportJson(){return{moves:this.getMoves(),pieces:this.configuration.pieces,turn:this.configuration.turn,isFinished:this.configuration.isFinished,check:this.hasPlayingPlayerCheck(),checkMate:this.configuration.checkMate,castling:this.configuration.castling,enPassant:this.configuration.enPassant,halfMove:this.configuration.halfMove,fullMove:this.configuration.fullMove}}calculateAiMove(t){return this.calculateAiMoves(t)[0]}calculateAiMoves(t){if(t=parseInt(t),!l.includes(t))throw new Error(`Invalid level ${t}. You can choose ${l.join(",")}`);this.shouldIncreaseLevel()&&t++;const e=[],i=this.calculateScore(this.getPlayingColor()),n=this.getMoves();for(const o in n)n[o].map(n=>{const s=this.getTestBoard(),r=Boolean(s.getPiece(n));s.move(o,n),e.push({from:o,to:n,score:s.testMoveScores(this.getPlayingColor(),t,r,r?s.calculateScore(this.getPlayingColor()):i,n).score+s.calculateScoreByPiecesLocation(this.getPlayingColor())+Math.floor(Math.random()*(this.configuration.halfMove>10?this.configuration.halfMove-10:1)*10)/10})});return e.sort((t,e)=>t.score<e.score?1:t.score>e.score?-1:0),e}shouldIncreaseLevel(){return this.getIngamePiecesValue()<50}getIngamePiecesValue(){let t=0;for(const e in this.configuration.pieces){t+=T(this.getPiece(e))}return t}getTestBoard(){const t={pieces:Object.assign({},this.configuration.pieces),castling:Object.assign({},this.configuration.castling),turn:this.configuration.turn,enPassant:this.configuration.enPassant};return new q(t)}testMoveScores(t,e,i,n,o,s=1){let r=null;if(s<u[e]&&this.hasPlayingPlayerCheck()?r=this.getMoves(this.getPlayingColor()):(s<a[e]||i&&s<u[e])&&(r=this.getMoves(this.getPlayingColor(),5)),this.configuration.isFinished)return{score:this.calculateScore(t)+(this.getPlayingColor()===t?s:-s),max:!0};if(!r){if(null!==n)return{score:n,max:!1};return{score:this.calculateScore(t),max:!1}}let c=this.getPlayingColor()===t?x:Q,l=!1;for(const i in r)l||r[i].map(o=>{if(l)return;const r=this.getTestBoard(),a=Boolean(r.getPiece(o));if(r.move(i,o),r.hasNonPlayingPlayerCheck())return;const u=r.testMoveScores(t,e,a,a?r.calculateScore(t):n,o,s+1);u.max&&(l=!0),c=this.getPlayingColor()===t?Math.max(c,u.score):Math.min(c,u.score)});return{score:c,max:!1}}calculateScoreByPiecesLocation(t=this.getPlayingColor()){const e={A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7};let i=0;for(const n in this.configuration.pieces){const o=this.getPiece(n);if(G[o]){const s=G[o][n[1]-1][e[n[0]]];i+=.5*(this.getPieceColor(o)===t?s:-s)}}return i}calculateScore(t=this.getPlayingColor()){let e=0;if(this.configuration.checkMate)return this.getPlayingColor()===t?x:Q;if(this.configuration.isFinished)return this.getPlayingColor()===t?Q:x;for(const i in this.configuration.pieces){const n=this.getPiece(i);this.getPieceColor(n)===t?e+=10*T(n):e-=10*T(n)}return e}}class ${constructor(t){this.board=new q(t)}move(t,e){t=t.toUpperCase(),e=e.toUpperCase();const i=this.board.getMoves();if(!i[t]||!i[t].includes(e))throw new Error(`Invalid move from ${t} to ${e} for ${this.board.getPlayingColor()}`);return this.board.addMoveToHistory(t,e),this.board.move(t,e),{[t]:e}}moves(t=null){return(t?this.board.getMoves()[t.toUpperCase()]:this.board.getMoves())||[]}setPiece(t,e){this.board.setPiece(t,e)}removePiece(t){this.board.removePiece(t)}aiMove(t=2){const e=this.board.calculateAiMove(t);return this.move(e.from,e.to)}getHistory(t=!1){return t?this.board.history.reverse():this.board.history}printToConsole(){!function(t){process.stdout.write("\n");let e=c;Object.assign([],o).reverse().map(i=>{process.stdout.write(""+i),n.map(n=>{switch(t.pieces[`${n}${i}`]){case"K":process.stdout.write("♚");break;case"Q":process.stdout.write("♛");break;case"R":process.stdout.write("♜");break;case"B":process.stdout.write("♝");break;case"N":process.stdout.write("♞");break;case"P":process.stdout.write("♟");break;case"k":process.stdout.write("♔");break;case"q":process.stdout.write("♕");break;case"r":process.stdout.write("♖");break;case"b":process.stdout.write("♗");break;case"n":process.stdout.write("♘");break;case"p":process.stdout.write("♙");break;default:process.stdout.write(e===c?"█":"░")}e=e===c?r:c}),e=e===c?r:c,process.stdout.write("\n")}),process.stdout.write(" "),n.map(t=>{process.stdout.write(""+t)}),process.stdout.write("\n")}(this.board.configuration)}exportJson(){return this.board.exportJson()}exportFEN(){return function(t){let e="";Object.assign([],o).reverse().map(i=>{let o=0;i<8&&(e+="/"),n.map(n=>{const s=t.pieces[`${n}${i}`];s?(o&&(e+=o.toString(),o=0),e+=s):o++}),e+=""+(o||"")}),e+=t.turn===c?" w ":" b ";const{whiteShort:i,whiteLong:s,blackLong:r,blackShort:l}=t.castling;return s||i||r||l?(i&&(e+="K"),s&&(e+="Q"),l&&(e+="k"),r&&(e+="q")):e+="-",e+=" "+(t.enPassant?t.enPassant.toLowerCase():"-"),e+=" "+t.halfMove,e+=" "+t.fullMove,e}(this.board.configuration)}}function J(t){if(!t)throw new Error("Configuration param required.");return new $(t).moves()}function V(t){if(!t)throw new Error("Configuration param required.");return new $(t).exportJson()}function Y(t){if(!t)throw new Error("Configuration param required.");return new $(t).exportFEN()}function z(t,e,i){if(!t)throw new Error("Configuration param required.");const n=new $(t);return n.move(e,i),"object"==typeof t?n.exportJson():n.exportFEN()}function X(t,e=2){if(!t)throw new Error("Configuration param required.");const i=new $(t).board.calculateAiMove(e);return{[i.from]:i.to}}}])}));
@@ -0,0 +1,21 @@
1
+ import jsChessEngine from '../dist/js-chess-engine.js'
2
+
3
+ const whiteAiLevel = 2
4
+ const blackAiLevel = 3
5
+
6
+ const game = new jsChessEngine.Game()
7
+ play()
8
+
9
+ function play () {
10
+ const status = game.exportJson()
11
+ if (status.isFinished) {
12
+ console.log(`${status.turn} is in ${status.checkMate ? 'checkmate' : 'draw'}`)
13
+ } else {
14
+ console.time('Calculated in')
15
+ const move = game.aiMove(status.turn === 'black' ? blackAiLevel : whiteAiLevel)
16
+ console.log(`${status.turn.toUpperCase()} move ${JSON.stringify(move)}`)
17
+ console.timeEnd('Calculated in')
18
+ game.printToConsole()
19
+ play()
20
+ }
21
+ }
package/lib/Board.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AI_LEVELS,
3
- AI_MAX_DEPTH,
3
+ AI_DEPTH_BY_LEVEL,
4
4
  COLORS,
5
5
  NEW_GAME_BOARD_CONFIG,
6
6
  NEW_GAME_SETTINGS,
@@ -797,6 +797,9 @@ export default class Board {
797
797
  if (!AI_LEVELS.includes(level)) {
798
798
  throw new Error(`Invalid level ${level}. You can choose ${AI_LEVELS.join(',')}`)
799
799
  }
800
+ if (this.shouldIncreaseLevel()) {
801
+ level++
802
+ }
800
803
  const scoreTable = []
801
804
  const initialScore = this.calculateScore(this.getPlayingColor())
802
805
  const moves = this.getMoves()
@@ -808,19 +811,23 @@ export default class Board {
808
811
  scoreTable.push({
809
812
  from,
810
813
  to,
811
- score: testBoard.testMoveScores(this.getPlayingColor(), level, wasScoreChanged ? testBoard.calculateScore(this.getPlayingColor()) : initialScore, to).score +
814
+ score: testBoard.testMoveScores(this.getPlayingColor(), level, wasScoreChanged, wasScoreChanged ? testBoard.calculateScore(this.getPlayingColor()) : initialScore, to).score +
812
815
  testBoard.calculateScoreByPiecesLocation(this.getPlayingColor()) +
813
- (Math.floor(Math.random() * 10) / 10),
816
+ (Math.floor(Math.random() * (this.configuration.halfMove > 10 ? this.configuration.halfMove - 10 : 1) * 10) / 10),
814
817
  })
815
818
  })
816
819
  }
817
820
 
818
821
  scoreTable.sort((previous, next) => {
819
- return previous.score < next.score ? 0 : -1
822
+ return previous.score < next.score ? 1 : previous.score > next.score ? -1 : 0
820
823
  })
821
824
  return scoreTable
822
825
  }
823
826
 
827
+ shouldIncreaseLevel () {
828
+ return this.getIngamePiecesValue() < 50
829
+ }
830
+
824
831
  getIngamePiecesValue () {
825
832
  let scoreIndex = 0
826
833
  for (const location in this.configuration.pieces) {
@@ -840,11 +847,11 @@ export default class Board {
840
847
  return new Board(testConfiguration)
841
848
  }
842
849
 
843
- testMoveScores (playingPlayerColor, level, initialScore, move, depth = 1) {
844
- let nextMoves = {}
845
- if (this.hasPlayingPlayerCheck()) {
850
+ testMoveScores (playingPlayerColor, level, capture, initialScore, move, depth = 1) {
851
+ let nextMoves = null
852
+ if (depth < AI_DEPTH_BY_LEVEL.EXTENDED[level] && this.hasPlayingPlayerCheck()) {
846
853
  nextMoves = this.getMoves(this.getPlayingColor())
847
- } else if (depth < AI_MAX_DEPTH) {
854
+ } else if (depth < AI_DEPTH_BY_LEVEL.BASE[level] || (capture && depth < AI_DEPTH_BY_LEVEL.EXTENDED[level])) {
848
855
  nextMoves = this.getMoves(this.getPlayingColor(), 5)
849
856
  }
850
857
 
@@ -855,12 +862,9 @@ export default class Board {
855
862
  }
856
863
  }
857
864
 
858
- if (depth >= AI_MAX_DEPTH) {
865
+ if (!nextMoves) {
859
866
  if (initialScore !== null) return { score: initialScore, max: false }
860
- let score = this.calculateScore(playingPlayerColor)
861
- if (level >= AI_MAX_DEPTH && this.isPieceUnderAttack(move)) {
862
- score -= getPieceValue(this.getPiece(move)) * PIECE_VALUE_MULTIPLIER
863
- }
867
+ const score = this.calculateScore(playingPlayerColor)
864
868
  return {
865
869
  score,
866
870
  max: false,
@@ -877,7 +881,7 @@ export default class Board {
877
881
  const wasScoreChanged = Boolean(testBoard.getPiece(to))
878
882
  testBoard.move(from, to)
879
883
  if (testBoard.hasNonPlayingPlayerCheck()) return
880
- const result = testBoard.testMoveScores(playingPlayerColor, level, wasScoreChanged ? testBoard.calculateScore(playingPlayerColor) : initialScore, to, depth + 1)
884
+ const result = testBoard.testMoveScores(playingPlayerColor, level, wasScoreChanged, wasScoreChanged ? testBoard.calculateScore(playingPlayerColor) : initialScore, to, depth + 1)
881
885
  if (result.max) {
882
886
  maxValueReached = true
883
887
  }
@@ -18,8 +18,25 @@ export const COLORS = {
18
18
  BLACK: 'black',
19
19
  WHITE: 'white',
20
20
  }
21
- export const AI_LEVELS = [0, 1, 2, 3]
22
- export const AI_MAX_DEPTH = 3
21
+ export const AI_LEVELS = [0, 1, 2, 3, 4]
22
+ export const AI_DEPTH_BY_LEVEL = {
23
+ BASE: {
24
+ 0: 1,
25
+ 1: 2,
26
+ 2: 2,
27
+ 3: 3,
28
+ 4: 3,
29
+ 5: 4,
30
+ },
31
+ EXTENDED: {
32
+ 0: 2,
33
+ 1: 2,
34
+ 2: 4,
35
+ 3: 4,
36
+ 4: 5,
37
+ 5: 5,
38
+ },
39
+ }
23
40
  export const NEW_GAME_SETTINGS = {
24
41
  fullMove: 1,
25
42
  halfMove: 0,
package/lib/utils.mjs CHANGED
@@ -35,23 +35,8 @@ export function printToConsole (configuration) {
35
35
  }
36
36
 
37
37
  export function getPieceValue (piece) {
38
- let value = 0
39
- switch (piece) {
40
- case 'K': value = 10; break
41
- case 'Q': value = 9; break
42
- case 'R': value = 5; break
43
- case 'B': value = 3; break
44
- case 'N': value = 3; break
45
- case 'P': value = 1; break
46
- case 'k': value = 10; break
47
- case 'q': value = 9; break
48
- case 'r': value = 5; break
49
- case 'b': value = 3; break
50
- case 'n': value = 3; break
51
- case 'p': value = 1; break
52
- }
53
-
54
- return value
38
+ const values = { k: 10, q: 9, r: 5, b: 3, n: 3, p: 1 }
39
+ return values[piece.toLowerCase()] || 0
55
40
  }
56
41
 
57
42
  export function getFEN (configuration) {
@@ -98,29 +83,25 @@ export function getFEN (configuration) {
98
83
  }
99
84
 
100
85
  export function getJSONfromFEN (fen = '') {
101
- const configuration = {
102
- pieces: {},
103
- }
104
- const parts = fen.split(' ')
105
- const pieces = parts[0]
106
- const player = parts[1]
107
- const castlings = parts[2]
108
- const enPassant = parts[3]
109
- const halfmove = parts[4]
110
- const fullmove = parts[5]
86
+ const [board, player, castlings, enPassant, halfmove, fullmove] = fen.split(' ')
111
87
 
112
88
  // pieces
113
- let columnIndex = 0
114
- let rowIndex = ROWS.length - 1
115
- for (let index = 0; index < pieces.length; index++) {
116
- if (['K', 'Q', 'R', 'B', 'N', 'P', 'k', 'q', 'r', 'b', 'n', 'p'].includes(pieces[index])) {
117
- configuration.pieces[`${COLUMNS[columnIndex]}${ROWS[rowIndex]}`] = pieces[index]; columnIndex++
118
- } else if (['1', '2', '3', '4', '5', '6', '7', '8'].includes(pieces[index])) {
119
- columnIndex += parseInt(pieces[index])
120
- } else if (pieces[index] === '/') {
121
- rowIndex--
122
- columnIndex = 0
123
- }
89
+ const configuration = {
90
+ pieces: Object.fromEntries(board.split('/').flatMap((row, rowIdx) => {
91
+ let colIdx = 0
92
+ return row.split('').reduce((acc, sign) => {
93
+ const piece = sign.match(/k|b|q|n|p|r/i)
94
+ if (piece) {
95
+ acc.push([`${COLUMNS[colIdx]}${ROWS[7 - rowIdx]}`, piece[0]])
96
+ colIdx += 1
97
+ }
98
+ const squares = sign.match(/[1-8]/)
99
+ if (squares) {
100
+ colIdx += Number(squares)
101
+ }
102
+ return acc
103
+ }, [])
104
+ })),
124
105
  }
125
106
 
126
107
  // playing player
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-chess-engine",
3
- "version": "0.11.2",
3
+ "version": "1.0.2",
4
4
  "description": "Simple and fast Node.js chess engine without dependencies",
5
5
  "keywords": [
6
6
  "chess",
@@ -11,9 +11,9 @@
11
11
  "scripts": {
12
12
  "server:watch": "nodemon --experimental-modules example/server.mjs",
13
13
  "console:watch": "nodemon --experimental-modules example/console.mjs",
14
- "test": "npm run test:eslint && mocha --experimental-modules --timeout 15000",
14
+ "test": "npm run test:eslint && mocha --experimental-modules --timeout 20000",
15
15
  "test:eslint": "eslint --ext mjs,js lib test",
16
- "test:badge": "npm run test:eslint && mocha --reporter mocha-badge-generator --timeout 15000 --experimental-modules && git add test/badge.svg",
16
+ "test:badge": "npm run test:eslint && mocha --reporter mocha-badge-generator --timeout 20000 --experimental-modules && git add test/badge.svg",
17
17
  "build": "webpack --config webpack.config.js",
18
18
  "version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
19
19
  "preversion": "npm run test:badge && npm run build && git add -A dist"
@@ -36,10 +36,10 @@
36
36
  "eslint-plugin-standard": "^4.0.1",
37
37
  "fastify": "^2.14.1",
38
38
  "fastify-cors": "^3.0.3",
39
- "mocha": "^7.1.2",
40
- "mocha-badge-generator": "^0.6.0",
39
+ "mocha": "^9.1.3",
40
+ "mocha-badge-generator": "^0.3.0",
41
41
  "nodemon": "^2.0.3",
42
42
  "webpack": "^4.43.0",
43
- "webpack-cli": "^3.3.11"
43
+ "webpack-cli": "^4.9.1"
44
44
  }
45
45
  }
package/test/ai.test.mjs CHANGED
@@ -5,7 +5,7 @@ const expect = chai.expect
5
5
 
6
6
  describe('Should properly calculate BEST AI move', function () {
7
7
  before(function () {
8
- this.aiLevel = 3
8
+ this.aiLevel = 4
9
9
  console.time('UI test calculated in')
10
10
  })
11
11
 
@@ -91,4 +91,42 @@ describe('Should properly calculate BEST AI move', function () {
91
91
  expect(['B8', 'G8'].includes(result.from)).to.be.equal(true)
92
92
  expect(['C6', 'F6'].includes(result.to)).to.be.equal(true)
93
93
  })
94
+
95
+ it('Should move with pawn', function () {
96
+ const game = new Game({
97
+ pieces: {
98
+ D1: 'Q',
99
+ A1: 'R',
100
+ B2: 'P',
101
+ C2: 'P',
102
+ F2: 'P',
103
+ G2: 'P',
104
+ H2: 'P',
105
+ D8: 'q',
106
+ A8: 'r',
107
+ A7: 'p',
108
+ B7: 'p',
109
+ C7: 'p',
110
+ F7: 'p',
111
+ G7: 'p',
112
+ H7: 'p',
113
+ E4: 'P',
114
+ E5: 'N',
115
+ A3: 'P',
116
+ C5: 'p',
117
+ D5: 'N',
118
+ G8: 'k',
119
+ F8: 'r',
120
+ B5: 'B',
121
+ B8: 'n',
122
+ E6: 'b',
123
+ G1: 'K',
124
+ F1: 'R',
125
+ },
126
+ turn: 'black',
127
+ })
128
+ game.printToConsole()
129
+ const move = game.aiMove(this.aiLevel)
130
+ expect(move).to.be.deep.equal({ C7: 'C6' })
131
+ })
94
132
  })
package/test/badge.svg CHANGED
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="83" height="20"><defs><linearGradient id="smooth" x2="0" y2="100%"><stop offset="0" stop-color="#aaa" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><style>text{font-size:11px;font-family:Verdana,DejaVu Sans,Geneva,sans-serif}text.shadow{fill:#010101;fill-opacity:.3}text.high{fill:#fff}</style><mask id="round"><rect width="100%" height="100%" rx="3" fill="#fff"/></mask></defs><g id="bg" mask="url(#round)"><path fill="#696969" d="M0 0h41v20H0z"/><path fill="#4c1" d="M41 0h42v20H41z"/><path fill="url(#smooth)" d="M0 0h83v20H0z"/></g><g id="fg"><text class="shadow" x="5.5" y="15">Tests</text><text class="high" x="5" y="14">Tests</text><text class="shadow" x="46.5" y="15">54/54</text><text class="high" x="46" y="14">54/54</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="83" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><mask id="a"><rect width="83" height="20" rx="3" fill="#fff"/></mask><g mask="url(#a)"><path fill="#555" d="M0 0h41v20H0z"/><path fill="#4C1" d="M41 0h42v20H41z"/><path fill="url(#b)" d="M0 0h83v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,DejaVu Sans,Geneva,sans-serif" font-size="11"><text x="20.5" y="15" fill="#010101" fill-opacity=".3">Tests</text><text x="20.5" y="14">Tests</text><text x="61" y="15" fill="#010101" fill-opacity=".3">55/55</text><text x="61" y="14">55/55</text></g></svg>