UNPKG

jocly

Version:

Board games 3D/2D UI and AI web library

1 lines 18.9 kB
exports.model=Model={Game:{},Board:{},Move:{}},Model.Game.InitGame=function(){for(var r=this,o=this.mOptions.size,e=[],t=[],i=0,n=0,a=[],s=0;s<o;s++)a.push(n),n+=(o-s)*(o-s);for(var s=0;s<o;s++)for(var p=0;p<o-s;p++)for(var u=0;u<o-s;u++){var h=i++;e[h]=[p,u,s],t[h]=[];for(var l=0;l<2;l++)for(var f=0;f<2;f++){var v=s-1,d=p+l,g=u+f;v>=0&&v<o&&d>=0&&d<o-v&&g>=0&&g<o-v?t[h].push(a[v]+d*(o-v)+g):t[h].push(null)}for(var c=[[0,-1],[0,1],[-1,0],[1,0]],y=0;y<c.length;y++){var b=c[y],v=s,d=p+b[0],g=u+b[1];v>=0&&v<o&&d>=0&&d<o-v&&g>=0&&g<o-v?t[h].push(a[v]+d*(o-v)+g):t[h].push(null)}for(var l=-1;l<1;l++)for(var f=-1;f<1;f++){var v=s+1,d=p+l,g=u+f;v>=0&&v<o&&d>=0&&d<o-v&&g>=0&&g<o-v?t[h].push(a[v]+d*(o-v)+g):t[h].push(null)}}this.g.Graph=t,this.g.Coord=e,this.g.Over=[],this.g.Beneath=[];for(var h=0;h<this.g.Graph.length;h++)this.g.Over[h]=null,this.g.Beneath[h]=null;for(var h=0;h<this.g.Graph.length;h++)for(var e=this.g.Coord[h],m=h+1;m<this.g.Graph.length;m++){var G=this.g.Coord[m];if(G[2]==e[2]+2&&G[0]==e[0]-1&&G[1]==e[1]-1){this.g.Over[h]=m,this.g.Beneath[m]=h;break}}this.g.EachDirection=function(o,e){for(var t=0;t<12;t++){var i=r.g.Graph[o][t];if(null!=i&&0==e(i,t))return}},this.g.EachDirectionDown=function(o,e){for(var t=[0,1,2,3],i=0;i<t.length;i++){var n=r.g.Graph[o][t[i]];if(null!=n&&0==e(n,t[i]))return}},this.g.EachDirectionUp=function(o,e){for(var t=[8,9,10,11],i=0;i<t.length;i++){var n=r.g.Graph[o][t[i]];if(null!=n&&0==e(n,t[i]))return}},this.g.EachDirectionFlat=function(o,e){for(var t=[4,5,6,7],i=0;i<t.length;i++){var n=r.g.Graph[o][t[i]];if(null!=n&&0==e(n,t[i]))return}},this.g.EachDirectionFlatDown=function(o,e){for(var t=[0,1,2,3,4,5,6,7],i=0;i<t.length;i++){var n=r.g.Graph[o][t[i]];if(null!=n&&0==e(n,t[i]))return}},this.g.EachDirectionFlatUp=function(o,e){for(var t=[4,5,6,7,8,9,10,11],i=0;i<t.length;i++){var n=r.g.Graph[o][t[i]];if(null!=n&&0==e(n,t[i]))return}},this.zobrist=new JocGame.Zobrist({board:{type:"array",size:this.g.Graph.length,values:[0,1]}}),this.InitGameExtra()},Model.Game.MapSameLevelDiagGraph=function(){for(var r=[0,16,25,29],o=0;o<4;o++)for(var e=0;e<4-o;e++)for(var t=0;t<4-o;t++)for(var i=r[o]+e*(4-o)+t,n=-1;n<2;n+=2)for(var a=-1;a<2;a+=2){var s=o,p=e+n,u=t+a;s>=0&&s<4&&p>=0&&p<4-s&&u>=0&&u<4-s?this.g.Graph[i].push(r[s]+p*(4-s)+u):this.g.Graph[i].push(null)}},Model.Game.InitGameExtra=function(){},Model.Game.DestroyGame=function(){this.DestroyGameExtra()},Model.Game.DestroyGameExtra=function(){},Model.Game.spUpdateZobrist=function(r,o,e,t,i,n){for(var a=0;a<o.length;a++)r=this.zobrist.update(r,"board",e,o[a]);for(var a=0;a<t.length;a++)r=this.zobrist.update(r,"board",i,t[a]);return r},Model.Move.Init=function(r){for(var o in r)r.hasOwnProperty(o)&&(this[o]=JSON.parse(JSON.stringify(r[o])))},Model.Move.ToString=function(){var r=["?","W","B","R"][this.clr],o="";switch(this.act){case"+":o+="+"+this.pos+r;break;case">":o+=this.from+">"+this.to+r}return o},Model.Board.Init=function(r){},Model.Board.InitialPosition=function(r){this.spInitialPosition(r)},Model.Board.spInitialPosition=function(r){this.board=[];for(var o=0;o<r.g.Graph.length;o++)this.board[o]=0;this.maxLayer=0,this.ballCount=[0,0,0],this.playables={},this.height=[0,0,0],this.zSign=0;for(var o=0;o<r.mOptions.size*r.mOptions.size;o++)this.playables[o]=!0},Model.Board.MakeFreeMoves=function(r){var o=[];for(var e in this.playables)this.playables.hasOwnProperty(e)&&o.push({act:"+",pos:e,clr:this.mWho==JocGame.PLAYER_A?1:2});return o},Model.Board.GenerateMoves=function(r){var o=this.GenerateAllMoves(r),e=r.mOptions.moveCount;0==o.length?(this.mFinished=!0,this.ballCount[1]>this.ballCount[2]?this.mWinner=JocGame.PLAYER_A:this.ballCount[1]<this.ballCount[2]?this.mWinner=JocGame.PLAYER_B:this.mWinner=JocGame.DRAW):void 0!==e&&o.length>e&&(r.ArrayShuffle(o),o.sort(function(r,o){o.nextBoard.evaluation,r.nextBoard.evaluation}),o.splice(e,o.length-e)),this.mMoves=o},Model.Board.GenerateAllMoves=function(r){return this.MakeFreeMoves(r)},Model.Board.Evaluate=function(r,o,e){this.mEvaluation=0},Model.Board.ApplyMove=function(r,o){this.spApplyMove(r,o)},Model.Board.spApplyMove=function(r,o){function e(o){delete t.playables[o],r.g.EachDirectionFlat(o,function(e,i){if(t.board[e]){var n,a;switch(i){case 4:n=7,a=10;break;case 5:n=6,a=9;break;case 6:n=4,a=8;break;case 7:n=5,a=11}var s=r.g.Graph[o][n];null!==s&&t.board[s]>0&&t.board[r.g.Graph[e][n]]&&(t.playables[r.g.Graph[o][a]]=!0)}})}var t=this;switch(o.act){case"+":this.board[o.pos]=o.clr;var i=r.g.Coord[o.pos][2];i>this.maxLayer&&(this.maxLayer=i),this.height[o.clr]+=i,this.ballCount[o.clr]++,e(o.pos);break;case">":o.down.length>0?this.playables[o.down[o.down.length-1]]=!0:this.playables[o.from]=!0;for(var n=o.from,a=0;a<o.down.length;a++){var s=o.down[a];this.height[this.board[s]]--,this.board[n]=this.board[s],n=s}this.board[n]=0,this.board[o.to]=o.clr;var i=r.g.Coord[o.to][2];this.height[o.clr]+=i,i>this.maxLayer&&(this.maxLayer=i),e(o.to)}},Model.Board.IsValidMove=function(r,o){return!0},Model.Board.ExtendMove=function(r,o){return{}},Model.Board.GetSignature=function(){return this.zSign},Model.Board.InitialPosition=function(r){this.spInitialPosition(r),this.groupMaxId=1,this.groups={},this.posGroup={},this.posFree={},this.center=0,this.moveEvaluation=0},Model.Board.GenerateAllMoves=function(r){for(var o=this.MakeFreeMoves(r),e=[],t=0;t<o.length;t++){var i=o[t],n=this.ExtendMove(r,i.pos);if(null!==n){i.nextBoard=n.board,i.remove=n.remove;var a=!1;r.mVisitedBoards&&r.mVisitedBoards[i.nextBoard.zSign]&&(a=!0),0==a&&e.push(i)}}return e},Model.Board.ExtendMove=function(r,o,e,t){function i(e){var t=p.board[e],i={side:t,p:{},pCount:1,f:{},fCount:0};i.p[e]=!0;for(var n=[e];n.length>0;){var a=n.pop();r.g.EachDirection(a,function(e,s){var u=p.board[e];if(u==t){if(e in i.p)return!0;var l=r.g.Over[e];if(null!==l&&(0!=p.board[l]||o==l))return!0;var f=m[s];if(void 0!==f){var v=r.g.Graph[a][f[0]],d=r.g.Graph[a][f[1]];if((v==o&&t==h||p.board[v]==3-t)&&(d==o&&t==h||p.board[d]==3-t))return!0}i.p[e]=!0,i.pCount++,n.push(e)}else if(0==u&&e!=o&&0==r.g.Coord[e][2]){if(e in i.f)return!0;i.f[e]=!0,i.fCount++}return!0})}return i}function n(r){var o=p.groupMaxId++;p.groups[o]=r;for(var e in r.p)if(r.p.hasOwnProperty(e)){p.posGroup[e];p.posGroup[e]=o}for(var t in r.f)r.f.hasOwnProperty(t)&&(void 0===p.posFree[t]&&(p.posFree[t]={}),p.posFree[t][o]=!0);return o}function a(r,o){var e=[];for(var t in o)o.hasOwnProperty(t)&&e.push(t);for(var i=e[0],n=p.groups[i],a=1;a<e.length;a++){var t=e[a],s=p.groups[t];for(var u in s.p)s.p.hasOwnProperty(u)&&(n.p[u]=!0,p.posGroup[u]=i);n.pCount+=s.pCount;for(var h in s.f)s.f.hasOwnProperty(h)&&(h in n.f||(n.f[h]=!0,n.fCount++),delete p.posFree[h][t],p.posFree[h][i]=!0);delete p.groups[t]}if(r>=0){for(var h in y)y.hasOwnProperty(h)&&(h in n.f||(n.f[h]=!0,n.fCount++),void 0===p.posFree[h]&&(p.posFree[h]={}),p.posFree[h][i]=!0);n.p[r]=!0,n.pCount++,p.posGroup[r]=i}}function s(r,o,e){var t=p.groups[o];for(var i in e)e.hasOwnProperty(i)&&(i in t.f||(t.f[i]=!0,t.fCount++,void 0===p.posFree[i]&&(p.posFree[i]={}),p.posFree[i][o]=!0));t.p[r]=!0,t.pCount++,p.posGroup[r]=o}arguments.length<3&&(e=0),arguments.length<4&&(t=null),null==t&&(t=this);var p=JSON.parse(JSON.stringify({board:t.board,playables:t.playables,ballCount:t.ballCount,groups:t.groups,posFree:t.posFree,posGroup:t.posGroup,groupMaxId:t.groupMaxId,center:t.center,zSign:t.zSign,mWho:t.mWho})),u={};0==e&&(e=this.mWho==JocGame.PLAYER_A?1:2);var h=3-e,l=r.g.Coord[o],f=l[2],v={},d=0,g={},c=0,y={},b=0,m={4:[8,10],5:[9,11],6:[8,9],7:[10,11]},G={4:[0,2],5:[1,3],6:[0,1],7:[2,3]},M={},C={},O=r.g.Beneath[o];if(null!=O){var w=p.posGroup[O],F=p.groups[w];delete F.p[O],F.pCount--,p.posGroup[O]=0;var P=p.board[O],E=r.g.Coord[O][2];r.g.EachDirection(O,function(o,e){var t=p.board[o];if(r.g.Coord[o][2]==E){var i=m[e],n=r.g.Graph[O][i[0]],a=r.g.Graph[O][i[1]];if(null!=n&&p.board[n]==3-P&&null!=a||p.board[a]==3-P)return!0}return t==P&&p.posGroup[o]>0&&(C[o]=!0),!0})}f>0&&r.g.EachDirectionFlat(o,function(t,i){if(p.board[t]==e){var n=G[i],a=r.g.Graph[o][n[0]],s=r.g.Graph[o][n[1]];p.board[a]==h&&p.board[s]==h&&(p.posGroup[a]&&(C[a]=!0),p.posGroup[s]&&(C[s]=!0))}return!0});var B={};for(var S in C)if(C.hasOwnProperty(S)){var x=p.posGroup[S];B[x]=!0}for(var x in B)B.hasOwnProperty(x)&&function(r){var o=p.groups[r];for(var e in o.p)o.p.hasOwnProperty(e)&&0!=p.posGroup[e]&&(p.posGroup[e]=-1);for(var t in o.f)o.f.hasOwnProperty(t)&&delete p.posFree[t][r];delete p.groups[r]}(x);for(var S in C)C.hasOwnProperty(S)&&p.posGroup[S]<0&&n(i(S));r.g.EachDirection(o,function(r){if(0==p.board[r])return!0;var o=p.posGroup[r];return 0==o||(p.board[r]==e?void 0===v[o]&&(v[o]=!0,d++):p.board[r]==h&&void 0===g[o]&&(g[o]=!0,c++),!0)}),0==f&&r.g.EachDirectionFlat(o,function(r){return 0==p.board[r]&&(y[r]=!0,b++),!0});var D=p.posFree[o];if(void 0!==D){for(var x in D)if(D.hasOwnProperty(x)){var F=p.groups[x];delete F.f[o],F.fCount--}delete p.posFree[o]}if(0==d){var F={side:e,p:{},pCount:1,f:y,fCount:b};F.p[o]=!0,n(F)}else if(1==d){for(var w in v)if(v.hasOwnProperty(w))break;s(o,w,y)}else a(o,v);var z=!1;for(var w in p.groups)if(p.groups.hasOwnProperty(w)){if(0==w)continue;var F=p.groups[w];if(F.side!=h)continue;0==F.fCount&&(!function(e){var t=p.groups[e],a={},s={},h=[];for(var l in t.p)t.p.hasOwnProperty(l)&&h.push({p:l,z:r.g.Coord[l][2]});h.sort(function(r,o){return o.z-r.z});for(var f=0;f<h.length;f++){var v=h[f],l=v.p,d=!1;if(r.g.EachDirectionUp(l,function(r){return!p.board[r]&&r!=o||(d=!0,!1)}),d)a[l]=!0,p.posGroup[l]=-1;else{0==v.z&&(s[l]=!0),p.board[l]=0,u[l]=!0,delete p.posGroup[l],p.ballCount[t.side]--,p.playables[l]=!0,r.g.EachDirectionUp(l,function(r){return p.playables[r]&&delete p.playables[r],!0});var g=r.g.Beneath[l];if(g)if(p.board[g]==t.side){var c=!1;if(r.g.EachDirectionDown(l,function(r){return p.board[r]!=t.side||(c=!0,!1)}),c){t.p[g]=!0,t.pCount++,p.posGroup[g]=e;for(var y={p:g,z:r.g.Coord[g][2]},b=f+1;b<h.length&&y.z<h[b].z;b++);h.splice(b,0,y)}else M[g]=!0}else M[g]=!0}}for(var m in t.f)t.f.hasOwnProperty(m)&&delete p.posFree[m][e];delete p.groups[e];for(var m in s)s.hasOwnProperty(m)&&r.g.EachDirectionFlat(m,function(r){var o=p.posGroup[r];if(void 0!==o&&o>0&&(void 0===p.posFree[m]&&(p.posFree[m]={}),void 0===p.posFree[m][o])){p.posFree[m][o]=!0;var e=p.groups[o];e.f[m]=!0,e.fCount++}return!0});for(var l in a)a.hasOwnProperty(l)&&-1==p.posGroup[l]&&n(i(l))}(w),z=!0)}for(var S in M)if(M.hasOwnProperty(S)){if(0!=p.posGroup[S])continue;var A=p.board[S],I={},J=0,k={},W=0,L=r.g.Coord[S][2];if(r.g.EachDirection(S,function(o,e){if(0==p.board[o])return!0;var t=p.posGroup[o];if(0==t)return!0;if(r.g.Coord[o][2]==L){var i=m[e],n=r.g.Graph[S][i[0]],a=r.g.Graph[S][i[1]];if(null!=n&&p.board[n]==3-A&&null!=a&&p.board[a]==3-A)return!0}return p.board[o]==A?void 0===I[t]&&(I[t]=!0,J++):0==p.board[o]&&0==r.g.Coord[o][2]&&(k[o]=!0,W++),!0}),0==J){var F={side:A,p:{},pCount:1,f:k,fCount:W};F.p[S]=!0;var w=n(F)}else if(1==J){for(var w in I)if(I.hasOwnProperty(w))break;s(S,w,{})}else a(S,I)}if(z){var N=[];for(var w in p.groups)if(p.groups.hasOwnProperty(w)){if(0==w)continue;var F=p.groups[w];F.side==e&&N.push(w)}N.sort(function(r,o){return parseInt(r)-parseInt(o)});for(var R=[],U=0;U<N.length;U++){var w=N[U],F=p.groups[w];for(var S in F.p)if(F.p.hasOwnProperty(S)){r.g.EachDirectionFlat(S,function(o,t){if(p.board[o]!=e)return!0;var i=p.posGroup[o];if(i!=w&&0!=i){var n=m[t],a=r.g.Graph[S][n[0]],s=r.g.Graph[S][n[1]];if(null==a||p.board[a]!=h||null==s||p.board[s]!=h){for(var u=null,l=[],f=0;f<R.length;f++){var v=R[f];if(w in v||i in v)if(u){for(var d in v)v.hasOwnProperty(d)&&(u[d]=!0);l.push(f)}else v[w]=!0,v[i]=!0,u=v}for(var f=l.length-1;f>=0;f--)R.splice(l[f],1);if(null==u){var v={};v[w]=!0,v[i]=!0,R.push(v)}}}return!0})}}for(var U=0;U<R.length;U++)a(-1,R[U])}for(var w in p.groups)if(p.groups.hasOwnProperty(w)){if(0==w)continue;var F=p.groups[w];if(F.side!=e)continue;if(0==F.fCount)for(var S in F.p)if(F.p.hasOwnProperty(S)){var H=!1;if(r.g.EachDirectionUp(S,function(r){return!(p.board[r]>0)||(H=!0,!1)}),0==H)return null}}var _=[];for(var w in p.groups)if(p.groups.hasOwnProperty(w)){var F=p.groups[w];F.eyes=0;for(var S in F.p)F.p.hasOwnProperty(S)&&_.push({p:S,z:r.g.Coord[S][2],group:F,gid:w})}_.sort(function(r,o){return o.z-r.z});for(var j={},Y={},U=0;U<_.length;U++){var V=_[U],Z=!1;r.g.EachDirectionUp(V.p,function(r){var o=j[r];return!(void 0!==o&&V.group.side&3-o)||(Z=!0,!1)}),V.pinned=Z,Y[V.p]=V,j[V.p]=Z?3:V.group.side}for(var T in p.posFree)if(p.posFree.hasOwnProperty(T)){var X=0,$=!0;r.g.EachDirectionFlat(T,function(r){if(0==p.board[r])return $=!1,!1;var o=p.posGroup[r];return 0!=X&&o!=X?($=!1,!1):(X=o,!0)}),0==X&&($=!1),$&&p.groups[X].eye++}p.relativeSecured=0,p.relativeHeight=0;var q=r.mOptions.levelOptions;for(var w in p.groups)if(p.groups.hasOwnProperty(w)){var F=p.groups[w],K=1==F.side?1:-1,Q=q.evalSafety;F.eyes>=2?Q=q.evalSafety2eyes+Math.log(F.eyes-1)*q.evalSafetyXEyesBonus:1==F.fCount?Q=q.evalSafety1f:3==F.fCount?Q=q.evalSafety3f:F.fCount>3&&(Q=q.evalSafety3fMore+Math.log(F.fCount-3)*q.evalSafety3fMoreBonus),1==F.eyes&&(Q+=q.evalSafety1eyeBonus);for(var S in F.p)if(F.p.hasOwnProperty(S)){var V=Y[S],rr=Q;V.pinned&&(rr+=q.evalSafetyPinnedBonus),p.relativeSecured+=rr*K,p.relativeHeight+=V.z*K}}if(0==f){var K=1==e?1:-1,or=Math.abs(l[0]-(r.mOptions.size-1)/2)+Math.abs(l[1]-(r.mOptions.size-1)/2);p.center+=or*K*-1}p.moveEvaluation=p.relativeSecured+q.evalHeightRatio*p.relativeHeight+q.evalCenterRatio*p.center;var er=[];for(var tr in u)u.hasOwnProperty(tr)&&er.push(tr);return p.zSign=r.spUpdateZobrist(p.zSign,[o],e-1,er,2-e),{board:p,remove:er}},Model.Board.Evaluate=function(r,o,e){this.mEvaluation=this.moveEvaluation},Model.Board.CheckConsistency=function(r){for(var o=[0,0,0],e=0;e<r.g.Graph.length;e++){var t=(r.g.Coord[e],this.board[e]);if(t>0){if(void 0===this.posGroup[e])return console.error("pos",e,"side",t,"not assigned to any group"),!1;if(this.posFree[e]){var i=null;for(i in this.posFree[e])if(this.posFree[e].hasOwnProperty(i))break;if(null!=i)return console.error("pos",e,"side",t,"set as free for group",i),!1}o[t]++}else if(this.posGroup[e])return console.error("empty pos",e,"in posGroup"),!1;var n=r.g.Over[e];if(null!=n&&this.board[n]>0&&0!=this.posGroup[e])return console.error("buried ball",e,"does not have posGroup 0 but",this.posGroup[e]),!0}if(o[1]!=this.ballCount[1]||o[2]!=this.ballCount[2])return console.error("ball count mismatch, got",o[1],o[2],"expecting",this.ballCount[1],this.ballCount[2]),!1;for(var e in this.posGroup)if(this.posGroup.hasOwnProperty(e)){if(0==this.board[e])return console.error("posGroup pos",e,"is empty"),!1;if(0!=this.posGroup[e]){if(void 0===this.groups[this.posGroup[e]])return console.error("posGroup",e,"in unknown group",this.posGroup[e]),!1;if(!(e in this.groups[this.posGroup[e]].p))return console.error("posGroup",e,"does not match group"),!1}}for(var e in this.posFree)if(this.posFree.hasOwnProperty(e)){if(0!=this.board[e])return console.error("posFree pos",e,"is not empty"),!1;for(var a in this.posFree[e])if(this.posFree[e].hasOwnProperty(a)){var s=this.groups[a];if(void 0===s)return console.error("posFree pos",e,"group",a,"does not exist"),!1;if(!(e in s.f))return console.error("posFree pos",e,"group",a,"not in group freedoms"),!1}}for(var a in this.groups)if(this.groups.hasOwnProperty(a)){var s=this.groups[a],p=0;for(var u in s.p)if(this.group.p.hasOwnProperty(u)){if(0==this.board[u])return console.error("pos",u,"in group",a,"marked as empty"),!1;if(this.board[u]!=s.side)return console.error("pos",u,"in group",a,"has wrong side"),!1;if(this.posGroup[u]!=a)return console.error("pos",u,"in group",a,"has wrong group",this.posGroup[u]),!1;p++}if(p!=s.pCount)return console.error("group",a,"count mismatch"),!1;p=0;for(var u in s.f)if(s.f.hasOwnProperty(u)){if(0!=this.board[u])return console.error("freedom pos",u,"in group",a,"is not empty"),!1;var h=r.g.Coord[u];if(0!=h[2])return console.error("freedom pos",u,"in group",a,"not at ground level"),!1;if(void 0===this.posFree[u])return console.error("freedom pos",u,"in group",a,"not in freedoms"),!1;if(!this.posFree[u][a])return console.error("freedom pos",u,"in group",a,"is not empty for group"),!1;p++}if(p!=s.fCount)return console.error("group",a,"freedom count mismatch"),!1}return!0},Model.Board.ApplyMove=function(r,o){if(void 0===o.nextBoard){var e=this.ExtendMove(r,o.pos);e||console.log("move",o,JSON.stringify(r.mPlayedMoves)),this.CopyFrom(e.board)}else this.CopyFrom(o.nextBoard);this.spApplyMove(r,o)},Model.Board.CopyFrom=function(r){this.groupMaxId=r.groupMaxId,this.center=r.center,this.maxLayer=r.maxLayer,this.zSign=r.zSign,this.mWho=r.mWho,this.moveEvaluation=r.moveEvaluation,this.board=[],this.ballCount=[0,r.ballCount[1],r.ballCount[2]];for(var o=0;o<r.board.length;o++)this.board.push(r.board[o]);this.playables={};for(var o in r.playables)r.playables.hasOwnProperty(o)&&(this.playables[o]=!0);this.groups={};for(var e in r.groups)if(r.groups.hasOwnProperty(e)){var t=r.groups[e],i={side:t.side,p:{},pCount:t.pCount,f:{},fCount:t.fCount};for(var o in t.p)t.p.hasOwnProperty(o)&&(i.p[o]=!0);for(var o in t.f)t.f.hasOwnProperty(o)&&(i.f[o]=!0);this.groups[e]=i}this.posFree={};for(var o in r.posFree)if(r.posFree.hasOwnProperty(o)){var n={};for(var a in r.posFree[o])r.posFree[o].hasOwnProperty(a)&&(n[a]=!0);this.posFree[o]=n}this.posGroup={};for(var o in r.posGroup)r.posGroup.hasOwnProperty(o)&&(this.posGroup[o]=r.posGroup[o]);r.height?this.height=[0,r.height[1],r.height[2]]:this.height=[0,0,0],void 0!==r.mEvaluation&&(this.mEvaluation=r.mEvaluation),void 0!==r.mFinished&&(this.mFinished=r.mFinished),void 0!==r.mWinner&&(this.mWinner=r.mWinner)},Model.Game.Save=function(){for(var r={playedMoves:[],game:JoclyHub.modelName},o=0;o<this.mPlayedMoves.length;o++){var e=new(this.GetMoveClass())(this.mPlayedMoves[o]);delete e.nextBoard,delete e.remove,delete e.boardJSON,r.playedMoves.push(e)}var t=new Date;if(r.date=t.getFullYear()+"-"+(t.getMonth()+1)+"-"+t.getDate()+"-"+t.getHours()+"_"+t.getMinutes()+"_"+t.getSeconds(),JoclyHub.network.connected){$(".jocly-temp").remove();var i=document.createElement("form");i.setAttribute("class","jocly-temp"),i.setAttribute("style","display: none;"),i.setAttribute("method","post"),i.setAttribute("action","/jocly/save-game");var n=document.createElement("input");n.setAttribute("type","hidden"),n.setAttribute("name","data"),n.setAttribute("value",JSON.stringify(r)),i.appendChild(n),document.body.appendChild(i),i.submit()}else{var a=r.game+"-"+r.date+".joc",s="data:application/x-joc;filename="+a+","+encodeURIComponent(JSON.stringify(r));window.open(s,a)}},Model.Move.Strip=function(){if(void 0!==this.nextBoard||void 0!==this.remove){var r={};for(var o in this)this.hasOwnProperty(o)&&"nextBoard"!=o&&(r[o]=JSON.parse(JSON.stringify(this[o])));return r}return this};