icon
icon

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

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

テックアカデミーマガジンは受講者数No.1のプログラミングスクール「テックアカデミー」が運営。初心者向けにプロが解説した記事を公開中。現役エンジニアの方はこちらをご覧ください。 ※ アンケートモニター提供元:GMOリサーチ株式会社 調査期間:2021年8月12日~8月16日  調査対象:2020年8月以降にプログラミングスクールを受講した18~80歳の男女1,000名  調査手法:インターネット調査

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

 

そもそもJavaについてよく分からないという方は、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やServletの技術を使ってWebアプリケーション開発を習得できるオンラインブートキャンプJava講座を開催しています。

挫折しない学習方法を知れる説明動画や、現役エンジニアとのビデオ通話とチャットサポート、学習用カリキュラムを体験できる無料体験も実施しているので、ぜひ参加してみてください。

初心者・未経験でもできる。まずはテックアカデミーに相談しよう

プログラミングを独学で学習していて、このように感じた経験はないでしょうか?

  • ・調べてもほしい情報が見つからない
  • ・独学のスキルが実際の業務で通用するのか不安
  • ・目標への学習プランがわからず、迷子になりそう

テックアカデミーでは、このような 学習に不安を抱えている方へ、マンツーマンで相談できる機会を無料で提供 しています。
30分間、オンラインでどんなことでも質問し放題です。

「受けてよかった」と感じていただけるよう カウンセラーやエンジニア・デザイナー があなたの相談に真摯に向き合います。

「自分に合っているか診断してほしい」
「漠然としているが話を聞いてみたい」

こんなささいな悩みでも大丈夫です。

無理な勧誘は一切ありません ので、まずはお気軽にご参加ください。
※体験用のカリキュラムも無料で配布いたします。(1週間限定)

今なら参加者限定の割引特典付き! 無料相談を予約する