【Java】初心者がオセロのコンソールアプリを制作した学習メモ

プログラミング（Java）の学習を始めて1ヶ月が経ったので、オセロのコンソールアプリ（Windowsならコマンドプロンプト、Macならターミナルで動作するアプリ）を制作した備忘録です。

# 使用環境
PC：MacBook Air 2018
OS：macOS Sonoma 14.3.1
IDE：Eclipse 2023

# 全体のソースコード
全体のソースコードは、以下のGitHubにて公開しています。

https://github.com/miya71/othello_cui

# 各クラスの解説

## Mainクラス
各クラスのインスタンス化と、Gameクラスに各インスタンスを渡してplayメソッドを実行するクラスです。
```java:Main.java
package othello;

public class Main {
	public static void main(String[] args) {
		Stone stone = new Stone();
		Player player = new Player();
		Turn turn = new Turn();
		Pass pass = new Pass();
		Board board = new Board(stone, player, turn, pass);
		Score score = new Score(board);

        // Gameクラスに各インスタンスを渡してplayメソッドを実行
		Game game = new Game(stone, player, turn, board, score, pass);
		game.play();
	}
	
}
```

## Gameクラス
盤面（Board）の表示と座標の入力、ゲーム全体のループ処理を実行するクラスです。
```java:Game.java
    // ゲーム全体のループ処理をするメソッド
	public void play() {
		System.out.println("オセロゲームを開始します。");
		board.reset();
		while(stone.getStone() < 64) {
			printBoard();
			score.countScore();
			System.out.println("黒：" + score.getBlackStone() + " 白：" + score.getWhiteStone());
			if(player.getMyColor().equals("black")) {
				System.out.println("黒の番です。");
			} else {
				System.out.println("白の番です。");
			}
			System.out.println("石を置くx軸を入力してください（1〜8、パスの場合は0）。");
			int x = inputX();
			System.out.println("石を置くy軸を入力してください（1〜8、パスの場合は0）。");
			int y = inputY();
			if(y == 0 && x == 0) {
                turn.setTurnEndFlag(true);
				System.out.println("パスしました。");
				pass.increasePassCount();
			} else if(!(board.getBoard((y-1), (x-1)).equals("none"))) {
				turn.setTurnEndFlag(false);
				System.out.println("既に石が置いてあります。");
			} else {
				board.putStone(y, x);
			}
			if(turn.getTurnEndFlag()) {
				player.changeColor();
			}
			if(board.getChangeFlag() == false) {
				System.out.println("1つ以上の石をひっくり返してください。");
			}
			if(pass.getPassCount() == 2) {
				System.out.println("どちらも石を置けなかったので終了します。");
				break;
			}
		}
    }
```
## Boardクラス
受け取った座標に石を置いてひっくり返しの処理をして、盤面の状況（石がどこに置かれているか）を返すクラスです。
```java:Board.java
    // 石を置いてひっくり返しの処理をするメソッド
	public void putStone(int y, int x) {
		y--;
		x--;
		changeFlag = false;
		changeTop(y, x);
		changeBottom(y, x);
		changeLeft(y, x);
		changeRight(y,x);
		changeTopLeft(y, x);
		changeTopRight(y, x);
		changeBottomLeft(y, x);
		changeBottomRight(y, x);
		if(changeFlag) {
			setBoard(y, x, player.getMyColor());
			stone.increaseStone();
            pass.resetPassCount();
			turn.setTurnEndFlag(true);
		}else {
			turn.setTurnEndFlag(false);
		}
	}
```
## Stoneクラス
Gameクラスのループ処理の条件に使うため、盤面の石の合計数を返すクラスです。
```java:Stone.java
    // 盤面の石を1増やすメソッド
	public void increaseStone() {
		stone++;
	}
    // 盤面の石の合計数を返すメソッド
	public int getStone() {
		return stone;
	}
```
## Playerクラス
手番の色の交代処理をして、手番と相手それぞれの石の色を返すクラスです。
```java:Player.java
    // 手番の石の色を返すメソッド
	public String getMyColor() {
		return myColor;
	}
    // 相手の石の色を返すメソッド
	public String getEnemyColor() {
		return enemyColor;
	}
    // 手番の色を交代するメソッド
	public void changeColor() {
		if(myColor.equals("black")) {
			myColor = "white";
			enemyColor = "black";
		} else {
			myColor = "black";
			enemyColor = "white";
		}
	}
```
## Turnクラス
ターンの終了判定（true or false）を受け取って、手番の交代判定用に返すクラスです。
```java:Turn.java
    // ターンの終了判定を受け取るメソッド
	public void setTurnEndFlag(boolean turnEndFlag) {
		this.turnEndFlag = turnEndFlag;
	}
    // ターンの終了判定を返すメソッド
	public boolean getTurnEndFlag() {
		return turnEndFlag;
	}
```
## Passクラス
ゲームの終了判定に使うため、パスの連続回数をカウントして返すクラスです。
```java:Pass.java
    // パスカウントを返すメソッド
	public int getPassCount() {
		return passCount;
	}
    // パスカウントを1増やすメソッド
	public void increasePassCount() {
		passCount++;
	}
    //　パスカウントをリセットするメソッド
	public void resetPassCount() {
		passCount = 0;
	}
```
## Scoreクラス
ゲーム終了時に、盤面上の黒と白の石の数を集計して、それぞれの石の数を返すクラスです。
```java:Score.java
    // 盤面上の黒と白の石の数を集計するメソッド
	public void countScore() {
		blackStone = 0;
		whiteStone = 0;
		for(int i = 0; i < board.getBoard().length; i++) {
			for(int j = 0; j < board.getBoard().length; j++) {
				if (board.getBoard(i, j).equals("black")) {
					blackStone++;
				} else if(board.getBoard(i, j).equals("white")) {
					whiteStone++;
				}
			}
		}
	}
    // 黒の石の数を返すメソッド
	public int getBlackStone() {
		return blackStone;
	}
    // 白の石の数を返すメソッド
	public int getWhiteStone() {
		return whiteStone;
	}
```

# 問題点と今後の解決案
パスの操作が手動なので、石を置けるのに間違えてパスする可能性がある
→石を置ける場合はtrue、置けない場合はfalse（パス）を返すクラスを作成してパスを自動化する

どちらのプレイヤーも操作が必要なので、2人いないと遊べない
→石を置ける座標を返すCpuクラスを作成して片方のプレイヤーを自動化する

座標を指定する操作が面倒で直感的ではない
→WebアプリやネイティブアプリにしてGUIで遊べるようにする