1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
3 export class TitanRules
extends ChessRules
{
5 static get IMAGE_EXTENSION() {
6 // Temporarily, for the time SVG pieces are being designed:
10 // Decode if normal piece, or + bishop or knight
12 const piece
= this.board
[x
][y
].charAt(1);
13 if (ChessRules
.PIECES
.includes(piece
)) return piece
;
34 // Code: a/c = bishop + knight/bishop j/l for king,
35 // m/o for knight, s/t for queen, u/v for rook
36 static get AUGMENTED_PIECES() {
55 // Decode above notation into additional piece
56 getExtraPiece(symbol
) {
57 if (['a','j','m','s','u'].includes(symbol
))
62 // Inverse operation: augment piece
64 const knight
= this.movesCount
<= 1;
66 case V
.ROOK: return (knight
? 'u' : 'v');
67 case V
.KNIGHT: return (knight
? 'm' : 'o');
68 case V
.BISHOP: return (knight
? 'a' : 'c');
69 case V
.QUEEN: return (knight
? 's' : 't');
70 case V
.KING: return (knight
? 'j' : 'l');
72 return '_'; //never reached
75 static IsGoodPosition(position
) {
76 if (position
.length
== 0) return false;
77 const rows
= position
.split("/");
78 if (rows
.length
!= V
.size
.x
) return false;
79 let kings
= { "w": 0, "b": 0 };
80 const allPiecesCodes
= V
.PIECES
.concat(V
.AUGMENTED_PIECES
);
81 const kingBlackCodes
= ['j','k','l'];
82 const kingWhiteCodes
= ['J','K','L'];
83 for (let row
of rows
) {
85 for (let i
= 0; i
< row
.length
; i
++) {
86 if (kingBlackCodes
.includes(row
[i
])) kings
['b']++;
87 else if (kingWhiteCodes
.includes(row
[i
])) kings
['w']++;
88 if (allPiecesCodes
.includes(row
[i
].toLowerCase())) sumElts
++;
90 const num
= parseInt(row
[i
], 10);
91 if (isNaN(num
)) return false;
95 if (sumElts
!= V
.size
.y
) return false;
97 // Both kings should be on board, only one of each color:
98 if (Object
.values(kings
).some(v
=> v
!= 1)) return false;
102 // Kings may be augmented:
104 this.kingPos
= { w: [-1, -1], b: [-1, -1] };
105 const rows
= V
.ParseFen(fen
).position
.split("/");
106 for (let i
= 0; i
< rows
.length
; i
++) {
107 let k
= 0; //column index on board
108 for (let j
= 0; j
< rows
[i
].length
; j
++) {
109 const piece
= rows
[i
].charAt(j
);
110 if (['j','k','l'].includes(piece
.toLowerCase())) {
111 const color
= (piece
.charCodeAt(0) <= 90 ? 'w' : 'b');
112 this.kingPos
[color
] = [i
, k
];
115 const num
= parseInt(rows
[i
].charAt(j
), 10);
116 if (!isNaN(num
)) k
+= num
- 1;
123 canIplay(side
, [x
, y
]) {
124 if (this.movesCount
>= 4) return super.canIplay(side
, [x
, y
]);
128 (side
== 'w' && x
== 7) ||
129 (side
== 'b' && x
== 0)
134 hoverHighlight([x
, y
]) {
137 this.movesCount
<= 3 &&
138 ((c
== 'w' && x
== 7) || (c
== 'b' && x
== 0))
144 this.movesCount
<= 3 ||
145 // TODO: next line theoretically shouldn't be required...
146 (this.movesCount
== 4 && this.getColor(x
, y
) != this.turn
)
150 // Special case of move 1 = choose squares, knight first, then bishop
152 if (this.movesCount
>= 4) return null;
153 const color
= this.turn
;
154 const [x
, y
] = [square
[0], square
[1]];
155 if ((color
== 'w' && x
!= 7) || (color
== 'b' && x
!= 0)) return null;
156 const selectedPiece
= this.board
[x
][y
][1];
157 // Prevent re-augmenting a chosen piece:
158 if (!ChessRules
.PIECES
.includes(selectedPiece
)) return null;
165 p: this.getAugmented(selectedPiece
)
176 start: { x: x
, y: y
},
181 // If piece not in usual list, bishop or knight appears.
182 getPotentialMovesFrom([x
, y
]) {
183 if (this.movesCount
<= 3) {
185 const move = this.doClick([x
, y
]);
186 return (!move ? [] : [move]);
188 let moves
= super.getPotentialMovesFrom([x
, y
]);
189 const initialPiece
= this.getPiece(x
, y
);
190 const color
= this.turn
;
192 ((color
== 'w' && x
== 7) || (color
== "b" && x
== 0)) &&
193 V
.AUGMENTED_PIECES
.includes(this.board
[x
][y
][1])
195 const newPiece
= this.getExtraPiece(this.board
[x
][y
][1]);
197 m
.appear
[0].p
= initialPiece
;
208 if (m
.vanish
.length
<= 1) return;
209 const [vx
, vy
] = [m
.vanish
[1].x
, m
.vanish
[1].y
];
211 m
.appear
.length
>= 2 && //3 if the king was also augmented
212 m
.vanish
.length
== 2 &&
213 m
.vanish
[1].c
== color
&&
214 V
.AUGMENTED_PIECES
.includes(this.board
[vx
][vy
][1])
216 // Castle, rook is an "augmented piece"
217 m
.appear
[1].p
= V
.ROOK
;
220 p: this.getExtraPiece(this.board
[vx
][vy
][1]),
233 if (this.movesCount
> 4) {
234 let piece
= move.vanish
[0].p
;
235 if (['j', 'l'].includes(piece
)) piece
= V
.KING
;
237 this.kingPos
[move.appear
[0].c
] = [move.appear
[0].x
, move.appear
[0].y
];
238 this.updateCastleFlags(move, piece
);
243 if (this.movesCount
>= 4) {
244 if (['j', 'k', 'l'].includes(this.getPiece(move.start
.x
, move.start
.y
)))
245 this.kingPos
[move.vanish
[0].c
] = [move.start
.x
, move.start
.y
];
251 for (let i
= 0; i
< V
.size
.x
; i
++) {
252 for (let j
= 0; j
< V
.size
.y
; j
++) {
253 if (this.board
[i
][j
] != V
.EMPTY
) {
254 const sign
= this.getColor(i
, j
) == "w" ? 1 : -1;
255 const piece
= this.getPiece(i
, j
);
256 evaluation
+= sign
* V
.VALUES
[piece
];
257 const symbol
= this.board
[i
][j
][1];
258 if (V
.AUGMENTED_PIECES
.includes(symbol
)) {
259 const extraPiece
= this.getExtraPiece(symbol
);
260 evaluation
+= sign
* V
.VALUES
[extraPiece
]
270 move.appear
[0].x
!= move.vanish
[0].x
||
271 move.appear
[0].y
!= move.vanish
[0].y
274 V
.AUGMENTED_PIECES
.includes(move.vanish
[0].p
) ||
276 move.appear
.length
>= 2 &&
277 move.vanish
.length
>= 2 &&
278 V
.AUGMENTED_PIECES
.includes(move.vanish
[1].p
)
281 // Simplify move before calling super.getNotation()
282 let smove
= JSON
.parse(JSON
.stringify(move));
283 if (ChessRules
.PIECES
.includes(move.vanish
[0].p
)) {
284 // Castle with an augmented rook
286 smove
.vanish
[1].p
= smove
.appear
[1].p
;
289 // Moving an augmented piece
291 smove
.vanish
[0].p
= smove
.appear
[0].p
;
293 smove
.vanish
.length
== 2 &&
294 smove
.vanish
[0].c
== smove
.vanish
[1].c
&&
295 V
.AUGMENTED_PIECES
.includes(move.vanish
[1].p
)
297 // Castle with an augmented rook
299 smove
.vanish
[1].p
= smove
.appear
[1].p
;
302 return super.getNotation(smove
);
304 // Else, more common case:
305 return super.getNotation(move);
307 // First moves in game, placements:
308 const square
= V
.CoordsToSquare(move.appear
[0]);
310 (['a','j','m','s','u'].includes(move.appear
[0].p
) ? 'N' : 'B');
311 return '+' + reserve
+ '@' + square
;