From: Benjamin Auder <benjamin.auder@somewhere>
Date: Wed, 12 Dec 2018 11:43:13 +0000 (+0100)
Subject: Advance on Ultima variant code
X-Git-Url: https://git.auder.net/variants/current/css/img/pieces/doc/common.css?a=commitdiff_plain;h=7688bf7781d10bdf7db2ff558a35852bebcaae53;p=vchess.git

Advance on Ultima variant code
---

diff --git a/public/javascripts/variants/Ultima.js b/public/javascripts/variants/Ultima.js
index 4612da10..18afe402 100644
--- a/public/javascripts/variants/Ultima.js
+++ b/public/javascripts/variants/Ultima.js
@@ -52,7 +52,33 @@ class UltimaRules extends ChessRules
 
 	getPotentialMovesFrom([x,y])
 	{
-		// TODO: pre-check: is thing on this square immobilized? If yes, return []
+		// Pre-check: is thing on this square immobilized?
+		// In this case add potential suicide as a move "taking the immobilizer"
+		const piece = this.getPiece(x,y);
+		const color = this.getColor(x,y);
+		const oppCol = this.getOppCol(color);
+		const V = VariantRules;
+		const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
+		const [sizeX,sizeY] = V.size;
+		for (let step of adjacentSteps)
+		{
+			const [i,j] = [x+step[0],y+step[1]];
+			if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] != V.EMPTY
+				&& this.getColor(i,j) == oppCol)
+			{
+				const oppPiece = this.getPiece(i,j);
+				if (oppPiece == V.IMMOBILIZER
+					|| (oppPiece == V.BISHOP && piece == V.IMMOBILIZER))
+				{
+					return [ new Move({
+						appear: [],
+						vanish: [{x:x,y:y,p:piece,c:color}],
+						start: {x:x,y:y},
+						end: {x:i,y:j}
+					}) ];
+				}
+			}
+		}
 		switch (this.getPiece(x,y))
 		{
 			case VariantRules.IMMOBILIZER:
@@ -60,11 +86,6 @@ class UltimaRules extends ChessRules
 			default:
 				return super.getPotentialMovesFrom([x,y]);
 		}
-		// TODO: add potential suicides as a move "taking the immobilizer"
-		// TODO: add long-leaper captures
-		// TODO: mark matching coordinator/withdrawer/chameleon moves as captures
-		// (will be a bit tedious for chameleons)
-		// --> filter directly in functions below
 	}
 
 	getSlideNJumpMoves([x,y], steps, oneStep)
@@ -97,29 +118,110 @@ class UltimaRules extends ChessRules
 		return moves;
 	}
 
+	// "Pincher"
 	getPotentialPawnMoves([x,y])
 	{
-		return super.getPotentialRookMoves([x,y]);
+		let moves = super.getPotentialRookMoves([x,y]);
+		// Add captures
+		moves.forEach(m => {
+			if (m
+		});
 	}
 
+	// Coordinator
 	getPotentialRookMoves(sq)
 	{
-		return super.getPotentialQueenMoves(sq);
+		const color = this.getColor(sq);
+		const oppCol = this.getOppCol(color);
+		const kp = this.kingPos[color];
+		let moves = super.getPotentialQueenMoves(sq);
+		moves.forEach(m => {
+			// Check piece-king rectangle (if any) corners for enemy pieces
+			if (m.end.x == kp[0] || m.end.y == kp[1])
+				return; //"flat rectangle"
+			const corner1 = [Math.max(m.end.x,kp[0]), Math.min(m.end.y,kp[1])];
+			const corner2 = [Math.min(m.end.x,kp[0]), Math.max(m.end.y,kp[1])];
+			for (let [i,j] of [corner1,corner2])
+			{
+				if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) == oppCol)
+				{
+					m.vanish.push( new PiPo({
+						x:i,
+						y:j,
+						p:this.getPiece(i,j),
+						c:oppCol
+					}) );
+				}
+			}
+		});
+		return moves;
 	}
 
-	getPotentialKnightMoves(sq)
+	// Long-leaper
+	getPotentialKnightMoves([x,y])
 	{
-		return super.getPotentialQueenMoves(sq);
+		let moves = super.getPotentialQueenMoves(sq);
+		// Look in every direction for captures
+		const V = VariantRules;
+		const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
+		const [sizeX,sizeY] = V.size;
+		const color = this.getColor(x,y);
+		for (let step of steps)
+		{
+			let [i,j] = [x+step[0], y+step[1]];
+			while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j]==V.EMPTY)
+			{
+				i += step[0];
+				j += step[1];
+			}
+			if (i<0 && i>=sizeX || j<0 || j>=sizeY || this.getColor(i,j)==color)
+				continue;
+			// Found an enemy piece: potential capture (if empty space behind)
+			// So, while we find enemy pieces + space in this direction, add captures!
+			i += step[0];
+			j += step[1];
+			while ( ) //TODO: finish........
+		}
+		return moves;
 	}
 
 	getPotentialBishopMoves(sq)
 	{
 		return super.getPotentialQueenMoves(sq);
+		// TODO: add captures of coordinators,pinchers,withdrawers... by re-using code
 	}
 
-	getPotentialQueenMoves(sq)
+	getPotentialQueenMoves([x,y])
 	{
-		return super.getPotentialQueenMoves(sq);
+		let moves = super.getPotentialQueenMoves(sq);
+		const V = VariantRules;
+		const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
+		let capturingDirections = [];
+		const color = this.getColor(x,y);
+		const oppCol = this.getOppCol(color);
+		adjacentSteps.forEach(step => {
+			const [i,j] = [x+step[0],y+step[1]];
+			if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol)
+				capturingDirections.push(step);
+		});
+		moves.forEach(m => {
+			const step = [
+				m.end.x!=x ? (m.end.x-x)/Math.abs(m.end.x-x) : 0,
+				m.end.y!=y ? (m.end.y-y)/Math.abs(m.end.y-y) : 0
+			];
+			// NOTE: includes() function does not work on complex array elements
+			// TODO: this test should be done only once per direction
+			if (capturingDirection.some(dir => _.isEqual(dir, step)))
+			{
+				const [i,j] = [x-step[0],y-step[1]];
+				m.vanish.push(new PiPo({
+					x:i,
+					y:j,
+					p:this.getPiece(i,j),
+					c:oppCol
+				}));
+			}
+		});
 	}
 
 	getPotentialImmobilizerMoves(sq)