Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 特定の状況でfillがうまくいかないバグを修正 #293

Merged
merged 1 commit into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 22 additions & 21 deletions src/Kakomimasu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,11 @@ class Field {
this.nAgent = nAgent;
this.nPlayer = nPlayer;
this.points = points;
this.tiles = new Array(width * height).fill({
type: Field.AREA,
player: null,
});
this.tiles = new Array(width * height);
// fillで初期化すると参照が同じになってしまうので、一つずつ初期化
for (let i = 0; i < width * height; i++) {
this.tiles[i] = { type: Field.AREA, player: null };
}
}

static fromJSON(data: FieldJson) {
Expand Down Expand Up @@ -297,46 +298,46 @@ class Field {
const mask = new Array(field.length);
for (let i = 0; i < mask.length; i++) mask[i] = 1;

// reduceはmaskの中身が全部0になるまで続けている
while (mask.reduce((s, c) => s + c)) {
const area = new Array(field.length);
for (let pid = 0; pid < this.nPlayer; pid++) {
for (let i = 0; i < field.length; i++) {
area[i] |= 1 << pid;
area[i] |= 1 << pid; // とりあえず全部自分の領地としてマーク?
}
// 外側の囲まれていないところを判定
// 0,0(上で余白のマスをつけているため必ず中立マス)から探索を初め壁にぶつかるまで探索することで囲まれていない部分を判定している
const chk = (x: number, y: number) => {
const n = x + y * (w + 2);
if (x < 0 || x >= w + 2 || y < 0 || y >= h + 2) return;
else if ((area[n] & (1 << pid)) === 0) return;
if (x < 0 || x >= w + 2 || y < 0 || y >= h + 2) return; // ボードの外を判定しようとしていたらreturn
else if ((area[n] & (1 << pid)) === 0) return; // すでに囲まれていないと判定されたところはスキップ
else if (
mask[n] !== 0 && field[n].type === Field.WALL &&
field[n].player === pid
) {
return;
} else {
area[n] &= ~(1 << pid);
chk(x - 1, y);
chk(x + 1, y);
chk(x - 1, y - 1);
chk(x, y - 1);
chk(x + 1, y - 1);
chk(x - 1, y + 1);
chk(x, y + 1);
chk(x + 1, y + 1);
area[n] &= ~(1 << pid); // 探索しているマスを「囲まれていない」と判定(ビットを下げる)
chk(x - 1, y); // 左のマスを探索
chk(x + 1, y); // 右のマスを探索
chk(x - 1, y - 1); // 左上のマスを探索
chk(x, y - 1); // 上のマスを探索
chk(x + 1, y - 1); // 右上のマスを探索
chk(x - 1, y + 1); // 左下のマスを探索
chk(x, y + 1); // 下のマスを探索
chk(x + 1, y + 1); // 右下のマスを探索
}
};
chk(0, 0);
//console.log(mask, narea, pid);
}

//console.log(area);

//console.log("mamamama");
//console.log(mask, area, "mask");
for (let i = 0; i < field.length; i++) {
if (area[i] === 0) {
mask[i] = 0;
} else if ((area[i] & (area[i] - 1)) === 0) { // 2のべき乗かを判定
mask[i] = 0; // どのプレイヤーの領地でもないと判定されたところはスキップするようにmaskを0に設定
} else if ((area[i] & (area[i] - 1)) === 0) { // 2のべき乗かを判定(Trueならそのプレイヤーの領地として確定)
field[i].player = Math.log2(area[i]);
mask[i] = 0;
}
Expand All @@ -348,7 +349,7 @@ class Field {
const n = i + j * w;
const nexp = (i + 1) + (j + 1) * (w + 2);
if (this.tiles[n].type !== Field.WALL) {
this.tiles[n].player = field[nexp].player;
this.tiles[n] = field[nexp];
}
}
}
Expand Down
78 changes: 78 additions & 0 deletions src/test/fillBase4_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Board, Field } from "../Kakomimasu.ts";
import { AssertionError } from "./deps.ts";

const cl = (...a: Parameters<Console["log"]>) => {
console.log(...a); //a;
}; //console.log(...a);

Deno.test("fill1", () => {
const nAgent = 6;
const [width, height] = [3, 4];
const board: Board = {
width,
height,
points: new Array(width * height),
nAgent,
};
const field = new Field(board);

const p = () => {
for (let i = 0; i < height; i++) {
const s = [];
for (let j = 0; j < width; j++) {
const n = field.tiles[j + i * width];
s.push(
"_W".charAt(n.type) + (n.player === null ? "." : n.player).toString(),
);
}
cl(s.join(" "));
}
cl();
};
const set = (s: string) => {
s = s.replace(/\n/g, "");
for (let i = 0; i < s.length; i++) {
const c = s.charAt(i);
if (c === "0") {
field.tiles[i] = { type: Field.WALL, player: 0 };
} else if (c === "1") {
field.tiles[i] = { type: Field.WALL, player: 1 };
}
}
};
const chk = (s: string) => {
s = s.replace(/\n/g, "");
for (let i = 0; i < s.length; i++) {
const c = s.charAt(i);
if (c !== ".") {
const n = parseInt(c);
const f = field.tiles[i];
if (f.type !== Field.AREA || f.player !== n) {
throw new AssertionError("");
}
}
}
};

p();

set(`
000
0.0
000
...
`);

p();

field.fillArea();

p();

chk(`
...
.0.
...
...
`);
});
Loading