/* * Copyright(c) 2013-2017 - jocly.com * * You are allowed to use and modify this source code as long as it is exclusively for use in the Jocly API. * * Original authors: Jocly team * */ (function() { var geometry = Model.Game.cbBoardGeometryGrid(12,12); Model.Game.cbDefine = function() { var $this = this; /* * Movement/capture graph for the prince */ function PrinceGraph(side) { var graph={}; for(var pos=0;pos0) graph[pos].push($this.cbTypedArray(away)); } } }); } return $this.cbMergeGraphs(geometry, $this.cbShortRangeGraph(geometry,[[-1,-1],[-1,1],[1,-1],[1,1]]), graph ); } return { geometry: geometry, pieceTypes: { 0: { name: 'pawn-w', aspect: 'fr-pawn', graph: this.cbPawnGraph(geometry,1), value: 1, abbrev: '', fenAbbrev: 'P', epCatch: false, }, 1: { name: 'ipawn-w', aspect: 'fr-pawn', graph: this.cbInitialPawnGraph(geometry,1), value: 1, abbrev: '', fenAbbrev: 'P', initial: [{s:1,p:24},{s:1,p:25},{s:1,p:26},{s:1,p:27},{s:1,p:28},{s:1,p:29},{s:1,p:30},{s:1,p:31},{s:1,p:32},{s:1,p:33},{s:1,p:34},{s:1,p:35}], epTarget: true, epCatch: false, }, 2: { name: 'pawn-b', aspect: 'fr-pawn', graph: this.cbPawnGraph(geometry,-1), value: 1, abbrev: '', fenAbbrev: 'P', epCatch: false, }, 3: { name: 'ipawn-b', aspect: 'fr-pawn', graph: this.cbInitialPawnGraph(geometry,-1), value: 1, abbrev: '', fenAbbrev: 'P', initial: [{s:-1,p:108},{s:-1,p:109},{s:-1,p:110},{s:-1,p:111},{s:-1,p:112},{s:-1,p:113},{s:-1,p:114},{s:-1,p:115},{s:-1,p:116},{s:-1,p:117},{s:-1,p:118},{s:-1,p:119}], epTarget: true, epCatch: false, }, 4: { name: 'knight', aspect: 'fr-knight', graph: this.cbKnightGraph(geometry), value: 2.9, abbrev: 'N', initial: [{s:1,p:14},{s:1,p:21},{s:-1,p:122},{s:-1,p:129}], }, 5: { name: 'bishop', aspect: 'fr-bishop', graph: this.cbBishopGraph(geometry), value: 3.1, abbrev: 'B', initial: [{s:1,p:15},{s:1,p:20},{s:-1,p:123},{s:-1,p:128}], }, 6: { name: 'rook', aspect: 'fr-rook', graph: this.cbRookGraph(geometry), value: 5, abbrev: 'R', initial: [{s:1,p:13},{s:1,p:22},{s:-1,p:121},{s:-1,p:130}], castle: true, }, 7: { name: 'queen', aspect: 'fr-queen', graph: this.cbQueenGraph(geometry), value: 9, abbrev: 'Q', initial: [{s:1,p:18},{s:-1,p:126}], }, 8: { name: 'king', aspect: 'fr-king', isKing: true, graph: this.cbKingGraph(geometry), abbrev: 'K', initial: [{s:1,p:17},{s:-1,p:125}], }, 9: { name: 'cannon', aspect: 'fr-cannon2', graph: this.cbXQCannonGraph(geometry), value: 3.5, abbrev: 'C', initial: [{s:1,p:0},{s:1,p:11},{s:-1,p:132},{s:-1,p:143}], }, 10: { name: 'elephant', aspect: 'fr-elephant', graph: this.cbShortRangeGraph(geometry,[[-1,-1],[-1,1],[1,-1],[1,1],[-2,-2],[-2,2],[2,-2],[2,2]]), value: 2.5, abbrev: 'E', initial: [{s:1,p:12},{s:1,p:23},{s:-1,p:120},{s:-1,p:131}], }, 11: { name: 'prince-w', aspect: 'fr-admiral', graph: PrinceGraph(1), value: 3, epTarget: true, abbrev: 'I', initial: [{s:1,p:16},{s:1,p:19}], }, 12: { name: 'prince-b', aspect: 'fr-admiral', graph: PrinceGraph(-1), epTarget: true, value: 3, abbrev: 'I', initial: [{s:-1,p:124},{s:-1,p:127}], }, 13: { name: 'camel', aspect: 'fr-camel', graph: this.cbShortRangeGraph(geometry,[[-3,-1],[-3,1],[3,-1],[3,1],[1,3],[1,-3],[-1,3],[-1,-3]]), value: 2, abbrev: 'M', initial: [{s:1,p:1},{s:1,p:10},{s:-1,p:133},{s:-1,p:142}], }, 14: { name: 'lion', aspect: 'fr-lion', graph: this.cbShortRangeGraph(geometry,[ [-1,-1],[-1,1],[1,-1],[1,1],[1,0],[0,1],[-1,0],[0,-1], [-2,0],[-2,-1],[-2,-2],[-1,-2],[0,-2], [1,-2],[2,-2],[2,-1],[2,0],[2,1], [2,2],[1,2],[0,2],[-1,2],[-2,2],[-2,1]]), value: 7.5, abbrev: 'L', initial: [{s:1,p:5},{s:-1,p:137}], }, 15: { name: 'eagle', aspect: 'fr-eagle', graph: EagleGraph(), value: 8, abbrev: 'A', initial: [{s:1,p:6},{s:-1,p:138}], }, 16: { name: 'unicorn', aspect: 'fr-unicorn', graph: this.cbMergeGraphs(geometry, this.cbShortRangeGraph(geometry,[ [-2,-2],[-2,0],[-2,2],[0,2],[2,2],[2,0],[2,-2],[0,-2], [-3,-3],[-3,0],[-3,3],[0,3],[3,3],[3,0],[3,-3],[0,-3]]), this.cbKingGraph(geometry), this.cbKnightGraph(geometry), this.cbLongRangeGraph(geometry,[[2,-1],[2,1],[-2,-1],[-2,1],[-1,2],[-1,-2],[1,2],[1,-2]]), this.cbShortRangeGraph(geometry,[[-3,-1],[-3,1],[3,-1],[3,1],[1,3],[1,-3],[-1,3],[-1,-3]]) ), value: 13, abbrev: 'Pa', initial: [{s:1,p:2},{s:-1,p:134}], }, 17: { name: 'dragon', aspect: 'fr-dragon', graph: this.cbMergeGraphs(geometry, this.cbQueenGraph(geometry), EagleGraph()), value: 14, abbrev: 'D', initial: [{s:1,p:4},{s:-1,p:136}], }, 18: { name: 'lighthouse', aspect: 'fr-lighthouse', graph: this.cbMergeGraphs(geometry, this.cbQueenGraph(geometry), this.cbXQCannonGraph(geometry), this.cbLongRangeGraph(geometry,[[1,-1],[-1,-1],[-1,1],[1,1]],null,this.cbConstants.FLAG_MOVE | this.cbConstants.FLAG_SCREEN_CAPTURE)), value: 12, abbrev: 'LH', initial: [{s:1,p:3},{s:-1,p:135}], }, 19: { name: 'emperor', aspect: 'fr-crowned-rook', graph: this.cbMergeGraphs(geometry, this.cbQueenGraph(geometry), this.cbXQCannonGraph(geometry), this.cbLongRangeGraph(geometry,[[1,-1],[-1,-1],[-1,1],[1,1]],null,this.cbConstants.FLAG_MOVE | this.cbConstants.FLAG_SCREEN_CAPTURE), EagleGraph(), this.cbShortRangeGraph(geometry,[ [-2,-2],[-2,0],[-2,2],[0,2],[2,2],[2,0],[2,-2],[0,-2], [-3,-3],[-3,0],[-3,3],[0,3],[3,3],[3,0],[3,-3],[0,-3]]), this.cbKnightGraph(geometry), this.cbLongRangeGraph(geometry,[[2,-1],[2,1],[-2,-1],[-2,1],[-1,2],[-1,-2],[1,2],[1,-2]]), this.cbShortRangeGraph(geometry,[[-3,-1],[-3,1],[3,-1],[3,1],[1,3],[1,-3],[-1,3],[-1,-3]])), value: 20, abbrev: 'EM', }, 20: { name: 'commander', aspect: 'fr-amazon', graph: this.cbMergeGraphs(geometry, this.cbQueenGraph(geometry), this.cbKnightGraph(geometry)), value: 13, abbrev: 'Co', initial: [{s:1,p:7},{s:-1,p:139}], }, 21: { name: 'cardinal', aspect: 'fr-cardinal', graph: this.cbMergeGraphs(geometry, this.cbBishopGraph(geometry), this.cbKnightGraph(geometry)), value: 6, abbrev: 'Ca', initial: [{s:1,p:9},{s:-1,p:141}], }, 22: { name: 'chancellor', aspect: 'fr-marshall', graph: this.cbMergeGraphs(geometry, this.cbRookGraph(geometry), this.cbKnightGraph(geometry)), value: 9, abbrev: 'Ch', initial: [{s:1,p:8},{s:-1,p:140}], castle: true, }, }, promote: function(aGame,piece,move) { if(piece.t==1 && geometry.R(move.t)==11) return [14,15,20,16,17,18]; else if(piece.t==3 && geometry.R(move.t)==0) return [14,15,20,16,17,18]; else if(piece.t==11 && geometry.R(move.t)==11) return [19]; else if(piece.t==12 && geometry.R(move.t)==0) return [19]; return []; }, }; } /* * Model.Board.GenerateMoves: * - handle setup phase * - handle king special move: a kind of castle involving only the king */ var kingLongMoves={ "1": { 17: [ [15,16],[19,18],[41,29],[39,28],[43,30],[3,4,16],[27,16,28],[40,28,29],[42,29,30],[31,18,30],[7,18,6] ], 5: [ [3,4],[7,8],[29,17],[27,16],[31,18],[15,4,6],[28,16,17],[30,17,18],[19,6,18] ], }, "-1": { 125: [ [127,126],[123,124],[101,113],[99,112],[103,114],[135,124,136],[111,112,124],[100,112,113],[102,113,114],[115,114,126],[139,126,138] ], 137: [ [139,138],[135,136],[113,125],[115,126],[111,124],[127,126,138],[114,125,126],[112,124,125],[123,124,136] ], }, } var SuperModelBoardGenerateMoves=Model.Board.GenerateMoves; Model.Board.GenerateMoves = function(aGame) { // first moves (white and black) are managed specifically to setup K,Q,E,L initial position if(this.setupState===undefined) { this.mMoves=[{}]; return; } if(this.setupState=="setup") { this.mMoves=[]; for(var i=0;i<12;i++) this.mMoves.push({setup:i}); return; } SuperModelBoardGenerateMoves.apply(this,arguments); // call regular GenerateMoves method // now consider special 2 cases king moves var kPiece=this.pieces[this.board[this.kings[this.mWho]]]; if(!kPiece.m && !this.check) { var lMoves=kingLongMoves[this.mWho][kPiece.p]; for(var i=0;i=0) continue; var canMove=true; var oppInCheck=false; for(var j=0;j0; if(!inCheck && j==0) oppInCheck=this.cbGetAttackers(aGame,this.kings[-this.mWho],-this.mWho,true).length>0; this.cbQuickUnapply(aGame,undo); this.board[pos]=tmpOut; this.cbIntegrity(aGame); if(inCheck) { canMove=false; break; } } if(canMove) this.mMoves.push({ f: kPiece.p, t: lMove[0], c: null, ck: oppInCheck, a: 'K', }); } } } /* * Model.Board.CopyFrom overriding to copy setupState property */ var SuperModelBoardCopyFrom = Model.Board.CopyFrom; Model.Board.CopyFrom = function(aBoard) { SuperModelBoardCopyFrom.apply(this,arguments); this.setupState = aBoard.setupState; } /* * Model.Board.Evaluate overriding: in setup phase, no evaluation */ var SuperModelBoardEvaluate = Model.Board.Evaluate; Model.Board.Evaluate = function(aGame) { if(this.setupState===undefined || this.setupState=="setup") return; SuperModelBoardEvaluate.apply(this,arguments); } /* * Model.Board.ApplyMove overriding: setup phase and king special move */ var SuperModelBoardApplyMove=Model.Board.ApplyMove; Model.Board.ApplyMove = function(aGame,move) { if(this.setupState===undefined) this.setupState="setup"; else if(this.setupState=="setup") { var $this=this, piece; // at this point, KQLE have arbitrary positions. remember those piece indexes so we can move them var starting={ "1": { K: 17, Q: 18, L: 5, E: 6 }, "-1": { K: 125, Q: 126, L: 137, E: 138 }, } var indexes={ "1": {}, "-1": {} }; ["1","-1"].forEach(function(side) { for(var p in starting[side]) indexes[side][p]=$this.board[starting[side][p]]; }); // remove KQLE from the board [5,6,17,18,125,126,137,138].forEach(function(pos) { var pIndex=$this.board[pos]; $this.board[pos]=-1; piece = $this.pieces[pIndex]; piece.p=-1; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,pos); }); // setup KQLE positions according to the setup var setup=move.setup; var remaining={}; if(setup/6<1) { this.board[17]=indexes[1].K; piece = this.pieces[indexes[1].K]; piece.p=17; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,17); this.kings[1]=17; remaining[1]=[18,5,6]; this.board[125]=indexes[-1].K; piece = this.pieces[indexes[-1].K]; piece.p=125; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,125); this.kings[-1]=125; remaining[-1]=[126,137,138]; } else { this.board[5]=indexes[1].K; piece = this.pieces[indexes[1].K]; piece.p=5; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,5); this.kings[1]=5; remaining[1]=[17,18,6]; this.board[137]=indexes[-1].K; piece = this.pieces[indexes[-1].K]; piece.p=137; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,137); this.kings[-1]=137; remaining[-1]=[125,126,138]; } setup%=6; var queen=Math.floor(setup/2); this.board[remaining[1][queen]]=indexes[1].Q; piece = this.pieces[indexes[1].Q]; piece.p=remaining[1][queen]; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,remaining[1][queen]); remaining[1].splice(queen,1); this.board[remaining[-1][queen]]=indexes[-1].Q; piece = this.pieces[indexes[-1].Q]; piece.p=remaining[-1][queen]; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,remaining[-1][queen]); remaining[-1].splice(queen,1); var eagle,lion; setup%=2; if(setup==0) { eagle=0; lion=1; } else { eagle=1; lion=0; } this.board[remaining[1][eagle]]=indexes[1].E; piece = this.pieces[indexes[1].E]; piece.p=remaining[1][eagle]; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,remaining[1][eagle]); this.board[remaining[1][lion]]=indexes[1].L; piece = this.pieces[indexes[1].L]; piece.p=remaining[1][lion]; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,remaining[1][lion]); this.board[remaining[-1][eagle]]=indexes[-1].E; piece = this.pieces[indexes[-1].E]; piece.p=remaining[-1][eagle]; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,remaining[-1][eagle]); this.board[remaining[-1][lion]]=indexes[-1].L; piece = this.pieces[indexes[-1].L]; piece.p=remaining[-1][lion]; $this.zSign=aGame.zobrist.update($this.zSign,"board",piece.t,remaining[1][lion]); this.setupState="done"; } else SuperModelBoardApplyMove.apply(this,arguments); } /* * Model.Move.ToString overriding for setup notation */ var SuperModelMoveToString = Model.Move.ToString; Model.Move.ToString = function() { if(this.f===undefined) { if(this.setup===undefined) return "--"; else return "#"+this.setup; } return SuperModelMoveToString.apply(this,arguments); } /* * Model.Board.CompactMoveString overriding to help reading PJN game transcripts */ var SuperModelBoardCompactMoveString = Model.Board.CompactMoveString; Model.Board.CompactMoveString = function(aGame,aMove,allMoves) { if(typeof aMove.ToString!="function") // ensure proper move object, if necessary aMove=aGame.CreateMove(aMove); if(this.setupState===undefined || this.setupState=="setup") return aMove.ToString(); return SuperModelBoardCompactMoveString.apply(this,arguments); } /* * Model.Board.StaticGenerateMoves overriding to prevent using AI during the setup phase */ Model.Board.StaticGenerateMoves = function(aGame) { if(this.setupState=="setup") return [aGame.CreateMove({setup:Math.floor(Math.random()*12)})]; return null; } })();