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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

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

Q&A

2回答

1553閲覧

[Java] Hit&Blow 表示の仕方

退会済みユーザー

退会済みユーザー

総合スコア0

Java

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

0グッド

0クリップ

投稿2018/06/17 16:53

編集2018/06/20 16:13

前提・実現したいこと

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

問題文

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

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

作成途中のソースコード

Java

1import java.io.IOException; 2import java.util.Arrays; 3import java.util.LinkedList; 4import java.util.List; 5import java.util.Scanner; 6 7public class Tokubetsu5 { 8 9 public static final String[] NUM_ARRAY = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"}; 10 11 public static final int MAX_LENGTH = 4; 12 13 public static void main(String[] args) throws IOException{ 14 Tokubetsu5 hb = new Tokubetsu5(); 15 hb.execute(); 16 } 17 18 private void execute() throws IOException{ 19 20 String[] cpuNumArray = CpuNumArray(); 21 22 boolean clear = false; 23 try(Scanner sc = new Scanner(System.in)){ 24 25 //攻略できるまでループ 26 while(!clear){ 27 28 String[] playerNumArray = PlayerNum(sc); 29 30 clear = checkHitAndBlow(cpuNumArray, playerNumArray); 31 32 } 33 } 34 35 System.out.println("終了します"); 36 37 } 38 39 40 private String[] CpuNumArray(){ 41 //数字の列を作成 42 List<String> tempList = new LinkedList<String>(Arrays.asList(NUM_ARRAY)); 43 44 String[] CpuNum = new String[4]; 45 46 //4回繰り返し、数字をランダムで取得 47 for(int i = 0; i < 4; i++){ 48 int num = (int)(Math.floor(Math.random() * (10-i))); 49 //一度使用した数字はリストから削除 50 51 CpuNum[i] = tempList.remove(num); 52 } 53 54 return CpuNum; 55 56 } 57 58 private String[] PlayerNum(Scanner sc) throws IOException{ 59 60 boolean Check = false; 61 String line = null; 62 63 //入力OKになるまで繰り返し 64 check: 65 while(!Check){ 66 67 System.out.println("4桁の数字を入力してください。"); 68 line = sc.nextLine(); 69 70 //文字数チェック 71 if(line.length() > MAX_LENGTH){ 72 System.out.println("入力した桁数が多いです"); 73 continue; 74 }else if(line.length() < MAX_LENGTH){ 75 System.out.println("入力した桁数が少ないです"); 76 continue; 77 } 78 79 80 Check = true; 81 82 } 83 84 return line.split(""); 85 } 86 87 88 private boolean checkHitAndBlow(String[] cpuNumArray, String[] playerNumArray){ 89 90 int hitCount = 0; 91 int blowCount = 0; 92 93 //数字のチェック 94 for(int i = 0; i < MAX_LENGTH; i++){ 95 for(int j = 0; j < MAX_LENGTH; j++){ 96 if(playerNumArray[i].equals(cpuNumArray[j])){ 97 blowCount++; 98 } 99 } 100 } 101 102 for(int i = 0; i < MAX_LENGTH; i++){ 103 if(playerNumArray[i].equals(cpuNumArray[i])){ 104 blowCount--; 105 hitCount++; 106 } 107 } 108 109 System.out.println(hitCount + " Hit " + blowCount + "Blow"); 110 111 if(hitCount == MAX_LENGTH){ 112 return true; 113 } 114 return false; 115 } 116} 117 118

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

Java

1 2import java.io.IOException; 3import java.util.Arrays; 4import java.util.LinkedList; 5import java.util.List; 6import java.util.Scanner; 7 8public class Tokubetsu5 { 9 10 public static final String[] NUM_ARRAY = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"}; 11 12 public static final int MAX_LENGTH = 4; 13 14 public static void main(String[] args) throws IOException{ 15 Tokubetsu5 hb = new Tokubetsu5(); 16 hb.execute(); 17 } 18 19 private void execute() throws IOException{ 20 21 String[] cpuNumArray = CpuNumArray(); 22 23 boolean clear = false; 24 try(Scanner sc = new Scanner(System.in)){ 25 26 //攻略できるまでループ 27 while(!clear){ 28 29 String[] playerNumArray = PlayerNum(sc); 30 31 clear = checkHitAndBlow(cpuNumArray, playerNumArray); 32 33 } 34 } 35 System.out.println("正解です"); 36 System.out.println("終了します"); 37 38 } 39 40 41 private String[] CpuNumArray(){ 42 //数字の列を作成 43 List<String> tempList = new LinkedList<String>(Arrays.asList(NUM_ARRAY)); 44 45 String[] CpuNum = new String[4]; 46 47 //1回繰り返し、数字をランダムで取得 48 for(int i = 1; i < 2; i++){ 49 int num = (int)(Math.floor(Math.random() * (10-i))); 50 //一度使用した数字はリストから削除 51 52 CpuNum[i] = tempList.remove(num); 53 54 //解答確認用 55 System.out.println(CpuNum[i]); 56 57 //3回繰り返し、数字をランダムで取得 58 for(int j = 1; j < 4; j++){ 59 int num2 = (int)(Math.floor(Math.random() * (10-j))); 60 //一度使用した数字はリストから削除 61 62 CpuNum[j] = tempList.remove(num2); 63 64 //解答確認用 65 System.out.println(CpuNum[j]); 66 } 67 } 68 69 return CpuNum; 70 71 } 72 73 private String[] PlayerNum(Scanner sc) throws IOException{ 74 75 boolean Check = false; 76 String line = null; 77 78 //入力OKになるまで繰り返し 79 check: 80 while(!Check){ 81 82 System.out.println("4桁の数字を入力してください。"); 83 line = sc.nextLine(); 84 85 //文字数チェック 86 if(line.length() > MAX_LENGTH){ 87 System.out.println("入力した桁数が多いです"); 88 continue; 89 }else if(line.length() < MAX_LENGTH){ 90 System.out.println("入力した桁数が少ないです"); 91 continue; 92 } 93 94 Check = true; 95 96 } 97 98 return line.split(""); 99 } 100 101 private boolean checkHitAndBlow(String[] cpuNumArray, String[] playerNumArray){ 102 103 int hitCount = 0; 104 int blowCount = 0; 105 106 //数字のチェック 107 for(int i = 0; i < MAX_LENGTH; i++){ 108 for(int j = 0; j < MAX_LENGTH; j++){ 109 if(playerNumArray[i].equals(cpuNumArray[j])){ 110 blowCount++; 111 112 } 113 114 } 115 break; 116 } 117 118 for(int i = 0; i < MAX_LENGTH; i++){ 119 if(playerNumArray[i].equals(cpuNumArray[i])){ 120 blowCount--; 121 hitCount++; 122 123 } 124 } 125 126 System.out.println(hitCount + " Hit " + blowCount + "Blow"); 127 128 if(hitCount == MAX_LENGTH){ 129 return true; 130 } 131 return false; 132 } 133} 134 135

やりたいこと

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

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

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

3333
1Hit 0Blow

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

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

Java
java version "1.8.0_161"

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

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

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

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

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

追記に対して

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

java

1 private String[] cpuNumArray(){ 2 3 List<String> tempList = new 4 LinkedList<String>(Arrays.asList(NUM_ARRAY)); 5 6 String[] CpuNum = new String[4]; 7 8 //1回しかしないならループ不要。 9 //for(int i = 1; i < 2; i++){ 10 11 //最初は1から9の乱数 floorも不要 12 int num = (int)(Math.random() * 9) + 1; 13 14 //ここのインデックスは0。 15 //元のコードではループカウンタのiを使っており、 16 //1で初期化されていたため、0番目に何も入らなかった 17 //これが3hitの理由 18 CpuNum[0] = tempList.remove(num); 19 System.out.println(CpuNum[0]); 20 21 for(int j = 1; j < 4; j++){ 22 int num2 = (int)(Math.random() * (10-j)); 23 CpuNum[j] = tempList.remove(num2); 24 System.out.println(CpuNum[j]); 25 } 26 //} 27 28 return CpuNum; 29 30 }

ムダなループがあったりする以外はOKかと。
####hitカウント、blowカウントについて
前の回答の間違いでした。
「重複=0blow」ならば、きちんと重複をチェックする必要があります。

3Hitの理由は上記コメントの通り、1桁目をcpuの配列の0番目ではなく1番目に入れているから。
例えばコメントのように5697と表示されたときは、実は次のような流れになっています。
0. 最初の3が配列の1番目に格納。CpuNumの中身は{null, "5", null, null}
0. 次の6が配列の1番目に格納。CpuNumの中身は{null, "6", null, null}
0. その後、9と7がそれぞれ2番目、3番目に格納され、CpuNumの中身は{null, "6", "9", "7"}
0. 入力された5697に対しては、blow判定が1ループでbreakしてしまうため、最初の5としか比較できない。(ここは本当はifの中でbreakしてというつもりだった)
5はCpuNumに入っていないため、blowは0になる。
0. 最初の5にhit判定ができず(nullとの比較のため)、3hit止まり。blowは3回引かれ、‐3blowとなる。

LinkedList不要

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

java

1private String[] cpuNumArray() { 2 String[] cpuNum = new String[MAX_LENGTH]; 3 int index = (int)(Math.random() * NUM_ARRAY.length); 4 switchElem(NUM_ARRAY, index, NUM_ARRAY.length - 1); 5 if (NUM_ARRAY[NUM_ARRAY.length - 1].equals("0")){ 6 index = (int)(Math.random() * (NUM_ARRAY.length - 1)); 7 switchElem(NUM_ARRAY, index, NUM_ARRAY.length - 1); 8 } 9 cpuNum[0] = NUM_ARRAY[NUM_ARRAY.length - 1]; 10 11 for (int i = 1; i < MAX_LENGTH; i++) { 12 index = (int)(Math.random() * (NUM_ARRAY.length - i)); 13 cpuNum[i] = NUM_ARRAY[index]; 14 switchElem(NUM_ARRAY, index, NUM_ARRAY.length - 1 - i); 15 } 16 return cpuNum; 17} 18 19private void switchElem(String[] a, int i, int j) { 20 if (i == j) return; 21 String temp = a[i]; 22 a[i] = a[j]; 23 a[j] = temp; 24}

Hit,Blowの判定の改善

java

1 private boolean checkHitAndBlow(String[] cpuNumArray, String[] playerNumArray){ 2 3 int hitCount = 0; 4 int blowCount = 0; 5 6 // 面倒なんで重複チェックはSetに任せた 7 boolean unique = new HashSet<String>(Arrays.asList(playerNumArray)).size() == MAX_LENGTH; 8 9 //数字のチェック 10 if (unique) { 11 for(int i = 0; i < MAX_LENGTH; i++){ 12 for(int j = 0; j < MAX_LENGTH; j++){ 13 if(playerNumArray[i].equals(cpuNumArray[j])){ 14 if (i == j) hitCount++; 15 else blowCount++ 16 break; 17 } 18 19 } 20 } 21 } else { 22 for (int i = 0; i < MAX_LENGTH; i++) { 23 if (playerNumArray[i].equals(cpuNumArray[j]) 24 hitCount++; 25 } 26 } 27 28 System.out.println(hitCount + " Hit " + blowCount + "Blow"); 29 30 if(hitCount == MAX_LENGTH){ 31 return true; 32 } 33 return false; 34 }

投稿2018/06/18 01:06

編集2018/06/24 17:38
swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/06/20 16: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/24 16:08

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

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 00:52

編集2018/06/18 01:32
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2018/06/18 01:08

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

2018/06/18 01:23 編集

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

退会済みユーザー

2018/06/20 16: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) に掲載いたしました。お手数おかけいたしますが何卒よろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問