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 // If piece not in usual list, bishop or knight appears.
124 getPotentialMovesFrom([x
, y
]) {
125 if (this.movesCount
<= 3) {
127 const color
= this.getColor(x
, y
);
128 const firstRank
= (color
== 'w' ? 7 : 0);
129 if (x
!= firstRank
|| V
.AUGMENTED_PIECES
.includes(this.board
[x
][y
][1]))
131 const piece
= this.getPiece(x
, y
);
132 const move = new Move({
134 new PiPo({ x: x
, y: y
, c: color
, p: this.getAugmented(piece
) })
137 new PiPo({ x: x
, y: y
, c: color
, p: piece
})
139 start: { x: x
, y: y
},
144 let moves
= super.getPotentialMovesFrom([x
, y
]);
145 const initialPiece
= this.getPiece(x
, y
);
146 const color
= this.turn
;
148 V
.AUGMENTED_PIECES
.includes(this.board
[x
][y
][1]) &&
149 ((color
== 'w' && x
== 7) || (color
== "b" && x
== 0))
151 const newPiece
= this.getExtraPiece(this.board
[x
][y
][1]);
153 m
.appear
[0].p
= initialPiece
;
165 if (m
.vanish
.length
<= 1) return;
166 const [vx
, vy
] = [m
.vanish
[1].x
, m
.vanish
[1].y
];
168 m
.appear
.length
>= 2 && //3 if the king was also augmented
169 m
.vanish
.length
== 2 &&
170 m
.vanish
[1].c
== color
&&
171 V
.AUGMENTED_PIECES
.includes(this.board
[vx
][vy
][1])
173 // Castle, rook is an "augmented piece"
174 m
.appear
[1].p
= V
.ROOK
;
177 p: this.getExtraPiece(this.board
[vx
][vy
][1]),
188 // Special case of move 1 = choose squares, knight first, then bishop
190 if (this.movesCount
>= 4) return null;
191 const color
= this.turn
;
192 const [x
, y
] = [square
[0], square
[1]];
193 if ((color
== 'w' && x
!= 7) || (color
== 'b' && x
!= 0)) return null;
194 const selectedPiece
= this.board
[x
][y
][1];
201 p: this.getAugmented(selectedPiece
)
212 start: { x: x
, y: y
},
218 if (this.movesCount
> 4) super.postPlay(move);
222 if (this.movesCount
>= 4) super.postUndo(move);
227 for (let i
= 0; i
< V
.size
.x
; i
++) {
228 for (let j
= 0; j
< V
.size
.y
; j
++) {
229 if (this.board
[i
][j
] != V
.EMPTY
) {
230 const sign
= this.getColor(i
, j
) == "w" ? 1 : -1;
231 const piece
= this.getPiece(i
, j
);
232 evaluation
+= sign
* V
.VALUES
[piece
];
233 const symbol
= this.board
[i
][j
][1];
234 if (V
.AUGMENTED_PIECES
.includes(symbol
)) {
235 const extraPiece
= this.getExtraPiece(symbol
);
236 evaluation
+= sign
* V
.VALUES
[extraPiece
]
246 move.appear
[0].x
!= move.vanish
[0].x
||
247 move.appear
[0].y
!= move.vanish
[0].y
250 V
.AUGMENTED_PIECES
.includes(move.vanish
[0].p
) ||
252 move.vanish
.length
>= 2 &&
253 V
.AUGMENTED_PIECES
.includes(move.vanish
[1].p
)
256 // Simplify move before calling super.getNotation()
257 let smove
= JSON
.parse(JSON
.stringify(move));
258 if (ChessRules
.PIECES
.includes(move.vanish
[0].p
)) {
259 // Castle with an augmented rook
261 smove
.vanish
[1].p
= smove
.appear
[1].p
;
264 // Moving an augmented piece
266 smove
.vanish
[0].p
= smove
.appear
[0].p
;
268 smove
.vanish
.length
== 2 &&
269 smove
.vanish
[0].c
== smove
.vanish
[1].c
&&
270 V
.AUGMENTED_PIECES
.includes(move.vanish
[1].p
)
272 // Castle with an augmented rook
274 smove
.vanish
[1].p
= smove
.appear
[1].p
;
277 return super.getNotation(smove
);
279 // Else, more common case:
280 return super.getNotation(move);
282 // First moves in game, placements:
283 const square
= V
.CoordsToSquare(move.appear
[0]);
285 (['a','j','m','s','u'].includes(move.appear
[0].p
) ? 'N' : 'B');
286 return '+' + reserve
+ '@' + square
;