18afe40268efffe4c38a9c018d4664cc0bbb4ab8
1 class UltimaRules
extends ChessRules
5 if (b
[1] == "m") //'m' for Immobilizer (I is too similar to 1)
7 return b
; //usual piece
12 this.kingPos
= {'w':[-1,-1], 'b':[-1,-1]};
13 const fenParts
= fen
.split(" ");
14 const position
= fenParts
[0].split("/");
15 for (let i
=0; i
<position
.length
; i
++)
18 for (let j
=0; j
<position
[i
].length
; j
++)
20 switch (position
[i
].charAt(j
))
23 this.kingPos
['b'] = [i
,k
];
26 this.kingPos
['w'] = [i
,k
];
29 let num
= parseInt(position
[i
].charAt(j
));
36 this.epSquares
= []; //no en-passant here
41 // TODO: for compatibility?
42 this.castleFlags
= {"w":[false,false], "b":[false,false]};
45 static get IMMOBILIZER() { return 'm'; }
46 // Although other pieces keep their names here for coding simplicity,
48 // - a "rook" is a coordinator, capturing by coordinating with the king
49 // - a "knight" is a long-leaper, capturing as in draughts
50 // - a "bishop" is a chameleon, capturing as its prey
51 // - a "queen" is a withdrawer, capturing by moving away from pieces
53 getPotentialMovesFrom([x
,y
])
55 // Pre-check: is thing on this square immobilized?
56 // In this case add potential suicide as a move "taking the immobilizer"
57 const piece
= this.getPiece(x
,y
);
58 const color
= this.getColor(x
,y
);
59 const oppCol
= this.getOppCol(color
);
60 const V
= VariantRules
;
61 const adjacentSteps
= V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]);
62 const [sizeX
,sizeY
] = V
.size
;
63 for (let step
of adjacentSteps
)
65 const [i
,j
] = [x
+step
[0],y
+step
[1]];
66 if (i
>=0 && i
<sizeX
&& j
>=0 && j
<sizeY
&& this.board
[i
][j
] != V
.EMPTY
67 && this.getColor(i
,j
) == oppCol
)
69 const oppPiece
= this.getPiece(i
,j
);
70 if (oppPiece
== V
.IMMOBILIZER
71 || (oppPiece
== V
.BISHOP
&& piece
== V
.IMMOBILIZER
))
75 vanish: [{x:x
,y:y
,p:piece
,c:color
}],
82 switch (this.getPiece(x
,y
))
84 case VariantRules
.IMMOBILIZER:
85 return this.getPotentialImmobilizerMoves([x
,y
]);
87 return super.getPotentialMovesFrom([x
,y
]);
91 getSlideNJumpMoves([x
,y
], steps
, oneStep
)
93 const color
= this.getColor(x
,y
);
94 const piece
= this.getPiece(x
,y
);
96 const [sizeX
,sizeY
] = VariantRules
.size
;
98 for (let step
of steps
)
102 while (i
>=0 && i
<sizeX
&& j
>=0 && j
<sizeY
103 && this.board
[i
][j
] == VariantRules
.EMPTY
)
105 moves
.push(this.getBasicMove([x
,y
], [i
,j
]));
106 if (oneStep
!== undefined)
111 // Only king can take on occupied square:
112 if (piece
==VariantRules
.KING
&& i
>=0 && i
<sizeX
&& j
>=0
113 && j
<sizeY
&& this.canTake([x
,y
], [i
,j
]))
115 moves
.push(this.getBasicMove([x
,y
], [i
,j
]));
122 getPotentialPawnMoves([x
,y
])
124 let moves
= super.getPotentialRookMoves([x
,y
]);
132 getPotentialRookMoves(sq
)
134 const color
= this.getColor(sq
);
135 const oppCol
= this.getOppCol(color
);
136 const kp
= this.kingPos
[color
];
137 let moves
= super.getPotentialQueenMoves(sq
);
139 // Check piece-king rectangle (if any) corners for enemy pieces
140 if (m
.end
.x
== kp
[0] || m
.end
.y
== kp
[1])
141 return; //"flat rectangle"
142 const corner1
= [Math
.max(m
.end
.x
,kp
[0]), Math
.min(m
.end
.y
,kp
[1])];
143 const corner2
= [Math
.min(m
.end
.x
,kp
[0]), Math
.max(m
.end
.y
,kp
[1])];
144 for (let [i
,j
] of [corner1
,corner2
])
146 if (this.board
[i
][j
] != VariantRules
.EMPTY
&& this.getColor(i
,j
) == oppCol
)
148 m
.vanish
.push( new PiPo({
151 p:this.getPiece(i
,j
),
161 getPotentialKnightMoves([x
,y
])
163 let moves
= super.getPotentialQueenMoves(sq
);
164 // Look in every direction for captures
165 const V
= VariantRules
;
166 const steps
= V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]);
167 const [sizeX
,sizeY
] = V
.size
;
168 const color
= this.getColor(x
,y
);
169 for (let step
of steps
)
171 let [i
,j
] = [x
+step
[0], y
+step
[1]];
172 while (i
>=0 && i
<sizeX
&& j
>=0 && j
<sizeY
&& this.board
[i
][j
]==V
.EMPTY
)
177 if (i
<0 && i
>=sizeX
|| j
<0 || j
>=sizeY
|| this.getColor(i
,j
)==color
)
179 // Found an enemy piece: potential capture (if empty space behind)
180 // So, while we find enemy pieces + space in this direction, add captures!
183 while ( ) //TODO: finish........
188 getPotentialBishopMoves(sq
)
190 return super.getPotentialQueenMoves(sq
);
191 // TODO: add captures of coordinators,pinchers,withdrawers... by re-using code
194 getPotentialQueenMoves([x
,y
])
196 let moves
= super.getPotentialQueenMoves(sq
);
197 const V
= VariantRules
;
198 const adjacentSteps
= V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]);
199 let capturingDirections
= [];
200 const color
= this.getColor(x
,y
);
201 const oppCol
= this.getOppCol(color
);
202 adjacentSteps
.forEach(step
=> {
203 const [i
,j
] = [x
+step
[0],y
+step
[1]];
204 if (this.board
[i
][j
] != V
.EMPTY
&& this.getColor(i
,j
) == oppCol
)
205 capturingDirections
.push(step
);
209 m
.end
.x
!=x
? (m
.end
.x
-x
)/Math
.abs(m
.end
.x
-x
) : 0,
210 m
.end
.y
!=y
? (m
.end
.y
-y
)/Math
.abs(m
.end
.y
-y
) : 0
212 // NOTE: includes() function does not work on complex array elements
213 // TODO: this test should be done only once per direction
214 if (capturingDirection
.some(dir
=> _
.isEqual(dir
, step
)))
216 const [i
,j
] = [x
-step
[0],y
-step
[1]];
217 m
.vanish
.push(new PiPo({
220 p:this.getPiece(i
,j
),
227 getPotentialImmobilizerMoves(sq
)
229 return super.getPotentialQueenMoves(sq
);
232 getPotentialKingMoves(sq
)
234 const V
= VariantRules
;
235 return this.getSlideNJumpMoves(sq
,
236 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), "oneStep");
239 // isAttacked() is OK because the immobilizer doesn't take
241 isAttackedByPawn([x
,y
], colors
)
243 // Square (x,y) must be surrounded by two enemy pieces,
244 // and one of them at least should be a pawn
248 isAttackedByRook(sq
, colors
)
250 // Enemy king must be on same file and a rook on same row (or reverse)
253 isAttackedByKnight(sq
, colors
)
255 // Square (x,y) must be on same line as a knight,
256 // and there must be empty square(s) behind.
259 isAttackedByBishop(sq
, colors
)
261 // switch on piece nature on square sq: a chameleon attack as this piece
262 // ==> call the appropriate isAttackedBy... (exception of immobilizers)
263 // Other exception: a chameleon cannot attack a chameleon (seemingly...)
266 isAttackedByQueen(sq
, colors
)
268 // Square (x,y) must be adjacent to a queen, and the queen must have
269 // some free space in the opposite direction from (x,y)
272 updateVariables(move)
274 // Just update king position
275 const piece
= this.getPiece(move.start
.x
,move.start
.y
);
276 const c
= this.getColor(move.start
.x
,move.start
.y
);
277 if (piece
== VariantRules
.KING
&& move.appear
.length
> 0)
279 this.kingPos
[c
][0] = move.appear
[0].x
;
280 this.kingPos
[c
][1] = move.appear
[0].y
;
284 static get VALUES() { //TODO: totally experimental!
296 static get SEARCH_DEPTH() { return 2; } //TODO?
298 static GenRandInitFen()
300 let pieces
= { "w": new Array(8), "b": new Array(8) };
301 // Shuffle pieces on first and last rank
302 for (let c
of ["w","b"])
304 let positions
= _
.range(8);
305 // Get random squares for every piece, totally freely
307 let randIndex
= _
.random(7);
308 const bishop1Pos
= positions
[randIndex
];
309 positions
.splice(randIndex
, 1);
311 randIndex
= _
.random(6);
312 const bishop2Pos
= positions
[randIndex
];
313 positions
.splice(randIndex
, 1);
315 randIndex
= _
.random(5);
316 const knight1Pos
= positions
[randIndex
];
317 positions
.splice(randIndex
, 1);
319 randIndex
= _
.random(4);
320 const knight2Pos
= positions
[randIndex
];
321 positions
.splice(randIndex
, 1);
323 randIndex
= _
.random(3);
324 const queenPos
= positions
[randIndex
];
325 positions
.splice(randIndex
, 1);
327 randIndex
= _
.random(2);
328 const kingPos
= positions
[randIndex
];
329 positions
.splice(randIndex
, 1);
331 randIndex
= _
.random(1);
332 const rookPos
= positions
[randIndex
];
333 positions
.splice(randIndex
, 1);
334 const immobilizerPos
= positions
[0];
336 pieces
[c
][bishop1Pos
] = 'b';
337 pieces
[c
][bishop2Pos
] = 'b';
338 pieces
[c
][knight1Pos
] = 'n';
339 pieces
[c
][knight2Pos
] = 'n';
340 pieces
[c
][queenPos
] = 'q';
341 pieces
[c
][kingPos
] = 'k';
342 pieces
[c
][rookPos
] = 'r';
343 pieces
[c
][immobilizerPos
] = 'm';
345 return pieces
["b"].join("") +
346 "/pppppppp/8/8/8/8/PPPPPPPP/" +
347 pieces
["w"].join("").toUpperCase() +
348 " 0000"; //TODO: flags?!
353 return "0000"; //TODO: or "-" ?