summaryrefslogtreecommitdiff
path: root/src/web
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-03-08 17:57:57 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-03-08 17:57:57 +0900
commit155012846d8f142515390adb2754b45cdfbb74ef (patch)
tree13b237f9464a7df918fee7f35ba6871d08c1ed1c /src/web
parentFix bug (diff)
downloadmisskey-155012846d8f142515390adb2754b45cdfbb74ef.tar.gz
misskey-155012846d8f142515390adb2754b45cdfbb74ef.tar.bz2
misskey-155012846d8f142515390adb2754b45cdfbb74ef.zip
#1200
Diffstat (limited to 'src/web')
-rw-r--r--src/web/app/common/views/components/othello.game.vue164
-rw-r--r--src/web/app/common/views/components/othello.gameroom.vue42
-rw-r--r--src/web/app/common/views/components/othello.room.vue152
-rw-r--r--src/web/app/common/views/components/othello.vue18
4 files changed, 286 insertions, 90 deletions
diff --git a/src/web/app/common/views/components/othello.game.vue b/src/web/app/common/views/components/othello.game.vue
index 1cb2400f7e..2ef6b645ce 100644
--- a/src/web/app/common/views/components/othello.game.vue
+++ b/src/web/app/common/views/components/othello.game.vue
@@ -1,23 +1,27 @@
<template>
<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 && logPos == logs.length">
- <template v-if="winner"><b>{{ winner.name }}</b>の勝ち</template>
+ <header><b>{{ blackUser.name }}</b>(黒) vs <b>{{ whiteUser.name }}</b>(白)</header>
+
+ <p class="turn" v-if="!iAmPlayer && !game.is_ended">{{ turnUser.name }}のターンです<mk-ellipsis/></p>
+ <p class="turn" v-if="logPos != logs.length">{{ turnUser.name }}のターン</p>
+ <p class="turn" v-if="iAmPlayer && !game.is_ended">{{ isMyTurn ? 'あなたのターンです' : '相手のターンです' }}<mk-ellipsis v-if="!isMyTurn"/></p>
+ <p class="result" v-if="game.is_ended && logPos == logs.length">
+ <template v-if="game.winner"><b>{{ game.winner.name }}</b>の勝ち{{ game.settings.is_llotheo ? ' (ロセオ)' : '' }}</template>
<template v-else>引き分け</template>
</p>
- <div class="board">
+
+ <div class="board" :style="{ 'grid-template-rows': `repeat(${ game.settings.map.size }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map.size }, 1fr)` }">
<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), prev: o.prevPos == i }"
+ :class="{ empty: stone == null, none: o.map.data[i] == ' ', myTurn: isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id ? 'black' : 'white', i) : null, prev: o.prevPos == i }"
@click="set(i)"
>
- <img v-if="stone == 'black'" :src="`${game.black_user.avatar_url}?thumbnail&size=64`" alt="">
- <img v-if="stone == 'white'" :src="`${game.white_user.avatar_url}?thumbnail&size=64`" alt="">
+ <img v-if="stone == 'black'" :src="`${blackUser.avatar_url}?thumbnail&size=128`" alt="">
+ <img v-if="stone == 'white'" :src="`${whiteUser.avatar_url}?thumbnail&size=128`" 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>
@@ -26,7 +30,8 @@
<div :style="{ height: `${ Math.floor(data.w * 100) }%` }"></div>
</div>
</div>
- <div class="player" v-if="isEnded">
+
+ <div class="player" v-if="game.is_ended">
<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>
@@ -38,58 +43,63 @@
<script lang="ts">
import Vue from 'vue';
-import { OthelloGameStream } from '../../scripts/streaming/othello-game';
-import Othello from '../../../../../common/othello';
+import Othello, { Color } from '../../../../../common/othello/core';
export default Vue.extend({
- props: ['game'],
+ props: ['game', 'connection'],
data() {
return {
- o: new Othello(),
+ o: null as Othello,
logs: [],
- logPos: 0,
- turn: null,
- isMyTurn: null,
- isEnded: false,
- winner: null,
- connection: null
+ logPos: 0
};
},
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;
+ return this.game.user1_id == (this as any).os.i.id || this.game.user2_id == (this as any).os.i.id;
},
- myColor(): string {
- return this.game.black_user_id == (this as any).os.i.id ? 'black' : 'white';
+ 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';
},
- opColor(): string {
+ opColor(): Color {
+ if (!this.iAmPlayer) return null;
return this.myColor == 'black' ? 'white' : 'black';
+ },
+ blackUser(): any {
+ return this.game.black == 1 ? this.game.user1 : this.game.user2;
+ },
+ whiteUser(): any {
+ return this.game.black == 1 ? this.game.user2 : this.game.user1;
+ },
+ turnUser(): any {
+ if (this.o.turn == 'black') {
+ return this.game.black == 1 ? this.game.user1 : this.game.user2;
+ } else if (this.o.turn == 'white') {
+ return this.game.black == 1 ? this.game.user2 : this.game.user1;
+ } else {
+ return null;
+ }
+ },
+ isMyTurn(): boolean {
+ if (this.turnUser == null) return null;
+ return this.turnUser.id == (this as any).os.i.id;
}
},
watch: {
logPos(v) {
- if (!this.isEnded) return;
- this.o = new Othello();
- this.turn = this.game.black_user;
+ if (!this.game.is_ended) return;
+ this.o = new Othello(this.game.settings.map, {
+ isLlotheo: this.game.settings.is_llotheo
+ });
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.o.put(log.color, log.pos);
}
});
this.$forceUpdate();
@@ -97,74 +107,65 @@ export default Vue.extend({
},
created() {
+ this.o = new Othello(this.game.settings.map, {
+ isLlotheo: this.game.settings.is_llotheo
+ });
+
this.game.logs.forEach(log => {
- this.o.set(log.color, log.pos);
+ this.o.put(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;
- if (!this.o.canReverse(this.myColor, pos)) return;
- this.o.set(this.myColor, pos);
- if (this.o.getPattern(this.opColor).length > 0) {
- this.isMyTurn = !this.isMyTurn;
- 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;
- this.winner = this.o.blackCount == this.o.whiteCount ? null : this.o.blackCount > this.o.whiteCount ? this.game.black_user : this.game.white_user;
- }
+ if (!this.o.canPut(this.myColor, pos)) return;
+
+ this.o.put(this.myColor, pos);
+
this.connection.send({
type: 'set',
pos
});
+
+ this.checkEnd();
+
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;
- 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;
- }
+ this.o.put(x.color, x.pos);
+ this.checkEnd();
+ this.$forceUpdate();
+ },
- if (x.color == 'black' && this.o.getPattern('white').length > 0) {
- this.turn = this.game.white_user;
- }
- if (x.color == 'black' && this.o.getPattern('white').length == 0) {
- this.turn = this.game.black_user;
- }
- if (x.color == 'white' && this.o.getPattern('black').length > 0) {
- this.turn = this.game.black_user;
- }
- if (x.color == 'white' && this.o.getPattern('black').length == 0) {
- this.turn = this.game.white_user;
+ checkEnd() {
+ this.game.is_ended = this.o.isEnded;
+ if (this.game.is_ended) {
+ if (this.o.winner == 'black') {
+ 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') {
+ 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 {
+ this.game.winner_id = null;
+ this.game.winner = null;
}
}
- this.$forceUpdate();
}
}
});
@@ -182,8 +183,6 @@ export default Vue.extend({
> .board
display grid
- grid-template-rows repeat(8, 1fr)
- grid-template-columns repeat(8, 1fr)
grid-gap 4px
width 300px
height 300px
@@ -221,6 +220,9 @@ export default Vue.extend({
&.prev
box-shadow 0 0 0 4px rgba($theme-color, 0.7)
+ &.none
+ border-color transparent !important
+
> img
display block
width 100%
diff --git a/src/web/app/common/views/components/othello.gameroom.vue b/src/web/app/common/views/components/othello.gameroom.vue
new file mode 100644
index 0000000000..9f4037515a
--- /dev/null
+++ b/src/web/app/common/views/components/othello.gameroom.vue
@@ -0,0 +1,42 @@
+<template>
+<div>
+ <x-room v-if="!g.is_started" :game="g" :connection="connection"/>
+ <x-game v-else :game="g" :connection="connection"/>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import XGame from './othello.game.vue';
+import XRoom from './othello.room.vue';
+import { OthelloGameStream } from '../../scripts/streaming/othello-game';
+
+export default Vue.extend({
+ components: {
+ XGame,
+ XRoom
+ },
+ props: ['game'],
+ data() {
+ return {
+ connection: null,
+ g: null
+ };
+ },
+ created() {
+ this.g = this.game;
+ this.connection = new OthelloGameStream((this as any).os.i, this.game);
+ this.connection.on('started', this.onStarted);
+ },
+ beforeDestroy() {
+ this.connection.off('started', this.onStarted);
+ this.connection.close();
+ },
+ methods: {
+ onStarted(game) {
+ Object.assign(this.g, game);
+ this.$forceUpdate();
+ }
+ }
+});
+</script>
diff --git a/src/web/app/common/views/components/othello.room.vue b/src/web/app/common/views/components/othello.room.vue
new file mode 100644
index 0000000000..b41d97ec61
--- /dev/null
+++ b/src/web/app/common/views/components/othello.room.vue
@@ -0,0 +1,152 @@
+<template>
+<div class="root">
+ <header><b>{{ game.user1.name }}</b> vs <b>{{ game.user2.name }}</b></header>
+
+ <p>ゲームの設定</p>
+
+ <el-select v-model="mapName" placeholder="マップを選択" @change="onMapChange">
+ <el-option v-for="m in maps" :key="m.name" :label="m.name" :value="m.name"/>
+ </el-select>
+
+ <div class="board" :style="{ 'grid-template-rows': `repeat(${ game.settings.map.size }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map.size }, 1fr)` }">
+ <div v-for="(x, i) in game.settings.map.data"
+ :class="{ none: x == ' ' }"
+ >
+ <template v-if="x == 'b'">%fa:circle%</template>
+ <template v-if="x == 'w'">%fa:circle R%</template>
+ </div>
+ </div>
+
+ <div class="rules">
+ <mk-switch v-model="game.settings.is_llotheo" @change="onIsLlotheoChange" text="石の少ない方が勝ち(ロセオ)"/>
+ </div>
+
+ <div class="actions">
+ <el-button @click="exit">キャンセル</el-button>
+ <el-button type="primary" @click="accept" v-if="!isAccepted">準備完了</el-button>
+ <el-button type="primary" @click="cancel" v-if="isAccepted">準備続行</el-button>
+ </div>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import * as maps from '../../../../../common/othello/maps';
+
+export default Vue.extend({
+ props: ['game', 'connection'],
+
+ data() {
+ return {
+ o: null,
+ isLlotheo: false,
+ mapName: maps.eighteight.name,
+ maps: maps
+ };
+ },
+
+ computed: {
+ isAccepted(): boolean {
+ if (this.game.user1_id == (this as any).os.i.id && this.game.user1_accepted) return true;
+ if (this.game.user2_id == (this as any).os.i.id && this.game.user2_accepted) return true;
+ return false;
+ }
+ },
+
+ created() {
+ this.connection.on('change-accepts', this.onChangeAccepts);
+ this.connection.on('update-settings', this.onUpdateSettings);
+ },
+
+ beforeDestroy() {
+ this.connection.off('change-accepts', this.onChangeAccepts);
+ this.connection.off('update-settings', this.onUpdateSettings);
+ },
+
+ methods: {
+ exit() {
+
+ },
+
+ accept() {
+ this.connection.send({
+ type: 'accept'
+ });
+ },
+
+ cancel() {
+ this.connection.send({
+ type: 'cancel-accept'
+ });
+ },
+
+ onChangeAccepts(accepts) {
+ this.game.user1_accepted = accepts.user1;
+ this.game.user2_accepted = accepts.user2;
+ this.$forceUpdate();
+ },
+
+ onUpdateSettings(settings) {
+ this.game.settings = settings;
+ this.mapName = this.game.settings.map.name;
+ },
+
+ onMapChange(v) {
+ this.game.settings.map = Object.entries(maps).find(x => x[1].name == v)[1];
+ this.connection.send({
+ type: 'update-settings',
+ settings: this.game.settings
+ });
+ this.$forceUpdate();
+ },
+
+ onIsLlotheoChange(v) {
+ this.connection.send({
+ type: 'update-settings',
+ settings: this.game.settings
+ });
+ this.$forceUpdate();
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+@import '~const.styl'
+
+.root
+ text-align center
+
+ > header
+ padding 8px
+ border-bottom dashed 1px #c4cdd4
+
+ > .board
+ display grid
+ grid-gap 4px
+ width 300px
+ height 300px
+ margin 16px auto
+
+ > div
+ background transparent
+ border solid 2px #eee
+ border-radius 6px
+ overflow hidden
+
+ *
+ pointer-events none
+ user-select none
+ width 100%
+ height 100%
+
+ &.none
+ border-color transparent
+
+ > .rules
+ max-width 300px
+ margin 0 auto
+
+ > .actions
+ margin-bottom 16px
+</style>
diff --git a/src/web/app/common/views/components/othello.vue b/src/web/app/common/views/components/othello.vue
index 326a8d80cc..31858fca19 100644
--- a/src/web/app/common/views/components/othello.vue
+++ b/src/web/app/common/views/components/othello.vue
@@ -1,7 +1,7 @@
<template>
<div class="mk-othello">
<div v-if="game">
- <x-game :game="game"/>
+ <x-gameroom :game="game"/>
</div>
<div class="matching" v-else-if="matching">
<h1><b>{{ matching.name }}</b>を待っています<mk-ellipsis/></h1>
@@ -40,18 +40,18 @@
<section v-if="myGames.length > 0">
<h2>自分の対局</h2>
<div class="game" v-for="g in myGames" tabindex="-1" @click="game = g">
- <img :src="`${g.black_user.avatar_url}?thumbnail&size=32`" alt="">
- <img :src="`${g.white_user.avatar_url}?thumbnail&size=32`" alt="">
- <span><b>{{ g.black_user.name }}</b> vs <b>{{ g.white_user.name }}</b></span>
+ <img :src="`${g.user1.avatar_url}?thumbnail&size=32`" alt="">
+ <img :src="`${g.user2.avatar_url}?thumbnail&size=32`" alt="">
+ <span><b>{{ g.user1.name }}</b> vs <b>{{ g.user2.name }}</b></span>
<span class="state">{{ g.is_ended ? '終了' : '進行中' }}</span>
</div>
</section>
<section v-if="games.length > 0">
<h2>みんなの対局</h2>
<div class="game" v-for="g in games" tabindex="-1" @click="game = g">
- <img :src="`${g.black_user.avatar_url}?thumbnail&size=32`" alt="">
- <img :src="`${g.white_user.avatar_url}?thumbnail&size=32`" alt="">
- <span><b>{{ g.black_user.name }}</b> vs <b>{{ g.white_user.name }}</b></span>
+ <img :src="`${g.user1.avatar_url}?thumbnail&size=32`" alt="">
+ <img :src="`${g.user2.avatar_url}?thumbnail&size=32`" alt="">
+ <span><b>{{ g.user1.name }}</b> vs <b>{{ g.user2.name }}</b></span>
<span class="state">{{ g.is_ended ? '終了' : '進行中' }}</span>
</div>
</section>
@@ -61,11 +61,11 @@
<script lang="ts">
import Vue from 'vue';
-import XGame from './othello.game.vue';
+import XGameroom from './othello.gameroom.vue';
export default Vue.extend({
components: {
- XGame
+ XGameroom
},
data() {
return {