Java ミニゲーム ソース付き 〜テスト駆動開発:文言出力部品を作る〜

今回は、RPGゲームでよくある文字を1文字ずつ読めるスピードで出力する部品を作ります。

今まで作成したテキストRPGゲームに追加します。
現状は、こんな感じで動きます。

文字の出力は、一括で出力するのでゲームっぽくありません。どちらかというとログ出力っぽいです(笑)

文字出力部品を作る

現状は、System.out.println()を使用しています。これは引数にある文字列を標準出力に出力します。
標準出力 = System.outになります。

問題

どーやって1文字ずつ出力するか?
とりあえずは、テスト駆動開発にしますので、テストケースを作成します。

毎度おなじみJUnit

JUnitを使用してテストクラスを動かします。

作成手順

  1. Eclipseのプロジェクトに「test」フォルダを作成する
  2. テストするクラスと同じパッケージを作成する
  3. テストするクラスの後にTestをつけたクラスを作成する
  4. 〜Testクラスにテストケースを作成する
具体的に。。。

実装した時の動画を作成しました。

詳細は以下のようになります。
上の手順4以降の記載になります。

JUnitをビルドパスに追加


動画にもあるのですが、上のような画面でJUnitを追加します。細かい部分は動画にありますので参照ください。

テストケースを作る

今回のテストケースはコンソールにゆっくりと表示できれば良いので、動かすだけになります。
故に、コードは下のようになります。

public class PrintUtilsTest {
    @Test
    public void testPrint01() {
        String mes = "アイウエオカキクケコ。。。。";
        try {
            PrintUtils.print(mes);
        } catch (InterruptedException e) {
            fail(e.getMessage());
        }
    }
}

今回の作成するクラスは、PrintUtilsクラスです。テストクラスは上のコードにある通りです。

作成するクラスをガワだけ作ったら、あとは、テストケースで呼び出してやる処理を実装してやるだけです。

あとは、実装→起動→修正→確認を繰り返して終了です。

シンプルなもんです(笑)

JUnitを使用したときの再生リストへのリンクです。

JUnitで10進数を2進数に変換する処理を実装

テストファーストで、補数算出メソッドの実装

EclipseでJUnitの起動設定~テストクラスの作成1

EclipseでJUnitの起動設定~テストクラスの作成2

Java テスト駆動で引き算のメソッドを作る

関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JavaFX関連ページ

  1. Eclipse SceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  4. Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜

ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

オブジェクト指向関連ページ

  1. [オブジェクト指向の概念1〜OracleDocのチュートリアル1〜](https://zenryokuservice.com/wp/2019/10/301. /%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5-%e3%80%9coracledoc%e3%81%ae%e3%83%81%e3%83%a5%e3%83%bc%e3%83%88%e3%83%aa%e3%82%a2%e3%83%ab%ef%bc%91/)
  2. オブジェクト指向の概念2〜クラスとは〜

Java ミニゲーム ソース付き 〜ここまでのまとめ〜

今回は、ミニゲーム作成で作ったものをまとめます。
まとめたのちに、次の実装はどうしようか決めようと考えた次第です。

Gitリポジトリはこちらです。下の方に、接続方法などの記事へのリンクがあります。

オブジェクト指向について

オブジェクト指向について、Oracle認定の書籍を参考にまとめた記事です。参考にどうぞ

大まかな処理フロー

GameMainクラス
クラスの記述内容がコードより、ライセンスのJavaDoc部分が大半を占める状態です(笑)

public class GameMain {
    public static void main(String[] args) {
        // ゲームクラス
        TextRpgGame main = new TextRpgGame();
        // 初期処理
        main.init();
        while (true) {
            // 入力受付
            String in = main.input();
            if ("bye".equals(in)) {
                break;
            }
            // データの更新
            if (main.update(in)) {
                // 画面の描画
                main.render();
            }
        }
    }
}

メインメソッドを持っていて、ループ処理を行っています。
while(true) { ... }の部分が俗にいう「ゲームループ」の部分になります。

処理の説明としては、以下の通りです。

  1. TextRpgGameのインスタンスを取得
  2. 初期処理を行う
  3. ゲームループ開始
  4. 標準入力を受け取る
  5. "bye"と入力されたらアプリの終了
  6. 入力データにより、ゲームで使用するデータ(プレーヤーとモンスター)の情報を更新する
  7. 表示するステータスを再描画

こんな感じの処理を行っています。

TextRpgGameについて

メインメソッドから呼ばれるそれぞれのメソッドを実装しています。
具体的には下のものです。

  1. init(): 初期処理を行う。ステータスの表示など
  2. input(): 標準入力を受け取る。
  3. update (): データの更新を行う。使用しているプレーヤークラス、モンスタークラスのデータを更新します。主にHPの値を更新します。
  4. render(): ステータスの更新、モンスターを倒したなどの戦闘終了の文言を表示する。
public class TextRpgGame {
    /** コマンド:たたかう */
    private static final String ATTACK = "1";
    /** コマンド:ぼうぎょ */
    private static final String DEFFENCE = "2";
    /** コマンド:にげる */
    private static final String ESCAPE = "3";

    /** 入力部品 */
    private Scanner scan;
    /** プレーヤー */
    private Player player;
    /** モンスター */
    private Monster monster;

    /** 初期表示を行う */
    public void init() {
        player = new Player(20, 10, 1, "プレーヤー");
        monster = new Monster(10, 5, 1, "たくのじ");

        System.out.println(monster.getName() + "が現れた!");
        monster.say();
        scan = new Scanner(System.in);
    }

    /** 入力処理 */
    public String input() {
        return scan.next();
    }

    /** 入力後に行う処理 */
    public boolean update(String input) {
        if (CheckerUtils.isNumber(input, CheckerUtils.REG_1_TO_3) == false) {
            System.out.println("1-3を入力してください。: " + input);
            return false;
        }
        // コマンド実行後の計算
        if (ATTACK.equals(input)) {
            // モンスターへダメージ
            int monsterDamage = this.calcAttack(player.attack(), monster.deffence(), player.getName());
            int monsterResult = monster.getHp() + monsterDamage;
            monster.setHp(monsterResult);
        }
        // モンスターの攻撃
        int monsterAttack = this.calcAttack(player.deffence(), monster.attack(), monster.getName());
        int playerResult = player.getHp() + monsterAttack;
        player.setHp(playerResult);

        return true;
    }

    /** 
     * 画面を更新する。
     * @return ture: 終了 false: 続く
     */
    public boolean render() {
        if (monster.getHp() > 0) {
            monster.say();
        } else if (player.getHp() <= 0 ) {
            System.out.print(player.getName() + "はたおれてしまった。");
            return true;
        } else {
            monster.lastMessage();
            System.out.print(monster.getName() + "をやっつけた。");
            return true;
        }
        return false;
    }

    public void viewStatus() {
        viewStatus(player.getHp(), player.getMp(), monster.getHp(), monster.getMp());
    }

    private void viewStatus(int playerHp, int playerMp, int monsterHp, int monsterMp) {
        String line1 = "たたかう: 1   プレーヤー   たくのじ";
        String line2 = "ぼうぎょ: 2   HP: A1     HP: B1";
        String line3 = "にげる : 3   MP: A2     MP: B2";
        // 値を入れ替える
        line2 = line2.replace("A1", String.format("%02d", playerHp)).replace("B1", String.format("%02d", monsterHp));
        line3 = line3.replace("A2", String.format("%02d", playerHp)).replace("B2", String.format("%02d", monsterHp));

        System.out.println(line1);
        System.out.println(line2);
        System.out.println(line3);
    }

    private int calcAttack(int attack, int deffence, String attackerName) {
        int result = 0;
        System.out.println(attackerName + "のこうげき");
        if (attack > deffence) {
            result = deffence - attack;
            System.out.println(Math.abs(result) + "のダメージ!");
        } else {
            System.out.println("こうげきを、はじいた!");
        }
        return attack > deffence ? deffence - attack : 0;
    }
}

じゃんけんゲームから比べてみると、コード量が増えたように見えます。がビビることはありません。

ポイントはメソッド単位で処理を見ることです。
そうすれば、12〜16行くらいなもんです。物により長大なものもありますが。。。

そして、気をつけなければいけないのが、フィールド変数と以下のクラスです。

スーパークラス(親クラス)

今回の実装では、PlayerとMonsterクラスが似たような処理だったので、同じ処理はスーパークラスで管理することにしました。
TextRpgGame#init()でインスタンスを取得している。2つのクラスが実装しています。
具体的には、スーパークラス(親クラス)のCharactorクラスを継承して実装している。ということです。

そして、ネーミングが悪いのもあるのですが、CharactorクラスはJavaのライブラリの中にもありますのでちょっとだけ注意です。

PlayerクラスとMonsterクラスはデータを保持するクラスです。戦闘して互いのHPを削り合う形でゲームは進むので、ほぼデータクラスです。
「たたかう、ぼうぎょ」などのコマンドはそれぞれのクラスに実装します。PlayerとMonsterでは攻撃方法が違うからです。

PlayerクラスとMonsterクラス

フィールド変数とGetter, Stterを主軸に実装したクラスです。
しかし、HPなどのフィールドはスーパークラスのCharactorクラスへ移動しました。

public abstract class Charactor {
    /** 名前 */
    protected String name;
    /** HP */
    protected int hp;
    /** MP */
    protected int mp;
    /** Level */
    protected int level;
    /** 攻撃力 */
    protected int atack;
    /** 防御力 */
    protected int defence;
    /** 武器 */
    protected Wepons wepons;
    /** 防具 */
    protected Armors armor;

    /** 抽象メソッド: 攻撃 */
    public abstract int attack();

    /** 抽象メソッド: 防御 */
    public abstract int deffence();
 ・
 ・
 ・
}

このように、スーパークラスでHPなどは管理しています。
これを継承するPlayerは下のようにコンストラクタとスーパークラスの抽象メソッドをオーバーライドします。

public class Player extends Charactor {

    /** コンストラクタ */
    public Player(int hp, int mp) {
        this.hp = hp;
        this.mp = mp;
    }

    /** コンストラクタ */
    public Player(int hp, int mp, int level, String name) {
        this.hp = hp;
        this.mp = mp;
        this.level = level;
        this.name = name;
        // 装備を行う
        setArms();
    }

    /**
     * 装備を行う。
     */
    private void setArms() {
        this.wepons = new Wepons("ひのきのぼう", 5);
        this.armor = new Armors("ぬののふく", 5);
    }
    /**
     * 攻撃コマンドのメソッド。
     * 武器の攻撃力を返却する。
     * @return 武器の攻撃力
     */
    @Override
    public int attack() {
        this.atack = wepons.getAttackPoint();
        return this.atack;
    }

    @Override
    public int deffence() {
        this.defence = armor.getDeffencePoint();
        return this.defence;
    }
}

そして、setArms()というメソッドでは、武器と防具クラスを生成して、Playerクラスのフィールドに設定しています。
名前の通りに、Weponsは武器、Armorsは防具を示しそれぞれ攻撃力と防御力を算出します。
現段階では、攻撃力と防御力がそのまま設定されていますが。。。

とりあえずは、こんな感じで作っています。
GitからPULLして遊んでみてください。
やり方は、こちらの動画にもあります。

記事もあります。
Eclipse GitからPULL

下の方に、関連ページの一覧がありますのでそちらもどうぞ



関連ページ

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

<ins class="adsbygoogle"
style="display:block"
data-ad-format="fluid"
data-ad-layout-key="-6t+ed+2i-1n-4w"
data-ad-client="ca-pub-7367785927150581"
data-ad-slot="3284986237">

関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Java ミニゲーム ソース 〜じゃんけんゲーム in Console 完成〜

コンソール版のじゃんけんゲームを作成しました。
しかし、とりあえず動く状況なので。。。

これに、細かい部分を作ってしまおうと思います。
まずは、バグ退治です。。。がしかしその前に処理の概要をいかに記載します。

  1. プログラムを起動する(Mainクラスのメインメソッド)
  2. コマンドで「exe」を入力してエンターキー押下
  3. じゃんけんゲームの起動(FirstCls#execute())
  4. じゃんけんゲームの入力を待つ
  5. 「1〜3」の入力かチェック
  6. 乱数を生成し CPUの手とする
  7. 両者の勝敗判定を行う

そして、修正した結果(差分)はこちらのリンクで確認できます。

バグのないようですが、じゃんけんゲームの入力時に「1〜3以外の値」が入力された時にMapから値が取得できず。。。
playerの手がnullになります。そして、処理は次へ行ってしまうので、「???」となります。

具体的なコードは下の部分です。
メインメソッドは下の部分で、FirstCls#handleInput()を呼び出しています。
Mainクラス

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String input = scan.next();

        FirstCls first = new FirstCls();
        if ("exe".equals(input)) {
            first.execute(scan);
        }
        boolean isNumber = first.isNumberString(input);
        if (isNumber) {
            System.out.println(input + "は数字です。");
        } else {
            System.out.println(input + "は数字ではありません。");
        }
    }
}

FirstCls#execute()でじゃんけんゲームが開始されます。

FirstClsクラス

public void handleInput(String input) {
    System.out.println("入力値: " + input);
    if (isNumberString(input)) {
        System.out.println(input + "は、数字です");
    } else {
        System.out.println(input + "は、数字ではありません");
    }
}

クラス名がリンクになっていますが、これはGithubへのリンクになります。

修正する(修正内容)

修正方法としては、チェック処理を入れてやります。
そして「クラスの使い方」という観点から、チェッククラスを作成します。

余計な音が履いていますが、これを作成した時の動画です。

ここで追加した実装はCheckUtilクラスです。
このクラスは、実装の過程で、メソッドが増えていきましたが、まぁそんなもんでしょう。

ちなみに、このクラスのメソッドは、全て「静的メソッド」と呼ばれるメソッドです。
呼び出す時にクラス名.メソッド名という形で、呼び出します。

チェック処理

このチェック処理のポイントはズバリ「正規表現」です。
使用している以下の正規表現は0〜9の文字にマッチするのであればTRUEを変えす(そうでなければFALSEを返す)メソッドを使用しています。
そして、同じ名前のメソッドがあります。並べてみると違いが一目瞭然です。

public static boolean isNumber(String numberStr) {};
public static boolean isNumber(String numberStr, String range) {};

そして、Stringクラスにあるメソッドを使用しています。この引数に渡す文字列が「正規表現」であり、このメソッドの返り値が判定結果になります。

numberStr.matches(range)

オーバーロード

上のような実装のことを「メソッドのオーバーロード」と言います。親クラスのメソッドを上書きする「オーバーライド」とこんがらないように気をつけてください。

処理の内容に関してですが
・引数が1つのメソッドは単純に「数字の入力かチェック」
・引数が2つのメソッドは、数字の範囲を指定してチェック」
というように、処理の内容が若干違います。

初めに「0-9の入力(数値入力)チェック」を作成したのですが、じゃんけんで使用するのは1〜3までだけではないか。。。と気がついたので、数字入力チェックに「範囲」を追加しました。

public class CheckUtil {
    /** 0-9(数字)判定をする時の正規表現 */
    public static final String REGREX = "[0-9]";

    /** 1-3までの判定に使用する正規表現 */
    public static final String REG_1_TO_3 = "[1-3]";

    /**
     * 必須入力チェック、第二引数にあう正規表現でのチェックを行う
     * 
     * @param numberStr 検証する文字列
     * @param range 判定用の正規表現
     * @return true: 正規表現にマッチ false: マッチしない
     */
    public static boolean isNumber(String numberStr, String range) {
        // 正規表現で判定します。数字のrangeに当てはまる時にtrue
        if (isEmpty(numberStr) && numberStr.length() != 1) {
            return false;
        }
        if (numberStr.matches(range)) {
            return true;
        }
        return false;   }
    /**
     * 引数の1文字が数字かどうかの判定をする。。
     * 
     * @param numberStr
     * @return true: 引数が0-9 false: 0-9ではない
     */
    public static boolean isNumber(String numberStr) {
        // 正規表現で判定します。数字の0-9に当てはまる時にtrue
        if (isEmpty(numberStr) && numberStr.length() != 1) {
            return false;
        }
        if (numberStr.matches("[0-9]")) {
            return true;
        }
        return false;
    }

    /**
     * 引数に渡した文字列が、Null、またはから文字("")
     * @param str 判定する文字列
     * @return ture; 
     */
    public static boolean isEmpty(String str) {
        if (str == null || "".equals(str)) {
            return true;
        }
        return false;
    }
}

ちなみに、静的メソッドは、static修飾子をつけて実装します。インスタンスを生成しないので、メモリの節約になりますが、作りすぎると余計な負担(メモリ使用)になるので注意です。

まとめ

今までに作成したクラスFirstClsでの処理を修正しました。
くどいようですが、Mainメソッドは修正していません。

そして、追加したCheckUtilクラスはチェック担当のクラスです。

なので、このクラスにはチェック処理しか追加しません。



関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JavaFX関連ページ

  1. Eclipse SceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  4. Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜

ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

Java ミニゲーム ソース 〜じゃんけんゲーム in Console 〜

今回は、Javaで作成するミニゲームと題して下のゲームを作成したいと思います。

じゃんけんゲーム

毎度おなじみ「じゃんけんゲーム」シンプルに、楽しめるゲームとして最もポピュラーなものだと思います。
それをJava言語を使ってコンソールゲームにしました。
しかし、バグもあります。。。

Mainメソッド

メインメソッドは変更しません。前回のコードはこちらから見れます。※前回の記事です。

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String input = scan.next();

        FirstCls first = new FirstCls();
        if ("exe".equals(input)) {
            first.execute(scan);
        }
        boolean isNumber = first.isNumberString(input);
        if (isNumber) {
            System.out.println(input + "は数字です。");
        } else {
            System.out.println(input + "は数字ではありません。");
        }
    }
}

今回の実装はFirstCls#executeから始めます。。。

実際に作ってみた

ここで、Mainメソッド変更しません。とはじめに記載したのではじめが分かりづらいです。起動したら「exe」と入力する必要がありました(笑)
そして、実装したコード(FirstCls)は下のようなコードです。
※使用していないゴミコードは削除しています。全体はこちらのGithubで見ることができます。

public class FirstCls {
    /** システム(OS)で使用する改行コード */
    private static final String SEPARATOR = System.getProperty("line.separator");
    /** プレーヤの勝利フラグ */
    private static final Integer WIN = 1;
    /** プレーヤの敗北フラグ */
    private static final Integer LOOSE = 2;
    /** プレーヤの引き分けフラグ */
    private static final Integer DRAW = 3;

    public void execute(Scanner scan) {
        System.out.println("*** EXECUTEを起動します ***");
        // じゃんけんの手のマップ
        Map<String, String> map = createJankenTe();
        // じゃんけんの勝敗マップ
        Map<String, Integer> judgeMap = createJudgement();
        Random rnd = new Random();
        while(true) {
            System.out.print("じゃんけん。。。");
            String player = scan.next();
            int cpu = rnd.nextInt();
            System.out.println("あなた:" + map.get(player) + " CPU:" + map.get(String.valueOf(cpu)));
            if (judgeMap.get(player + cpu) == WIN) {
                System.out.println("You win!");
            } else if (judgeMap.get(player + cpu) == LOOSE) {
                System.out.println("You loose!");
            } else if (judgeMap.get(player + cpu) == DRAW) {
                System.out.println("Draw! one more time ...");
                continue;
            }
            System.out.println(SEPARATOR + "もう一度やる?" + SEPARATOR + "y: もう一度 n: やめる");

            String more = scan.next();
            if ("n".equals(more)) {
                break;
            } 
        }
    }

    /**
     * じゃんけんの手を設定したMapを返却する
     * @return Map
     */
    private Map<String, String> createJankenTe() {
        Map<String, String> map = new HashMap<>();
        map.put("1", "グー");
        map.put("2", "チョキ");
        map.put("3", "パー");
        return map;
    }

    /**
     * じゃんけんの勝敗パターンをMapに設定
     * @return Map
     */
    private Map<String, Integer> createJudgement() {
        Map<String, Integer> map = new HashMap<>();
        map.put("12", WIN);
        map.put("23", WIN);
        map.put("31", WIN);
        map.put("21", LOOSE);
        map.put("32", LOOSE);
        map.put("13", LOOSE);
        map.put("11", DRAW);
        map.put("22", DRAW);
        map.put("33", DRAW);
        return map;
    }
}

こんな感じです。

処理内容

Mainメソッドは。。。割愛します。
FirstCls#execute()では、ジャンケンで取りうる手(グー・チョキ・パー)をMapに設定しておき、1~3の入力に対応してそれぞれの手を表示、じゃんけんの判定にしようします。

勝敗の判定には、全てのパターンをMapに記憶してプレーヤーの手とCPUの手を連結→プレーヤー:グー、CPU: チョキであれば"12"で勝敗マップからは「1」が取得できます。

1は勝利判定のフラグです。
詳細は上のコードに書いてありますので。。。

近くに、これの解説動画も作成いたします。

問題

バグがあるのですが、それはどこでしょうか?
<ヒント>
動かしてみるとわかります。

でわでわ。。。

関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜