プロジェクト作成
yarn create nuxt-app marubatsu
項目 | 選択肢 |
---|---|
Project name | そのまま |
Programming language | JavaScript |
パッケージマネージャー | yarn |
UI Framework | Vuetify |
Nuxt.js modules | チェックなし |
Linting tools | なし |
Testing framework | None |
Rendering mode | Single Page App |
Deployment target | Static |
Development tool | jsconfig.json (Recommended for VS Code) |
cd marubatsu yarn dev
実装手順
設計を考える
マーク | 数値 |
---|---|
◯ | 1 |
× | -1 |
なし | 0 |
v-forを使って3x3のマスを書く
マスがクリックされたらコールされるメソッドを作る(引数に場所を渡す)
◯のターンor×のターンを表示し、マスがクリックされるたびに切り替える
クリックしたマス(配列)に◯or×を設定する
マスを指定したら文字(◯or×or空白)を返す関数を作り、各マスに文字を表示する
既にマークが置かれているところには置けないようにする
3つ揃ったら勝敗判定をしダイアログを表示
全てのマスが揃って勝敗が決まっていなかったら引き分け判定をしダイアログを表示
ダイアログを閉じたらリセットし、始めから
回答例
<template> <v-container> <h2>{{`${numToChar(turn)}のターンです`}}</h2> <div class="row" v-for="y of LINE_NUM" :key="y"> <div class="cell" v-for="x of LINE_NUM" :key="x" @click="onCellClick(x-1,y-1)"> <div>{{getCellChar(x-1,y-1)}}</div> </div> </div> <v-dialog v-model="dialog" @click:outside="reset" max-width="290"> <v-card> <v-card-title> <h2>{{dialogMessage}}</h2> </v-card-title> </v-card> </v-dialog> </v-container> </template> <script> export default { data: function() { return { turn: -1, cells: Array(9), LINE_NUM: 3, dialog: false, dialogMessage: "" }; }, mounted() { this.reset(); }, methods: { reset() { this.turn = -1; this.dialog = false; this.dialogMessage = ""; this.cells.fill(0); }, onCellClick(x, y) { if (0 === this.getCellNum(x, y)) { this.cells[y * this.LINE_NUM + x] = this.turn; if (this.checkLines()) { this.dialogMessage = `${this.numToChar(this.turn)}の勝ちです`; this.dialog = true; } else { this.turn *= -1; if (this.isFullArray()) { this.dialogMessage = `引き分けです`; this.dialog = true; } } } }, getCellNum(x, y) { return this.cells[y * this.LINE_NUM + x]; }, numToChar(num) { switch (num) { case 0: return " "; break; case 1: return "◯"; break; case -1: return "×"; } return " "; }, getCellChar(x, y) { return this.numToChar(this.getCellNum(x, y)); }, isFullArray() { let ret = true; for (let i = 0; i < this.cells.length; i++) { if (this.cells[i] === 0) { ret = false; break; } } return ret; }, isCompleteArray(arr) { let ret = true; for (let i = 0; i < arr.length; i++) { if (arr[0] !== arr[i]) { ret = false; break; } } return ret && arr[0] !== 0; }, checkLines() { let completed = false; // 横 for (let y = 0; y < this.LINE_NUM; y++) { const line = []; for (let x = 0; x < this.LINE_NUM; x++) { line.push(this.getCellNum(x, y)); } if (this.isCompleteArray(line)) { completed = true; } } // 縦 for (let x = 0; x < this.LINE_NUM; x++) { const line = []; for (let y = 0; y < this.LINE_NUM; y++) { line.push(this.getCellNum(x, y)); } if (this.isCompleteArray(line)) { completed = true; } } // 斜め { const line = []; for (let x = 0; x < this.LINE_NUM; x++) { line.push(this.getCellNum(x, x)); } if (this.isCompleteArray(line)) { completed = true; } } // 斜め { const line = []; for (let x = 0; x < this.LINE_NUM; x++) { line.push(this.getCellNum(x, this.LINE_NUM - x - 1)); } if (this.isCompleteArray(line)) { completed = true; } } return completed; } }, computed: {} }; </script> <style scoped> .cell { border: 1px solid; text-align: center; font-size: 2rem; width: 4em; height: 4em; line-height: 4em; } </style>