<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <link rel="stylesheet" href="jquery.jocly.min.css"> <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> <script src="jquery.jocly.min.js"></script> <title>Jocly development stub web page</title> <script> $(document).ready(function() { $("#applet").jocly({}); $("#applet").jocly("localPlay","custom-draughts",{ }); $("#applet").jocly("setFeatures",{ notifyEnd: false, hasEndSound: false, }); $("#options").joclyListener("listen","viewOptions",function(message) { console.log("viewOptions",message); $("#options-skin").hide().children("option").remove(); if(message.options.skin && message.skins && message.skins.length>0) { message.skins.forEach(function(skin) { $("<option/>").attr("value",skin.name).text(skin.title).appendTo($("#options-skin")); }); $("#options-skin").show().val(message.options.skin); } $("#options-notation").hide(); if(message.options.notation!==undefined) $("#options-notation").show().children("input").prop("checked",message.options.notation); $("#options-moves").hide(); if(message.options.moves!==undefined) $("#options-moves").show().children("input").prop("checked",message.options.moves); $("#options-autocomplete").hide(); if(message.options.autocomplete!==undefined) $("#options-autocomplete").show().children("input").prop("checked",message.options.autocomplete); $("#options-sounds").hide(); if(message.options.sounds!==undefined) $("#options-sounds").show().children("input").prop("checked",message.options.sounds); $("#options").show(); }); $("#options").on("change",function() { var options={}; if($("#options-skin").is(":visible")) options.skin=$("#options-skin").val(); if($("#options-notation").is(":visible")) options.notation=$("#options-notation-input").prop("checked"); if($("#options-moves").is(":visible")) options.moves=$("#options-moves-input").prop("checked"); if($("#options-autocomplete").is(":visible")) options.autocomplete=$("#options-autocomplete-input").prop("checked"); if($("#options-sounds").is(":visible")) options.sounds=$("#options-sounds-input").prop("checked"); $("#applet").jocly("viewOptions",options); }); var defaultLevel=0; $("#mode-panel").joclyListener("listen","players",function(message) { console.warn("players",message); function UpdatePlayer(player,key,levels) { if(player.type=="computer") { var select=$("#select-level-"+key); select.empty(); for(var i=0;i<levels.length;i++) $("<option/>").attr("value",i).text(levels[i].label).appendTo(select); select.val(player.level); $("#level-"+key).show(); } else $("#level-"+key).hide(); } UpdatePlayer(message.players[1],'a',message.levels); UpdatePlayer(message.players[-1],'b',message.levels); var modeSelect=$("#mode"); modeSelect.show(); if(message.players[1].type=="self" && message.players[-1].type=="self") modeSelect.val("self-self"); else if(message.players[1].type=="self" && message.players[-1].type=="computer") modeSelect.val("self-comp"); else if(message.players[1].type=="computer" && message.players[-1].type=="self") modeSelect.val("comp-self"); else if(message.players[1].type=="computer" && message.players[-1].type=="computer") modeSelect.val("comp-comp"); else modeSelect.hide(); message.levels.forEach(function(level,index) { if(level.isDefault) defaultLevel=index; }); $("#mode-panel").show(); }); $("#mode-panel").on("change",function() { console.log("changed mode",$("#mode").val(),$("#select-level-a").val(),$("#select-level-b").val()); var players; switch($("#mode").val()) { case "self-self": players={"1":{type:"self"},"-1":{type:"self"}}; break; case "self-comp": players={"1":{type:"self"},"-1":{type:"computer",level:$("#select-level-b").val() || defaultLevel}}; break; case "comp-self": players={"1":{type:"computer",level:$("#select-level-a").val() || defaultLevel},"-1":{type:"self"}}; break; case "comp-comp": players={"1":{type:"computer",level:$("#select-level-a").val() || defaultLevel}, "-1":{type:"computer",level:$("#select-level-b").val() || defaultLevel}}; break; } $("#applet").jocly("setPlayers",players); }); $("#restart").on("click",function() { $("#applet").jocly("restartGame"); }); $("#takeback").on("click",function() { $("#applet").jocly("takeBack"); }); $("#fullscreen").on("click",function() { $("#applet").joclyFullscreen(); }); }); </script> <style type="text/css"> * { box-sizing: border-box; } body { } #container { width: 100%; display: table; table-layout: fixed; } #applet { display: table-cell; width: 60%; } #controls { display: table-cell; width: 33%; vertical-align: top; padding: 0 .5em 0 .5em; } .box { background-color: #f0f0f0; border: 2px solid #e0e0e0; border-radius: 1em; padding: 1em; } </style> <script type="text/jocly-model-view" data-jocly-game="draughts/custom-draughts"> <!-- --> </script> </head> <body> <div id="container"> <div id="applet"></div> <div id="controls"> <div id="mode-panel" style="display: none;" class="box"> <h3>Controls</h3> <button id="restart">Restart game</button><br/><br/> <button id="takeback">Take back</button><br/><br/> <select id="mode"> <option value="self-self">Self / Self</option> <option value="self-comp">Self / Computer</option> <option value="comp-self">Computer / Self</option> <option value="comp-comp">Computer / Computer</option> </select><br/><br/> <label id="level-a" for="select-level-a">Computer(A) level<br/> <select id="select-level-a"></select><br/><br/> </label> <label id="level-b" for="select-level-b">Computer(B) level<br/> <select id="select-level-b"></select><br/><br/> </label> <button id="fullscreen">Full screen</button><br/><br/> </div> <br/> <div id="options" style="display: none;" class="box"> <h3>Options</h3> <select id="options-skin"></select><br/><br/> <label id="options-notation" for="options-notation-input"> <input id="options-notation-input" type="checkbox"/> Notation<br/> </label> <label id="options-moves" for="options-moves-input"> <input id="options-moves-input" type="checkbox"/> Show possible moves<br/> </label> <label id="options-autocomplete" for="options-autocomplete-input"> <input id="options-autocomplete-input" type="checkbox"/> Auto-complete moves<br/> </label> <label id="options-sounds" for="options-sounds-input"> <input id="options-sounds-input" type="checkbox"/> Sounds<br/> </label> </div> </div> </div> </body> </html>
<script type="text/jocly-model-view" data-jocly-game="draughts/custom-draughts"> { "view": { "js": [ "checkers-xd-view.js", "draughts8-xd-view.js" ] }, "model": { "js": [ "checkersbase-custom-model.js", "draughts-model.js" ], "gameOptions": { "preventRepeat": true, "width": 4, "height": 8, "initial": { "a": [[0,0],[0,1],[0,2],[0,3],[1,0],[1,1],[1,2],[1,3],[2,0],[2,1],[2,2],[2,3]], "b": [[7,0],[7,1],[7,2],[7,3],[6,0],[6,1],[6,2],[6,3],[5,0],[5,1],[5,2],[5,3]] }, "variant": { "compulsoryCatch": true, "canStepBack": false, "mustMoveForward": false, "mustMoveForwardStrict": true, "lastRowFreeze": false, "lastRowCrown": true, "captureLongestLine": true, "kingCaptureShort": false, "canCaptureBackward": true, "longRangeKing": true, "captureInstantRemove": false, "lastRowFactor": 0.001 }, "uctTransposition": "state" } } } </script> <script type="text/jocly-resources" data-jocly-game="custom-draughts"> { "checkersbase-custom-model.js": "checkersbase-custom-model.js" } </script>
... if(aGame.g.captureLongestLine) { var moves0=this.mMoves; var moves1=[]; var bestLength=0; for(var i in moves0) { var move=moves0[i]; if(move.pos.length==bestLength) moves1.push(move); else if(move.pos.length>bestLength) { moves1=[move]; bestLength=move.pos.length; } } this.mMoves=moves1; } ...
Model.Board.ApplyMove = function(aGame,move) { + var pieceCrowned=false; var WIDTH=aGame.mOptions.width; var HEIGHT=aGame.mOptions.height; var pos0=move.pos[0]; var pIndex=this.board[pos0]; var piece=this.pieces[pIndex]; var player=piece.s; piece.l=pos0; var toBeRemoved={}; this.zSign=aGame.zobrist.update(this.zSign,"board",piece.s+"/"+piece.t,piece.p); for(var i=1;i<move.pos.length;i++) { var pos=move.pos[i]; this.board[piece.p]=-1; piece.p=pos; + if (aGame.g.russianCustom==true) { + var r=aGame.g.Coord[pos][0]; + if((player==JocGame.PLAYER_A && r==HEIGHT-1) || (player==JocGame.PLAYER_B && r==0)) { + pieceCrowned=true; + } + } this.board[pos]=pIndex; var caught=move.capt[i]; if(caught!=null) { if(this.board[caught]>=0) toBeRemoved[this.board[caught]]=true; this.board[caught]=-1; } pos0=pos; } this.zSign=aGame.zobrist.update(this.zSign,"board",piece.s+"/"+piece.t,pos); var plp=move.capt[move.capt.length-1] piece.plp=plp?plp:move.pos[move.pos.length-2]; for(var index in toBeRemoved) { var piece0=this.pieces[index]; var other=(1-piece0.s)/2; this.pCount[other]--; switch(piece0.t) { case 0: this.spCount[other]--; break; case 1: this.kpCount[other]--; break; } this.zSign=aGame.zobrist.update(this.zSign,"board",piece0.s+"/"+piece0.t,piece0.p); this.pieces[index]=null; } if(aGame.g.lastRowCrown && this.pieces[pIndex].t==0) { var r=aGame.g.Coord[move.pos[move.pos.length-1]][0]; - if((player==JocGame.PLAYER_A && r==HEIGHT-1) || (player==JocGame.PLAYER_B && r==0)) { + if(pieceCrowned || (player==JocGame.PLAYER_A && r==HEIGHT-1) || (player==JocGame.PLAYER_B && r==0)) { var piece0=this.pieces[pIndex]; piece0.t=1; var self=(1-player)/2; this.spCount[self]--; this.kpCount[self]++; this.zSign=aGame.zobrist.update(this.zSign,"board",piece0.s+"/0",piece0.p); this.zSign=aGame.zobrist.update(this.zSign,"board",piece0.s+"/1",piece0.p); } } }
function catchPieces(pos,poss,capts,dirs,king) { while(true) { var nextPoss=[]; var nextCapts=[]; var nextDirs=[]; aGame.CheckersEachDirection(pos,function(pos0,dir) { var r; if(aGame.g.canCaptureBackward==false) r=aGame.g.Coord[pos][0]; var dir0=aGame.Checkers2WaysDirections[dir]; + if (aGame.g.russianCustom==true) { + if($this.board[pos0]>=0 && $this.pieces[$this.board[pos0]].s==-$this.mWho) { + var pp=aGame.g.Graph[pos0][dir]; + if (aGame.g.Coord[pp]) { + var rr=aGame.g.Coord[pp][0]; + var HEIGHT=aGame.mOptions.height; + if(($this.mWho==JocGame.PLAYER_A && rr==HEIGHT-1) || + ($this.mWho==JocGame.PLAYER_B && rr==0)) { + king=true; + } + } + } + } if(!king) { if($this.board[pos0]>=0 && $this.pieces[$this.board[pos0]].s==-$this.mWho) { var r0,forward; if(aGame.g.canCaptureBackward==false) { r0=aGame.g.Coord[pos0][0]; forward=false; if(($this.mWho==JocGame.PLAYER_A && r0>=r) || ($this.mWho==JocGame.PLAYER_B && r0<=r)) forward=true; } if(aGame.g.canCaptureBackward || forward==true) { var pos1=aGame.g.Graph[pos0][dir]; if(pos1!=null && ($this.board[pos1]==-1 || pos1==poss[0])) { var keep=true; for(var i=0;i<dirs.length;i++) if((aGame.g.captureInstantRemove && capts[i]==pos0) || (aGame.g.captureInstantRemove==false && capts[i]==pos0 && dirs[i]==dir0)) { keep=false; break; } if(keep) { nextPoss.push(pos1); nextCapts.push(pos0); nextDirs.push(dir0); } } } } } else { // king if(aGame.g.longRangeKing) while($this.board[pos0]==-1 || (aGame.g.king180deg && pos0!=null && capts.indexOf(pos0)>=0)) pos0=aGame.g.Graph[pos0][dir]; if(pos0!=null) { if($this.board[pos0]>=0 && $this.pieces[$this.board[pos0]].s==-$this.mWho) { var caught=pos0; pos0=aGame.g.Graph[pos0][dir]; if(aGame.g.kingCaptureShort) { if($this.board[pos0]==-1 || pos0==poss[0]) { var keep=true; for(var i=0;i<dirs.length;i++) if(!aGame.g.king180deg) { if((aGame.g.captureInstantRemove && capts[i]==caught) || (aGame.g.captureInstantRemove==false && capts[i]==caught && dirs[i]==dir0)) { keep=false; break; } } else if(capts[i]==caught) { keep=false; break; } if(keep) { nextPoss.push(pos0); nextCapts.push(caught); nextDirs.push(dir0); } pos0=aGame.g.Graph[pos0][dir]; } } else { while($this.board[pos0]==-1 || pos0==poss[0]) { var keep=true; for(var i=0;i<dirs.length;i++) if((aGame.g.captureInstantRemove && capts[i]==caught) || (aGame.g.captureInstantRemove==false && capts[i]==caught && dirs[i]==dir0)) { keep=false; break; } if(keep) { nextPoss.push(pos0); nextCapts.push(caught); nextDirs.push(dir0); } pos0=aGame.g.Graph[pos0][dir]; } } } } } return true; }); if(nextPoss.length==0) { if(poss.length>1) $this.mMoves.push({ pos: poss, capt: capts }); break; } if(!aGame.g.compulsoryCatch && poss.length>1) { var poss1=[]; for(var i=0;i<poss.length;i++) poss1.push(poss[i]); var capts1=[]; for(var i=0;i<capts.length;i++) capts1.push(capts[i]); $this.mMoves.push({ pos: poss1, capt: capts1 }); } if(nextPoss.length==1) { pos=nextPoss[0]; poss.push(pos); capts.push(nextCapts[0]); dirs.push(nextDirs[0]); } else { for(var i=0;i<nextPoss.length;i++) { var poss1=[]; for(var j=0;j<poss.length;j++) poss1.push(poss[j]); poss1.push(nextPoss[i]); var capts1=[]; for(var j=0;j<capts.length;j++) capts1.push(capts[j]); capts1.push(nextCapts[i]); var dirs1=[]; for(var j=0;j<dirs.length;j++) dirs1.push(dirs[j]); dirs1.push(nextDirs[i]); catchPieces(nextPoss[i],poss1,capts1,dirs1,king); } break; } } }
: Custom-Engine ( -- ) -10000 BestScore ! 0 Nodes ! $FirstMove BEGIN $CloneBoard DUP $MoveString CurrentMove! DUP .moveCFA EXECUTE MaxDepth Depth ! 0 EvalCount ! BestScore @ 10000 turn-offset next-turn-offset Score 0 5 $RAND-WITHIN + BestScore @ OVER < IF DUP BestScore ! Score! 0 Depth! DUP $MoveString BestMove! ELSE DROP ENDIF $DeallocateBoard Nodes ++ Nodes @ Nodes! $Yield $NextMove DUP NOT UNTIL DROP ;
Source: https://habr.com/ru/post/280334/
All Articles