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];
163 p: this.getAugmented(selectedPiece
)
174 start: { x: x
, y: y
},
179 // If piece not in usual list, bishop or knight appears.
180 getPotentialMovesFrom([x
, y
]) {
181 if (this.movesCount
<= 3) {
183 const move = this.doClick([x
, y
]);
184 return (!move ? [] : [move]);
186 let moves
= super.getPotentialMovesFrom([x
, y
]);
187 const initialPiece
= this.getPiece(x
, y
);
188 const color
= this.turn
;
190 ((color
== 'w' && x
== 7) || (color
== "b" && x
== 0)) &&
191 V
.AUGMENTED_PIECES
.includes(this.board
[x
][y
][1])
193 const newPiece
= this.getExtraPiece(this.board
[x
][y
][1]);
195 m
.appear
[0].p
= initialPiece
;
206 if (m
.vanish
.length
<= 1) return;
207 const [vx
, vy
] = [m
.vanish
[1].x
, m
.vanish
[1].y
];
209 m
.appear
.length
>= 2 && //3 if the king was also augmented
210 m
.vanish
.length
== 2 &&
211 m
.vanish
[1].c
== color
&&
212 V
.AUGMENTED_PIECES
.includes(this.board
[vx
][vy
][1])
214 // Castle, rook is an "augmented piece"
215 m
.appear
[1].p
= V
.ROOK
;
218 p: this.getExtraPiece(this.board
[vx
][vy
][1]),
231 if (this.movesCount
> 4) {
232 let piece
= move.vanish
[0].p
;
233 if (['j', 'l'].includes(piece
)) piece
= V
.KING
;
235 this.kingPos
[move.appear
[0].c
] = [move.appear
[0].x
, move.appear
[0].y
];
236 this.updateCastleFlags(move, piece
);
241 if (this.movesCount
>= 4) {
242 if (['j', 'k', 'l'].includes(this.getPiece(move.start
.x
, move.start
.y
)))
243 this.kingPos
[move.vanish
[0].c
] = [move.start
.x
, move.start
.y
];
249 for (let i
= 0; i
< V
.size
.x
; i
++) {
250 for (let j
= 0; j
< V
.size
.y
; j
++) {
251 if (this.board
[i
][j
] != V
.EMPTY
) {
252 const sign
= this.getColor(i
, j
) == "w" ? 1 : -1;
253 const piece
= this.getPiece(i
, j
);
254 evaluation
+= sign
* V
.VALUES
[piece
];
255 const symbol
= this.board
[i
][j
][1];
256 if (V
.AUGMENTED_PIECES
.includes(symbol
)) {
257 const extraPiece
= this.getExtraPiece(symbol
);
258 evaluation
+= sign
* V
.VALUES
[extraPiece
]
268 move.appear
[0].x
!= move.vanish
[0].x
||
269 move.appear
[0].y
!= move.vanish
[0].y
272 V
.AUGMENTED_PIECES
.includes(move.vanish
[0].p
) ||
274 move.appear
.length
>= 2 &&
275 move.vanish
.length
>= 2 &&
276 V
.AUGMENTED_PIECES
.includes(move.vanish
[1].p
)
279 // Simplify move before calling super.getNotation()
280 let smove
= JSON
.parse(JSON
.stringify(move));
281 if (ChessRules
.PIECES
.includes(move.vanish
[0].p
)) {
282 // Castle with an augmented rook
284 smove
.vanish
[1].p
= smove
.appear
[1].p
;
287 // Moving an augmented piece
289 smove
.vanish
[0].p
= smove
.appear
[0].p
;
291 smove
.vanish
.length
== 2 &&
292 smove
.vanish
[0].c
== smove
.vanish
[1].c
&&
293 V
.AUGMENTED_PIECES
.includes(move.vanish
[1].p
)
295 // Castle with an augmented rook
297 smove
.vanish
[1].p
= smove
.appear
[1].p
;
300 return super.getNotation(smove
);
302 // Else, more common case:
303 return super.getNotation(move);
305 // First moves in game, placements:
306 const square
= V
.CoordsToSquare(move.appear
[0]);
308 (['a','j','m','s','u'].includes(move.appear
[0].p
) ? 'N' : 'B');
309 return '+' + reserve
+ '@' + square
;