From f4fd6580a227a352f6e0e95870954bc2fa2ce97f Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Thu, 13 Dec 2018 15:10:03 +0100
Subject: [PATCH] Finish Ultima rules. Seems ok (still potential bugs)

---
 public/javascripts/variants/Ultima.js | 125 ++++++++++++--------------
 1 file changed, 59 insertions(+), 66 deletions(-)

diff --git a/public/javascripts/variants/Ultima.js b/public/javascripts/variants/Ultima.js
index 57f3e25c..d5b9f884 100644
--- a/public/javascripts/variants/Ultima.js
+++ b/public/javascripts/variants/Ultima.js
@@ -53,36 +53,6 @@ class UltimaRules extends ChessRules
 	// Is piece on square (x,y) immobilized?
 	isImmobilized([x,y])
 	{
-					// Final check: is this knight immobilized?
-					let foundImmobilizer = false;
-					let neutralized = false;
-					outerLoop:
-					for (let step of steps)
-					{
-						const [i2,j2] = [i+step[0],j+step[1]];
-						if (i2>=0 && i2<sizeX && j2>=0 && j2<sizeY
-							&& this.board[i2][j2] != V.EMPTY
-							&& this.getColor(i2,j2) == oppCol
-							&& this.getPiece(i2,j2) == V.IMMOBILIZER)
-						{
-							foundImmobilizer = true;
-							// Moving is possible only if this immobilizer is neutralized
-							for (let step2 of steps)
-							{
-								const [i3,j3] = [i2+step2[0],j2+step2[1]];
-								if (i3>=0 && i3<sizeX && j3>=0 && j3<sizeY
-									&& this.board[i3][j3] != V.EMPTY && this.getColor(i3,j3) == color
-									&& [V.BISHOP,V.IMMOBILIZER].includes(this.getPiece(i3,j3)))
-								{
-									neutralized = true;
-									break outerLoop;
-								}
-							}
-						}
-					}
-					if (!foundImmobilizer || neutralized)
-						return false;
-		
 		const piece = this.getPiece(x,y);
 		const color = this.getColor(x,y);
 		const oppCol = this.getOppCol(color);
@@ -98,7 +68,7 @@ class UltimaRules extends ChessRules
 			{
 				const oppPiece = this.getPiece(i,j);
 				if (oppPiece == V.BISHOP && piece == V.IMMOBILIZER)
-					return [];
+					return true;
 				if (oppPiece == V.IMMOBILIZER && ![V.BISHOP,V.IMMOBILIZER].includes(piece))
 				{
 					// Moving is impossible only if this immobilizer is not neutralized
@@ -108,15 +78,15 @@ class UltimaRules extends ChessRules
 						if (i2>=0 && i2<sizeX && j2>=0 && j2<sizeY
 							&& this.board[i2][j2] != V.EMPTY && this.getColor(i2,j2) == color)
 						{
-							const friendlyPiece = this.getPiece(i2,j2);
-							if ([V.BISHOP,V.IMMOBILIZER].includes(friendlyPiece))
-								break outerLoop;
+							if ([V.BISHOP,V.IMMOBILIZER].includes(this.getPiece(i2,j2)))
+								return false;
 						}
 					}
-					return []; //immobilizer isn't neutralized
+					return true; //immobilizer isn't neutralized
 				}
 			}
 		}
+		return false;
 	}
 
 	getPotentialMovesFrom([x,y])
@@ -412,59 +382,82 @@ class UltimaRules extends ChessRules
 
 	// isAttacked() is OK because the immobilizer doesn't take
 
-	// TODO: check if any pawn can reach capturing square + !immobilized
 	isAttackedByPawn([x,y], colors)
 	{
-		// Square (x,y) must be surrounded by two enemy pieces,
-		// and one of them at least should be a pawn.
+		// Square (x,y) must be surroundable by two enemy pieces,
+		// and one of them at least should be a pawn (moving).
 		const dirs = [ [1,0],[0,1],[1,1],[-1,1] ];
+		const steps = VariantRules.steps[VariantRules.ROOK]
+			.concat(VariantRules.steps[VariantRules.BISHOP]);
 		const [sizeX,sizeY] = VariantRules.size;
 		for (let dir of dirs)
 		{
 			const [i1,j1] = [x-dir[0],y-dir[1]]; //"before"
 			const [i2,j2] = [x+dir[0],y+dir[1]]; //"after"
 			if (i1>=0 && i1<sizeX && i2>=0 && i2<sizeX
-				&& j1>=0 && j1<sizeY && j2>=0 && j2<sizeY
-				&& this.board[i1][j1]!=VariantRules.EMPTY
-				&& this.board[i2][j2]!=VariantRules.EMPTY
-				&& colors.includes(this.getColor(i1,j1))
-				&& colors.includes(this.getColor(i2,j2))
-				&& [this.getPiece(i1,j1),this.getPiece(i2,j2)].includes(VariantRules.PAWN))
+				&& j1>=0 && j1<sizeY && j2>=0 && j2<sizeY)
 			{
-				return true;
+				if ((this.board[i1][j1]!=VariantRules.EMPTY
+					&& colors.includes(this.getColor(i1,j1))
+					&& this.board[i2][j2]==VariantRules.EMPTY)
+						||
+					(this.board[i2][j2]!=VariantRules.EMPTY
+					&& colors.includes(this.getColor(i2,j2))
+					&& this.board[i1][j1]==VariantRules.EMPTY))
+				{
+					// Search a movable enemy pawn landing on the empty square
+					for (let step of steps)
+					{
+						let [ii,jj] = (this.board[i1][j1]==VariantRules.EMPTY ? [i1,j1] : [i2,j2]);
+						let [i3,j3] = [ii+step[0],jj+step[1]];
+						while (i3>=0 && i3<sizeX && j3>=0 && j3<sizeY
+							&& this.board[i3][j3]==VariantRules.EMPTY)
+						{
+							i3 += step[0];
+							j3 += step[1];
+						}
+						if (i3>=0 && i3<sizeX && j3>=0 && j3<sizeY
+							&& this.getPiece(i3,j3) == VariantRules.PAWN
+							&& !this.isImmobilized([i3,j3]))
+						{
+							return true;
+						}
+					}
+				}
 			}
 		}
 		return false;
 	}
 
-	// TODO: check if enemy's rook can reach capturing squares + !immobilized
 	isAttackedByRook([x,y], colors)
 	{
+		// King must be on same column or row,
+		// and a rook should be able to reach a capturing square
 		const [sizeX,sizeY] = VariantRules.size;
-		// King must be on same column and a rook on same row (or reverse)
-		if (x == this.kingPos[colors[0]][0]) //using colors[0], only element in this case
-		{
-			// Look for enemy rook on this column
-			for (let i=0; i<sizeY; i++)
-			{
-				if (this.board[x][i] != VariantRules.EMPTY
-					&& colors.includes(this.getColor(x,i))
-					&& this.getPiece(x,i) == VariantRules.ROOK)
-				{
-					return true;
-				}
-			}
-		}
-		else if (y == this.kingPos[colors[0]][1])
+		// colors contains only one element, giving the oppCol and thus king position
+		const sameRow = (x == this.kingPos[colors[0]][0]);
+		const sameColumn = (y == this.kingPos[colors[0]][1]);
+		if (sameRow || sameColumn)
 		{
-			// Look for enemy rook on this row
+			// Look for the enemy rook (maximum 1)
 			for (let i=0; i<sizeX; i++)
 			{
-				if (this.board[i][y] != VariantRules.EMPTY
-					&& colors.includes(this.getColor(i,y))
-					&& this.getPiece(i,y) == VariantRules.ROOK)
+				for (let j=0; j<sizeY; j++)
 				{
-					return true;
+					if (this.board[i][j] != VariantRules.EMPTY
+						&& this.getPiece(i,j) == VariantRules.ROOK)
+					{
+						if (this.isImmobilized([i,j]))
+							return false; //because only one rook
+						// Can it reach a capturing square?
+						// Easy but quite suboptimal way (TODO): generate all moves (turn is OK)
+						const moves = this.getPotentialMovesFrom([i,j]);
+						for (let move of moves)
+						{
+							if (sameRow && move.end.y == y || sameColumn && move.end.x == x)
+								return true;
+						}
+					}
 				}
 			}
 		}
-- 
2.44.0