Typo in Minishogi
[vchess.git] / client / src / variants / Absorption.js
1 import { ChessRules } from "@/base_rules";
2
3 export class AbsorptionRules extends ChessRules {
4
5 getPpath(b) {
6 if ([V.BN, V.RN, V.QN].includes(b[1])) return "Absorption/" + b;
7 return b;
8 }
9
10 // Three new pieces: rook+knight, bishop+knight and queen+knight
11 static get RN() {
12 // Empress
13 return 'e';
14 }
15 static get BN() {
16 // Princess
17 return 's';
18 }
19 static get QN() {
20 // Amazon
21 return 'a';
22 }
23
24 static get PIECES() {
25 return ChessRules.PIECES.concat([V.RN, V.BN, V.QN]);
26 }
27
28 static get MergeComposed() {
29 return {
30 "be": "a",
31 "bs": "s",
32 "er": "e",
33 "rs": "a",
34 "eq": "a",
35 "qs": "a",
36 "ee": "e",
37 "es": "a",
38 "ss": "s"
39 };
40 }
41
42 static Fusion(p1, p2) {
43 if (p1 == V.KING) return p1;
44 if (p1 == V.PAWN) return p2;
45 if (p2 == V.PAWN) return p1;
46 if ([p1, p2].includes(V.KNIGHT)) {
47 if ([p1, p2].includes(V.QUEEN)) return V.QN;
48 if ([p1, p2].includes(V.ROOK)) return V.RN;
49 if ([p1, p2].includes(V.BISHOP)) return V.BN;
50 // p1 or p2 already have knight + other piece
51 return (p1 == V.KNIGHT ? p2 : p1);
52 }
53 if ([p1, p2].includes(V.QN)) return V.QN;
54 for (let p of [p1, p2]) {
55 if ([V.BN, V.RN].includes(p))
56 return V.MergeComposed[[p1, p2].sort().join("")];
57 }
58 // bishop + rook, or queen + [bishop or rook]
59 return V.QUEEN;
60 }
61
62 getPotentialMovesFrom(sq) {
63 let moves = [];
64 const piece = this.getPiece(sq[0], sq[1]);
65 switch (piece) {
66 case V.RN:
67 moves =
68 super.getPotentialRookMoves(sq).concat(
69 super.getPotentialKnightMoves(sq));
70 break;
71 case V.BN:
72 moves =
73 super.getPotentialBishopMoves(sq).concat(
74 super.getPotentialKnightMoves(sq));
75 break;
76 case V.QN:
77 moves =
78 super.getPotentialQueenMoves(sq).concat(
79 super.getPotentialKnightMoves(sq));
80 break;
81 default:
82 moves = super.getPotentialMovesFrom(sq);
83 }
84 // Filter out capturing promotions (except one),
85 // because they are all the same.
86 moves = moves.filter(m => {
87 return (
88 m.vanish.length == 1 ||
89 m.vanish[0].p != V.PAWN ||
90 [V.PAWN, V.QUEEN].includes(m.appear[0].p)
91 );
92 });
93 moves.forEach(m => {
94 if (
95 m.vanish.length == 2 &&
96 m.appear.length == 1 &&
97 piece != m.vanish[1].p
98 ) {
99 // Augment pieces abilities in case of captures
100 m.appear[0].p = V.Fusion(piece, m.vanish[1].p);
101 }
102 });
103 return moves;
104 }
105
106 isAttacked(sq, color) {
107 return (
108 super.isAttacked(sq, color) ||
109 this.isAttackedByBN(sq, color) ||
110 this.isAttackedByRN(sq, color) ||
111 this.isAttackedByQN(sq, color)
112 );
113 }
114
115 isAttackedByBN(sq, color) {
116 return (
117 this.isAttackedBySlideNJump(sq, color, V.BN, V.steps[V.BISHOP]) ||
118 this.isAttackedBySlideNJump(
119 sq, color, V.BN, V.steps[V.KNIGHT], 1)
120 );
121 }
122
123 isAttackedByRN(sq, color) {
124 return (
125 this.isAttackedBySlideNJump(sq, color, V.RN, V.steps[V.ROOK]) ||
126 this.isAttackedBySlideNJump(
127 sq, color, V.RN, V.steps[V.KNIGHT], 1)
128 );
129 }
130
131 isAttackedByQN(sq, color) {
132 return (
133 this.isAttackedBySlideNJump(
134 sq, color, V.QN, V.steps[V.BISHOP].concat(V.steps[V.ROOK])) ||
135 this.isAttackedBySlideNJump(
136 sq, color, V.QN, V.steps[V.KNIGHT], 1)
137 );
138 }
139
140 static get VALUES() {
141 return Object.assign(
142 { a: 12, e: 7, s: 5 },
143 ChessRules.VALUES
144 );
145 }
146
147 getNotation(move) {
148 let notation = super.getNotation(move);
149 if (move.vanish[0].p != V.PAWN && move.appear[0].p != move.vanish[0].p)
150 // Fusion (not from a pawn: handled in ChessRules)
151 notation += "=" + move.appear[0].p.toUpperCase();
152 return notation;
153 }
154
155 };