Skip to content
Snippets Groups Projects
Commit e6f68e0b authored by syuilo's avatar syuilo
Browse files

オセロで黒白を真理値で表現するように

parent 1d62003e
No related branches found
No related tags found
No related merge requests found
......@@ -25,7 +25,11 @@ export interface IGame {
is_started: boolean;
is_ended: boolean;
winner_id: mongo.ObjectID;
logs: any[];
logs: Array<{
at: Date;
color: boolean;
pos: number;
}>;
settings: {
map: string[];
bw: string | number;
......
......@@ -214,9 +214,9 @@ export default function(request: websocket.request, connection: websocket.connec
if (o.isEnded) {
let winner;
if (o.winner == 'black') {
if (o.winner === true) {
winner = freshGame.black == 1 ? freshGame.user1_id : freshGame.user2_id;
} else if (o.winner == 'white') {
} else if (o.winner === false) {
winner = freshGame.black == 1 ? freshGame.user2_id : freshGame.user1_id;
} else {
winner = null;
......@@ -263,17 +263,17 @@ export default function(request: websocket.request, connection: websocket.connec
const myColor =
(game.user1_id.equals(user._id) && game.black == 1) || (game.user2_id.equals(user._id) && game.black == 2)
? 'black'
: 'white';
? true
: false;
if (!o.canPut(myColor, pos)) return;
o.put(myColor, pos);
let winner;
if (o.isEnded) {
if (o.winner == 'black') {
if (o.winner === true) {
winner = game.black == 1 ? game.user1_id : game.user2_id;
} else if (o.winner == 'white') {
} else if (o.winner === false) {
winner = game.black == 1 ? game.user2_id : game.user1_id;
} else {
winner = null;
......
export type Color = 'black' | 'white';
/**
* true ... 黒
* false ... 白
*/
export type Color = boolean;
const BLACK = true;
const WHITE = false;
export type MapPixel = 'null' | 'empty';
export type Options = {
......@@ -7,6 +14,23 @@ export type Options = {
loopedBoard: boolean;
};
export type Undo = {
/**
* 色
*/
color: Color,
/**
* どこに打ったか
*/
pos: number;
/**
* 反転した石の位置の配列
*/
effects: number[];
};
/**
* オセロエンジン
*/
......@@ -15,19 +39,20 @@ export default class Othello {
public mapWidth: number;
public mapHeight: number;
public board: Color[];
public turn: Color = 'black';
public turn: Color = BLACK;
public opts: Options;
public prevPos = -1;
public stats: Array<{
b: number;
w: number;
}>;
public prevColor: Color = null;
/**
* ゲームを初期化します
*/
constructor(map: string[], opts: Options) {
//#region binds
this.put = this.put.bind(this);
//#endregion
//#region Options
this.opts = opts;
if (this.opts.isLlotheo == null) this.opts.isLlotheo = false;
......@@ -42,8 +67,8 @@ export default class Othello {
this.board = mapData.split('').map(d => {
if (d == '-') return null;
if (d == 'b') return 'black';
if (d == 'w') return 'white';
if (d == 'b') return BLACK;
if (d == 'w') return WHITE;
return undefined;
});
......@@ -53,18 +78,12 @@ export default class Othello {
});
//#endregion
// Init stats
this.stats = [{
b: this.blackP,
w: this.whiteP
}];
// ゲームが始まった時点で片方の色の石しかないか、始まった時点で勝敗が決定するようなマップの場合がある
if (this.canPutSomewhere('black').length == 0) {
if (this.canPutSomewhere('white').length == 0) {
if (this.canPutSomewhere(BLACK).length == 0) {
if (this.canPutSomewhere(WHITE).length == 0) {
this.turn = null;
} else {
this.turn = 'white';
this.turn = WHITE;
}
}
}
......@@ -73,14 +92,14 @@ export default class Othello {
* 黒石の数
*/
public get blackCount() {
return this.board.filter(x => x == 'black').length;
return this.board.filter(x => x === BLACK).length;
}
/**
* 白石の数
*/
public get whiteCount() {
return this.board.filter(x => x == 'white').length;
return this.board.filter(x => x === WHITE).length;
}
/**
......@@ -123,36 +142,53 @@ export default class Othello {
* @param color 石の色
* @param pos 位置
*/
public put(color: Color, pos: number) {
if (!this.canPut(color, pos)) return;
public put(color: Color, pos: number, fast = false): Undo {
if (!fast && !this.canPut(color, pos)) return null;
this.prevPos = pos;
this.prevColor = color;
this.write(color, pos);
// 反転させられる石を取得
const reverses = this.effects(color, pos);
const effects = this.effects(color, pos);
// 反転させる
reverses.forEach(pos => {
effects.forEach(pos => {
this.write(color, pos);
});
this.stats.push({
b: this.blackP,
w: this.whiteP
});
this.calcTurn();
return {
color,
pos,
effects
};
}
private calcTurn() {
// ターン計算
const opColor = color == 'black' ? 'white' : 'black';
const opColor = this.prevColor === BLACK ? WHITE : BLACK;
if (this.canPutSomewhere(opColor).length > 0) {
this.turn = color == 'black' ? 'white' : 'black';
} else if (this.canPutSomewhere(color).length > 0) {
this.turn = color == 'black' ? 'black' : 'white';
this.turn = this.prevColor === BLACK ? WHITE : BLACK;
} else if (this.canPutSomewhere(this.prevColor).length > 0) {
this.turn = this.prevColor === BLACK ? BLACK : WHITE;
} else {
this.turn = null;
}
}
public undo(undo: Undo) {
this.prevColor = undo.color;
this.prevPos = undo.pos;
this.write(null, undo.pos);
for (const pos of undo.effects) {
const color = this.board[pos];
this.write(!color, pos);
}
this.calcTurn();
}
/**
* 指定したマスの状態を取得します
* @param pos 位置
......@@ -207,8 +243,8 @@ export default class Othello {
* @param color 自分の色
* @param pos 位置
*/
private effects(color: Color, pos: number): number[] {
const enemyColor = color == 'black' ? 'white' : 'black';
public effects(color: Color, pos: number): number[] {
const enemyColor = !color;
// ひっくり返せる石(の位置)リスト
let stones = [];
......@@ -225,7 +261,7 @@ export default class Othello {
// 座標が指し示す位置がボード外に出たとき
if (this.opts.loopedBoard) {
if (x < 0 ) x = this.mapWidth - ((-x) % this.mapWidth);
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;
......@@ -259,16 +295,17 @@ export default class Othello {
const stone = this.get(pos);
// 石が置かれていないマスなら走査終了
if (stone == null) break;
if (stone === null) break;
// 相手の石なら「ひっくり返せるかもリスト」に入れておく
if (stone == enemyColor) found.push(pos);
if (stone === enemyColor) found.push(pos);
// 自分の石なら「ひっくり返せるかもリスト」を「ひっくり返せるリスト」に入れ、走査終了
if (stone == color) {
if (stone === color) {
stones = stones.concat(found);
break;
}
i++;
}
};
......@@ -303,9 +340,9 @@ export default class Othello {
if (this.blackCount == this.whiteCount) return null;
if (this.opts.isLlotheo) {
return this.blackCount > this.whiteCount ? 'white' : 'black';
return this.blackCount > this.whiteCount ? WHITE : BLACK;
} else {
return this.blackCount > this.whiteCount ? 'black' : 'white';
return this.blackCount > this.whiteCount ? BLACK : WHITE;
}
}
}
......@@ -60,13 +60,13 @@ export default Vue.extend({
},
myColor(): Color {
if (!this.iAmPlayer) return null;
if (this.game.user1_id == (this as any).os.i.id && this.game.black == 1) return 'black';
if (this.game.user2_id == (this as any).os.i.id && this.game.black == 2) return 'black';
return 'white';
if (this.game.user1_id == (this as any).os.i.id && this.game.black == 1) return true;
if (this.game.user2_id == (this as any).os.i.id && this.game.black == 2) return true;
return false;
},
opColor(): Color {
if (!this.iAmPlayer) return null;
return this.myColor == 'black' ? 'white' : 'black';
return this.myColor === true ? false : true;
},
blackUser(): any {
return this.game.black == 1 ? this.game.user1 : this.game.user2;
......@@ -75,9 +75,9 @@ export default Vue.extend({
return this.game.black == 1 ? this.game.user2 : this.game.user1;
},
turnUser(): any {
if (this.o.turn == 'black') {
if (this.o.turn === true) {
return this.game.black == 1 ? this.game.user1 : this.game.user2;
} else if (this.o.turn == 'white') {
} else if (this.o.turn === false) {
return this.game.black == 1 ? this.game.user2 : this.game.user1;
} else {
return null;
......@@ -99,7 +99,7 @@ export default Vue.extend({
});
this.logs.forEach((log, i) => {
if (i < v) {
this.o.put(log.color, log.pos);
this.o.put(log.color, log.pos, true);
}
});
this.$forceUpdate();
......@@ -116,7 +116,7 @@ export default Vue.extend({
});
this.game.logs.forEach(log => {
this.o.put(log.color, log.pos);
this.o.put(log.color, log.pos, true);
});
this.logs = this.game.logs;
......@@ -190,10 +190,10 @@ export default Vue.extend({
checkEnd() {
this.game.is_ended = this.o.isEnded;
if (this.game.is_ended) {
if (this.o.winner == 'black') {
if (this.o.winner === true) {
this.game.winner_id = this.game.black == 1 ? this.game.user1_id : this.game.user2_id;
this.game.winner = this.game.black == 1 ? this.game.user1 : this.game.user2;
} else if (this.o.winner == 'white') {
} else if (this.o.winner === false) {
this.game.winner_id = this.game.black == 1 ? this.game.user2_id : this.game.user1_id;
this.game.winner = this.game.black == 1 ? this.game.user2 : this.game.user1;
} else {
......@@ -214,7 +214,7 @@ export default Vue.extend({
});
this.game.logs.forEach(log => {
this.o.put(log.color, log.pos);
this.o.put(log.color, log.pos, true);
});
this.logs = this.game.logs;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment