From e6d2cbe6a3331894dca198e006c1c4c02c3f3d69 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 10 Mar 2018 21:23:00 +0900
Subject: [PATCH] =?UTF-8?q?=E3=83=AB=E3=83=BC=E3=83=97=E3=83=A2=E3=83=BC?=
 =?UTF-8?q?=E3=83=89=E5=AE=9F=E8=A3=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/models/othello-game.ts                |  1 +
 src/api/stream/othello-game.ts                |  6 ++-
 src/common/othello/core.ts                    | 39 +++++++++++++++++--
 src/common/othello/maps.ts                    | 14 ++++++-
 .../common/views/components/othello.game.vue  |  6 ++-
 .../common/views/components/othello.room.vue  |  1 +
 6 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/src/api/models/othello-game.ts b/src/api/models/othello-game.ts
index b9d33007bf..a8c3025108 100644
--- a/src/api/models/othello-game.ts
+++ b/src/api/models/othello-game.ts
@@ -31,6 +31,7 @@ export interface IGame {
 		bw: string | number;
 		is_llotheo: boolean;
 		can_put_everywhere: boolean;
+		looped_board: boolean;
 	};
 }
 
diff --git a/src/api/stream/othello-game.ts b/src/api/stream/othello-game.ts
index 05f244f769..5f61f0cc2c 100644
--- a/src/api/stream/othello-game.ts
+++ b/src/api/stream/othello-game.ts
@@ -126,7 +126,8 @@ export default function(request: websocket.request, connection: websocket.connec
 				//#region 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理
 				const o = new Othello(map, {
 					isLlotheo: freshGame.settings.is_llotheo,
-					canPutEverywhere: freshGame.settings.can_put_everywhere
+					canPutEverywhere: freshGame.settings.can_put_everywhere,
+					loopedBoard: freshGame.settings.looped_board
 				});
 
 				if (o.isEnded) {
@@ -168,7 +169,8 @@ export default function(request: websocket.request, connection: websocket.connec
 
 		const o = new Othello(game.settings.map, {
 			isLlotheo: game.settings.is_llotheo,
-			canPutEverywhere: game.settings.can_put_everywhere
+			canPutEverywhere: game.settings.can_put_everywhere,
+			loopedBoard: game.settings.looped_board
 		});
 
 		game.logs.forEach(log => {
diff --git a/src/common/othello/core.ts b/src/common/othello/core.ts
index 851f1b79c7..418b461c6f 100644
--- a/src/common/othello/core.ts
+++ b/src/common/othello/core.ts
@@ -4,6 +4,7 @@ export type MapPixel = 'null' | 'empty';
 export type Options = {
 	isLlotheo: boolean;
 	canPutEverywhere: boolean;
+	loopedBoard: boolean;
 };
 
 /**
@@ -31,6 +32,7 @@ export default class Othello {
 		this.opts = opts;
 		if (this.opts.isLlotheo == null) this.opts.isLlotheo = false;
 		if (this.opts.canPutEverywhere == null) this.opts.canPutEverywhere = false;
+		if (this.opts.loopedBoard == null) this.opts.loopedBoard = false;
 		//#endregion
 
 		//#region Parse map data
@@ -206,21 +208,50 @@ export default class Othello {
 	 */
 	private effects(color: Color, pos: number): number[] {
 		const enemyColor = color == 'black' ? 'white' : 'black';
-		const [x, y] = this.transformPosToXy(pos);
+
+		// ひっくり返せる石(の位置)リスト
 		let stones = [];
 
+		const initPos = pos;
+
+		// 走査
 		const iterate = (fn: (i: number) => number[]) => {
 			let i = 1;
 			const found = [];
+
 			while (true) {
-				const [x, y] = fn(i);
-				if (x < 0 || y < 0 || x >= this.mapWidth || y >= this.mapHeight) break;
+				let [x, y] = fn(i);
+
+				// 座標が指し示す位置がボード外に出たとき
+				if (this.opts.loopedBoard) {
+					if (x < 0            ) x = this.mapWidth - (-x);
+					if (y < 0            ) y = this.mapHeight - (-y);
+					if (x >= this.mapWidth ) x = x - this.mapWidth;
+					if (y >= this.mapHeight) y = y - this.mapHeight;
+
+					// 一周して自分に帰ってきたら
+					if (this.transformXyToPos(x, y) == initPos) break;
+				} else {
+					if (x == -1 || y == -1 || x == this.mapWidth || y == this.mapHeight) break;
+				}
+
 				const pos = this.transformXyToPos(x, y);
+
+				//#region 「配置不能」マスに当たった場合走査終了
 				const pixel = this.mapDataGet(pos);
 				if (pixel == 'null') break;
+				//#endregion
+
+				// 石取得
 				const stone = this.get(pos);
+
+				// 石が置かれていないマスなら走査終了
 				if (stone == null) break;
+
+				// 相手の石なら「ひっくり返せるかもリスト」に入れておく
 				if (stone == enemyColor) found.push(pos);
+
+				// 自分の石なら「ひっくり返せるかもリスト」を「ひっくり返せるリスト」に入れ、走査終了
 				if (stone == color) {
 					stones = stones.concat(found);
 					break;
@@ -229,6 +260,8 @@ export default class Othello {
 			}
 		};
 
+		const [x, y] = this.transformPosToXy(pos);
+
 		iterate(i => [x    , y - i]); // 上
 		iterate(i => [x + i, y - i]); // 右上
 		iterate(i => [x + i, y    ]); // 右
diff --git a/src/common/othello/maps.ts b/src/common/othello/maps.ts
index a6a1c46046..3518259bba 100644
--- a/src/common/othello/maps.ts
+++ b/src/common/othello/maps.ts
@@ -793,7 +793,7 @@ export const twoBoard: Map = {
 	]
 };
 
-export const test: Map = {
+export const test1: Map = {
 	name: 'Test1',
 	category: 'Test',
 	data: [
@@ -803,3 +803,15 @@ export const test: Map = {
 		'--------'
 	]
 };
+
+export const test2: Map = {
+	name: 'Test2',
+	category: 'Test',
+	data: [
+		'------',
+		'------',
+		'-b--w-',
+		'-w--b-',
+		'-w--b-'
+	]
+};
diff --git a/src/web/app/common/views/components/othello.game.vue b/src/web/app/common/views/components/othello.game.vue
index fa3ed8d9a5..a84dcedd44 100644
--- a/src/web/app/common/views/components/othello.game.vue
+++ b/src/web/app/common/views/components/othello.game.vue
@@ -90,7 +90,8 @@ export default Vue.extend({
 			if (!this.game.is_ended) return;
 			this.o = new Othello(this.game.settings.map, {
 				isLlotheo: this.game.settings.is_llotheo,
-				canPutEverywhere: this.game.settings.can_put_everywhere
+				canPutEverywhere: this.game.settings.can_put_everywhere,
+				loopedBoard: this.game.settings.looped_board
 			});
 			this.logs.forEach((log, i) => {
 				if (i < v) {
@@ -104,7 +105,8 @@ export default Vue.extend({
 	created() {
 		this.o = new Othello(this.game.settings.map, {
 			isLlotheo: this.game.settings.is_llotheo,
-			canPutEverywhere: this.game.settings.can_put_everywhere
+			canPutEverywhere: this.game.settings.can_put_everywhere,
+			loopedBoard: this.game.settings.looped_board
 		});
 
 		this.game.logs.forEach(log => {
diff --git a/src/web/app/common/views/components/othello.room.vue b/src/web/app/common/views/components/othello.room.vue
index b7c28ae67d..dfdc43ef96 100644
--- a/src/web/app/common/views/components/othello.room.vue
+++ b/src/web/app/common/views/components/othello.room.vue
@@ -26,6 +26,7 @@
 
 	<div class="rules">
 		<mk-switch v-model="game.settings.is_llotheo" @change="updateSettings" text="石の少ない方が勝ち(ロセオ)"/>
+		<mk-switch v-model="game.settings.looped_board" @change="updateSettings" text="ループマップ"/>
 		<mk-switch v-model="game.settings.can_put_everywhere" @change="updateSettings" text="どこでも置けるモード"/>
 		<div>
 			<el-radio v-model="game.settings.bw" label="random" @change="updateSettings">ランダム</el-radio>