summaryrefslogtreecommitdiff
path: root/src/games/reversi/core.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/games/reversi/core.ts')
-rw-r--r--src/games/reversi/core.ts94
1 files changed, 31 insertions, 63 deletions
diff --git a/src/games/reversi/core.ts b/src/games/reversi/core.ts
index 9199efa092..e724917fbf 100644
--- a/src/games/reversi/core.ts
+++ b/src/games/reversi/core.ts
@@ -1,4 +1,4 @@
-import { count, countIf } from "../../prelude/array";
+import { count, concat } from "../../prelude/array";
// MISSKEY REVERSI ENGINE
@@ -110,7 +110,7 @@ export default class Reversi {
* 白石の数
*/
public get whiteCount() {
- return count(BLACK, this.board);
+ return count(WHITE, this.board);
}
/**
@@ -238,87 +238,55 @@ export default class Reversi {
/**
* 指定のマスに石を置いた時の、反転させられる石を取得します
* @param color 自分の色
- * @param pos 位置
+ * @param initPos 位置
*/
- public effects(color: Color, pos: number): number[] {
+ public effects(color: Color, initPos: number): number[] {
const enemyColor = !color;
- // ひっくり返せる石(の位置)リスト
- let stones: number[] = [];
+ const diffVectors: [number, number][] = [
+ [ 0, -1], // 上
+ [ +1, -1], // 右上
+ [ +1, 0], // 右
+ [ +1, +1], // 右下
+ [ 0, +1], // 下
+ [ -1, +1], // 左下
+ [ -1, 0], // 左
+ [ -1, -1] // 左上
+ ];
- const initPos = pos;
-
- // 走査
- const iterate = (fn: (i: number) => number[]) => {
- let i = 1;
- const found = [];
+ const effectsInLine = ([dx, dy]: [number, number]): number[] => {
+ const nextPos = (x: number, y: number): [number, number] => [x + dx, y + dy];
+ const found: number[] = []; // 挟めるかもしれない相手の石を入れておく配列
+ let [x, y] = this.transformPosToXy(initPos);
while (true) {
- let [x, y] = fn(i);
+ [x, y] = nextPos(x, y);
// 座標が指し示す位置がボード外に出たとき
if (this.opts.loopedBoard) {
- if (x < 0 ) x = this.mapWidth - ((-x) % this.mapWidth);
- if (y < 0 ) y = this.mapHeight - ((-y) % this.mapHeight);
- if (x >= this.mapWidth ) x = x % this.mapWidth;
- if (y >= this.mapHeight) y = y % this.mapHeight;
-
- // for debug
- //if (x < 0 || y < 0 || x >= this.mapWidth || y >= this.mapHeight) {
- // console.log(x, y);
- //}
+ x = ((x % this.mapWidth) + this.mapWidth) % this.mapWidth;
+ y = ((y % this.mapHeight) + this.mapHeight) % this.mapHeight;
- // 一周して自分に帰ってきたら
if (this.transformXyToPos(x, y) == initPos) {
- // ↓のコメントアウトを外すと、「現時点で自分の石が隣接していないが、
- // そこに置いたとするとループして最終的に挟んだことになる」というケースを有効化します。(Test4のマップで違いが分かります)
- // このケースを有効にした方が良いのか無効にした方が良いのか判断がつかなかったためとりあえず無効としておきます
- // (あと無効な方がゲームとしておもしろそうだった)
- stones = stones.concat(found);
- break;
+ // 盤面の境界でループし、自分が石を置く位置に戻ってきたとき、挟めるようにしている (ref: Test4のマップ)
+ return found;
}
} else {
- if (x == -1 || y == -1 || x == this.mapWidth || y == this.mapHeight) break;
+ if (x == -1 || y == -1 || x == this.mapWidth || y == this.mapHeight) {
+ return []; // 挟めないことが確定 (盤面外に到達)
+ }
}
const pos = this.transformXyToPos(x, y);
-
- //#region 「配置不能」マスに当たった場合走査終了
- const pixel = this.mapDataGet(pos);
- if (pixel == 'null') break;
- //#endregion
-
- // 石取得
+ if (this.mapDataGet(pos) === 'null') return []; // 挟めないことが確定 (配置不可能なマスに到達)
const stone = this.board[pos];
-
- // 石が置かれていないマスなら走査終了
- if (stone === null) break;
-
- // 相手の石なら「ひっくり返せるかもリスト」に入れておく
- if (stone === enemyColor) found.push(pos);
-
- // 自分の石なら「ひっくり返せるかもリスト」を「ひっくり返せるリスト」に入れ、走査終了
- if (stone === color) {
- stones = stones.concat(found);
- break;
- }
-
- i++;
+ if (stone === null) return []; // 挟めないことが確定 (石が置かれていないマスに到達)
+ if (stone === enemyColor) found.push(pos); // 挟めるかもしれない (相手の石を発見)
+ if (stone === color) return found; // 挟めることが確定 (対となる自分の石を発見)
}
};
- const [x, y] = this.transformPosToXy(pos);
-
- iterate(i => [x , y - i]); // 上
- iterate(i => [x + i, y - i]); // 右上
- iterate(i => [x + i, y ]); // 右
- iterate(i => [x + i, y + i]); // 右下
- iterate(i => [x , y + i]); // 下
- iterate(i => [x - i, y + i]); // 左下
- iterate(i => [x - i, y ]); // 左
- iterate(i => [x - i, y - i]); // 左上
-
- return stones;
+ return concat(diffVectors.map(effectsInLine));
}
/**