Javaでオセロゲームを作成を現役エンジニアが解説【初心者向け】

初心者向けにJavaでオセロゲームを作成する方法について解説しています。最初にオセロを実装するための基本設計について解説します。次にその手順に沿って、サンプルコードを作成していきます。それぞれの処理について見ていきましょう。

TechAcademyマガジンはオンラインのプログラミングスクールTechAcademy [テックアカデミー]が運営する教育×テクノロジーのWebメディアです。初心者でもすぐ勉強できる記事が2,000以上あります。

Javaでオセロゲームを作成する方法について解説します。実際にプログラムを書いて説明しているので、ぜひ理解しておきましょう。

 

なお本記事は、TechAcademyのJava講座の内容をもとに作成しています。

 

 

田島悠介

今回は、Javaに関する内容だね!

大石ゆかり

どういう内容でしょうか?

田島悠介

オセロゲームを作成する方法について詳しく説明していくね!

大石ゆかり

お願いします!

 

オセロゲームのアルゴリズム

javaでオセロゲームを作成します。8×8の表の中に”○”または”●”を配置していきます。

駒の位置は座標で管理します。座標はx方向に0~7、同じくy方向に0~7とします。座標中にどの駒がおかれえいるかどうかはString[8][8]の多次元配列で管理します。

オセロゲームにおいて一番肝心となるのが同色で挟んだ駒をひっくり返す部分です。ある位置に駒をおくと、その上、下、右、左、左上、右上、左下、右下の8方向に配置済みの駒を確認し今おいた駒と挟むことができる場合はひっくり返します。

例として右上方向の配置を確認してひっくり返すアルゴリズムを記述します。

  1. 指定されたx座標をx、y座標をyとします
  2. 右上方向の隣の駒が相手の駒であるかどうかを確認します
  3. 隣の駒の座標はx+1 y-1 ですので、配列[y – 1][x + 1] の要素の値です
  4. 隣の駒が自分の駒の場合は続きの処理はありません
  5. 相手の駒の場合は、さらにその右上方向の駒をひとつづつ確認します。ここでは自駒からの距離をあらわすiをインクリメントしつつfor文で処理をします
  6. 自分の駒がある場合は挟まれた位置にある駒を全て自分の駒として多次元配列の値を上書きします
  7. 多次元配列の値を上書きする処理はfor文を使って行います
  8. 自分の駒がない場合や、座標が8×8の表から出てしまう場合は処理を終了します。

このような処理を8方向分作成し、駒を配置するごとに8方向全てを確認し駒をひっくり返します。

駒のひっくり返しが終った状態の情報になっている配列の要素をひとつづつ取り出し、表として出力します。
表の出力は2重for文を使って行います。

表を出力後に、各駒の数の集計と次うつ駒の入れ替えを行います。今回クラスは2つ作成します。座標(多次元配列)としてのオセロ版クラスとコンソールからの入力値をオセロ版へ伝えるメインクラスです。

メインクラスでは実行開始後オセロ版の初期化(座標の要素をすべてクリアし、駒を最初の配置に設定する)後はwhile文でまだ駒が配置されていない座標がある間は、コンソールからの座標入力を促します。

 

Javaでオセロゲームを作成してみよう

オセロ版クラスです。

public class Board {

  //ゲーム実行中フラグ
  static boolean game = true;

  //オセロ版に対応した多次元配列
  static String[][] board = new String[8][8];

  static final String EMPTY = " ";
  static final String BLACK = "●";
  static final String WHITE = "○";

  static String stone;
  static String rev_stone;

  static public void initialize() {

    //オセロ版の要素を全てクリアする
    for (int i = 0; i < 8; i++) {

      for (int j = 0; j < 8; j++) {

        board[i][j] = EMPTY;

      }

    }

    //初期状態の配置
    board[3][3] = BLACK;
    board[3][4] = WHITE;
    board[4][3] = WHITE;
    board[4][4] = BLACK;

    //次うつ駒の色を指定
    stone = BLACK;
    rev_stone = WHITE;

    //ゲーム実行中フラグ
    game = true;

  }

  static public void showBoard() {

    //まだ空いている座標があるか
    boolean existempty = false;
    //黒い駒の数集計用
    int cnt_black = 0;
    //白い駒の数集計用
    int cnt_white = 0;

 

    //オセロ版を描写する
    int i = 0;
    System.out.println(" |0 |1 |2 |3 |4 |5 |6 |7 |");
    System.out.println("――――――――――――――");
    for (String[] sarr : board) {

      System.out.print(i + " |");
      for (String s : sarr) {

        System.out.print(s);
        System.out.print("|");

        //空いている座標があるか、各駒数の集計
        if (s.equals(EMPTY)) {
          existempty = true;
        } else if (s.equals(BLACK)) {
          cnt_black++;
        } else if (s.equals(WHITE)) {
          cnt_white++;
        }

      }
      System.out.println();
      System.out.println("――――――――――――――");

      i++;

    }

    System.out.println(BLACK + ":" + cnt_black);
    System.out.println(WHITE + ":" + cnt_white);
    System.out.println("――――――――――――――");

    if (existempty) {

      System.out.println(stone + "のターンです");
    } else {
      System.out.println(stone + "ゲーム終了!");
      game = false;
    }

  }

  static public void setStone(int x, int y) {

    // 版外の座標を指定した場合
    if (x > 7 || y > 7) {
      System.out.println("その位置に駒はおけません");
    }

    // 駒を配置できる場合
    if (board[y][x].equals(EMPTY)) {
      board[y][x] = stone;

      // ひっくり返す処理
      turnStone(x, y);

      // 次うつ駒の設定
      String next_rev_storn = stone;
      stone = rev_stone;
      rev_stone = next_rev_storn;

      // オセロ版の描写
      showBoard();

    } else {

      // 既に駒がおいてある位置を指定した場合
      System.out.println("その位置に駒はおけません");
    }

  }

  static public void turnStone(int x, int y) {

    // 8方向の駒の配置を確認し、ひっくり返す

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

  }

  static public void turnLeftUp(int x, int y) {
    if (y > 1 && x > 1) {

      // となりの駒
      String next = board[y - 1][x - 1];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (x - i < 0 || y - i < 0 || board[y - i][x - i].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y - i][x - i].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y - t][x - t] = stone;
            }
            break;
          }
        }
      }

    }
  }

  static public void turnUp(int x, int y) {
    if (y > 1) {

      // となりの駒
      String next = board[y - 1][x];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (y - i < 0 || board[y - i][x].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y - i][x].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y - t][x] = stone;
            }
            break;
          }
        }
      }

    }
  }

  static public void turnRightUp(int x, int y) {
    if (y > 1 && x < 6) {

      // となりの駒
      String next = board[y - 1][x + 1];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (x + i > 7 || y - i < 0 || board[y - i][x + i].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y - i][x + i].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y - t][x + t] = stone;
            }
            break;
          }
        }
      }

    }
  }

  static public void turnDown(int x, int y) {
    if (y < 6) {

      // となりの駒
      String next = board[y + 1][x];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (y + i > 7 || board[y + i][x].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y + i][x].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y + t][x] = stone;
            }
            break;
          }
        }
      }

    }
  }

  static public void turnRight(int x, int y) {
    if (x < 6) {

      // となりの駒
      String next = board[y][x + 1];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (x + i > 7 || board[y][x + i].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y][x + i].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y][x + t] = stone;
            }
            break;
          }
        }
      }

    }
  }

  static public void turnLeftDown(int x, int y) {
    if (y < 6 && x > 1) {

      // となりの駒
      String next = board[y + 1][x - 1];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (x - i < 0 || y + i > 7 || board[y + i][x - i].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y + i][x - i].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y + t][x - t] = stone;
            }
            break;
          }
        }
      }

    }
  }

  static public void turnLeft(int x, int y) {
    if (x > 1) {

      // となりの駒
      String next = board[y][x - 1];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (x - i < 0 || board[y][x - i].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y][x - i].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y][x - t] = stone;
            }
            break;
          }
        }
      }

    }
  }

  static public void turnRightDown(int x, int y) {
    if (y < 6 && x < 6) {

      // となりの駒
      String next = board[y + 1][x + 1];

      // となりの駒が裏駒の場合
      if (next.equals(rev_stone)) {

        // さらにその一つとなりから順に確認
        for (int i = 2; true; i++) {

          if (x + i > 7 || y + i > 7 || board[y + i][x + i].equals(EMPTY)) {
            // 駒がない場合終了
            break;
          } else if (board[y + i][x + i].equals(stone)) {
            // 自駒の場合

            // あいだの駒をすべて自駒にひっくりかえす
            for (int t = 1; t < i; t++) {
              // 配列の要素を上書き
              board[y + t][x + t] = stone;
            }
            break;
          }
        }
      }

    }
  }

}

実行クラスです

import java.util.Scanner;

public class Othello {

  public static void main(String[] args){

    Board.initialize();
    Board.showBoard();

    //コンソールからの入力を受け付ける
    Scanner s = new Scanner(System.in);

    //ゲーム実行中フラグがtrueのあいだループする
    while(Board.game){

      System.out.print("駒をおくx座標を入力してください:");
      int x = s.nextInt();

      System.out.print("駒をおくy座標を入力してください:");
      int y = s.nextInt();

      Board.setStone(x, y);

    }

    s.close();
  }

}

 

実行すると

|0 |1 |2 |3 |4 |5 |6 |7 |
――――――――――――――
0 | | | | | | | | |
――――――――――――――
1 | | | | | | | | |
――――――――――――――
2 | | | | | | | | |
――――――――――――――
3 | | | |●|○| | | |
――――――――――――――
4 | | | |○|●| | | |
――――――――――――――
5 | | | | | | | | |
――――――――――――――
6 | | | | | | | | |
――――――――――――――
7 | | | | | | | | |
――――――――――――――
●:2
○:2
――――――――――――――
●のターンです
駒をおくx座標を入力してください:

のように座標を促します
駒をおくx座標を入力してください:2
駒をおくy座標を入力してください:4
|0 |1 |2 |3 |4 |5 |6 |7 |
――――――――――――――
0 | | | | | | | | |
――――――――――――――
1 | | | | | | | | |
――――――――――――――
2 | | | | | | | | |
――――――――――――――
3 | | | |●|○| | | |
――――――――――――――
4 | | |●|●|●| | | |
――――――――――――――
5 | | | | | | | | |
――――――――――――――
6 | | | | | | | | |
――――――――――――――
7 | | | | | | | | |
――――――――――――――
●:4
○:1
――――――――――――――
○のターンです

入力した座標に応じて駒が配置され、挟まれた駒がひっくりかえります。最終的に、全ての座標が埋まるとゲーム終了です

○のターンです
駒をおくx座標を入力してください:7
駒をおくy座標を入力してください:2
|0 |1 |2 |3 |4 |5 |6 |7 |
――――――――――――――
0 |○|○|○|○|○|○|○|○|
――――――――――――――
1 |●|●|●|●|●|●|○|○|
――――――――――――――
2 |●|○|○|○|●|○|○|○|
――――――――――――――
3 |●|○|●|●|○|●|○|○|
――――――――――――――
4 |●|●|●|○|●|○|○|●|
――――――――――――――
5 |○|●|○|○|○|○|○|●|
――――――――――――――
6 |○|●|●|○|○|○|○|●|
――――――――――――――
7 |○|○|○|○|○|○|○|●|
――――――――――――――
●:23
○:41
――――――――――――――
●ゲーム終了!

 

[PR] Javaで挫折しない学習方法を動画で公開中

監修してくれたメンター

長屋雅美

独立系SIerで7年勤務後、現在はフリーのエンジニアとして自宅をオフィスとして活動しています。
JavaやC♯、shellscriptを用いた開発を主に担当し、TechAcademyではJavaコースを担当しています。

 

大石ゆかり

内容分かりやすくて良かったです!

田島悠介

ゆかりちゃんも分からないことがあったら質問してね!

大石ゆかり

分かりました。ありがとうございます!

オンラインのプログラミングスクールTechAcademyでは、Java講座を開催しています。

JavaやServletの技術を使ってWebアプリケーションの開発を学ぶことができます。

現役エンジニアがパーソナルメンターとして受講生に1人ずつつき、マンツーマンのメンタリングで学習をサポートし、最短4週間で習得することが可能です。

また、現役エンジニアから学べる無料のプログラミング体験会も実施しているので、ぜひ参加してみてください。