回答編集履歴

3

オリジナルに近い表示に修正, SystemIO 追加

2021/12/25 13:28

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -104,6 +104,46 @@
104
104
 
105
105
 
106
106
 
107
+ //ユーザーインターフェース(System版)
108
+
109
+ class SystemIO implements IO {
110
+
111
+ private Scanner sc;
112
+
113
+ SystemIO(){
114
+
115
+ sc = new Scanner(System.in);
116
+
117
+ }
118
+
119
+ @Override
120
+
121
+ public void println(String s) {
122
+
123
+ System.out.println(s);
124
+
125
+ }
126
+
127
+ @Override
128
+
129
+ public char[] input() {
130
+
131
+ return sc.nextLine().toCharArray();
132
+
133
+ }
134
+
135
+ @Override
136
+
137
+ public char[] inputPassword() {
138
+
139
+ return sc.nextLine().toCharArray();
140
+
141
+ }
142
+
143
+ }
144
+
145
+
146
+
107
147
  //三桁の数字
108
148
 
109
149
  class Numbers {
@@ -272,6 +312,8 @@
272
312
 
273
313
  IO io = new ConsoleIO();
274
314
 
315
+ //IO io = new SystemIO(); //テスト用 (inputPassword の入力が見えてしまう)
316
+
275
317
 
276
318
 
277
319
  //ゲーム説明
@@ -290,7 +332,9 @@
290
332
 
291
333
  for(int i=0; i<NAMES.length; i++) {
292
334
 
293
- Numbers numbers = inputNumbers(io, true, NAMES[i] + "さん3桁の数字を設定してください");
335
+ io.println(NAMES[i] + "さん3桁の数字を設定してください");
336
+
337
+ Numbers numbers = inputNumbers(io, true);
294
338
 
295
339
  players[i] = new Player(NAMES[i], numbers);
296
340
 
@@ -302,11 +346,13 @@
302
346
 
303
347
  for(int i=0; i<players.length; i++) {
304
348
 
349
+ Player target = players[(i+1)%players.length]; //予想する相手
350
+
351
+ io.println(players[i].name + "さん, " + target.name + "さんの3桁を予想してください");
352
+
305
353
  while(true) {
306
354
 
307
- Player target = players[(i+1)%players.length]; //予想する相手
308
-
309
- Numbers predict = inputNumbers(io, false, players[i].name + "さん, " + target.name + "さんの3桁を予想してください");
355
+ Numbers predict = inputNumbers(io, false);
310
356
 
311
357
  players[i].incrementPredictCount();
312
358
 
@@ -352,9 +398,7 @@
352
398
 
353
399
  //数字入力
354
400
 
355
- static Numbers inputNumbers(IO io, boolean hide, String prompt) {
401
+ static Numbers inputNumbers(IO io, boolean hide) {
356
-
357
- io.println(prompt);
358
402
 
359
403
  char[] s;
360
404
 

2

コード追加

2021/12/25 13:28

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -15,3 +15,383 @@
15
15
  まず、処理毎に分類し、それぞれをメソッドにしてください。その際、何をパラメータとして渡し何を戻り値として返すようにするとメソッドの独立性が確保されるかを考えられると良いかと思います。
16
16
 
17
17
  メソッドの分け方が適切であれば、自然と再利用できるようになり、全体として小さくなるはずです。
18
+
19
+
20
+
21
+ ----
22
+
23
+ 入出力を IO インターフェースに纏める形にしてみました。
24
+
25
+ Player, Numbers もクラス化すると思ったより大き目になった感じです。(toString() とかありますしね…。)
26
+
27
+ 副作用的に NAMES を増やせば 3 人以上でもプレイできると思います。(試してはいません。)
28
+
29
+ ```java
30
+
31
+ package teratail_java.q375509;
32
+
33
+
34
+
35
+ import java.io.Console;
36
+
37
+ import java.io.PrintWriter;
38
+
39
+ import java.util.*;
40
+
41
+
42
+
43
+ //ユーザーインターフェース
44
+
45
+ interface IO {
46
+
47
+ void println(String s);
48
+
49
+ char[] input();
50
+
51
+ char[] inputPassword();
52
+
53
+ }
54
+
55
+
56
+
57
+ //ユーザーインターフェース(コンソール版)
58
+
59
+ class ConsoleIO implements IO {
60
+
61
+ private Console cons;
62
+
63
+ private PrintWriter out;
64
+
65
+ ConsoleIO() {
66
+
67
+ cons = System.console();
68
+
69
+ if(cons == null) {
70
+
71
+ throw new IllegalStateException();
72
+
73
+ }
74
+
75
+ out = cons.writer();
76
+
77
+ }
78
+
79
+ @Override
80
+
81
+ public void println(String s) {
82
+
83
+ out.println(s);
84
+
85
+ }
86
+
87
+ @Override
88
+
89
+ public char[] input() {
90
+
91
+ return cons.readLine().toCharArray();
92
+
93
+ }
94
+
95
+ @Override
96
+
97
+ public char[] inputPassword() {
98
+
99
+ return cons.readPassword();
100
+
101
+ }
102
+
103
+ }
104
+
105
+
106
+
107
+ //三桁の数字
108
+
109
+ class Numbers {
110
+
111
+ static boolean checkNumbers(char[] s) {
112
+
113
+ if(s.length != 3 || s[0] == s[1] || s[1] == s[2] || s[2] == s[0]) return false;
114
+
115
+ for(int i=0; i<s.length; i++) if("0123456789".indexOf(s[i]) < 0) return false;
116
+
117
+ return true;
118
+
119
+ }
120
+
121
+
122
+
123
+ static class HitAndBlow {
124
+
125
+ final int hit, blow;
126
+
127
+
128
+
129
+ HitAndBlow(int hit, int blow) {
130
+
131
+ this.hit = hit;
132
+
133
+ this.blow = blow;
134
+
135
+ }
136
+
137
+
138
+
139
+ @Override
140
+
141
+ public String toString() {
142
+
143
+ return hit + "Hit " + blow + "Blow";
144
+
145
+ }
146
+
147
+ }
148
+
149
+
150
+
151
+ private final char[] numbers;
152
+
153
+ Numbers(char[] numbers) {
154
+
155
+ if(!checkNumbers(numbers)) throw new IllegalArgumentException();
156
+
157
+ this.numbers = numbers;
158
+
159
+ }
160
+
161
+
162
+
163
+ HitAndBlow checkHitAndBlow(Numbers other) {
164
+
165
+ //ロジックはオリジナル尊重
166
+
167
+ int hit = 0, blow = 0;
168
+
169
+ for(int i = 0; i < numbers.length; i++) {
170
+
171
+ if(numbers[i] == other.numbers[i]) {
172
+
173
+ hit++;
174
+
175
+ } else {
176
+
177
+ for(int j = 0; j < numbers.length; j++) {
178
+
179
+ if(numbers[i] == other.numbers[j]) {
180
+
181
+ blow++;
182
+
183
+ }
184
+
185
+ }
186
+
187
+ }
188
+
189
+ }
190
+
191
+ return new HitAndBlow(hit, blow);
192
+
193
+ }
194
+
195
+
196
+
197
+ @Override
198
+
199
+ public String toString() {
200
+
201
+ return Arrays.toString(numbers);
202
+
203
+ }
204
+
205
+ }
206
+
207
+
208
+
209
+ //プレイヤー
210
+
211
+ class Player {
212
+
213
+ final String name;
214
+
215
+ private final Numbers numbers;
216
+
217
+ private int predictCount;
218
+
219
+ Player(String name, Numbers numbers) {
220
+
221
+ this.name = name;
222
+
223
+ this.numbers = numbers;
224
+
225
+ this.predictCount = 0;
226
+
227
+ }
228
+
229
+
230
+
231
+ void incrementPredictCount() { predictCount++; }
232
+
233
+ int getPredictCount() { return predictCount; }
234
+
235
+
236
+
237
+ Numbers.HitAndBlow checkHitAndBlow(Numbers other) {
238
+
239
+ return numbers.checkHitAndBlow(other);
240
+
241
+ }
242
+
243
+
244
+
245
+ @Override
246
+
247
+ public String toString() {
248
+
249
+ StringJoiner sj = new StringJoiner(",", "Player[", "]");
250
+
251
+ sj.add("name=" + name);
252
+
253
+ sj.add("numbers=" + numbers);
254
+
255
+ sj.add("predictCount=" + predictCount);
256
+
257
+ return sj.toString();
258
+
259
+ }
260
+
261
+ }
262
+
263
+
264
+
265
+ public class Sample1 {
266
+
267
+ private static final String[] NAMES = new String[]{ "player1", "player2" };
268
+
269
+
270
+
271
+ public static void main(String[] args) {
272
+
273
+ IO io = new ConsoleIO();
274
+
275
+
276
+
277
+ //ゲーム説明
278
+
279
+ io.println("このゲームは3桁の数字を当てるゲームです");
280
+
281
+ io.println("正解するまでの回数が少なかった方が勝利です");
282
+
283
+ io.println("数字と桁が両方合っていればHit,数字のみならばBlowと表示されます");
284
+
285
+
286
+
287
+ //プレイヤー
288
+
289
+ Player[] players = new Player[NAMES.length];
290
+
291
+ for(int i=0; i<NAMES.length; i++) {
292
+
293
+ Numbers numbers = inputNumbers(io, true, NAMES[i] + "さん3桁の数字を設定してください");
294
+
295
+ players[i] = new Player(NAMES[i], numbers);
296
+
297
+ }
298
+
299
+
300
+
301
+ //プレイ
302
+
303
+ for(int i=0; i<players.length; i++) {
304
+
305
+ while(true) {
306
+
307
+ Player target = players[(i+1)%players.length]; //予想する相手
308
+
309
+ Numbers predict = inputNumbers(io, false, players[i].name + "さん, " + target.name + "さんの3桁を予想してください");
310
+
311
+ players[i].incrementPredictCount();
312
+
313
+ Numbers.HitAndBlow hab = target.checkHitAndBlow(predict);
314
+
315
+ if(hab.hit == 3) {
316
+
317
+ io.println(players[i].name + "さんは" + players[i].getPredictCount() + "回目で正解しました。");
318
+
319
+ break;
320
+
321
+ }
322
+
323
+ io.println(hab.toString());
324
+
325
+ }
326
+
327
+ }
328
+
329
+
330
+
331
+ //結果
332
+
333
+ List<Player> winnerList = judgement(players);
334
+
335
+ if(winnerList.size() == players.length) { //全員勝利=同点
336
+
337
+ io.println("引き分けです");
338
+
339
+ } else {
340
+
341
+ StringJoiner sj = new StringJoiner(",", "", "さんの勝利です!");
342
+
343
+ for(Player p : winnerList) sj.add(p.name);
344
+
345
+ io.println(sj.toString());
346
+
347
+ }
348
+
349
+ }
350
+
351
+
352
+
353
+ //数字入力
354
+
355
+ static Numbers inputNumbers(IO io, boolean hide, String prompt) {
356
+
357
+ io.println(prompt);
358
+
359
+ char[] s;
360
+
361
+ while(true) {
362
+
363
+ s = hide ? io.inputPassword() : io.input();
364
+
365
+ //System.out.println("s="+Arrays.toString(s));
366
+
367
+ if(Numbers.checkNumbers(s)) break;
368
+
369
+ io.println("数字は重複せず、3桁です");
370
+
371
+ }
372
+
373
+ return new Numbers(s);
374
+
375
+ }
376
+
377
+
378
+
379
+ //最終判定
380
+
381
+ static List<Player> judgement(Player[] players) {
382
+
383
+ List<Player> winnerList = new ArrayList<Player>(Arrays.asList(players));
384
+
385
+ Collections.sort(winnerList, (o1,o2) -> o1.getPredictCount()-o2.getPredictCount());
386
+
387
+ //for(Player p : winnerList) System.out.println(p);
388
+
389
+ for(int i=winnerList.size()-1; winnerList.get(i).getPredictCount()>winnerList.get(0).getPredictCount(); i--) winnerList.remove(i);
390
+
391
+ return winnerList;
392
+
393
+ }
394
+
395
+ }
396
+
397
+ ```

1

追加

2021/12/25 10:00

投稿

jimbe
jimbe

スコア12648

test CHANGED
@@ -1,3 +1,13 @@
1
+ > readPassword以外で自分で数字を設定できてかつ非表示にする方法
2
+
3
+
4
+
5
+ コンソール版であればそれが一番確実なのではないでしょうか。
6
+
7
+ コンソール以外に移植することを前提とするのであれば、入出力に関する部分をインターフェースとして定義してそのコンソール版実装クラスを作成しておくのが良いかと思います。
8
+
9
+
10
+
1
11
  > このコードは同じ構文を繰り返していますが、他にもっと短縮簡素化
2
12
 
3
13