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 switch (this.getPiece(x
,y
))
57 case VariantRules
.IMMOBILIZER:
58 return this.getPotentialImmobilizerMoves([x
,y
]);
60 return super.getPotentialMovesFrom([x
,y
]);
62 // TODO: add potential suicides as a move "taking the immobilizer"
63 // TODO: add long-leaper captures
64 // TODO: mark matching coordinator/withdrawer/chameleon moves as captures
65 // (will be a bit tedious for chameleons)
66 // --> filter directly in functions below
69 getSlideNJumpMoves([x
,y
], steps
, oneStep
)
71 const color
= this.getColor(x
,y
);
72 const piece
= this.getPiece(x
,y
);
74 const [sizeX
,sizeY
] = VariantRules
.size
;
76 for (let step
of steps
)
80 while (i
>=0 && i
<sizeX
&& j
>=0 && j
<sizeY
81 && this.board
[i
][j
] == VariantRules
.EMPTY
)
83 moves
.push(this.getBasicMove([x
,y
], [i
,j
]));
84 if (oneStep
!== undefined)
89 // Only king can take on occupied square:
90 if (piece
==VariantRules
.KING
&& i
>=0 && i
<sizeX
&& j
>=0
91 && j
<sizeY
&& this.canTake([x
,y
], [i
,j
]))
93 moves
.push(this.getBasicMove([x
,y
], [i
,j
]));
99 getPotentialPawnMoves([x
,y
])
101 return super.getPotentialRookMoves([x
,y
]);
104 getPotentialRookMoves(sq
)
106 return super.getPotentialQueenMoves(sq
);
109 getPotentialKnightMoves(sq
)
111 return super.getPotentialQueenMoves(sq
);
114 getPotentialBishopMoves(sq
)
116 return super.getPotentialQueenMoves(sq
);
119 getPotentialQueenMoves(sq
)
121 return super.getPotentialQueenMoves(sq
);
124 getPotentialKingMoves(sq
)
126 const V
= VariantRules
;
127 return this.getSlideNJumpMoves(sq
,
128 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), "oneStep");
131 // isAttacked() is OK because the immobilizer doesn't take
133 isAttackedByPawn([x
,y
], colors
)
135 // Square (x,y) must be surrounded by two enemy pieces,
136 // and one of them at least should be a pawn
140 isAttackedByRook(sq
, colors
)
142 // Enemy king must be on same file and a rook on same row (or reverse)
145 isAttackedByKnight(sq
, colors
)
147 // Square (x,y) must be on same line as a knight,
148 // and there must be empty square(s) behind.
151 isAttackedByBishop(sq
, colors
)
153 // switch on piece nature on square sq: a chameleon attack as this piece
154 // ==> call the appropriate isAttackedBy... (exception of immobilizers)
155 // Other exception: a chameleon cannot attack a chameleon (seemingly...)
158 isAttackedByQueen(sq
, colors
)
160 // Square (x,y) must be adjacent to a queen, and the queen must have
161 // some free space in the opposite direction from (x,y)
164 updateVariables(move)
166 // Just update king position
167 const piece
= this.getPiece(move.start
.x
,move.start
.y
);
168 const c
= this.getColor(move.start
.x
,move.start
.y
);
169 if (piece
== VariantRules
.KING
&& move.appear
.length
> 0)
171 this.kingPos
[c
][0] = move.appear
[0].x
;
172 this.kingPos
[c
][1] = move.appear
[0].y
;
176 static get VALUES() { //TODO: totally experimental!
188 static get SEARCH_DEPTH() { return 2; } //TODO?
190 static GenRandInitFen()
192 let pieces
= { "w": new Array(8), "b": new Array(8) };
193 // Shuffle pieces on first and last rank
194 for (let c
of ["w","b"])
196 let positions
= _
.range(8);
197 // Get random squares for every piece, totally freely
199 let randIndex
= _
.random(7);
200 const bishop1Pos
= positions
[randIndex
];
201 positions
.splice(randIndex
, 1);
203 randIndex
= _
.random(6);
204 const bishop2Pos
= positions
[randIndex
];
205 positions
.splice(randIndex
, 1);
207 randIndex
= _
.random(5);
208 const knight1Pos
= positions
[randIndex
];
209 positions
.splice(randIndex
, 1);
211 randIndex
= _
.random(4);
212 const knight2Pos
= positions
[randIndex
];
213 positions
.splice(randIndex
, 1);
215 randIndex
= _
.random(3);
216 const queenPos
= positions
[randIndex
];
217 positions
.splice(randIndex
, 1);
219 randIndex
= _
.random(2);
220 const kingPos
= positions
[randIndex
];
221 positions
.splice(randIndex
, 1);
223 randIndex
= _
.random(1);
224 const rookPos
= positions
[randIndex
];
225 positions
.splice(randIndex
, 1);
226 const immobilizerPos
= positions
[2];
228 pieces
[c
][bishop1Pos
] = 'b';
229 pieces
[c
][bishop2Pos
] = 'b';
230 pieces
[c
][knight1Pos
] = 'n';
231 pieces
[c
][knight2Pos
] = 'n';
232 pieces
[c
][queenPos
] = 'q';
233 pieces
[c
][kingPos
] = 'k';
234 pieces
[c
][rookPos
] = 'r';
235 pieces
[c
][immobilizerPos
] = 'm';
237 return pieces
["b"].join("") +
238 "/pppppppp/8/8/8/8/PPPPPPPP/" +
239 pieces
["w"].join("").toUpperCase() +
240 " 0000"; //TODO: flags?!
245 return "0000"; //TODO: or "-" ?