diff --git a/src/api/stream/othello-game.ts b/src/api/stream/othello-game.ts index a5fb379e8..d08647815 100644 --- a/src/api/stream/othello-game.ts +++ b/src/api/stream/othello-game.ts @@ -55,9 +55,7 @@ export default function(request: websocket.request, connection: websocket.connec let winner; if (isEnded) { - const blackCount = o.board.filter(s => s == 'black').length; - const whiteCount = o.board.filter(s => s == 'white').length; - winner = blackCount == whiteCount ? null : blackCount > whiteCount ? game.black_user_id : game.white_user_id; + winner = o.blackCount == o.whiteCount ? null : o.blackCount > o.whiteCount ? game.black_user_id : game.white_user_id; } const log = { @@ -79,9 +77,6 @@ export default function(request: websocket.request, connection: websocket.connec } }); - publishOthelloGameStream(gameId, 'set', { - color: myColor, - pos - }); + publishOthelloGameStream(gameId, 'set', log); } } diff --git a/src/common/othello.ts b/src/common/othello.ts index fc27d72dc..1057e6b9a 100644 --- a/src/common/othello.ts +++ b/src/common/othello.ts @@ -3,6 +3,11 @@ const BOARD_SIZE = 8; export default class Othello { public board: Array<'black' | 'white'>; + public stats: Array<{ + b: number; + w: number; + }> = []; + /** * ゲームを初期化します */ @@ -17,6 +22,27 @@ export default class Othello { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ]; + + this.stats.push({ + b: 0.5, + w: 0.5 + }); + } + + public get blackCount() { + return this.board.filter(s => s == 'black').length; + } + + public get whiteCount() { + return this.board.filter(s => s == 'white').length; + } + + public get blackP() { + return this.blackCount / (this.blackCount + this.whiteCount); + } + + public get whiteP() { + return this.whiteCount / (this.blackCount + this.whiteCount); } public setByNumber(color, n) { @@ -88,6 +114,11 @@ export default class Othello { break; } }); + + this.stats.push({ + b: this.blackP, + w: this.whiteP + }); } public set(color, pos) { @@ -118,10 +149,11 @@ export default class Othello { /** * 指定の位置に石を打つことができるかどうか(相手の石を1つでも反転させられるか)を取得します */ - public canReverse2(myColor, targetx, targety): boolean { - return this.getReverse(myColor, targetx, targety) !== null; + public canReverse2(myColor, x, y): boolean { + return this.canReverse(myColor, x + (y * 8)); } public canReverse(myColor, pos): boolean { + if (this.board[pos] != null) return false; const x = pos % BOARD_SIZE; const y = Math.floor(pos / BOARD_SIZE); return this.getReverse(myColor, x, y) !== null; @@ -181,7 +213,7 @@ export default class Othello { // 右下 iterate = createIterater(); - for (let c = 0, i = 1; i < Math.min(BOARD_SIZE - targetx, BOARD_SIZE - targety); c++, i++) { + for (let c = 0, i = 1; i <= Math.min(BOARD_SIZE - targetx, BOARD_SIZE - targety); c++, i++) { if (iterate(targetx + i, targety + i)) { res.push([3, c]); break; @@ -199,7 +231,7 @@ export default class Othello { // 左下 iterate = createIterater(); - for (let c = 0, i = 1; i < Math.min(targetx, BOARD_SIZE - targety); c++, i++) { + for (let c = 0, i = 1; i <= Math.min(targetx, BOARD_SIZE - targety); c++, i++) { if (iterate(targetx - i, targety + i)) { res.push([5, c]); break; diff --git a/src/web/app/common/views/components/othello.game.vue b/src/web/app/common/views/components/othello.game.vue index b7c23e704..70c9965ee 100644 --- a/src/web/app/common/views/components/othello.game.vue +++ b/src/web/app/common/views/components/othello.game.vue @@ -2,12 +2,13 @@
{{ game.black_user.name }}(黒) vs {{ game.white_user.name }}(白)

{{ turn.name }}のターンです

+

{{ turn.name }}のターン

{{ isMyTurn ? 'あなたのターンです' : '相手のターンです' }}

-

+

-
+
+

黒:{{ o.blackCount }} 白:{{ o.whiteCount }} 合計:{{ o.blackCount + o.whiteCount }}

+
+
+
+
+
+
+
+
+
+ %fa:fast-backward% + %fa:backward% + {{ logPos }} / {{ logs.length }} + %fa:forward% + %fa:fast-forward% +
@@ -26,9 +43,12 @@ import Othello from '../../../../../common/othello'; export default Vue.extend({ props: ['game'], + data() { return { o: new Othello(), + logs: [], + logPos: 0, turn: null, isMyTurn: null, isEnded: false, @@ -36,6 +56,7 @@ export default Vue.extend({ connection: null }; }, + computed: { iAmPlayer(): boolean { return this.game.black_user_id == (this as any).os.i.id || this.game.white_user_id == (this as any).os.i.id; @@ -47,24 +68,57 @@ export default Vue.extend({ return this.myColor == 'black' ? 'white' : 'black'; } }, + + watch: { + logPos(v) { + if (!this.isEnded) return; + this.o = new Othello(); + this.turn = this.game.black_user; + this.logs.forEach((log, i) => { + if (i < v) { + this.o.set(log.color, log.pos); + + if (log.color == 'black' && this.o.getPattern('white').length > 0) { + this.turn = this.game.white_user; + } + if (log.color == 'black' && this.o.getPattern('white').length == 0) { + this.turn = this.game.black_user; + } + if (log.color == 'white' && this.o.getPattern('black').length > 0) { + this.turn = this.game.black_user; + } + if (log.color == 'white' && this.o.getPattern('black').length == 0) { + this.turn = this.game.white_user; + } + } + }); + this.$forceUpdate(); + } + }, + created() { this.game.logs.forEach(log => { this.o.set(log.color, log.pos); }); + this.logs = this.game.logs; + this.logPos = this.logs.length; this.turn = this.game.turn_user_id == this.game.black_user_id ? this.game.black_user : this.game.white_user; this.isMyTurn = this.game.turn_user_id == (this as any).os.i.id; this.isEnded = this.game.is_ended; this.winner = this.game.winner; }, + mounted() { this.connection = new OthelloGameStream((this as any).os.i, this.game); this.connection.on('set', this.onSet); }, + beforeDestroy() { this.connection.off('set', this.onSet); this.connection.close(); }, + methods: { set(pos) { if (!this.isMyTurn) return; @@ -75,9 +129,7 @@ export default Vue.extend({ this.turn = this.myColor == 'black' ? this.game.white_user : this.game.black_user; } else if (this.o.getPattern(this.myColor).length == 0) { this.isEnded = true; - const blackCount = this.o.board.filter(s => s == 'black').length; - const whiteCount = this.o.board.filter(s => s == 'white').length; - this.winner = blackCount == whiteCount ? null : blackCount > whiteCount ? this.game.black_user : this.game.white_user; + this.winner = this.o.blackCount == this.o.whiteCount ? null : this.o.blackCount > this.o.whiteCount ? this.game.black_user : this.game.white_user; } this.connection.send({ type: 'set', @@ -85,13 +137,15 @@ export default Vue.extend({ }); this.$forceUpdate(); }, + onSet(x) { + this.logs.push(x); + this.logPos++; this.o.set(x.color, x.pos); + if (this.o.getPattern('black').length == 0 && this.o.getPattern('white').length == 0) { this.isEnded = true; - const blackCount = this.o.board.filter(s => s == 'black').length; - const whiteCount = this.o.board.filter(s => s == 'white').length; - this.winner = blackCount == whiteCount ? null : blackCount > whiteCount ? this.game.black_user : this.game.white_user; + this.winner = this.o.blackCount == this.o.whiteCount ? null : this.o.blackCount > this.o.whiteCount ? this.game.black_user : this.game.white_user; } else { if (this.iAmPlayer && this.o.getPattern(this.myColor).length > 0) { this.isMyTurn = true; @@ -126,7 +180,7 @@ export default Vue.extend({ padding 8px border-bottom dashed 1px #c4cdd4 - > div + > .board display grid grid-template-rows repeat(8, 1fr) grid-template-columns repeat(8, 1fr) @@ -168,4 +222,29 @@ export default Vue.extend({ display block width 100% height 100% + + > .graph + display grid + grid-template-columns repeat(61, 1fr) + width 300px + height 38px + margin 0 auto 16px auto + + > div + &:not(:empty) + background #ccc + + > div:first-child + background #333 + + > div:last-child + background #ccc + + > .player + margin-bottom 16px + + > span + display inline-block + margin 0 8px + min-width 70px