プログラミング(Java)の学習を始めて1ヶ月が経ったので、オセロのコンソールアプリ(Windowsならコマンドプロンプト、Macならターミナルで動作するアプリ)を制作した備忘録です。
使用環境
PC:MacBook Air 2018
OS:macOS Sonoma 14.3.1
IDE:Eclipse 2023
全体のソースコード
全体のソースコードは、以下のGitHubにて公開しています。
各クラスの解説
Mainクラス
各クラスのインスタンス化と、Gameクラスに各インスタンスを渡してplayメソッドを実行するクラスです。
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)の表示と座標の入力、ゲーム全体のループ処理を実行するクラスです。
// ゲーム全体のループ処理をするメソッド
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クラス
受け取った座標に石を置いてひっくり返しの処理をして、盤面の状況(石がどこに置かれているか)を返すクラスです。
// 石を置いてひっくり返しの処理をするメソッド
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クラスのループ処理の条件に使うため、盤面の石の合計数を返すクラスです。
// 盤面の石を1増やすメソッド
public void increaseStone() {
stone++;
}
// 盤面の石の合計数を返すメソッド
public int getStone() {
return stone;
}
Playerクラス
手番の色の交代処理をして、手番と相手それぞれの石の色を返すクラスです。
// 手番の石の色を返すメソッド
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)を受け取って、手番の交代判定用に返すクラスです。
// ターンの終了判定を受け取るメソッド
public void setTurnEndFlag(boolean turnEndFlag) {
this.turnEndFlag = turnEndFlag;
}
// ターンの終了判定を返すメソッド
public boolean getTurnEndFlag() {
return turnEndFlag;
}
Passクラス
ゲームの終了判定に使うため、パスの連続回数をカウントして返すクラスです。
// パスカウントを返すメソッド
public int getPassCount() {
return passCount;
}
// パスカウントを1増やすメソッド
public void increasePassCount() {
passCount++;
}
// パスカウントをリセットするメソッド
public void resetPassCount() {
passCount = 0;
}
Scoreクラス
ゲーム終了時に、盤面上の黒と白の石の数を集計して、それぞれの石の数を返すクラスです。
// 盤面上の黒と白の石の数を集計するメソッド
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で遊べるようにする