✌️
This commit is contained in:
		
							parent
							
								
									88d1ac2556
								
							
						
					
					
						commit
						50e40ed61e
					
				
					 3 changed files with 126 additions and 20 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,12 +2,13 @@
 | 
			
		|||
<div class="root">
 | 
			
		||||
	<header><b>{{ game.black_user.name }}</b>(黒) vs <b>{{ game.white_user.name }}</b>(白)</header>
 | 
			
		||||
	<p class="turn" v-if="!iAmPlayer && !isEnded">{{ turn.name }}のターンです<mk-ellipsis/></p>
 | 
			
		||||
	<p class="turn" v-if="logPos != logs.length">{{ turn.name }}のターン</p>
 | 
			
		||||
	<p class="turn" v-if="iAmPlayer && !isEnded">{{ isMyTurn ? 'あなたのターンです' : '相手のターンです' }}<mk-ellipsis v-if="!isMyTurn"/></p>
 | 
			
		||||
	<p class="result" v-if="isEnded">
 | 
			
		||||
	<p class="result" v-if="isEnded && logPos == logs.length">
 | 
			
		||||
		<template v-if="winner"><b>{{ winner.name }}</b>の勝ち</template>
 | 
			
		||||
		<template v-else>引き分け</template>
 | 
			
		||||
	</p>
 | 
			
		||||
	<div>
 | 
			
		||||
	<div class="board">
 | 
			
		||||
		<div v-for="(stone, i) in o.board"
 | 
			
		||||
			:class="{ empty: stone == null, myTurn: isMyTurn, can: o.canReverse(turn.id == game.black_user.id ? 'black' : 'white', i) }"
 | 
			
		||||
			@click="set(i)"
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +17,22 @@
 | 
			
		|||
			<img v-if="stone == 'white'" :src="`${game.white_user.avatar_url}?thumbnail&size=64`" alt="">
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<p>黒:{{ o.blackCount }} 白:{{ o.whiteCount }} 合計:{{ o.blackCount + o.whiteCount }}</p>
 | 
			
		||||
	<div class="graph">
 | 
			
		||||
		<div v-for="n in 61 - o.stats.length">
 | 
			
		||||
		</div>
 | 
			
		||||
		<div v-for="data in o.stats">
 | 
			
		||||
			<div :style="{ height: `${ Math.floor(data.b * 100) }%` }"></div>
 | 
			
		||||
			<div :style="{ height: `${ Math.floor(data.w * 100) }%` }"></div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="player" v-if="isEnded">
 | 
			
		||||
		<el-button type="primary" @click="logPos = 0" :disabled="logPos == 0">%fa:fast-backward%</el-button>
 | 
			
		||||
		<el-button type="primary" @click="logPos--" :disabled="logPos == 0">%fa:backward%</el-button>
 | 
			
		||||
		<span>{{ logPos }} / {{ logs.length }}</span>
 | 
			
		||||
		<el-button type="primary" @click="logPos++" :disabled="logPos == logs.length">%fa:forward%</el-button>
 | 
			
		||||
		<el-button type="primary" @click="logPos = logs.length" :disabled="logPos == logs.length">%fa:fast-forward%</el-button>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue