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

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

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

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

Q&A

解決済

3回答

1000閲覧

Java HitandBlow

退会済みユーザー

退会済みユーザー

総合スコア0

Java

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

0グッド

0クリップ

投稿2021/12/25 05:54

java

1 2 3import java.io.Console; 4import java.util.Scanner; 5public class sampul1{ 6 public static void main(String[] args) { 7 8 //ゲーム説明 9 System.out.print("このゲームは3桁の数字を当てるゲームです"); 10 System.out.println("正解するまでの回数が少なかった方が勝利です"); 11 System.out.println("数字と桁が両方合っていればHit,数字のみならばBlowと表示されます"); 12 13 //数字設定 14 Scanner sc=new Scanner(System.in); 15 Console cons=System.console(); 16 if(cons==null) { 17 System.out.println("cons==null"); 18 return; 19 } 20 String name1="player1"; 21 System.out.println(name1+"さん3桁の数字を設定してください"); 22 while(true) { 23 boolean number=true; 24 char[] answer1=cons.readPassword(); 25 String input=new String(answer1); 26 char []a=input.toCharArray(); 27 int il=input.length(); 28 for(int i=0; i<3; i++) { 29 for(int j=i+1; j<3; j++) { 30 if(a[i]==a[j]||il!=3) { 31 number=false; 32 } 33 } 34 } 35 if(number==false) { 36 System.out.println("数字は重複せず、3桁です"); 37 continue; 38 } 39 String name2="player2"; 40 System.out.println(name2+"さん3桁の数字を設定してください"); 41 while(true) { 42 boolean num=true; 43 char[] answer2=cons.readPassword(); 44 String reinput=new String(answer2); 45 char[]b=reinput.toCharArray(); 46 int rl=reinput.length(); 47 for(int i=0; i<3; i++) { 48 for(int j=i+1; j<3; j++) { 49 if(b[i]==b[j]||rl!=3) { 50 num=false; 51 } 52 } 53 } 54 if(num==false) { 55 System.out.println("数字は重複せず、3桁です"); 56 continue; 57 } 58 //player1 59 System.out.println(name1+"さん相手の3桁を予想してください"); 60 int count=1; 61 while(true) { 62 boolean nu=true; 63 String c=sc.nextLine(); 64 char[] d=c.toCharArray(); 65 int cl=c.length(); 66 for(int i=0; i<3; i++) { 67 for(int j=i+1; j<3; j++) { 68 if(d[i]==d[j]||cl!=3) { 69 nu=false; 70 } 71 } 72 } 73 if(nu==false) { 74 System.out.println("数字は重複せず、3桁です"); 75 continue; 76 } 77 78 int hit=0, blow=0; 79 for(int i=0; i<3; i++) { 80 if(d[i]==b[i]) { 81 hit++; 82 }else{ 83 for(int j=0; j<3; j++) { 84 if(d[i]==b[j]) { 85 blow++; 86 } 87 } 88 } 89 } 90 if(hit!=3) { 91 System.out.println(hit+"Hit "+blow+"Blow"); 92 count++; 93 } 94 if(hit==3) { 95 System.out.println(name1+"さんは"+count+"回目で正解しました。"); 96 break; 97 } 98 } 99 100 101 102 //player2 103 System.out.println(name2+"さん相手の3桁の数字を予想してください"); 104 int recount=1; 105 while(true) { 106 boolean n=true; 107 String e=sc.nextLine(); 108 char[] f=e.toCharArray(); 109 int el=e.length(); 110 for(int i=0; i<3; i++) { 111 for(int j=i+1; j<3; j++) { 112 if(f[i]==f[j]||el!=3) { 113 n=false; 114 } 115 } 116 } 117 if(n==false) { 118 System.out.println("数字は重複せず、3桁です"); 119 continue; 120 } 121 int ahit=0, ablow=0; 122 for(int i=0; i<3; i++) { 123 if(f[i]==a[i]) { 124 ahit++; 125 }else{ 126 for(int j=0; j<3; j++) { 127 if(f[i]==a[j]) { 128 ablow++; 129 } 130 } 131 } 132 } 133 if(ahit!=3) { 134 System.out.println(ahit+"Hit "+ablow+"Blow"); 135 recount++; 136 } 137 if(ahit==3) { 138 System.out.println(name2+"さんは"+recount+"回目で正解しました。"); 139 if(count==recount) { 140 System.out.println("引き分けです"); 141 } 142 if(count<recount) { 143 System.out.println(name1+"さんの勝利です!"); 144 } 145 if(count>recount) { 146 System.out.println(name2+"さんの勝利です!"); 147 } 148 break; 149 } 150 } 151 152 153 154 155 156 157 158 159 } 160 } 161 162 } 163} 164 165 166 167 168

java初心者です。一応完成形?に近い形まで出来ました。
①readPassword以外で自分で数字を設定できてかつ非表示にする方法はないのでしょうか?(readPasswordはターミナルでしか実行できなくなるので。)
②このコードは同じ構文を繰り返していますが、他にもっと短縮簡素化できるコードは何かありますか?

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

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

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

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

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

guest

回答3

0

①readPassword以外で自分で数字を設定できてかつ非表示にする方法はないのでしょうか?(readPasswordはターミナルでしか実行できなくなるので。)

たしかにIDEですごくデバッグしずらいですね(何か方法はあるんでしょうが)
JPasswordFieldを使うとか?^^;

②このコードは同じ構文を繰り返していますが、他にもっと短縮簡素化できるコードは何かありますか?

まずwhileのネストが深く、非常に読みにくいです。

Java

1while (true) { 2 // player1 設定 3 4 while (true) { 5 // player2 設定 6 7 while (true) { 8 // 相手(player2)の予想 9 10 // 正解でbreak 11 break; 12 } 13 14 while (true) { 15 // 相手(player1)の予想 16 17 // 正解でbreak 結果判定 18 break; 19 } 20 } 21}

現状このような構成になっています。

しかしこのようなネストは不要のはずですし、バグ(想定していないであろう挙動)があります。
結果判定後breakで抜けるのは一番内側のwhileですから、player2 設定から繰り返しています。

何度も遊べるようにplayer1 設定から繰り返すならわかりますが、おそらくそういうつもりではなかったと推測します。

Java

1while (true) { 2 // player1 設定 3 break; 4} 5while (true) { 6 // player2 設定 7 break; 8} 9while (true) { 10 // 相手(player2)の予想 11 12 // 正解でbreak 13 break; 14} 15while (true) { 16 // 相手(player1)の予想 17 18 // 正解でbreak 19 break; 20} 21// 結果判定

こういう構成で十分なはずです(変数のスコープの問題でこうできなかったのかな?)

明らかに重複している部分をどうメソッドに切り出すべきかですが、「こうなってくれたらいいのにな」というのをまず先に定義してそうなるように後からメソッドを作るといい気がします。

今どきのIDEはリファクタリング機能(メソッドの抽出等)もよくできているので、いろいろ試してもいいと思います。

とくにmainメソッドはだらだら書いてしまいがちなので、最初から全体の大きな流れをコメントで書いてそれを埋めるようにメソッドを作っていくと自然と分けられる気がします。

ループがネストしてややこしいところや大域脱出(多重ループを一気に抜ける)したくなった時(Javaはlabelでジャンプできますが)は、大概メソッドに分けるとすっきり書けます。


わたしだったらmainはこのくらいになったらうれしいなぁと考えます。
頭のメモリが少ないので1メソッド1画面(30行くらい)じゃないと把握できないのです^^;

Java

1public static void main(String[] args) { 2 p("このゲームは3桁の数字を当てるゲームです"); 3 p("正解するまでの回数が少なかった方が勝利です"); 4 p("数字と桁が両方合っていればHit,数字のみならばBlowと表示されます"); 5 6 7 String name1 = "player1"; 8 p(name1 + "さん3桁の数字を設定してください"); 9 char[] answer1 = getSecretNumber(); 10 11 String name2 = "player2"; 12 p(name2 + "さん3桁の数字を設定してください"); 13 char[] answer2 = getSecretNumber(); 14 15 16 p(name1 + "さん相手の3桁を予想してください"); 17 int count1 = challenge(answer2); 18 p(name1 + "さんは" + count1 + "回目で正解しました。"); 19 20 p(name2 + "さん相手の3桁の数字を予想してください"); 21 int count2 = challenge(answer1); 22 p(name2 + "さんは" + count2 + "回目で正解しました。"); 23 24 25 if (count1 < count2) { 26 p(name1 + "さんの勝利です!"); 27 } else if (count1 > count2) { 28 p(name2 + "さんの勝利です!"); 29 } else { 30 p("引き分けです"); 31 } 32}

「なるほどそうだな」と思ったら、そうなるようにメソッドを作ってみてください。
「うーんちょっと違うな」と思ったら、robinjakusonさんの理想の分け方を考えてみてください^^;

投稿2021/12/25 12:22

TN8001

総合スコア9862

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

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

退会済みユーザー

退会済みユーザー

2021/12/25 12:57

ありがとうございます。 自分で見ても何か長くてダサいなと思ったいたので、もう少し見やすいコードに改善していきます。
TN8001

2021/12/25 14:15

着実に学習が進んでおられるようで、すばらしいですね。 そのため余計な?(ぶれるような)ことをしないようにした結果、中途半端なコード提示になってしまいましたがもし「参考までに見てみたい」ということでしたらおっしゃってください(別にそんな素晴らしいコードというわけではありませんがw あと書き忘れましたが、現状数字以外も入力できてしまいます(それはそれで面白そうですがおそらく難しすぎですね^^;
guest

0

入力、データチェック、NGならどーこー、の部分を無限ループに入れといて、
データチェックの結果OKならそのループを抜ける、というふうにしましょう。

ついでに、そこんところを関数にしてしまえば、いろんなところで使いまわしできます

投稿2021/12/25 06:59

y_waiwai

総合スコア88042

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

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

0

ベストアンサー

readPassword以外で自分で数字を設定できてかつ非表示にする方法

コンソール版であればそれが一番確実なのではないでしょうか。
コンソール以外に移植することを前提とするのであれば、入出力に関する部分をインターフェースとして定義してそのコンソール版実装クラスを作成しておくのが良いかと思います。

このコードは同じ構文を繰り返していますが、他にもっと短縮簡素化

まず、処理毎に分類し、それぞれをメソッドにしてください。その際、何をパラメータとして渡し何を戻り値として返すようにするとメソッドの独立性が確保されるかを考えられると良いかと思います。
メソッドの分け方が適切であれば、自然と再利用できるようになり、全体として小さくなるはずです。


入出力を IO インターフェースに纏める形にしてみました。
Player, Numbers もクラス化すると思ったより大き目になった感じです。(toString() とかありますしね…。)
副作用的に NAMES を増やせば 3 人以上でもプレイできると思います。(試してはいません。)

java

1package teratail_java.q375509; 2 3import java.io.Console; 4import java.io.PrintWriter; 5import java.util.*; 6 7//ユーザーインターフェース 8interface IO { 9 void println(String s); 10 char[] input(); 11 char[] inputPassword(); 12} 13 14//ユーザーインターフェース(コンソール版) 15class ConsoleIO implements IO { 16 private Console cons; 17 private PrintWriter out; 18 ConsoleIO() { 19 cons = System.console(); 20 if(cons == null) { 21 throw new IllegalStateException(); 22 } 23 out = cons.writer(); 24 } 25 @Override 26 public void println(String s) { 27 out.println(s); 28 } 29 @Override 30 public char[] input() { 31 return cons.readLine().toCharArray(); 32 } 33 @Override 34 public char[] inputPassword() { 35 return cons.readPassword(); 36 } 37} 38 39//ユーザーインターフェース(System版) 40class SystemIO implements IO { 41 private Scanner sc; 42 SystemIO(){ 43 sc = new Scanner(System.in); 44 } 45 @Override 46 public void println(String s) { 47 System.out.println(s); 48 } 49 @Override 50 public char[] input() { 51 return sc.nextLine().toCharArray(); 52 } 53 @Override 54 public char[] inputPassword() { 55 return sc.nextLine().toCharArray(); 56 } 57} 58 59//三桁の数字 60class Numbers { 61 static boolean checkNumbers(char[] s) { 62 if(s.length != 3 || s[0] == s[1] || s[1] == s[2] || s[2] == s[0]) return false; 63 for(int i=0; i<s.length; i++) if("0123456789".indexOf(s[i]) < 0) return false; 64 return true; 65 } 66 67 static class HitAndBlow { 68 final int hit, blow; 69 70 HitAndBlow(int hit, int blow) { 71 this.hit = hit; 72 this.blow = blow; 73 } 74 75 @Override 76 public String toString() { 77 return hit + "Hit " + blow + "Blow"; 78 } 79 } 80 81 private final char[] numbers; 82 Numbers(char[] numbers) { 83 if(!checkNumbers(numbers)) throw new IllegalArgumentException(); 84 this.numbers = numbers; 85 } 86 87 HitAndBlow checkHitAndBlow(Numbers other) { 88 //ロジックはオリジナル尊重 89 int hit = 0, blow = 0; 90 for(int i = 0; i < numbers.length; i++) { 91 if(numbers[i] == other.numbers[i]) { 92 hit++; 93 } else { 94 for(int j = 0; j < numbers.length; j++) { 95 if(numbers[i] == other.numbers[j]) { 96 blow++; 97 } 98 } 99 } 100 } 101 return new HitAndBlow(hit, blow); 102 } 103 104 @Override 105 public String toString() { 106 return Arrays.toString(numbers); 107 } 108} 109 110//プレイヤー 111class Player { 112 final String name; 113 private final Numbers numbers; 114 private int predictCount; 115 Player(String name, Numbers numbers) { 116 this.name = name; 117 this.numbers = numbers; 118 this.predictCount = 0; 119 } 120 121 void incrementPredictCount() { predictCount++; } 122 int getPredictCount() { return predictCount; } 123 124 Numbers.HitAndBlow checkHitAndBlow(Numbers other) { 125 return numbers.checkHitAndBlow(other); 126 } 127 128 @Override 129 public String toString() { 130 StringJoiner sj = new StringJoiner(",", "Player[", "]"); 131 sj.add("name=" + name); 132 sj.add("numbers=" + numbers); 133 sj.add("predictCount=" + predictCount); 134 return sj.toString(); 135 } 136} 137 138public class Sample1 { 139 private static final String[] NAMES = new String[]{ "player1", "player2" }; 140 141 public static void main(String[] args) { 142 IO io = new ConsoleIO(); 143 //IO io = new SystemIO(); //テスト用 (inputPassword の入力が見えてしまう) 144 145 //ゲーム説明 146 io.println("このゲームは3桁の数字を当てるゲームです"); 147 io.println("正解するまでの回数が少なかった方が勝利です"); 148 io.println("数字と桁が両方合っていればHit,数字のみならばBlowと表示されます"); 149 150 //プレイヤー 151 Player[] players = new Player[NAMES.length]; 152 for(int i=0; i<NAMES.length; i++) { 153 io.println(NAMES[i] + "さん3桁の数字を設定してください"); 154 Numbers numbers = inputNumbers(io, true); 155 players[i] = new Player(NAMES[i], numbers); 156 } 157 158 //プレイ 159 for(int i=0; i<players.length; i++) { 160 Player target = players[(i+1)%players.length]; //予想する相手 161 io.println(players[i].name + "さん, " + target.name + "さんの3桁を予想してください"); 162 while(true) { 163 Numbers predict = inputNumbers(io, false); 164 players[i].incrementPredictCount(); 165 Numbers.HitAndBlow hab = target.checkHitAndBlow(predict); 166 if(hab.hit == 3) { 167 io.println(players[i].name + "さんは" + players[i].getPredictCount() + "回目で正解しました。"); 168 break; 169 } 170 io.println(hab.toString()); 171 } 172 } 173 174 //結果 175 List<Player> winnerList = judgement(players); 176 if(winnerList.size() == players.length) { //全員勝利=同点 177 io.println("引き分けです"); 178 } else { 179 StringJoiner sj = new StringJoiner(",", "", "さんの勝利です!"); 180 for(Player p : winnerList) sj.add(p.name); 181 io.println(sj.toString()); 182 } 183 } 184 185 //数字入力 186 static Numbers inputNumbers(IO io, boolean hide) { 187 char[] s; 188 while(true) { 189 s = hide ? io.inputPassword() : io.input(); 190 //System.out.println("s="+Arrays.toString(s)); 191 if(Numbers.checkNumbers(s)) break; 192 io.println("数字は重複せず、3桁です"); 193 } 194 return new Numbers(s); 195 } 196 197 //最終判定 198 static List<Player> judgement(Player[] players) { 199 List<Player> winnerList = new ArrayList<Player>(Arrays.asList(players)); 200 Collections.sort(winnerList, (o1,o2) -> o1.getPredictCount()-o2.getPredictCount()); 201 //for(Player p : winnerList) System.out.println(p); 202 for(int i=winnerList.size()-1; winnerList.get(i).getPredictCount()>winnerList.get(0).getPredictCount(); i--) winnerList.remove(i); 203 return winnerList; 204 } 205}

投稿2021/12/25 06:22

編集2021/12/25 13:28
jimbe

総合スコア13209

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

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

退会済みユーザー

退会済みユーザー

2021/12/25 06:30

ありがとうございます。 特に移植する予定もないのでこのままにしとこうと思います。
退会済みユーザー

退会済みユーザー

2021/12/25 13:32

わざわざありがとうございます。 同じ機能でも違った書き方があって参考になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問