質問: 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"
回答: > > 4桁の数字の先頭を0から始めてはならない > > > これは簡単。1回目だけ乱数の範囲を0から9ではなく、1から9にすればいい。 > > 入力値は重複させないようにすること。(0blowと表示) > > > ~~これも簡単。blowCountが増えた時点でbreakしてしまえばいい。~~ 間違いでした。詳細は後述 ### 追記に対して #### cpuNumArrayメソッドについて メソッド名は小文字始まりが慣例なので修正。ガタガタインデントも修正。 ``` private String[] cpuNumArray(){ List tempList = new LinkedList(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(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; } ```