UNPKG

@maoshizhong/chess

Version:

Simple code-only Chessboard written in TypeScript. Handles FEN and PGN.

5 lines (3 loc) 14.8 kB
"use strict";var vt=Object.defineProperty;var Y=i=>{throw TypeError(i)};var mt=(i,t,e)=>t in i?vt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var v=(i,t,e)=>mt(i,typeof t!="symbol"?t+"":t,e),U=(i,t,e)=>t.has(i)||Y("Cannot "+e);var u=(i,t,e)=>(U(i,t,"read from private field"),e?e.call(i):t.get(i)),y=(i,t,e)=>t.has(i)?Y("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(i):t.set(i,e),m=(i,t,e,s)=>(U(i,t,"write to private field"),s?s.call(i,e):t.set(i,e),e),M=(i,t,e)=>(U(i,t,"access private method"),e);var L=(i,t,e,s)=>({set _(o){m(i,t,o,e)},get _(){return u(i,t,s)}});Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class k{constructor(t,e){v(this,"letter");v(this,"colour");this.letter=e==="w"?t:t.toLowerCase(),this.colour=e}}const H={SHORT:"O-O",LONG:"O-O-O"};function W(i){const[t,e]=i.split("");return[P[Number(e)],d[t]]}function Pt([i,t]){return`${"abcdefgh"[t]}${P[i]}`}function Nt({from:i,to:t},e){const[s,o]=W(i),[n,a]=W(t),r=e.board[n][a]instanceof k,c=e.board[s][o];if(!c)return[!1,""];const l=c.letter.toUpperCase();if(l==="P"){const p=r?`${i[0]}x${t}`:t;return o===a||r?[!0,p]:[!1,""]}else{if(l==="K"&&o-a===2)return[!0,"O-O-O"];if(l==="K"&&o-a===-2)return[!0,"O-O"]}let h="",g="";const f=p=>n===p[0]&&a===p[1];return e.board.forEach((p,F)=>{p.forEach((w,S)=>{var b;if(w!==c&&(w==null?void 0:w.letter)===c.letter){if(!((b=e.getValidMoves({rank:F,file:S,isCapture:r}))==null?void 0:b.some(f)))return;s===F&&(g=i[0]),o===S&&(h=i[1])}})}),[!0,`${l}${g}${h}${r?"x":""}${t}`]}function wt(i){const t=i.includes("x"),e=t&&i[0]===i[0].toLowerCase(),s=i.replace("x",""),o=[];if(i===H.SHORT||i===H.LONG)o.push(...St(s));else if(e){const n=Z(s.substring(1).split(""));n.piece.file=d[i[0]],o.push(n)}else o.push(Z(s.split("")));return{isCapture:t,piecesToMove:o}}function St(i){const t={piece:{letter:"K"},destination:[0,0]},e={piece:{letter:"R"},destination:[0,0]};return i===H.SHORT?(t.destination[1]=d.g,e.destination[1]=d.f,e.piece.file=d.h):(t.destination[1]=d.c,e.destination[1]=d.d,e.piece.file=d.a),[t,e]}function Z(i){const t={piece:{letter:"P"},destination:[0,0]};switch(i.includes("=")&&(t.promoteTo=i.at(-1),i.splice(-2,2)),i.length){case 2:{const[e,s]=i;t.piece.letter="P",t.destination[0]=P[Number(s)],t.destination[1]=d[e];break}case 3:{const[e,s,o]=i;t.piece.letter=e,t.destination[0]=P[Number(o)],t.destination[1]=d[s];break}case 4:{const[e,s,o,n]=i;t.piece.letter=e,Number(s)?t.piece.rank=P[Number(s)]:t.piece.file=d[s],t.destination[0]=P[Number(n)],t.destination[1]=d[o];break}case 5:{const[e,s,o,n,a]=i;t.piece.letter=e,t.piece.rank=P[Number(o)],t.piece.file=d[s],t.destination[0]=P[Number(a)],t.destination[1]=d[n];break}}return t}class tt extends k{constructor(t){super("B",t)}get maximumMoves(){return[[[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7]],[[1,-1],[2,-2],[3,-3],[4,-4],[5,-5],[6,-6],[7,-7]],[[-1,1],[-2,2],[-3,3],[-4,4],[-5,5],[-6,6],[-7,7]],[[-1,-1],[-2,-2],[-3,-3],[-4,-4],[-5,-5],[-6,-6],[-7,-7]]]}}class O extends k{constructor(e){super("K",e);v(this,"hasMoved",!1)}get maximumMoves(){const e=[[[0,1]],[[1,1]],[[1,0]],[[1,-1]],[[0,-1]],[[-1,-1]],[[-1,0]],[[-1,1]],[[0,2]],[[0,-2]]];return this.hasMoved?e.slice(0,-2):e}}class et extends k{constructor(t){super("N",t)}get maximumMoves(){return[[[1,2]],[[2,1]],[[2,-1]],[[1,-2]],[[-1,-2]],[[-2,-1]],[[-2,1]],[[-1,2]]]}}var j,ot;class $ extends k{constructor(e){super("P",e);y(this,j);v(this,"hasMoved",!1)}get maximumMoves(){const e=[[[1,0],[2,0]],[[1,-1]],[[1,1]]];return this.hasMoved&&e[0].splice(-1,1),this.colour==="w"?e:M(this,j,ot).call(this,e)}}j=new WeakSet,ot=function(e){return e.map(s=>s.map(([o,n])=>[o*-1,n*-1]))};class st extends k{constructor(t){super("Q",t)}get maximumMoves(){return[[[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0]],[[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7]],[[-1,0],[-2,0],[-3,0],[-4,0],[-5,0],[-6,0],[-7,0]],[[0,-1],[0,-2],[0,-3],[0,-4],[0,-5],[0,-6],[0,-7]],[[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7]],[[1,-1],[2,-2],[3,-3],[4,-4],[5,-5],[6,-6],[7,-7]],[[-1,1],[-2,2],[-3,3],[-4,4],[-5,5],[-6,6],[-7,7]],[[-1,-1],[-2,-2],[-3,-3],[-4,-4],[-5,-5],[-6,-6],[-7,-7]]]}}class Q extends k{constructor(e){super("R",e);v(this,"hasMoved",!1)}get maximumMoves(){return[[[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0]],[[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7]],[[-1,0],[-2,0],[-3,0],[-4,0],[-5,0],[-6,0],[-7,0]],[[0,-1],[0,-2],[0,-3],[0,-4],[0,-5],[0,-6],[0,-7]]]}}const nt={P:$,p:$,R:Q,r:Q,N:et,n:et,B:tt,b:tt,Q:st,q:st,K:O,k:O};function rt(i){return i.split("").map(s=>{const o=Mt(s)?"w":"b";return Number(s)?Array(Number(s)).fill(null):new nt[s](o)}).flat()}function at(i,t,e,s,o,n){const a=_(i);let r="";return e.w.short&&(r+="K"),e.w.long&&(r+="Q"),e.b.short&&(r+="k"),e.b.long&&(r+="q"),r||(r="-"),[a,t,r,s?Pt(s):"-",o,n].join(" ")}function _(i){return i.map(t=>{let e="",s=0;for(const o of t)o instanceof k?(e+=s,s=0,e+=o.letter):s++;return e+=s,e.replaceAll("0","")}).join("/")}function q(i){const t=i.split(" ");yt(i,t);const[e,s,o,n,a,r]=t,c={w:{short:o.includes("K"),long:o.includes("Q")},b:{short:o.includes("k"),long:o.includes("q")}},l=n==="-"?null:W(n);return[e,s,c,l,Number(a),Number(r)]}function yt(i,[t,e,s,o,n,a]){const r=new TypeError(`${i} is not a valid FEN string.`),c=/^([rnbqkp1-8]{1,8}\/){7}[rnbqkp1-8]{1,8}$/i.test(t),l=/^(w|b)$/.test(e),h=/^(-|K?Q?k?q?)$/.test(s),g=/^(-|[a-h](3|6))$/.test(o),f=/^(\d{1,2}|100)$/.test(n),p=/^\d+$/.test(a);if(!c||!l||!h||!g||!f||!p)throw r;const F=t.split("/");for(const w of F)if(w.split("").map(b=>Number(b)?Array(Number(b)).fill(""):b).flat().length!==8)throw r}function Mt(i){return i===i.toUpperCase()}const kt=Object.freeze(Object.defineProperty({__proto__:null,PIECES:nt,serialise:at,serialisePosition:_,split:q,toChessRow:rt},Symbol.toStringTag,{value:"Module"})),P=[1/0,7,6,5,4,3,2,1,0],d={a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7};var A,T,lt,ct,ht;const z=class z{constructor(t,e={w:{short:!0,long:!0},b:{short:!0,long:!0}},s=null){y(this,T);v(this,"board");v(this,"enPassant");y(this,A);m(this,A,e),this.board=M(this,T,lt).call(this,t,u(this,A)),this.enPassant=s}getValidMoves({rank:t,file:e,isCapture:s=!0,isForFindingChecks:o=!1}){const n=this.board[t][e];if(!n)return null;const r=n instanceof O&&!n.hasMoved,c=[];return n.maximumMoves.forEach((l,h,g)=>{const f=r&&h>=g.length-2&&!o;if(f&&M(this,T,ht).call(this,t,e,l[0])){const F=l[0][1];c.push([t,e+F])}else f||c.push(...M(this,T,ct).call(this,n,t,e,l,s,o))}),c}isSquareInCheck(t,e,s){return this.board.some((o,n)=>o.some((a,r)=>{if(a===null||a.colour===t)return!1;const c=this.getValidMoves({rank:n,file:r,isCapture:!0,isForFindingChecks:!0});return c==null?void 0:c.find(h=>h[0]===e&&h[1]===s)}))}isKingInCheck(t){const e=this.board.findIndex(o=>o.find(n=>n instanceof O&&n.colour===t)),s=this.board[e].findIndex(o=>o instanceof O&&o.colour===t);return this.isSquareInCheck(t,e,s)}canPlayContinue(t){const e=this.isKingInCheck(t),s=[];this.board.forEach((n,a)=>{n.forEach((r,c)=>{if(r===null||r.colour!==t)return;const l=this.getValidMoves({rank:a,file:c});l!=null&&l.length&&s.push(...l.map(h=>({from:[a,c],to:h})))})});const o=s.filter(n=>!this.simulateMove(n).isKingInCheck(t));return e&&!o.length?[!1,"checkmate"]:!e&&!o.length?[!1,"stalemate"]:[!0,void 0]}move({from:t,to:e,promoteTo:s}){const[o,n]=t,[a,r]=e,{PIECES:c}=kt,l=(s==null?void 0:s.toUpperCase())===s?"w":"b",h=s?new c[s](l):this.board[o][n];this.board[a][r]=h,this.board[o][n]=null,(h instanceof O||h instanceof $)&&(h.hasMoved=!0)}simulateMove(t){const e=new z(_(this.board),u(this,A));return e.move(t),e}flip(){this.board.reverse(),this.board.forEach(t=>t.reverse())}};A=new WeakMap,T=new WeakSet,lt=function(t,e){const o=t.split("/").map(n=>rt(n));return o.forEach((n,a)=>{n.forEach((r,c)=>{!(r instanceof Q)&&!(r instanceof O)&&!(r instanceof $)||(r.hasMoved=(()=>{switch(r.constructor){case $:return r.colour==="w"&&a!==P[2]||r.colour==="b"&&a!==P[7];case O:return!e[r.colour].short&&!e[r.colour].long;case Q:return c===d.a&&!e[r.colour].long||c===d.h&&!e[r.colour].short;default:return!1}})())})}),o},ct=function(t,e,s,o,n,a){var h,g,f;const r=t instanceof $,c=t instanceof k&&!(t instanceof $),l=[];for(const[p,F]of o){const w=e-p,S=s-F,b=(h=this.board[w])==null?void 0:h[S],B=b instanceof k&&b.colour===t.colour,J=b instanceof k&&b.colour!==t.colour||((g=this.enPassant)==null?void 0:g[0])===w&&((f=this.enPassant)==null?void 0:f[1])===S,X=c&&J||r&&S!==s&&n&&(J||a),bt=c&&b===null||r&&S===s&&b===null;if(B||((bt||X)&&l.push([w,S]),X))break}return l},ht=function(t,e,[s,o]){const n=this.board[t],r=o>0?n[d.h]:n[d.a];if(!r||!(r instanceof Q))return!1;const c=[[t,e],[t,e+o/2],[t,e+o]],h=[n[c[1][1]],n[c[2][1]]].some(f=>f instanceof k),g=c.some(([f,p])=>this.isSquareInCheck(r.colour,f,p));return!r.hasMoved&&!h&&!g};let D=z;var x,G,ut,ft;class it{constructor(t,e,s){y(this,G);v(this,"colour");v(this,"castlingRights");y(this,x);this.colour=t,this.castlingRights=e,m(this,x,s)}move(t){var c;if(t==="O-O"&&!this.castlingRights.short||t==="O-O-O"&&!this.castlingRights.long)return[!1];let e=!1,s=null;const{isCapture:o,piecesToMove:n}=wt(t),a=n.length===2,r=[];for(const l of n){a&&(l.destination[0]=this.colour==="w"?P[1]:P[8]),this.colour==="b"&&(l.piece.letter=l.piece.letter.toLowerCase(),l.promoteTo=(c=l.promoteTo)==null?void 0:c.toLowerCase());const[h,g,f]=M(this,G,ut).call(this,l,o);if(!h)return[!1];if(l.piece.letter.toUpperCase()==="P"){e=!0;const[w,S]=l.destination,b=S===d[t[0]],B=Math.abs(w-g)===2;switch(this.colour){case"w":w===P[4]&&b&&B&&(s=[P[3],S]);break;case"b":w===P[5]&&b&&B&&(s=[P[6],S]);break}}const p={from:[g,f],to:l.destination,promoteTo:l.promoteTo};if(u(this,x).simulateMove(p).isKingInCheck(this.colour))return[!1];r.push(p),M(this,G,ft).call(this,l.piece.letter,f)}for(const l of r)u(this,x).move(l);return[n.length>0,o||e,s,u(this,x).isKingInCheck(this.colour==="w"?"b":"w")]}}x=new WeakMap,G=new WeakSet,ut=function({piece:t,destination:e},s){const o=[];if(u(this,x).board.forEach((a,r)=>{a.forEach((c,l)=>{if(c===null||c.letter!==t.letter)return;const h=u(this,x).getValidMoves({rank:r,file:l,isCapture:s});(h==null?void 0:h.some(f=>f[0]===e[0]&&f[1]===e[1]))&&o.push([r,l])})}),o.length===1)return[!0,...o[0]];const n=o.find(a=>t.rank&&t.file?a[0]===t.rank&&a[1]===t.file:a[0]===(t==null?void 0:t.rank)||a[1]===(t==null?void 0:t.file));return n?[!0,...n]:[!1,0,0]},ft=function(t,e){const s=t.toUpperCase();"KR".includes(s)&&(s==="K"?(this.castlingRights.short=!1,this.castlingRights.long=!1):e===d.h?this.castlingRights.short=!1:e===d.a&&(this.castlingRights.long=!1))};function Ct(i,t=!1){const[{FEN:e},...s]=i;let n=e==="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"||t?"":`[SetUp "1"] [FEN "${e}"] `;const a=Number(e.split(" ").at(-1))-1;return s.forEach((r,c)=>{const[l,h]=q(r.FEN);if(c===0&&h==="w")n+=`${a+1}... `;else if(h==="b"){const g=Math.ceil(c/2+1+a);n+=`${g}. `}n+=`${r.move} `,r.result&&(n+=r.result)}),n.trim()}function Et(i){var e;return((e=i.match(new RegExp('(?<=\\[FEN ").+(?="\\])')))==null?void 0:e[0])??"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"}function Rt(i){var e;return(((e=i.match(/\d+\.+ .+/))==null?void 0:e[0])??"").split(" ").filter(s=>!/\.|1-0|0-1|1\/2-1\/2/.test(s)).map(s=>s.endsWith("#")||s.endsWith("+")?s.slice(0,-1):s)}var N,E,I;class Ft{constructor(t){y(this,N);y(this,E);y(this,I);m(this,N,0),m(this,E,[{FEN:t}]),m(this,I,{[t.split(" ")[0]]:1})}get length(){return u(this,E).length}get currentState(){return this.getState(u(this,N))}get currentFEN(){return u(this,E)[u(this,N)].FEN}getState(t){const[e,s,o,n,a,r]=q(u(this,E)[t].FEN);return{board:new D(e,o).board,activeColour:s,castlingRights:o,enPassantTarget:n,halfMoves:a,fullMoves:r}}toNthState(t){return 0<=t&&t<this.length?m(this,N,t):t<0?m(this,N,0):m(this,N,this.length-1),this.currentState}toPreviousState(){return u(this,N)>0&&L(this,N)._--,this.currentState}toNextState(){return u(this,N)<u(this,E).length-1&&L(this,N)._++,this.currentState}record(t,e,s){const o=at(...e),n=o.split(" ")[0];u(this,I)[n]=(u(this,I)[n]??0)+1,L(this,N)._++,u(this,E).splice(u(this,N),1/0,{FEN:o,move:t,result:s})}isThreefoldRepetition(){return Object.values(u(this,I)).some(t=>t===3)}toPGN(t){return Ct(u(this,E),t)}}N=new WeakMap,E=new WeakMap,I=new WeakMap;var C,K,R,V,gt,pt;class dt{constructor(t="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",{isPGN:e}={isPGN:!1}){y(this,R);v(this,"history");v(this,"board");v(this,"players");v(this,"activePlayer");v(this,"isGameInPlay");v(this,"result");y(this,C);y(this,K);const s=e?Et(t):t,[o,n,a,r,c,l]=q(s);this.history=new Ft(s),this.board=new D(o,a,r),this.players={w:new it("w",a.w,this.board),b:new it("b",a.b,this.board)},this.activePlayer=this.players[n],this.isGameInPlay=this.board.canPlayContinue(this.activePlayer.colour)[0],m(this,C,c),m(this,K,l),e&&M(this,R,pt).call(this,t)}get halfMoves(){return u(this,C)}get fullMoves(){return u(this,K)}get castlingRights(){return{w:this.players.w.castlingRights,b:this.players.b.castlingRights}}playMove(t){const[e,s]=typeof t=="string"?[!0,t]:Nt(t,this.board),o=new Error(`${e?s:t} is not a valid move`);if(!e||!this.isGameInPlay)return[o,""];const[n,a,r,c]=this.activePlayer.move(s);if(!n)return[o,""];m(this,C,a?0:u(this,C)+1),m(this,K,u(this,K)+ +(this.activePlayer.colour==="b")),this.board.enPassant=r,M(this,R,gt).call(this);const l=[this.board.board,this.activePlayer.colour,this.castlingRights,r,u(this,C),u(this,K)];let h=!1;const[g,f]=this.board.canPlayContinue(this.activePlayer.colour);return g&&(this.history.record(c?`${s}+`:s,l),h=this.history.isThreefoldRepetition(),u(this,C)<100&&!h)?[null,s]:(this.isGameInPlay=!1,f==="stalemate"||u(this,C)>=100||h?this.result="1/2-1/2":f==="checkmate"&&(this.result=this.activePlayer.colour==="w"?"0-1":"1-0"),g||this.history.record(f==="checkmate"?`${s}#`:s,l,this.result),[null,s])}toPreviousPosition(){return M(this,R,V).call(this,this.history.toPreviousState()),this}toNextPosition(){return M(this,R,V).call(this,this.history.toNextState()),this}toNthPosition(t){return M(this,R,V).call(this,this.history.toNthState(t)),this}toPGN({movesOnly:t}={movesOnly:!1}){return this.history.toPGN(t)}toFEN(){return this.history.currentFEN}}C=new WeakMap,K=new WeakMap,R=new WeakSet,V=function({board:t,activeColour:e,castlingRights:s,enPassantTarget:o,halfMoves:n,fullMoves:a}){this.board.board.length=0,this.board.board.push(...t),this.board.enPassant=o,this.players.w.castlingRights=s.w,this.players.b.castlingRights=s.b,this.activePlayer=this.players[e],m(this,C,n),m(this,K,a)},gt=function(){this.activePlayer=this.activePlayer.colour==="w"?this.players.b:this.players.w},pt=function(t){const e=Rt(t);for(const s of e){const[o]=this.playMove(s);if(o)throw new Error(`Invalid PGN - could not play ${s}`)}};module.exports={Chess:dt};exports.Chess=dt;