Cleaner fen generation + first draft of Apocalypse + a few fixes
[xogo.git] / variants / Alapo / class.js
1 import ChessRules from "/base_rules.js";
2 import {ArrayFun} from "/utils/array.js";
3 import {Random} from "/utils/alea.js";
4
5 export default class AlapoRules extends ChessRules {
6
7 static get Options() {
8 return {
9 select: C.Options.select,
10 styles: C.Options.styles.filter(s => s != "teleport")
11 };
12 }
13
14 get hasFlags() {
15 return false;
16 }
17 get hasEnpassant() {
18 return false;
19 }
20
21 getSvgChessboard() {
22 let board = super.getSvgChessboard().slice(0, -6);
23 // Add lines to delimitate goals
24 board += `
25 <line x1="0" y1="10" x2="60" y2="10" stroke="black" stroke-width="0.1"/>
26 <line x1="0" y1="50" x2="60" y2="50" stroke="black" stroke-width="0.1"/>
27 </svg>`;
28 return board;
29 }
30
31 genRandInitBaseFen() {
32 let fen = "";
33 if (this.options["randomness"] == 0)
34 fen = "rbqqbr/tcssct/6/6/TCSSCT/RBQQBR w 0";
35 else {
36 const piece2pawn = {
37 r: 't',
38 q: 's',
39 b: 'c'
40 };
41 let pieces = { w: new Array(6), b: new Array(6) };
42 // Shuffle pieces on first (and last rank if randomness == 2)
43 for (let c of ["w", "b"]) {
44 if (c == 'b' && this.options["randomness"] == 1) {
45 pieces['b'] = pieces['w'];
46 break;
47 }
48 let positions = ArrayFun.range(6);
49 // Get random squares for bishops
50 let randIndex = 2 * Random.randInt(3);
51 const bishop1Pos = positions[randIndex];
52 let randIndex_tmp = 2 * Random.randInt(3) + 1;
53 const bishop2Pos = positions[randIndex_tmp];
54 positions.splice(Math.max(randIndex, randIndex_tmp), 1);
55 positions.splice(Math.min(randIndex, randIndex_tmp), 1);
56 // Get random square for queens
57 randIndex = Random.randInt(4);
58 const queen1Pos = positions[randIndex];
59 positions.splice(randIndex, 1);
60 randIndex = Random.randInt(3);
61 const queen2Pos = positions[randIndex];
62 positions.splice(randIndex, 1);
63 // Rooks positions are now fixed,
64 const rook1Pos = positions[0];
65 const rook2Pos = positions[1];
66 pieces[c][rook1Pos] = "r";
67 pieces[c][bishop1Pos] = "b";
68 pieces[c][queen1Pos] = "q";
69 pieces[c][queen2Pos] = "q";
70 pieces[c][bishop2Pos] = "b";
71 pieces[c][rook2Pos] = "r";
72 }
73 fen = (
74 pieces["b"].join("") + "/" +
75 pieces["b"].map(p => piece2pawn[p]).join("") +
76 "/6/6/" +
77 pieces["w"].map(p => piece2pawn[p].toUpperCase()).join("") + "/" +
78 pieces["w"].join("").toUpperCase() +
79 " w 0"
80 );
81 }
82 return { fen: fen, o: {} };
83 }
84
85 // Triangles are rotated from opponent viewpoint (=> suffix "_inv")
86 pieces(color, x, y) {
87 const allSpecs = super.pieces(color, x, y);
88 return {
89 'r': allSpecs['r'],
90 'q': allSpecs['q'],
91 'b': Object.assign({}, allSpecs['b'],
92 {"class": "bishop" + (this.playerColor != color ? "_inv" : "")}),
93 's': { //"square"
94 "class": "babyrook",
95 moves: [
96 {
97 steps: [[0, 1], [0, -1], [1, 0], [-1, 0]],
98 range: 1
99 }
100 ]
101 },
102 'c': { //"circle"
103 "class": "babyqueen",
104 moves: [
105 {
106 steps: [
107 [0, 1], [0, -1], [1, 0], [-1, 0],
108 [1, 1], [1, -1], [-1, 1], [-1, -1]
109 ],
110 range: 1
111 }
112 ]
113 },
114 't': { //"triangle"
115 "class": "babybishop" + (this.playerColor != color ? "_inv" : ""),
116 moves: [
117 {
118 steps: [[1, 1], [1, -1], [-1, 1], [-1, -1]],
119 range: 1
120 }
121 ]
122 }
123 };
124 }
125
126 get size() {
127 return {
128 x: 6,
129 y: 6
130 };
131 }
132
133 filterValid(moves) {
134 return moves;
135 }
136
137 getCurrentScore() {
138 // Try both colors (to detect potential suicides)
139 let won = {};
140 for (let c of ['w', 'b']) {
141 const oppCol = C.GetOppCol(c);
142 const goal = (c == 'w' ? 0 : 5);
143 won[c] = this.board[goal].some((b,j) => {
144 return (
145 this.getColor(goal, j) == c &&
146 !this.findCapturesOn(
147 [goal, j],
148 {
149 one: true,
150 oppCol: oppCol,
151 segments: this.options["cylinder"]
152 }
153 )
154 );
155 });
156 }
157 if (won['w'] && won['b'])
158 return "?"; //no idea who won, not relevant anyway :)
159 return (won['w'] ? "1-0" : (won['b'] ? "0-1" : "*"));
160 }
161
162 };