2 // - pass btn on top + message if opponent just passed
3 // - do not count points: rely on players' ability to do that
4 // - implement Ko rule (need something in fen: lastMove)
6 import ChessRules
from "/base_rules.js";
7 import Move
from "/utils/Move.js";
8 import PiPo
from "/utils/PiPo.js";
9 import {ArrayFun
} from "/utils/array.js";
11 export default class WeiqiRules
extends ChessRules
{
13 // TODO: option oneColor (just alter pieces class of white stones)
14 static get Options() {
38 const flipped
= (this.playerColor
== 'b');
41 viewBox="0 0 ${10*(this.size.y)} ${10*(this.size.x)}"
42 class="chessboard_SVG">`;
43 for (let i
=0; i
< this.size
.x
; i
++) {
44 for (let j
=0; j
< this.size
.y
; j
++) {
45 const ii
= (flipped
? this.size
.x
- 1 - i : i
);
46 const jj
= (flipped
? this.size
.y
- 1 - j : j
);
49 id="${this.coordsToId({x: ii, y: jj})}"
58 // Add lines to delimitate "squares"
59 for (let i
= 0; i
< this.size
.x
; i
++) {
60 const y
= i
* 10 + 5, maxX
= this.size
.y
* 10 - 5;
62 <line x1="5" y1="${y}" x2="${maxX}" y2="${y}"
63 stroke="black" stroke-width="0.2"/>`;
65 for (let i
= 0; i
< this.size
.x
; i
++) {
66 const x
= i
* 10 + 5, maxY
= this.size
.x
* 10 - 5;
68 <line x1="${x}" y1="5" x2="${x}" y2="${maxY}"
69 stroke="black" stroke-width="0.2"/>`;
77 x: this.options
["bsize"],
78 y: this.options
["bsize"],
82 genRandInitBaseFen() {
83 const fenLine
= C
.FenEmptySquares(this.size
.y
);
85 fen: (fenLine
+ '/').repeat(this.size
.x
- 1) + fenLine
+ " w 0",
100 const [x
, y
] = [coords
.x
, coords
.y
];
101 if (this.board
[x
][y
] != "")
103 const color
= this.turn
;
104 const oppCol
= C
.GetOppCol(color
);
105 let move = new Move({
106 appear: [ new PiPo({ x: x
, y: y
, c: color
, p: 's' }) ],
110 this.playOnBoard(move); //put the stone
111 let noSuicide
= false;
113 for (let s
of [[0, 1], [1, 0], [0, -1], [-1, 0]]) {
114 const [i
, j
] = [x
+ s
[0], y
+ s
[1]];
115 if (this.onBoard(i
, j
)) {
116 if (this.board
[i
][j
] == "")
117 noSuicide
= true; //clearly
118 else if (this.getColor(i
, j
) == color
) {
119 // Free space for us = not a suicide
121 let explored
= ArrayFun
.init(this.size
.x
, this.size
.y
, false);
122 noSuicide
= this.searchForEmptySpace([i
, j
], color
, explored
);
126 // Free space for opponent = not a capture
127 let explored
= ArrayFun
.init(this.size
.x
, this.size
.y
, false);
128 const captureSomething
=
129 !this.searchForEmptySpace([i
, j
], oppCol
, explored
);
130 if (captureSomething
) {
131 for (let ii
= 0; ii
< this.size
.x
; ii
++) {
132 for (let jj
= 0; jj
< this.size
.y
; jj
++) {
133 if (explored
[ii
][jj
])
134 captures
.push(new PiPo({ x: ii
, y: jj
, c: oppCol
, p: 's' }));
141 this.undoOnBoard(move); //remove the stone
142 if (!noSuicide
&& captures
.length
== 0)
144 Array
.prototype.push
.apply(move.vanish
, captures
);
148 searchForEmptySpace([x
, y
], color
, explored
) {
150 return false; //didn't find empty space
151 explored
[x
][y
] = true;
153 for (let s
of [[1, 0], [0, 1], [-1, 0], [0, -1]]) {
154 const [i
, j
] = [x
+ s
[0], y
+ s
[1]];
155 if (this.onBoard(i
, j
)) {
156 if (this.board
[i
][j
] == "")
158 else if (this.getColor(i
, j
) == color
)
159 res
= this.searchForEmptySpace([i
, j
], color
, explored
) || res
;
166 // Suicide check not here, because side-computation of captures
171 return "*"; //Go game is a little special...