X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=public%2Fjavascripts%2Fvariants%2FMagnetic.js;h=17efeaa923918e94506cc4768b468e8a8a8381a9;hb=643479f8d7c3622b57fc49c4f10d9950793ebf4f;hp=e94153229532d42acaf32dd1c06ea6f7ae0717de;hpb=1af36beb39aa5d59735483e915fd1040f93eecca;p=vchess.git diff --git a/public/javascripts/variants/Magnetic.js b/public/javascripts/variants/Magnetic.js index e9415322..17efeaa9 100644 --- a/public/javascripts/variants/Magnetic.js +++ b/public/javascripts/variants/Magnetic.js @@ -1,128 +1,212 @@ -class MagneticRules +class MagneticRules extends ChessRules { - getEpSquare(move) - { - return undefined; //no en-passant - } + static get HasEnpassant { return false; } - // Complete a move with magnetic actions - applyMagneticLaws([x,y], move) + setOtherVariables(fen) { - // TODO + // No en-passant: + const parsedFen = V.ParseFen(fen); + this.setFlags(fenParsed.flags); + this.scanKingsRooks(fen); } - getBasicMove([sx,sy], [ex,ey], tr) + getPotentialMovesFrom([x,y]) { - var mv = new Move({ - appear: [ - new PiPo({ - x: ex, - y: ey, - c: !!tr ? tr.c : this.getColor(sx,sy), - p: !!tr ? tr.p : this.getPiece(sx,sy) - }) - ], - vanish: [ - new PiPo({ - x: sx, - y: sy, - c: this.getColor(sx,sy), - p: this.getPiece(sx,sy) - }) - ] + let standardMoves = super.getPotentialMovesFrom([x,y]); + let moves = []; + standardMoves.forEach(m => { + let newMove_s = this.applyMagneticLaws(m); + if (newMove_s.length == 1) + moves.push(newMove_s[0]); + else //promotion + moves = moves.concat(newMove_s); }); - - if (this.board[ex][ey] != VariantRules.EMPTY) - { - mv.vanish.push( - new PiPo({ - x: ex, - y: ey, - c: this.getColor(ex,ey), - p: this.getPiece(ex,ey) - }) - ); - } - this.applyMagneticLaws([ex,ey], mv); - return mv; + return moves; } - getCastleMoves([x,y]) + getPotentialPawnMoves([x,y]) { - const c = this.getColor(x,y); - if (x != (c=="w" ? 7 : 0) || y != this.INIT_COL_KING[c]) - return []; //x isn't first rank, or king has moved (shortcut) - - const V = VariantRules; - - // Castling ? - const oppCol = this.getOppCol(c); + const color = this.turn; let moves = []; - let i = 0; - const finalSquares = [ [2,3], [6,5] ]; //king, then rook - castlingCheck: - for (let castleSide=0; castleSide < 2; castleSide++) //large, then small - { - if (!this.flags[c][castleSide]) - continue; - // If this code is reached, rooks and king are on initial position + const [sizeX,sizeY] = [V.size.x,V.size.y]; + const shift = (color == "w" ? -1 : 1); + const firstRank = (color == 'w' ? sizeX-1 : 0); + const startRank = (color == "w" ? sizeX-2 : 1); + const lastRank = (color == "w" ? 0 : sizeX-1); - // Nothing on the path of the king (and no checks; OK also if y==finalSquare)? - let step = finalSquares[castleSide][0] < y ? -1 : 1; - for (i=y; i!=finalSquares[castleSide][0]; i+=step) + if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank) + { + // Normal moves + if (this.board[x+shift][y] == V.EMPTY) { - if (this.isAttacked([x,i], oppCol) || (this.board[x][i] != V.EMPTY && - // NOTE: next check is enough, because of chessboard constraints - (this.getColor(x,i) != c || ![V.KING,V.ROOK].includes(this.getPiece(x,i))))) + moves.push(this.getBasicMove([x,y], [x+shift,y])); + // Next condition because variants with pawns on 1st rank allow them to jump + if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY) { - continue castlingCheck; + // Two squares jump + moves.push(this.getBasicMove([x,y], [x+2*shift,y])); } } - - // Nothing on the path to the rook? - step = castleSide == 0 ? -1 : 1; - for (i = y + step; i != this.INIT_COL_ROOK[c][castleSide]; i += step) + // Captures + if (y>0 && this.board[x+shift][y-1] != V.EMPTY + && this.canTake([x,y], [x+shift,y-1])) { - if (this.board[x][i] != V.EMPTY) - continue castlingCheck; + moves.push(this.getBasicMove([x,y], [x+shift,y-1])); } - const rookPos = this.INIT_COL_ROOK[c][castleSide]; - - // Nothing on final squares, except maybe king and castling rook? - for (i=0; i<2; i++) + if (y { + // Normal move + if (this.board[x+shift][y] == V.EMPTY) + moves.push(this.getBasicMove([x,y], [x+shift,y], {c:pawnColor,p:p})); + // Captures + if (y>0 && this.board[x+shift][y-1] != V.EMPTY + && this.canTake([x,y], [x+shift,y-1])) + { + moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:pawnColor,p:p})); + } + if (y=2 || Math.abs(j-y)>=2) && this.getPiece(i,j) != V.KING) + { + move.vanish.push( + new PiPo({ + p:this.getPiece(i,j), + c:this.getColor(i,j), + x:i, + y:j + }) + ); + move.appear.push( + new PiPo({ + p:this.getPiece(i,j), + c:this.getColor(i,j), + x:x+step[0], + y:y+step[1] + }) + ); + } + } + else + { + // Repulsion + if (this.getPiece(i,j) != V.KING) + { + // Push it until we meet an obstacle or edge of the board + let [ii,jj] = [i+step[0],j+step[1]]; + while (V.OnBoard(ii,jj)) + { + if (this.board[ii][jj] != V.EMPTY) + break; + ii += step[0]; + jj += step[1]; + } + ii -= step[0]; + jj -= step[1]; + if (Math.abs(ii-i)>=1 || Math.abs(jj-j)>=1) + { + move.vanish.push( + new PiPo({ + p:this.getPiece(i,j), + c:this.getColor(i,j), + x:i, + y:j + }) + ); + move.appear.push( + new PiPo({ + p:this.getPiece(i,j), + c:this.getColor(i,j), + x:ii, + y:jj + }) + ); + } + } + } + break; + } + i += step[0]; + j += step[1]; + } + } + this.undo(standardMove); + let moves = []; + // Scan move for pawn (max 1) on 8th rank + for (let i=1; i { + let tmp = m.appear[0]; + m.appear[0] = m.appear[i]; + m.appear[i] = tmp; + }); + break; + } + } + if (moves.length == 0) //no pawn on 8th rank + moves.push(move); return moves; } - // TODO: verify this assertion -// atLeastOneMove() -// { -// return true; //always at least one possible move -// } + atLeastOneMove() + { + if (this.kingPos[this.turn][0] < 0) + return false; + return true; //TODO: is it right? + } underCheck(move) { @@ -135,9 +219,9 @@ class MagneticRules const saveKingPos = this.kingPos[c]; //king might be taken this.play(move); // The only way to be "under check" is to have lost the king (thus game over) - let res = this.kingPos[c][0] < 0; - ? [ JSON.parse(JSON.stringify(saveKingPos)) ] - : [ ]; + let res = this.kingPos[c][0] < 0 + ? [JSON.parse(JSON.stringify(saveKingPos))] + : []; this.undo(move); return res; } @@ -146,15 +230,25 @@ class MagneticRules { super.updateVariables(move); const c = this.getColor(move.start.x,move.start.y); - if (c != this.getColor(move.end.x,move.end.y) - && this.board[move.end.x][move.end.y] != VariantRules.EMPTY - && this.getPiece(move.end.x,move.end.y) == VariantRules.KING) + if (this.board[move.end.x][move.end.y] != V.EMPTY + && c != this.getColor(move.end.x,move.end.y) + && this.getPiece(move.end.x,move.end.y) == V.KING) { // We took opponent king ! const oppCol = this.getOppCol(c); this.kingPos[oppCol] = [-1,-1]; - this.flags[oppCol] = [false,false]; + this.castleFlags[oppCol] = [false,false]; } + // Did we magnetically move our (init) rooks or opponents' ones ? + const firstRank = (c == "w" ? 7 : 0); + const oppFirstRank = 7 - firstRank; + const oppCol = this.getOppCol(c); + move.vanish.forEach(psq => { + if (psq.x == firstRank && this.INIT_COL_ROOK[c].includes(psq.y)) + this.castleFlags[c][psq.y==this.INIT_COL_ROOK[c][0] ? 0 : 1] = false; + else if (psq.x == oppFirstRank && this.INIT_COL_ROOK[oppCol].includes(psq.y)) + this.castleFlags[oppCol][psq.y==this.INIT_COL_ROOK[oppCol][0] ? 0 : 1] = false; + }); } unupdateVariables(move) @@ -176,22 +270,16 @@ class MagneticRules } } - checkGameOver() - { - if (this.checkRepetition()) - return "1/2"; - - const color = this.turn; - // TODO: do we need "atLeastOneMove()"? - if (this.atLeastOneMove() && this.kingPos[color][0] >= 0) - return "*"; - - return this.checkGameEnd(); - } - checkGameEnd() { // No valid move: our king disappeared return this.turn == "w" ? "0-1" : "1-0"; } + + static get THRESHOLD_MATE() + { + return 500; //checkmates evals may be slightly below 1000 + } } + +const VariantRules = MagneticRules;