LoginSignup
3
0

More than 1 year has passed since last update.

javaでCUIオセロの制作

Last updated at Posted at 2021-09-13

はじめに

javaを勉強する目的で制作してみました。いくつかのサイトを参考にしましたが、裏返すロジックの部分やmainメソッド内など自分で考えた部分が多いので、バグや不都合があるかもしれないです。

ゲームの流れ

実行するとオセロが開始します。縦列、横列の順番で1~8までの整数を入力していきます。盤上の有効なマスに置くと白と黒のターンが変わり再び入力になります。すべてのマスに駒が置かれるか、白黒どちらか一色になった時点で勝敗を表示します。

スクリーンショット (24).png
スクリーンショット (23).png

コード

実行クラス

まずgameクラスのインスタンスを生成や変数の定義をします。そしてループ(各ターン)を開始して、正しい値の入力が確認された後その値と色(1なら黒2なら白)をturnOverメソッドに渡し裏返しの処理をします。裏返せたら色を交代して、駒の合計に1を足します。盤面に駒が埋まる=駒の数が64個、になったらループが終了します。そしてshowResultを呼び出し結果を表示します。

Othello.java
public class Othello {

    public static void main(String[] args) {
        // TODO 自動生成されたメソッド・スタブ

        game game = new game();

        int x = 0;
        int y = 0;

        //1なら黒、2なら白
        int num = 1;

        //ボードの駒の数
        int komaTotal = 4;

        Scanner sc = new Scanner(System.in);

        //ここで終了判定
        while(komaTotal < 64) {

            //整数入力、それ以外の場合の例外
            try{
                System.out.println("行を入力してください。");
                y = sc.nextInt();
                System.out.println("列を入力してください。");
                x = sc.nextInt();
            }catch (InputMismatchException e){
                System.out.println("整数を入力してください");
                sc.next();
                continue;
            }

            //盤上か(1~8)
            if (x <= 0 || x > 8) {
                System.out.println("盤上に置いてください");
                continue;
            } else if (y <= 0 || y > 8) {
                System.out.println("盤上に置いてください");
                continue;
            }

            //メソッドの実行  裏返した駒の合計
            int sumReverse = game.turnOver(y - 1, x - 1, num);

            //0なら裏返せてない=無効な場所
            //-1ならどちらかが一色になって決着
            if (sumReverse == 0) {
                System.out.println("有効な場所に置いてください");
                continue;
            } else if (sumReverse == -1) {
                break;
            }

            //交代
            if (num == 1) {
                num = 2;
            } else if (num == 2) {
                num = 1;
            }

            komaTotal++;

        }

        sc.close();
        System.out.println("終了");

        game.showResult();

    }
}

continueでループをスキップするのは3パターン。
下記の場合は色の交代と駒(ターン)のカウントを行わず再度入力になる。
1.整数以外が入力された場合→InputMismatchExceptionの例外を投げる
2.盤外である1~8の数字が入力された場合
3.turnOverメソッドを実行して、0が返ってきた場合→裏返せていない。ルール上置いてはいけない。

gameクラス

ボード(盤面)の管理や表示、裏返しメソッドなどを記述。黒は1、白は2、空は0で管理します。

メンバ変数とコンストラクタ

コンストラクタで初期の配置の挿入をします。

game.java
private int[][] bored = new int[8][8];

private int white = 0;
private int black = 0;

private int colour = 0;

//コンストラクタ
public game() {

    //初期配置。[3][3],[4][4]は白、[3][4],[4][3]は黒
    bored[3][4] = 1;
    bored[4][3] = 1;
    bored[3][3] = 2;
    bored[4][4] = 2;

    showBoard();
}

ボードの表示

盤上の駒を表示します。bored配列をループでそれぞれ取り出します。さらに1マスずつループし、1なら●、2なら○、0なら□というようにlistに追加して1列ごと表示します。それと同時に色のカウントも行い、白黒の数を最後に表示します。

game.java
public void showBoard() {

    white = 0;
    black = 0;

    //arrayListに数字と対応する駒を入れて表示と各色のカウント
    for (int[] nums : bored) {

        ArrayList<String> list = new ArrayList<>();

        for (int a : nums) {
            if (a == 0) {
                list.add("□");
            } else if (a == 1) {
                list.add("●");
                black++;
            } else if (a == 2) {
                list.add("◯");
                white++;
            }
        }

        System.out.println(list);

    }

    System.out.println("黒:" + black + "個");
    System.out.println("白:" + white + "個");
}

ターン

入力された位置のy,x座標の数字を9個の(9方向分の)裏返すメソッドに渡します。1つも裏返せてない場合やもう駒が置かれている場合は0を、showBoredでカウントしてある色の数の片方が0になり決着がついた場合は-1を返すようになっています。

game.java
public int turnOver(int y, int x, int num) {

    //裏返した駒の合計
    int sumReverse = 0;
    //自分の色(数字)のセット
    colour = num;

    //置く場所が空なら
    if (bored[y][x] == 0) {

        sumReverse += turnUp(y,x);
        sumReverse += turnDown(y,x);
        sumReverse += turnLeft(y,x);
        sumReverse += turnRight(y,x);
        sumReverse += turnRightUp(y,x);
        sumReverse += turnRightDown(y,x);
        sumReverse += turnLeftUp(y,x);
        sumReverse += turnLeftDown(y,x);

    }

    showBoard();

    //どちらか一色になったら
    if (white == 0 || black == 0) {
        return -1;
    }

    return sumReverse;

}

裏返し

全方向だと長くなってしまうので、例として上方向と斜め左下を裏返すものを載せました。駒が置かれた位置が引数のyとxになります。それぞれの方向の駒を調べたいため、上方向ならyから1ずつ引き・斜め左下ならxから1引きyに1を足す・・・という風にして調べていきます。次が相手の駒である限りマス目を移っていき、自分の駒にたどり着くまでループをします。途中でマスが空の場合や盤外になった場合は、何も裏返せていないため0を返します。自分の駒にたどり着いたら、そこの位置と置いた位置の差だけループして裏返し、その数を返します。

//上方向
public int turnUp(int y, int x) {

    //次のマスのインデックスへ
    int targetY = y - 1;

    //次のマス目が盤上にあるか
    if(targetY < 0) {
        return 0;
    }

    //相手の駒である限りループ(空または自分の色でない)
    while(bored[targetY][x] != 0 && bored[targetY][x] != colour) {

        //次のマスへ
        targetY--;

        //盤外なら終了
        if(targetY < 0) {
            break;
        }

        //自分の駒までたどり着いたら
        if (bored[targetY][x] == colour) {

                //自分の色にした駒の数
                int count = 0;

                //置いた位置からたどり着いた自分の駒の分ループして色を変える
                for (; targetY < y; y--) {

                    bored[y][x] = colour;
                    count++;
                }

                //置いた駒を引いて、裏返した相手の駒の数を返す
                return count - 1;
        }

    }

    return 0;

}

//斜め左下
public int turnLeftDown(int y, int x) {

    int targetX = x - 1;
    int targetY = y + 1;

    if (targetX < 0 || targetY > 7) {
        return 0;
    }

    while(bored[targetY][targetX] != 0 && bored[targetY][targetX] != colour) {

        targetX--;
        targetY++;

        if (targetX < 0 || targetY > 7) {
            break;
        }

        if (bored[targetY][targetX] == colour) {

                int count = 0;

                for (;targetX < x; x--, y++) {

                    bored[y][x] = colour;
                    count++;
                }

                return count - 1;
        }

    }

    return 0;

}

結果の表示

showBoredで数をカウントし直して、白黒比べて結果を表示します。

game.java
public void showResult() {

    showBoard();

    if (black < white) {
        System.out.println("白の勝ち");
    } else if (white < black) {
        System.out.println("黒の勝ち");
    } else {
        System.out.println("引き分け");
    }

}

今後追加したいところ

1.対戦相手の制作
今は交互に入力して対戦してく形式ですが、一人でも使えるようにしたいです。
更新しました。javaでCUIオセロの制作その2

2.パス機能
オセロのルールで自分の駒をどこに置いても相手の駒が裏返せない場合(まだ自分の駒が残っていてパーフェクトではない)は、パスになり相手のターンになります。まだこの機能がなく、不完全なオセロなので追加したいです。

参考にしたサイト

Javaでオセロゲームを作成を現役エンジニアが解説【初心者向け】
Javaで普通のオセロをつくった話
Javaでオセロを書いてみました。

スキャナで取得した値を指定したデータ型の値として取得する
ArrayListの使い方

3
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0