From 2526c041baf44968b0aa7b98af56730e88f6a595 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Wed, 21 Nov 2018 13:05:33 +0100
Subject: [PATCH] Remove some redundant code [Checkered/Magnetic still buggish]

---
 TODO                                     |   1 +
 public/javascripts/base_rules.js         |  63 +++---
 public/javascripts/components/game.js    |   4 +-
 public/javascripts/variants/Atomic.js    |   8 +-
 public/javascripts/variants/Checkered.js | 258 ++++-------------------
 public/javascripts/variants/Magnetic.js  | 188 +++--------------
 6 files changed, 117 insertions(+), 405 deletions(-)
 create mode 100644 TODO

diff --git a/TODO b/TODO
new file mode 100644
index 00000000..5ad48808
--- /dev/null
+++ b/TODO
@@ -0,0 +1 @@
+For animation, moves should contains "moving" and "fading" maybe...
diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js
index 7c52fc1c..f07aaff2 100644
--- a/public/javascripts/base_rules.js
+++ b/public/javascripts/base_rules.js
@@ -52,7 +52,7 @@ class ChessRules
 		this.moves = moves;
 		// Use fen string to initialize variables, flags and board
 		this.board = VariantRules.GetBoard(fen);
-		this.flags = VariantRules.GetFlags(fen);
+		this.setFlags(fen);
 		this.initVariables(fen);
 	}
 
@@ -125,14 +125,13 @@ class ChessRules
 	}
 
 	// Overridable: flags can change a lot
-	static GetFlags(fen)
+	setFlags(fen)
 	{
 		// white a-castle, h-castle, black a-castle, h-castle
-		let flags = {'w': new Array(2), 'b': new Array(2)};
-		let fenFlags = fen.split(" ")[1]; //flags right after position
+		this.castleFlags = {'w': new Array(2), 'b': new Array(2)};
+		let flags = fen.split(" ")[1]; //flags right after position
 		for (let i=0; i<4; i++)
-			flags[i < 2 ? 'w' : 'b'][i%2] = (fenFlags.charAt(i) == '1');
-		return flags;
+			this.castleFlags[i < 2 ? 'w' : 'b'][i%2] = (flags.charAt(i) == '1');
 	}
 
 	///////////////////
@@ -176,6 +175,17 @@ class ChessRules
 		};
 	}
 
+	// Aggregates flags into one object
+	get flags() {
+		return this.castleFlags;
+	}
+
+	// Reverse operation
+	parseFlags(flags)
+	{
+		this.castleFlags = flags;
+	}
+
 	// En-passant square, if any
 	getEpSquare(move)
 	{
@@ -222,7 +232,7 @@ class ChessRules
 	// Build a regular move from its initial and destination squares; tr: transformation
 	getBasicMove([sx,sy], [ex,ey], tr)
 	{
-		var mv = new Move({
+		let mv = new Move({
 			appear: [
 				new PiPo({
 					x: ex,
@@ -260,7 +270,7 @@ class ChessRules
 	getSlideNJumpMoves([x,y], steps, oneStep)
 	{
 		const color = this.getColor(x,y);
-		var moves = [];
+		let moves = [];
 		const [sizeX,sizeY] = VariantRules.size;
 		outerLoop:
 		for (let step of steps)
@@ -284,13 +294,14 @@ class ChessRules
 	// What are the pawn moves from square x,y considering color "color" ?
 	getPotentialPawnMoves([x,y])
 	{
-		const color = this.getColor(x,y);
-		var moves = [];
-		var V = VariantRules;
+		const color = this.turn;
+		let moves = [];
+		const V = VariantRules;
 		const [sizeX,sizeY] = VariantRules.size;
-		let shift = (color == "w" ? -1 : 1);
-		let startRank = (color == "w" ? sizeY-2 : 1);
-		let lastRank = (color == "w" ? 0 : sizeY-1);
+		const shift = (color == "w" ? -1 : 1);
+		const firstRank = (color == 'w' ? sizeY-1 : 0);
+		const startRank = (color == "w" ? sizeY-2 : 1);
+		const lastRank = (color == "w" ? 0 : sizeY-1);
 
 		if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
 		{
@@ -298,7 +309,8 @@ class ChessRules
 			if (this.board[x+shift][y] == V.EMPTY)
 			{
 				moves.push(this.getBasicMove([x,y], [x+shift,y]));
-				if (x==startRank && this.board[x+2*shift][y] == V.EMPTY)
+				// Next condition because variants with pawns on 1st rank generally allow them to jump
+				if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY)
 				{
 					// Two squares jump
 					moves.push(this.getBasicMove([x,y], [x+2*shift,y]));
@@ -394,7 +406,7 @@ class ChessRules
 		castlingCheck:
 		for (let castleSide=0; castleSide < 2; castleSide++) //large, then small
 		{
-			if (!this.flags[c][castleSide])
+			if (!this.castleFlags[c][castleSide])
 				continue;
 			// If this code is reached, rooks and king are on initial position
 
@@ -658,7 +670,7 @@ class ChessRules
 		{
 			this.kingPos[c][0] = move.appear[0].x;
 			this.kingPos[c][1] = move.appear[0].y;
-			this.flags[c] = [false,false];
+			this.castleFlags[c] = [false,false];
 			return;
 		}
 		const oppCol = this.getOppCol(c);
@@ -666,14 +678,14 @@ class ChessRules
 		if (move.start.x == firstRank //our rook moves?
 			&& this.INIT_COL_ROOK[c].includes(move.start.y))
 		{
-			const flagIdx = move.start.y == this.INIT_COL_ROOK[c][0] ? 0 : 1;
-			this.flags[c][flagIdx] = false;
+			const flagIdx = (move.start.y == this.INIT_COL_ROOK[c][0] ? 0 : 1);
+			this.castleFlags[c][flagIdx] = false;
 		}
 		else if (move.end.x == oppFirstRank //we took opponent rook?
 			&& this.INIT_COL_ROOK[c].includes(move.end.y))
 		{
-			const flagIdx = move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1;
-			this.flags[oppCol][flagIdx] = false;
+			const flagIdx = (move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1);
+			this.castleFlags[oppCol][flagIdx] = false;
 		}
 	}
 
@@ -687,11 +699,11 @@ class ChessRules
 
 	play(move, ingame)
 	{
+		console.log("AVANT " + this.getNotation(move) + " "  + this.board[1][5]);
 		if (!!ingame)
 			move.notation = this.getNotation(move);
 
-		// Save flags (for undo)
-		move.flags = JSON.stringify(this.flags); //TODO: less costly?
+		move.flags = JSON.stringify(this.flags); //save flags (for undo)
 		this.updateVariables(move);
 		this.moves.push(move);
 		this.epSquares.push( this.getEpSquare(move) );
@@ -704,7 +716,8 @@ class ChessRules
 		this.epSquares.pop();
 		this.moves.pop();
 		this.unupdateVariables(move);
-		this.flags = JSON.parse(move.flags);
+		this.parseFlags(JSON.parse(move.flags));
+		console.log("APRES " + this.getNotation(move) + " "  + this.board[1][5]);
 	}
 
 	//////////////
@@ -982,7 +995,7 @@ class ChessRules
 		for (let i of ['w','b'])
 		{
 			for (let j=0; j<2; j++)
-				fen += this.flags[i][j] ? '1' : '0';
+				fen += this.castleFlags[i][j] ? '1' : '0';
 		}
 		return fen;
 	}
diff --git a/public/javascripts/components/game.js b/public/javascripts/components/game.js
index 18632858..170aeac9 100644
--- a/public/javascripts/components/game.js
+++ b/public/javascripts/components/game.js
@@ -575,7 +575,7 @@ Vue.component('my-game', {
 			this.newGame("computer");
 		},
 		newGame: function(mode, fenInit, color, oppId, moves, continuation) {
-			const fen = fenInit || VariantRules.GenRandInitFen();
+			const fen = "brnbnkrq/pppppppp/8/8/8/8/PPPPPPPP/BNNRKBQR 11111111111111111111";//fenInit || VariantRules.GenRandInitFen();
 			console.log(fen); //DEBUG
 			this.score = "*";
 			if (mode=="human" && !oppId)
@@ -635,7 +635,7 @@ Vue.component('my-game', {
 			}
 			else //against computer
 			{
-				this.mycolor = Math.random() < 0.5 ? 'w' : 'b';
+				this.mycolor = "w";//Math.random() < 0.5 ? 'w' : 'b';
 				if (this.mycolor == 'b')
 					setTimeout(this.playComputerMove, 500);
 			}
diff --git a/public/javascripts/variants/Atomic.js b/public/javascripts/variants/Atomic.js
index f32e21d1..2b7b1ac3 100644
--- a/public/javascripts/variants/Atomic.js
+++ b/public/javascripts/variants/Atomic.js
@@ -72,7 +72,7 @@ class AtomicRules extends ChessRules
 				&& Math.abs(this.kingPos[c][1]-move.end.y) <= 1)
 			{
 				this.kingPos[c] = [-1,-1];
-				this.flags[c] = [false,false];
+				this.castleFlags[c] = [false,false];
 			}
 
 			// Did we explode opponent king ?
@@ -80,7 +80,7 @@ class AtomicRules extends ChessRules
 				&& Math.abs(this.kingPos[oppCol][1]-move.end.y) <= 1)
 			{
 				this.kingPos[oppCol] = [-1,-1];
-				this.flags[oppCol] = [false,false];
+				this.castleFlags[oppCol] = [false,false];
 			}
 			else
 			{
@@ -88,9 +88,9 @@ class AtomicRules extends ChessRules
 				if (Math.abs(move.end.x-oppFirstRank) <= 1)
 				{
 					if (Math.abs(move.end.y-this.INIT_COL_ROOK[oppCol][0]) <= 1)
-						this.flags[oppCol][0] = false;
+						this.castleFlags[oppCol][0] = false;
 					if (Math.abs(move.end.y-this.INIT_COL_ROOK[oppCol][1]) <= 1)
-						this.flags[oppCol][1] = false;
+						this.castleFlags[oppCol][1] = false;
 				}
 			}
 		}
diff --git a/public/javascripts/variants/Checkered.js b/public/javascripts/variants/Checkered.js
index 6ed73a8b..4f523edb 100644
--- a/public/javascripts/variants/Checkered.js
+++ b/public/javascripts/variants/Checkered.js
@@ -32,205 +32,71 @@ class CheckeredRules extends ChessRules
 		return ChessRules.fen2board(f);
 	}
 
-	static GetFlags(fen)
+	setFlags(fen)
 	{
-		let flags = [
-			ChessRules.GetFlags(fen), //castle
-			{
-				"w": new Array(8), //pawns can move 2 squares
-				"b": new Array(8)
-			}
-		];
-		const fenFlags = fen.split(" ")[1].substr(4); //skip first 4 digits, for castle
+		super.setFlags(fen); //castleFlags
+		this.pawnFlags =
+		{
+			"w": new Array(8), //pawns can move 2 squares?
+			"b": new Array(8)
+		};
+		const flags = fen.split(" ")[1].substr(4); //skip first 4 digits, for castle
 		for (let c of ['w','b'])
 		{
 			for (let i=0; i<8; i++)
-				flags[1][c][i] = (fenFlags.charAt((c=='w'?0:8)+i) == '1');
+				this.pawnFlags[c][i] = (flags.charAt((c=='w'?0:8)+i) == '1');
 		}
-		return flags;
 	}
 
-	canTake([x1,y1], [x2,y2])
-	{
-		const color1 = this.getColor(x1,y1);
-		const color2 = this.getColor(x2,y2);
-		// Checkered aren't captured
-		return color1 != color2 && color2 != 'c' && (color1 != 'c' || color2 != this.turn);
+	// Aggregates flags into one object
+	get flags() {
+		return [this.castleFlags, this.pawnFlags];
 	}
 
-	addCaptures([sx,sy], [ex,ey], moves)
+	// Reverse operation
+	parseFlags(flags)
 	{
-		const piece = this.getPiece(sx,sy);
-		if (piece != VariantRules.KING)
-		{
-			moves.push(this.getBasicMove([sx,sy], [ex,ey], {c:'c',p:piece}));
-			const takePiece = this.getPiece(ex,ey);
-			if (takePiece != piece)
-				moves.push(this.getBasicMove([sx,sy], [ex,ey], {c:'c',p:takePiece}));
-		}
-		else
-			moves.push(this.getBasicMove([sx,sy], [ex,ey]));
+		this.castleFlags = flags[0];
+		this.pawnFlags = flags[1];
 	}
 
-	// Generic method to find possible moves of non-pawn pieces ("sliding or jumping")
-	getSlideNJumpMoves([x,y], steps, oneStep)
-	{
-		const color = this.getColor(x,y);
-		let moves = [];
-		const [sizeX,sizeY] = VariantRules.size;
-		outerLoop:
-		for (var loop=0; loop<steps.length; loop++)
-		{
-			let step = steps[loop];
-			let i = x + step[0];
-			let j = y + step[1];
-			while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] == VariantRules.EMPTY)
-			{
-				moves.push(this.getBasicMove([x,y], [i,j])); //no capture
-				if (oneStep !== undefined)
-					continue outerLoop;
-				i += step[0];
-				j += step[1];
-			}
-			if (i>=0 && i<8 && j>=0 && j<8 && this.canTake([x,y], [i,j]))
-				this.addCaptures([x,y], [i,j], moves);
-		}
-		return moves;
-	}
-
-	// What are the pawn moves from square x,y considering color "color" ?
-	getPotentialPawnMoves([x,y])
+	canTake([x1,y1], [x2,y2])
 	{
-		const color = this.getColor(x,y);
-		var moves = [];
-		var V = VariantRules;
-		let [sizeX,sizeY] = VariantRules.size;
-		const c = (color == 'c' ? this.turn : color);
-		const shift = (c == "w" ? -1 : 1);
-		let startRank = (c == "w" ? sizeY-2 : 1);
-		let lastRank = (c == "w" ? 0 : sizeY-1);
-
-		if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
-		{
-			// Normal moves
-			if (this.board[x+shift][y] == V.EMPTY)
-			{
-				moves.push(this.getBasicMove([x,y], [x+shift,y]));
-				if (x==startRank && this.board[x+2*shift][y] == V.EMPTY && this.flags[1][c][y])
-				{
-					// Two squares jump
-					moves.push(this.getBasicMove([x,y], [x+2*shift,y]));
-				}
-			}
-			// Captures
-			if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
-				this.addCaptures([x,y], [x+shift,y-1], moves);
-			if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
-				this.addCaptures([x,y], [x+shift,y+1], moves);
-		}
-
-		if (x+shift == lastRank)
-		{
-			// Promotion
-			let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
-			promotionPieces.forEach(p => {
-				// Normal move
-				if (this.board[x+shift][y] == V.EMPTY)
-					moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
-				// Captures
-				if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
-					moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:'c',p:p}));
-				if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
-					moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:'c',p:p}));
-			});
-		}
-
-		// En passant
-		const Lep = this.epSquares.length;
-		const epSquare = Lep>0 ? this.epSquares[Lep-1] : undefined;
-		if (!!epSquare && epSquare.x == x+shift && Math.abs(epSquare.y - y) == 1)
-		{
-			let epStep = epSquare.y - y;
-			var enpassantMove = this.getBasicMove([x,y], [x+shift,y+epStep]);
-			enpassantMove.vanish.push({
-				x: x,
-				y: y+epStep,
-				p: 'p',
-				c: this.getColor(x,y+epStep)
-			});
-			enpassantMove.appear[0].c = 'c';
-			moves.push(enpassantMove);
-		}
-
-		return moves;
+		const color1 = this.getColor(x1,y1);
+		const color2 = this.getColor(x2,y2);
+		// Checkered aren't captured
+		return color1 != color2 && color2 != 'c' && (color1 != 'c' || color2 != this.turn);
 	}
 
-	getCastleMoves([x,y])
+	// Post-processing: apply "checkerization" of standard moves
+	getPotentialMovesFrom([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);
+		let standardMoves = super.getPotentialMovesFrom([x,y]);
+		if (this.getPiece(x,y) == VariantRules.KING)
+			return standardMoves; //king has to be treated differently (for castles)
 		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[0][c][castleSide])
-				continue;
-			// If this code is reached, rooks and king are on initial position
-
-			// 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)
+		standardMoves.forEach(m => {
+			if (m.vanish[0].p == VariantRules.PAWN && Math.abs(m.end.x-m.start.x)==2
+				&& !this.pawnFlags[this.turn][m.start.y])
 			{
-				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)))))
-				{
-					continue castlingCheck;
-				}
+				return; //skip forbidden 2-squares jumps
 			}
-
-			// 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)
-			{
-				if (this.board[x][i] != V.EMPTY)
-					continue castlingCheck;
-			}
-			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 (m.vanish.length == 1)
+				moves.push(m); //no capture
+			else
 			{
-				if (this.board[x][finalSquares[castleSide][i]] != V.EMPTY &&
-					this.getPiece(x,finalSquares[castleSide][i]) != V.KING &&
-					finalSquares[castleSide][i] != rookPos)
+				// A capture occured (m.vanish.length == 2)
+				m.appear[0].c = "c";
+				moves.push(JSON.parse(JSON.stringify(m)));
+				if (m.appear[0].p != m.vanish[1].p)
 				{
-					continue castlingCheck;
+					// Add transformation into captured piece
+					let m2 = JSON.parse(JSON.stringify(m));
+					m2.vanish[1].p = m.appear[0].p;
+					moves.push(m2);
 				}
 			}
-
-			// If this code is reached, castle is valid
-			moves.push( new Move({
-				appear: [
-					new PiPo({x:x,y:finalSquares[castleSide][0],p:V.KING,c:c}),
-					new PiPo({x:x,y:finalSquares[castleSide][1],p:V.ROOK,c:c})],
-				vanish: [
-					new PiPo({x:x,y:y,p:V.KING,c:c}),
-					new PiPo({x:x,y:rookPos,p:V.ROOK,c:c})],
-				end: Math.abs(y - rookPos) <= 2
-					? {x:x, y:rookPos}
-					: {x:x, y:y + 2 * (castleSide==0 ? -1 : 1)}
-			}) );
-		}
-
+		});
 		return moves;
 	}
 
@@ -310,40 +176,14 @@ class CheckeredRules extends ChessRules
 
 	updateVariables(move)
 	{
-		const piece = this.getPiece(move.start.x,move.start.y);
 		const c = this.getColor(move.start.x,move.start.y);
-
 		if (c != 'c') //checkered not concerned by castle flags
-		{
-			const firstRank = (c == "w" ? 7 : 0);
-			// Update king position + flags
-			if (piece == VariantRules.KING && move.appear.length > 0)
-			{
-				this.kingPos[c][0] = move.appear[0].x;
-				this.kingPos[c][1] = move.appear[0].y;
-				this.flags[0][c] = [false,false];
-				return;
-			}
-			const oppCol = this.getOppCol(c);
-			const oppFirstRank = 7 - firstRank;
-			if (move.start.x == firstRank //our rook moves?
-				&& this.INIT_COL_ROOK[c].includes(move.start.y))
-			{
-				const flagIdx = move.start.y == this.INIT_COL_ROOK[c][0] ? 0 : 1;
-				this.flags[0][c][flagIdx] = false;
-			}
-			else if (move.end.x == oppFirstRank //we took opponent rook?
-				&& this.INIT_COL_ROOK[c].includes(move.end.y))
-			{
-				const flagIdx = move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1;
-				this.flags[0][oppCol][flagIdx] = false;
-			}
-		}
+			super.updateVariables(move);
 
 		// Does it turn off a 2-squares pawn flag?
 		const secondRank = [1,6];
 		if (secondRank.includes(move.start.x) && move.vanish[0].p == VariantRules.PAWN)
-			this.flags[1][move.start.x==6 ? "w" : "b"][move.start.y] = false;
+			this.pawnFlags[move.start.x==6 ? "w" : "b"][move.start.y] = false;
 	}
 
 	checkGameEnd()
@@ -385,18 +225,12 @@ class CheckeredRules extends ChessRules
 
 	getFlagsFen()
 	{
-		let fen = "";
-		// Add castling flags
-		for (let c of ['w','b'])
-		{
-			for (let i=0; i<2; i++)
-				fen += this.flags[0][c][i] ? '1' : '0';
-		}
+		let fen = super.getFlagsFen();
 		// Add pawns flags
 		for (let c of ['w','b'])
 		{
 			for (let i=0; i<8; i++)
-				fen += this.flags[1][c][i] ? '1' : '0';
+				fen += this.pawnFlags[c][i] ? '1' : '0';
 		}
 		return fen;
 	}
diff --git a/public/javascripts/variants/Magnetic.js b/public/javascripts/variants/Magnetic.js
index 4151f9ad..d5731a63 100644
--- a/public/javascripts/variants/Magnetic.js
+++ b/public/javascripts/variants/Magnetic.js
@@ -5,10 +5,24 @@ class MagneticRules extends ChessRules
 		return undefined; //no en-passant
 	}
 
+	getPotentialMovesFrom([x,y])
+	{
+		const 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(moves, newMove_s);
+		});
+	}
+
 	// Complete a move with magnetic actions
-	applyMagneticLaws([x,y], move)
+	applyMagneticLaws(standardMove)
 	{
-		const standardMove = JSON.parse(JSON.stringify(move));
+		const [x,y] = [moves.start.x, move.start.y];
+		let move = JSON.parse(JSON.stringify(standardMove));
 		this.play(standardMove);
 		const color = this.getColor(x,y);
 		const [sizeX,sizeY] = VariantRules.size;
@@ -88,172 +102,22 @@ class MagneticRules extends ChessRules
 			}
 		}
 		this.undo(standardMove);
-	}
-
-	// TODO: when pawn is pushed to 8th rank, apply promotions (similar change as in Checkered)
-	getBasicMove([sx,sy], [ex,ey], tr)
-	{
-		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)
-				})
-			]
-		});
-
-		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;
-	}
-
-	getPotentialPawnMoves([x,y])
-	{
-		const color = this.getColor(x,y);
-		var moves = [];
-		var V = VariantRules;
-		const [sizeX,sizeY] = VariantRules.size;
-		let shift = (color == "w" ? -1 : 1);
-		let startRank = (color == "w" ? sizeY-2 : 1);
-		let firstRank = (color == 'w' ? sizeY-1 : 0);
-		let lastRank = (color == "w" ? 0 : sizeY-1);
-
-		if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
-		{
-			// Normal moves
-			if (this.board[x+shift][y] == V.EMPTY)
-			{
-				moves.push(this.getBasicMove([x,y], [x+shift,y]));
-				if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY)
-				{
-					// Two squares jump
-					moves.push(this.getBasicMove([x,y], [x+2*shift,y]));
-				}
-			}
-			// Captures
-			if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
-				moves.push(this.getBasicMove([x,y], [x+shift,y-1]));
-			if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
-				moves.push(this.getBasicMove([x,y], [x+shift,y+1]));
-		}
-
-		if (x+shift == lastRank)
-		{
-			// Promotion
-			let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
-			promotionPieces.forEach(p => {
-				// Normal move
-				if (this.board[x+shift][y] == V.EMPTY)
-					moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
-				// Captures
-				if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY)
-					moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:p}));
-				if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1]) && this.board[x+shift][y+1] != V.EMPTY)
-					moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:p}));
-			});
-		}
-
-		// No en passant
-
-		return moves;
-	}
-
-	getCastleMoves([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);
 		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 (..condition pawn promote)
 		{
-			if (!this.flags[c][castleSide])
-				continue;
-			// If this code is reached, rooks and king are on initial position
-
-			// 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 (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)))))
-				{
-					continue castlingCheck;
-				}
-			}
-
-			// 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)
-			{
-				if (this.board[x][i] != V.EMPTY)
-					continue castlingCheck;
-			}
-			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 (this.board[x][finalSquares[castleSide][i]] != V.EMPTY &&
-					this.getPiece(x,finalSquares[castleSide][i]) != V.KING &&
-					finalSquares[castleSide][i] != rookPos)
-				{
-					continue castlingCheck;
-				}
-			}
-
-			// If this code is reached, castle is valid
-			let cmove = new Move({
-				appear: [
-					new PiPo({x:x,y:finalSquares[castleSide][0],p:V.KING,c:c}),
-					new PiPo({x:x,y:finalSquares[castleSide][1],p:V.ROOK,c:c})],
-				vanish: [
-					new PiPo({x:x,y:y,p:V.KING,c:c}),
-					new PiPo({x:x,y:rookPos,p:V.ROOK,c:c})],
-				end: Math.abs(y - rookPos) <= 2
-					? {x:x, y:rookPos}
-					: {x:x, y:y + 2 * (castleSide==0 ? -1 : 1)}
-			});
-			this.applyMagneticLaws([x,finalSquares[castleSide][1]], cmove);
-			moves.push(cmove);
+			move. ... = ... //loop
+			moves.push(...);
 		}
-
+		else
+			moves.push(move);
 		return moves;
 	}
 
 	// TODO: verify this assertion
-//	atLeastOneMove()
-//	{
-//		return true; //always at least one possible move
-//	}
+	atLeastOneMove()
+	{
+		return true; //always at least one possible move
+	}
 
 	underCheck(move)
 	{
@@ -284,7 +148,7 @@ class MagneticRules extends ChessRules
 			// We took opponent king !
 			const oppCol = this.getOppCol(c);
 			this.kingPos[oppCol] = [-1,-1];
-			this.flags[oppCol] = [false,false];
+			this.castleFlags[oppCol] = [false,false];
 		}
 	}
 
-- 
2.44.0