From 608a5b23ec74c1ea2c30b2f3858db2271acc1de7 Mon Sep 17 00:00:00 2001 From: Yuki Takenaka Date: Thu, 21 Oct 2021 19:44:01 +0900 Subject: [PATCH] =?UTF-8?q?=E8=89=B2=E3=80=85=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.ts | 5 +- src/model/board.ts | 18 +++---- src/model/io.ts | 4 +- src/model/othello.ts | 123 +++++++++++++++++++++++-------------------- 4 files changed, 79 insertions(+), 71 deletions(-) diff --git a/src/main.ts b/src/main.ts index 131018c..8f58086 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,10 +7,7 @@ import { StoneCreator } from './model/stone'; (async () => { try { - const board = new Board(); - const io = new IO(prompt); - - const othello = new Othello(board, new StoneCreator, new PlayerCreator, io); + const othello = new Othello(new Board(), new StoneCreator(), new PlayerCreator(), new IO(prompt)); othello.start(); } catch (e) { const _e = e as Error; diff --git a/src/model/board.ts b/src/model/board.ts index 6c8942c..41097cc 100644 --- a/src/model/board.ts +++ b/src/model/board.ts @@ -9,7 +9,7 @@ export interface IBoard { size: number; state: Array[]; putStone: (coodinate: Coodinate, stone: IStone) => void; - canPutStone: (coodinate: Coodinate) => boolean; + isEmpty: (coodinate: Coodinate) => boolean; getStone: (coodinate: Coodinate) => IStone | null; countStone: (state: StoneState) => number; isFull: () => boolean; @@ -54,12 +54,12 @@ export class Board implements IBoard { return false; }; - public canPutStone = (coodinate: Coodinate) => { - return this.existSpace(coodinate) && !Boolean(this._state[coodinate.y][coodinate.x]); + public isEmpty = (coodinate: Coodinate) => { + return this.existSquare(coodinate) && !Boolean(this._state[coodinate.y][coodinate.x]); }; - private existSpace = (coodinate: Coodinate) => { - // 範囲外 + // マス目が存在するか + private existSquare = (coodinate: Coodinate) => { if (this._state[coodinate.y] === undefined || this._state[coodinate.y][coodinate.x] === undefined) { return false; } @@ -68,7 +68,7 @@ export class Board implements IBoard { }; public putStone = (coodinate: Coodinate, stone: IStone) => { - if (!this.existSpace(coodinate) || !this.canPutStone(coodinate)) { + if (!this.existSquare(coodinate) || !this.isEmpty(coodinate)) { throw new Error('置けないよ'); } @@ -76,7 +76,7 @@ export class Board implements IBoard { }; public getStone = (coodinate: Coodinate) => { - if (!this.existSpace(coodinate)) { + if (!this.existSquare(coodinate)) { throw new Error('範囲外だよ'); } @@ -98,9 +98,9 @@ export class Board implements IBoard { public isFull = () => { if (this.countStone('white') + this.countStone('black') < this.size ** 2) { - return false + return false; } return true; - } + }; } diff --git a/src/model/io.ts b/src/model/io.ts index 0088047..6437c42 100644 --- a/src/model/io.ts +++ b/src/model/io.ts @@ -2,7 +2,7 @@ import inquirer from 'inquirer'; import { Coodinate, IBoard } from './board'; export interface IIO { - message: (message: any) => void; + showMessage: (message: any) => void; selectBoardSize: () => Promise; selectXYCoodinate: (board: IBoard) => Promise; showBoard: (board: IBoard) => void; @@ -14,7 +14,7 @@ export class IO implements IIO { public constructor(prompt: inquirer.PromptModule) { this.prompt = prompt; } - public message = (message: any) => { + public showMessage = (message: any) => { console.log(message); }; diff --git a/src/model/othello.ts b/src/model/othello.ts index c0eb8c3..4edd549 100644 --- a/src/model/othello.ts +++ b/src/model/othello.ts @@ -10,7 +10,7 @@ export interface XYDirection { x: Direction; } -export const directions: XYDirection[] = [ +const directions: XYDirection[] = [ { y: -1, x: 0 }, { y: -1, x: 1 }, { y: 0, x: 1 }, @@ -27,8 +27,8 @@ export class Othello { private readonly player1: IPlayer; private readonly player2: IPlayer; private readonly io: IIO; - private turnPlayer: IPlayer; - private pass = 0; + private currentPlayer: IPlayer; + private passedCount = 0; constructor(board: IBoard, stoneCreator: IStoneCreator, playerCreator: IPlayerCreator, io: IIO) { this.board = board; @@ -37,30 +37,19 @@ export class Othello { this.player2 = playerCreator.factory('white', '白'); this.io = io; - this.turnPlayer = this.player1; + this.currentPlayer = this.player1; } public start = async () => { try { - const answer = await this.io.selectBoardSize(); - this.board.init(answer); - - const base = answer / 2 - 1; - - for (let y = 0; y < 2; y++) { - for (let x = 0; x < 2; x++) { - if (x === y) { - this.board.putStone({ y: y + base, x: x + base }, this.stoneCreator.factory('black')); - } else { - this.board.putStone({ y: y + base, x: x + base }, this.stoneCreator.factory('white')); - } - } - } + // 初期盤面の生成 + const size = await this.io.selectBoardSize(); + this.setInitialBoard(size); - this.io.message(`先行は${this.turnPlayer.name}です`); + this.io.showMessage(`先行は${this.currentPlayer.name}です`); // 2連続パスか盤面が一杯になるまで - while (this.pass < 2 && !this.board.isFull()) { + while (this.passedCount < 2 && !this.board.isFull()) { await this.playTurn(); this.changeTurn(); } @@ -68,65 +57,87 @@ export class Othello { this.end(); } catch (e) { const _e = e as Error; - this.io.message(_e.message); + this.io.showMessage(_e.message); + } + }; + + private setInitialBoard = (size: number) => { + this.board.init(size); + + const base = size / 2 - 1; + + for (let y = 0; y < 2; y++) { + for (let x = 0; x < 2; x++) { + if (x === y) { + this.board.putStone({ y: y + base, x: x + base }, this.stoneCreator.factory('black')); + } else { + this.board.putStone({ y: y + base, x: x + base }, this.stoneCreator.factory('white')); + } + } } }; private putStone = (coodinate: Coodinate) => { - const flipableStones = this.getFlipableStoneCoodinates(coodinate); + const flippableStones = this.getFlipableStoneCoodinates(coodinate); - if (flipableStones.length === 0) { + if (flippableStones.length === 0) { throw new Error('ひっくり返せる石がないよ'); } - this.board.putStone(coodinate, this.stoneCreator.factory(this.turnPlayer.color)); - flipableStones.forEach(flipableStone => { + this.board.putStone(coodinate, this.stoneCreator.factory(this.currentPlayer.color)); + flippableStones.forEach(flipableStone => { const stone = this.board.getStone(flipableStone); stone?.flip(); }); }; private changeTurn = () => { - this.turnPlayer = this.turnPlayer === this.player1 ? this.player2 : this.player1; + this.currentPlayer = this.currentPlayer === this.player1 ? this.player2 : this.player1; }; private playTurn = async () => { this.io.showBoard(this.board); - this.io.message(`${this.turnPlayer.name}の番`); + this.io.showMessage(`${this.currentPlayer.name}の番`); + + if (!this.canPutStone()) { + // 置く場所がない場合 + this.passedCount++; + this.io.showMessage(`${this.currentPlayer.name}は置けないのでパス`); + return; + } + + this.passedCount = 0; + + // 置けるまで聞く + while (true) { + try { + const coodinate = await this.io.selectXYCoodinate(this.board); + this.putStone(coodinate); + break; + } catch (e) { + const _e = e as Error; + console.log(`\n${_e.message}\n`); + } + } + }; + + // 置ける場所があるかどうか + private canPutStone = () => { // 全部のマスを調べて置ける場所があるかどうか調べる for (let i = 0; i < this.board.size; i++) { for (let j = 0; j < this.board.size; j++) { - if (!this.board.canPutStone({ y: i, x: j })) { + if (!this.board.isEmpty({ y: i, x: j })) { continue; } - - const flipableStones = this.getFlipableStoneCoodinates({ y: i, x: j }); - - // 置く場所があればターンを実行して終了 - if (flipableStones.length > 0) { - this.pass = 0; - - // 置けるまで聞く - while (true) { - const coodinate = await this.io.selectXYCoodinate(this.board); - try { - this.putStone(coodinate); - break; - } catch (e) { - const _e = e as Error; - console.log(`\n${_e.message}\n`); - } - } - return; + const flippableStones = this.getFlipableStoneCoodinates({ y: i, x: j }); + if (flippableStones.length > 0) { + return true; } } } - // 置く場所がない場合 - this.pass++; - - this.io.message(`${this.turnPlayer.name}は置けないのでパス`); + return false; }; // 全方向を見て裏返せる石を探す @@ -163,7 +174,7 @@ export class Othello { } //自分の石があったならcoodinatesを返す - if (boardMapCoordinate.state === this.turnPlayer.color) { + if (boardMapCoordinate.state === this.currentPlayer.color) { return coodinates; } @@ -183,15 +194,15 @@ export class Othello { const player1Count = this.board.countStone(this.player1.color); const player2Count = this.board.countStone(this.player2.color); - this.io.message(`${this.player1.name}: ${player1Count}`); - this.io.message(`${this.player2.name}: ${player2Count}`); + this.io.showMessage(`${this.player1.name}: ${player1Count}`); + this.io.showMessage(`${this.player2.name}: ${player2Count}`); let winner = player1Count > player2Count ? this.player1.name : this.player2.name; if (player1Count === player2Count) { winner = 'なし'; } - this.io.message(`勝者は: ${winner}`); - this.io.message('\nゲーム終了'); + this.io.showMessage(`勝者は: ${winner}`); + this.io.showMessage('\nゲーム終了'); }; }