質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.33%

  • Java

    14464questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

[Java] Hit&Blow 表示の仕方

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 275
退会済みユーザー

退会済みユーザー

 前提・実現したいこと

こんばんは、Javaについての質問です。
課題にてHit&Blowをjavaを用いて作成しております。
あともう一歩で完成という段階まできたのですが、問題の条件の一部である、
「4桁の数字の先頭を0から始めてはならない」
「入力値は重複させないようにすること。(0blowと表示)」
という部分がどうしてもできず、困っております。
どなたかご教授願えませんでしょうか。
よろしくお願いいたします。

 問題文

javaを用いてHit&Blowを作成しなさい。また、以下の条件を踏まえることとする。

条件:
4桁の数字を探すゲームであること。
4桁の数字が正解するまで再入力させること。
答えの数は乱数を用いること。
4桁の数字の先頭を0から始めてはならない。
3366など、入力値は重複させないようにすること。( 0blowと表示させること )

 作成途中のソースコード

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class Tokubetsu5 {

    public static final String[] NUM_ARRAY = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};

    public static final int MAX_LENGTH = 4;

    public static void main(String[] args) throws IOException{
        Tokubetsu5 hb = new Tokubetsu5();
        hb.execute();
    }

    private void execute() throws IOException{

        String[] cpuNumArray = CpuNumArray();

        boolean clear = false;
        try(Scanner sc = new Scanner(System.in)){

            //攻略できるまでループ
            while(!clear){

                String[] playerNumArray = PlayerNum(sc);

                clear = checkHitAndBlow(cpuNumArray, playerNumArray);

            }
        }

        System.out.println("終了します");

    }


    private String[] CpuNumArray(){
        //数字の列を作成
        List<String> tempList = new LinkedList<String>(Arrays.asList(NUM_ARRAY));

        String[] CpuNum = new String[4];

        //4回繰り返し、数字をランダムで取得
        for(int i = 0; i < 4; i++){
            int num = (int)(Math.floor(Math.random() * (10-i)));
            //一度使用した数字はリストから削除

            CpuNum[i] = tempList.remove(num);
        }

        return CpuNum;

    }

    private String[] PlayerNum(Scanner sc) throws IOException{

        boolean Check = false;
        String line = null;

        //入力OKになるまで繰り返し
        check:
            while(!Check){

                System.out.println("4桁の数字を入力してください。");
                line = sc.nextLine();

                //文字数チェック
                if(line.length() > MAX_LENGTH){
                    System.out.println("入力した桁数が多いです");
                    continue;
                }else if(line.length() < MAX_LENGTH){
                    System.out.println("入力した桁数が少ないです");
                    continue;
                }


                Check = true;

            }

        return line.split("");
    }


    private boolean checkHitAndBlow(String[] cpuNumArray, String[] playerNumArray){

        int hitCount = 0;
        int blowCount = 0;

        //数字のチェック
        for(int i = 0; i < MAX_LENGTH; i++){
            for(int j = 0; j < MAX_LENGTH; j++){
                if(playerNumArray[i].equals(cpuNumArray[j])){
                    blowCount++;
                }
            }
        }

        for(int i = 0; i < MAX_LENGTH; i++){
            if(playerNumArray[i].equals(cpuNumArray[i])){
                blowCount--;
                hitCount++;
            }
        }

        System.out.println(hitCount + " Hit  " + blowCount + "Blow");

        if(hitCount == MAX_LENGTH){
            return true;
        }
        return false;
    }
}

 作成途中のソースコード(追記 2018.6.21)

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class Tokubetsu5 {

    public static final String[] NUM_ARRAY = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};

    public static final int MAX_LENGTH = 4;

    public static void main(String[] args) throws IOException{
        Tokubetsu5 hb = new Tokubetsu5();
        hb.execute();
    }

    private void execute() throws IOException{

        String[] cpuNumArray = CpuNumArray();

        boolean clear = false;
        try(Scanner sc = new Scanner(System.in)){

            //攻略できるまでループ
            while(!clear){

                String[] playerNumArray = PlayerNum(sc);

                clear = checkHitAndBlow(cpuNumArray, playerNumArray);

            }
        }
    System.out.println("正解です");
        System.out.println("終了します");

    }


    private String[] CpuNumArray(){
        //数字の列を作成
        List<String> tempList = new LinkedList<String>(Arrays.asList(NUM_ARRAY));

        String[] CpuNum = new String[4];

        //1回繰り返し、数字をランダムで取得
    for(int i = 1; i < 2; i++){
    int num = (int)(Math.floor(Math.random() * (10-i)));
            //一度使用した数字はリストから削除

            CpuNum[i] = tempList.remove(num);

        //解答確認用
        System.out.println(CpuNum[i]);

     //3回繰り返し、数字をランダムで取得  
        for(int j = 1; j < 4; j++){
            int num2 = (int)(Math.floor(Math.random() * (10-j)));
            //一度使用した数字はリストから削除

            CpuNum[j] = tempList.remove(num2);

        //解答確認用
        System.out.println(CpuNum[j]);
        }
    }

        return CpuNum;

    }

    private String[] PlayerNum(Scanner sc) throws IOException{

        boolean Check = false;
        String line = null;

        //入力OKになるまで繰り返し
        check:
            while(!Check){

                System.out.println("4桁の数字を入力してください。");
                line = sc.nextLine();

                //文字数チェック
                if(line.length() > MAX_LENGTH){
                    System.out.println("入力した桁数が多いです");
                    continue;
                }else if(line.length() < MAX_LENGTH){
                    System.out.println("入力した桁数が少ないです");
                    continue;
                }

                Check = true;

            }

        return line.split("");
    }

    private boolean checkHitAndBlow(String[] cpuNumArray, String[] playerNumArray){

        int hitCount = 0;
        int blowCount = 0;

        //数字のチェック
        for(int i = 0; i < MAX_LENGTH; i++){
            for(int j = 0; j < MAX_LENGTH; j++){
                if(playerNumArray[i].equals(cpuNumArray[j])){
                    blowCount++;

                }

            }
        break;
        }

        for(int i = 0; i < MAX_LENGTH; i++){
            if(playerNumArray[i].equals(cpuNumArray[i])){
                blowCount--;
                hitCount++;

            }
        }

        System.out.println(hitCount + " Hit  " + blowCount + "Blow");

        if(hitCount == MAX_LENGTH){
            return true;
        }
        return false;
    }
}

 やりたいこと

現状のコードでHit&Blowはプレイすることが可能ではありますが、
入力した4桁の数値が重複した場合、

4桁の数字を入力してください。
3333
1 Hit  3Blow

といった表示になってしまいます。理想としては、

3333
1Hit 0Blow

という表示をさせたいのですが、自力では閃かず、お力をお借りしたく思います。
また、現状では先頭0始まり( 例: 0123 )の表示も通ってしまうため、
0始まりにならない方法もご教授願いたく思います。
お手数おかけしますが、何卒よろしくお願いいたします。

 補足情報(FW/ツールのバージョンなど)

Java
java version "1.8.0_161"

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

Javaと言うよりはプログラミング問題ですね。惜しいところまで行っていると思いますので、ヒントのみご提示させていただきます。

「4桁の数字の先頭を0から始めてはならない」

CpuNumArrayメソッドで、乱数で4つの数字をひとつずつ求めてセットしている訳ですよね。
インデックス[0]〜[3]のループで回していて、インデックス[0]の数字は千の位、先頭な訳ですから。。。さて。

「入力値は重複させないようにすること。(0blowと表示)」

CpuNumArrayで求めた4桁の数字と、PlayerNumで求めた入力数字4桁の並びを考えます。
それぞれの並びの位置(インデックス)で比較して、同じ値ならそれはHitです。
Browの数に関して、Hit で比較した文字はもはや対象外となります。残った数字が4桁の数字の中にあれば、その数がBrowになるはずです。
※条件に、4桁の数字が重複しているか否かが明示されていませんが、どちらでも動作するはずです。


※追記しました:
以下は私の間違いですので、取り消しとさせていただきます。コメントでご指摘いただいたswordoneさん、どうもありがとうございます。
ご提示のコードですが、ご質問の内容とは別に問題(バグ)があります。その点を指摘させていただきます。

  for(int i = 0; i < 4; i++){
            int num = (int)(Math.floor(Math.random() * (10-i)));
            //一度使用した数字はリストから削除

            CpuNum[i] = tempList.remove(num);
        }


の部分ですが、もし、乱数で求めたnumが、6, 7, 8, 9, となった場合、tempList.remove(i)でどうなるでしょうか。List remove
また、そもそも「一度使用した数字はリストから削除」を求めての処置だと思いますが、全体として期待している通りの効果を成しているでしょうか。ちょっと考えてみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/18 10:08

    numは後半では8とか9とかにはならないですよ。

    キャンセル

  • 2018/06/18 10:22 編集

    swordoneさん、ご指摘ありがとうございます。
    (int)(Math.floor(Math.random() * (10-i))
    の作用で、おっしゃる通りですね。 CpuNum[i] = tempList.remove(num); ここだけに目が行っていました。それで言うと私のバグとの指摘も、間違っていました。

    キャンセル

  • 2018/06/21 01:14

    ご回答いただき、ありがとうございます。
    「4桁の数字の先頭を0から始めてはならない」,「入力値は重複させないようにすること。(0blowと表示)」
    についてヒントをいただきありがとうございます。
    いただきましたヒントからいろいろと試行錯誤をしてみたのですが、

    5
    6
    9
    7
    4桁の数字を入力してください。
    5697
    3 Hit -3Blow
    4桁の数字を入力してください。

    上記のような表示となり、現状
    ・1桁目の数字(千の位)がHitとしてもBlowとしても数えられておらず,3桁のみ数えられているため、breakすることができない(4桁の数字を求められないため終了できない)
    ・Blowの値にマイナスの値が表示されてしまう
    ・何度か試すと0で始まる場合もある(0始まりが回避できていない)
    となってしまっております。
    ご多忙のところ大変恐縮ではございますが、もう少しだけヒントをいただけませんでしょうか。
    現在作成途中のコードは上記の
     作成途中のソースコード(追記 2018.6.21)
    に掲載いたしました。お手数おかけいたしますが何卒よろしくお願いいたします。

    キャンセル

0

4桁の数字の先頭を0から始めてはならない

これは簡単。1回目だけ乱数の範囲を0から9ではなく、1から9にすればいい。

入力値は重複させないようにすること。(0blowと表示)

これも簡単。blowCountが増えた時点でbreakしてしまえばいい。
間違いでした。詳細は後述

 追記に対して

cpuNumArrayメソッドについて

メソッド名は小文字始まりが慣例なので修正。ガタガタインデントも修正。

    private String[] cpuNumArray(){

        List<String> tempList = new 
        LinkedList<String>(Arrays.asList(NUM_ARRAY));

        String[] CpuNum = new String[4];

        //1回しかしないならループ不要。
        //for(int i = 1; i < 2; i++){

        //最初は1から9の乱数 floorも不要
        int num = (int)(Math.random() * 9) + 1;

        //ここのインデックスは0。
        //元のコードではループカウンタのiを使っており、
        //1で初期化されていたため、0番目に何も入らなかった
        //これが3hitの理由
        CpuNum[0] = tempList.remove(num);
        System.out.println(CpuNum[0]);

        for(int j = 1; j < 4; j++){
            int num2 = (int)(Math.random() * (10-j));
            CpuNum[j] = tempList.remove(num2);
            System.out.println(CpuNum[j]);
        }
        //}

        return CpuNum;

    }


ムダなループがあったりする以外はOKかと。

hitカウント、blowカウントについて

前の回答の間違いでした。
「重複=0blow」ならば、きちんと重複をチェックする必要があります。

3Hitの理由は上記コメントの通り、1桁目をcpuの配列の0番目ではなく1番目に入れているから。
例えばコメントのように5697と表示されたときは、実は次のような流れになっています。

  1. 最初の3が配列の1番目に格納。CpuNumの中身は{null, "5", null, null}
  2. 次の6が配列の1番目に格納。CpuNumの中身は{null, "6", null, null}
  3. その後、9と7がそれぞれ2番目、3番目に格納され、CpuNumの中身は{null, "6", "9", "7"}
  4. 入力された5697に対しては、blow判定が1ループでbreakしてしまうため、最初の5としか比較できない。(ここは本当はifの中でbreakしてというつもりだった)
    5はCpuNumに入っていないため、blowは0になる。
  5. 最初の5にhit判定ができず(nullとの比較のため)、3hit止まり。blowは3回引かれ、‐3blowとなる。

 LinkedList不要

フィッシャー・イェーツ法という、効率的なシャッフルアルゴリズムを利用すれば、LinkedListを作らなくても桁重複なしの乱数が作れます。

private String[] cpuNumArray() {
    String[] cpuNum = new String[MAX_LENGTH];
    int index = (int)(Math.random() * NUM_ARRAY.length);
    switchElem(NUM_ARRAY, index, NUM_ARRAY.length - 1);
    if (NUM_ARRAY[NUM_ARRAY.length - 1].equals("0")){
        index = (int)(Math.random() * (NUM_ARRAY.length - 1));
        switchElem(NUM_ARRAY, index, NUM_ARRAY.length - 1);
    }
    cpuNum[0] = NUM_ARRAY[NUM_ARRAY.length - 1];

    for (int i = 1; i < MAX_LENGTH; i++) {
        index = (int)(Math.random() * (NUM_ARRAY.length - i));
        cpuNum[i] = NUM_ARRAY[index];
        switchElem(NUM_ARRAY, index, NUM_ARRAY.length - 1 - i);
    }
    return cpuNum;
}

private void switchElem(String[] a, int i, int j) {
    if (i == j) return;
    String temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

 Hit,Blowの判定の改善

    private boolean checkHitAndBlow(String[] cpuNumArray, String[] playerNumArray){

        int hitCount = 0;
        int blowCount = 0;

        // 面倒なんで重複チェックはSetに任せた
        boolean unique = new HashSet<String>(Arrays.asList(playerNumArray)).size() == MAX_LENGTH;

        //数字のチェック
        if (unique) {
            for(int i = 0; i < MAX_LENGTH; i++){
                for(int j = 0; j < MAX_LENGTH; j++){
                    if(playerNumArray[i].equals(cpuNumArray[j])){
                        if (i == j) hitCount++;
                        else blowCount++
                        break;
                    }

                }
            }
        } else {
            for (int i = 0; i < MAX_LENGTH; i++) {
                if (playerNumArray[i].equals(cpuNumArray[j])
                    hitCount++;
            }
        }

        System.out.println(hitCount + " Hit  " + blowCount + "Blow");

        if(hitCount == MAX_LENGTH){
            return true;
        }
        return false;
    }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/21 01:17

    ご回答いただき、ありがとうございます。
    「4桁の数字の先頭を0から始めてはならない」,「入力値は重複させないようにすること。(0blowと表示)」
    についてご助言いただきありがとうございます。
    また少し自力で考えてみたのですが、上手くいかず、お手間をおかけいたしますが、もう少しだけご助言いただけませんでしょうか。

    まず、
    >1回目だけ乱数の範囲を0から9ではなく、1から9にすればいい。

    につきまして、CpuNumArrayメソッドで4つの数字を一つずつ求めるのではなく、1回目と2回目〜4回目を別々に求めるということでしょうか?
    記述の仕方がよく理解できておらず、少々悩んでおります。

    また、
    >blowCountが増えた時点でbreakしてしまえばいい。

    とご教授いただきましたとおり、blowCountの増えた時点にbreak;を追加したところ、0blowに表示が変わり、これはできたのでは!と喜んでいたのですが、実行時の表示が

    5
    6
    9
    7
    4桁の数字を入力してください。
    5697
    3 Hit -3Blow
    4桁の数字を入力してください。

    と、blowにマイナスの値が表示され、どう対処すればよいのか悩んでおります。
    また、0始まりを回避しようと修正した記述がうまくいっていないためか、1回目に表示された数字がHitに数えられておらず、正解の数値を入力してもbreakしない状況になっております。
    現在作成途中のコードは上記の
     作成途中のソースコード(追記 2018.6.21)
    に掲載いたしました。
    お手数おかけいたしますがご教授のほど何卒よろしくお願いいたします。

    キャンセル

  • 2018/06/25 01:08

    こんばんは、前回の質問に対し、解説いただきありがとうございます。
    何が起こっているのか分かっていなかったのですが、ご丁寧にお教えいただけたおかげで何故マイナス値になってしまったのか理解できました。
    また、フィッシャー・イェーツ法といったアルゴリズムは初めてお聞きしました。なるほど、こういった記述方法もあるのだと、またひとつ見聞を広めることができました。ありがとうございます。
    ただ、お教えいただいたLinkedListを作らずに桁重複なしの乱数を作成する記述の仕方を試してあれこれプログラムをいじってみたのですが、どうしても重複をBlowが数えてしまい(1Hit 3Blowのような表記になってしまいます)、目指している0Blowの形になりませんでした。
    私の理解不足で申し訳ありませんが、もう少しだけご教授いただけますと幸いです。

    キャンセル

同じタグがついた質問を見る

  • Java

    14464questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。