teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

5

追記

2018/04/26 05:29

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -317,8 +317,8 @@
317
317
 
318
318
  このスコア部分をテストしたい場合、回答文のコードなら以下のようなテストコードを作れます。
319
319
  テストメソッドの結果がtrueなら、J,Q,Kのスコア算出に関しては頭の意識外にほぼ置いて置けるのです。
320
- 残りのスコア計算で必要なのはaceカードかそうでないかを判定して処理を記述するだけです。
320
+ 残りのスコア計算で必要なのはaceカードかそうでないかを判定して処理を記述するだけです。そしてこのコードに関してはキーボード入力は必要ないのです。
321
- int型やString型を変数に使うのも一つの手ですが、クラス化してテストしやすさを意識してみるといいかもです。
321
+ `int`型や`String`型を変数に使うのも一つの手ですが、クラス化して**テストしやすさ**を意識してみるといいかもです。
322
322
 
323
323
  ```Java
324
324
  public static boolean testCardScore_JQK() {

4

追記

2018/04/26 05:29

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -282,6 +282,53 @@
282
282
  return Arrays.toString(cards.toArray(new Card[0]));
283
283
  }
284
284
  }
285
+ ```
285
286
 
287
+ ---
286
288
 
289
+ > 実際の処理はできるだけMain関数には書かず自分でつくったクラス、メソッドの中に
290
+ > 書いたほうがいいのでしょうか?
291
+
292
+ コードの規模とコーディングルールとかによって変わりますが。
293
+ **ぶっちゃけて言うとteratailでよくある質問内容なら、mainに全部書いても動くことは動きます。**
294
+
295
+ 私が`main`メソッドに書かない理由は以下の2点です。
296
+ 0. `main`メソッドが`static`メソッドである点
297
+ →このため他のメソッドを呼び出す時に`static`宣言しないといけない
298
+ 0. 一つのメソッドが長いと依存が増えてテストしずらい。
299
+ →テスト容易性は大事です。今回のコードでキーボードからの外部入力が必要な部分は**Playerクラスのtrunメソッドだけ**です。他のクラスはキーボードからの外部入力は不要です。でもmainに全部記述すると、
300
+ いちいちキーボード入力を行う必要があります。
301
+ ※ここは後ほど具体的なコードで説明します。
302
+
303
+ クラス分けに関しては最初はアクター:役者(もしくは主語)をクラス化してみてどうでしょうか、今回の場合だと、以下のようになります。
304
+ |アクター|クラス|
305
+ |:--|:--:|
306
+ |ゲームマスター|GameMaster|
307
+ |プレイヤー|Player|
308
+ |ディラー|Dealer|
309
+ |カード|Card|
310
+ |カードデッキ|CardDeck|
311
+
312
+ 話を戻しますが、例えばブラックジャックのスコア計算を行いたい場合
313
+
314
+ 0. カードの11:J, 12:Q, 13:Kはスコアを10として扱う。
315
+ 0. Aceカードは1または11として扱う。
316
+ 0. 残りのカードは数字(Rank)をスコアとして加算する。
317
+
318
+ このスコア部分をテストしたい場合、回答文のコードなら以下のようなテストコードを作れます。
319
+ テストメソッドの結果がtrueなら、J,Q,Kのスコア算出に関しては頭の意識外にほぼ置いて置けるのです。
320
+ 残りのスコア計算で必要なのはaceカードかそうでないかを判定して処理を記述するだけです。
321
+ int型やString型を変数に使うのも一つの手ですが、クラス化してテストしやすさを意識してみるといいかもです。
322
+
323
+ ```Java
324
+ public static boolean testCardScore_JQK() {
325
+
326
+ Card[] jqk = { new Card("\u2660", 11), new Card("\u2660", 12), new Card("\u2660", 13) };
327
+ for (Card c : jqk) {
328
+ if (c.calcScore() != 10) {
329
+ return false;
330
+ }
331
+ }
332
+ return true;
333
+ }
287
334
  ```

3

追記

2018/04/26 05:20

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -4,12 +4,8 @@
4
4
  私がStars1024さんが書いたコードをクラス分けするとしたらこんな感じになります。
5
5
 
6
6
  ※)元の質問文の要件にはないですが、柄(Suit)対応も行いました。
7
- ポイントはcard_listからのカードを配る(deal)事をCardDeckクラスを新設して管理している点でしょうか。こうすることで、dealメソッドが正しく動作すれば、他のクラスではcard_listの状態を意識しなくても良くなります。
7
+ ポイントは`card_list`からのカードを配る(`deal`)事を`CardDeck`クラスを新設して管理している点でしょうか。こうすることで、`CardDeck#deal`メソッドが正しく動作すれば、他のクラスでは`card_list`内部状態を意識しなくても良くなります。
8
- ```Java
9
- int []card_list = new int[13];
10
- ```
11
8
 
12
-
13
9
  ```Java
14
10
  import java.util.ArrayDeque;
15
11
  import java.util.ArrayList;

2

コメントを追加!

2018/04/25 22:26

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -4,7 +4,12 @@
4
4
  私がStars1024さんが書いたコードをクラス分けするとしたらこんな感じになります。
5
5
 
6
6
  ※)元の質問文の要件にはないですが、柄(Suit)対応も行いました。
7
+ ポイントはcard_listからのカードを配る(deal)事をCardDeckクラスを新設して管理している点でしょうか。こうすることで、dealメソッドが正しく動作すれば、他のクラスではcard_listの状態を意識しなくても良くなります。
8
+ ```Java
9
+ int []card_list = new int[13];
10
+ ```
7
11
 
12
+
8
13
  ```Java
9
14
  import java.util.ArrayDeque;
10
15
  import java.util.ArrayList;
@@ -22,7 +27,7 @@
22
27
  public static void main(String[] args) {
23
28
  GameMaster game = new GameMaster();
24
29
  game.start();
25
- game.show_result();
30
+ game.showResult();
26
31
  }
27
32
  }
28
33
 
@@ -42,8 +47,8 @@
42
47
 
43
48
  class GameMaster {
44
49
  private static final CardDeck deck = new CardDeck();
45
- private final List<Player> players = Collections
46
- .unmodifiableList(Arrays.asList(new Player("あなた"), new Dealer("ディラー")));
50
+ private final Player dealer = new Dealer("ディラー");
51
+ private final List<Player> players = Collections.unmodifiableList(Arrays.asList(new Player("あなた"), dealer));
47
52
 
48
53
  enum Judge {
49
54
  Win("勝ちました!!"), Draw("引き分け"), Lose("負けました.....");
@@ -68,7 +73,7 @@
68
73
  }
69
74
  });
70
75
  // ディラーのカードを表示
71
- System.out.println(players.get(1));
76
+ System.out.println(dealer);
72
77
 
73
78
  while (true) {
74
79
  int skiped = players.stream().mapToInt(Player::trun).sum();
@@ -83,7 +88,7 @@
83
88
  return deck.deal();
84
89
  }
85
90
 
86
- public Judge Judge(Player player, Player dealer) {
91
+ public Judge judge(Player player, Player dealer) {
87
92
  int compared = player.compareTo(dealer);
88
93
  if (compared == 0) {
89
94
  return Judge.Draw;
@@ -94,15 +99,15 @@
94
99
  return Judge.Win;
95
100
  }
96
101
 
97
- public void show_result() {
102
+ public void showResult() {
98
- System.out.println(String.join("", Collections.nCopies(30, "#")));
103
+ System.out.println(String.join("", Collections.nCopies(40, "#")));
99
104
  System.out.println("最終結果");
100
105
  for (Player p : players) {
101
106
  System.out.print(p);
102
107
  System.out.println(" 合計:" + p.calcScore());
103
108
  }
104
109
  // プレイヤーとディラーの勝敗判定
105
- Judge judge = Judge(players.get(0), players.get(1));
110
+ Judge judge = judge(players.get(0), dealer);
106
111
  System.out.println(judge);
107
112
  }
108
113
  }
@@ -112,6 +117,7 @@
112
117
  // 手札
113
118
  private final List<Card> myCardList = new ArrayList<>();
114
119
  private final String name;
120
+ // 変数:user_stopと変数:dealer_stopはここ
115
121
  protected boolean skiped = false;
116
122
 
117
123
  public Player(String name) {
@@ -123,6 +129,7 @@
123
129
  }
124
130
 
125
131
  public void deal() {
132
+ // Player#Draw_Cardはここ
126
133
  // 山から一枚カードを引いて手札に加える。
127
134
  Card c = GameMaster.deal();
128
135
  myCardList.add(c);
@@ -153,10 +160,12 @@
153
160
  }
154
161
 
155
162
  public boolean isBusting() {
163
+ // Player#Judge_burstはここ
156
164
  return calcScore() > BLACK_JACK;
157
165
  }
158
166
 
159
167
  public int calcScore() {
168
+ // Player#calc_sumはここ
160
169
  int aces_count = 0;
161
170
  int sum = 0;
162
171
  for (Card c : this.myCardList) {
@@ -192,6 +201,7 @@
192
201
 
193
202
  @Override
194
203
  public String toString() {
204
+ // Player#Show_Listはここ
195
205
  return name + "が持っているカード:" + myCardList.stream().map(String::valueOf).collect(Collectors.joining(" "));
196
206
  }
197
207
  }
@@ -244,11 +254,13 @@
244
254
 
245
255
  @Override
246
256
  public String toString() {
257
+ // Player#card_nameはここ
247
258
  return this.suit + RANKS.get(this.rank - 1);
248
259
  }
249
260
  }
250
261
 
251
262
  class CardDeck {
263
+ // Sum#mainの変数:card_list はここ
252
264
  private final Deque<Card> cards;
253
265
 
254
266
  public CardDeck() {
@@ -275,4 +287,5 @@
275
287
  }
276
288
  }
277
289
 
290
+
278
291
  ```

1

追記

2018/04/25 22:24

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -3,15 +3,19 @@
3
3
  `Dealer`(ディラークラス)が`Player` を継承する是非についてはスルーしていただくとして。
4
4
  私がStars1024さんが書いたコードをクラス分けするとしたらこんな感じになります。
5
5
 
6
+ ※)元の質問文の要件にはないですが、柄(Suit)対応も行いました。
7
+
6
8
  ```Java
7
9
  import java.util.ArrayDeque;
8
10
  import java.util.ArrayList;
9
11
  import java.util.Arrays;
10
12
  import java.util.Collections;
13
+ import java.util.Deque;
11
14
  import java.util.List;
15
+ import java.util.Objects;
12
16
  import java.util.Random;
13
17
  import java.util.Scanner;
14
- import java.util.StringJoiner;
18
+ import java.util.stream.Collectors;
15
19
  import java.util.stream.IntStream;
16
20
 
17
21
  public class A122097 {
@@ -26,13 +30,20 @@
26
30
  private static Scanner sc = new Scanner(System.in);
27
31
 
28
32
  public static int readInt() {
33
+ while (true) {
34
+ try {
29
- return Integer.parseInt(sc.nextLine());
35
+ return Integer.parseInt(sc.nextLine());
36
+ } catch (NumberFormatException ex) {
37
+ System.err.println(ex);
38
+ }
39
+ }
30
40
  }
31
41
  }
32
42
 
33
43
  class GameMaster {
34
- private final Deck deck = new Deck();
44
+ private static final CardDeck deck = new CardDeck();
45
+ private final List<Player> players = Collections
35
- private final Player[] players = { new Player("あなた", deck), new Dealer("ディラー", deck) };
46
+ .unmodifiableList(Arrays.asList(new Player("あなた"), new Dealer("ディラー")));
36
47
 
37
48
  enum Judge {
38
49
  Win("勝ちました!!"), Draw("引き分け"), Lose("負けました.....");
@@ -49,29 +60,29 @@
49
60
  }
50
61
  }
51
62
 
52
- GameMaster() {
63
+ public void start() {
53
- // 最初に2枚配る。
64
+ // 参加者に2枚ずつカードを配る。
54
- for (int i = 0; i < 2; i++) {
65
+ IntStream.range(0, 2).forEach((i) -> {
55
66
  for (Player p : players) {
56
67
  p.deal();
57
68
  }
58
- }
69
+ });
59
- }
70
+ // ディラーのカードを表示
71
+ System.out.println(players.get(1));
60
72
 
61
- public void start() {
62
73
  while (true) {
63
- int skiped = 0;
64
- for (Player p : players) {
65
- skiped += p.Turn();
66
- //System.out.println(p);
74
+ int skiped = players.stream().mapToInt(Player::trun).sum();
67
- }
68
- // 全員スキップなら
75
+ // 参加者全員スキップなら
69
76
  if (skiped == 0) {
70
77
  break;
71
78
  }
72
79
  }
73
80
  }
74
81
 
82
+ public static Card deal() {
83
+ return deck.deal();
84
+ }
85
+
75
86
  public Judge Judge(Player player, Player dealer) {
76
87
  int compared = player.compareTo(dealer);
77
88
  if (compared == 0) {
@@ -91,57 +102,58 @@
91
102
  System.out.println(" 合計:" + p.calcScore());
92
103
  }
93
104
  // プレイヤーとディラーの勝敗判定
94
- Judge judge = Judge(players[0], players[1]);
105
+ Judge judge = Judge(players.get(0), players.get(1));
95
106
  System.out.println(judge);
96
107
  }
97
108
  }
98
109
 
99
110
  class Player implements Comparable<Player> {
100
- private final Deck deck;
111
+ private static final int BLACK_JACK = 21;
101
112
  // 手札
102
113
  private final List<Card> myCardList = new ArrayList<>();
103
- private final String myName;
114
+ private final String name;
104
- private boolean skiped = false;
115
+ protected boolean skiped = false;
105
116
 
106
- public Player(String name, Deck deck) {
117
+ public Player(String name) {
107
- this.myName = name;
118
+ this.name = name;
108
- this.deck = deck;
109
119
  }
110
120
 
111
121
  public String getName() {
112
- return this.myName;
122
+ return this.name;
113
123
  }
114
124
 
115
- public Card deal() {
125
+ public void deal() {
116
126
  // 山から一枚カードを引いて手札に加える。
117
- Card c = this.deck.deal();
127
+ Card c = GameMaster.deal();
118
128
  myCardList.add(c);
119
- return c;
120
129
  }
121
130
 
122
131
  public boolean isSkip() {
123
- return skiped || isBurst();
132
+ return skiped || isBusting();
124
133
  }
125
134
 
126
- public int Turn() {
135
+ public int trun() {
127
136
  if (isSkip()) {
128
137
  return 0;
129
138
  }
130
139
  System.out.println(this.toString());
131
- System.out.println("カードを引きますか?");
140
+ System.out.println("カードを引きますか?");
132
- System.out.println("yes -> 1 no -> 0 を入力");
141
+ System.out.print("yes -> 1 no -> 0 を入力");
142
+ int n = 0;
143
+ do {
133
- int n = InputUtils.readInt();
144
+ n = InputUtils.readInt();
134
- if (n == 0) {
145
+ if (n == 0) {
135
- skiped = true;
146
+ skiped = true;
136
- return 0;
147
+ return 0;
137
- }
148
+ }
149
+ } while (n != 1);
150
+
138
151
  this.deal();
139
-
140
152
  return 1;
141
153
  }
142
154
 
143
- public boolean isBurst() {
155
+ public boolean isBusting() {
144
- return calcScore() > 21;
156
+ return calcScore() > BLACK_JACK;
145
157
  }
146
158
 
147
159
  public int calcScore() {
@@ -155,23 +167,24 @@
155
167
  }
156
168
  sum += rank;
157
169
  }
158
- // カードのAのスコア計算
159
170
  if (aces_count == 0) {
160
171
  return sum;
161
172
  }
173
+ // Aceカードのスコア計算
162
174
  int aces_sum = 11 + (aces_count - 1);
163
- if (aces_sum + sum > 21)
175
+ if (aces_sum + sum > BLACK_JACK) {
164
176
  aces_sum = aces_count;
177
+ }
165
178
  return sum + aces_sum;
166
179
  }
167
180
 
168
181
  @Override
169
182
  public int compareTo(Player o) {
170
- if (this.isBurst()) {
183
+ if (this.isBusting()) {
171
184
  return -1;
172
185
  }
173
186
  // ディラー
174
- if (o.isBurst()) {
187
+ if (o.isBusting()) {
175
188
  return 1;
176
189
  }
177
190
  return Integer.compare(this.calcScore(), o.calcScore());
@@ -179,25 +192,25 @@
179
192
 
180
193
  @Override
181
194
  public String toString() {
182
- StringJoiner joiner = new StringJoiner(" ");
183
- for (Card c : this.myCardList) {
184
- joiner.add(c.toString());
185
- }
186
- return myName + "が持っているカード:" + joiner.toString();
195
+ return name + "が持っているカード:" + myCardList.stream().map(String::valueOf).collect(Collectors.joining(" "));
187
196
  }
188
197
  }
189
198
 
190
199
  class Dealer extends Player {
191
- public Dealer(String name, Deck deck) {
200
+ public Dealer(String name) {
192
- super(name, deck);
201
+ super(name);
193
202
  }
194
203
 
195
204
  @Override
196
- public int Turn() {
205
+ public int trun() {
206
+ if (isSkip()) {
207
+ return 0;
208
+ }
197
209
  /// soft 17 rule
198
210
  int score = this.calcScore();
199
211
  if (score >= 17) {
200
212
  System.out.println(this.getName() + "はカードを引きません。");
213
+ skiped = true;
201
214
  return 0;
202
215
  }
203
216
  System.out.println(this.getName() + "はカードを引きます。");
@@ -207,59 +220,46 @@
207
220
  }
208
221
 
209
222
  class Card {
223
+ // BLACK SPADE, BLACK CLUB, WHITE DIAMOND, WHITE HEART
210
- private final String Mark;
224
+ public static final List<String> SUITS = Collections
225
+ .unmodifiableList(Arrays.asList("\u2660", "\u2663", "\u2662", "\u2661"));
211
- private final int Rank;
226
+ public static final List<String> RANKS = Collections
227
+ .unmodifiableList(Arrays.asList("A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"));
212
228
 
229
+ private final String suit;
230
+ private final int rank;
231
+
213
- public Card(String Mark, int Rank) {
232
+ public Card(String suit, int rank) {
233
+ Objects.requireNonNull(suit);
234
+ if (rank > RANKS.size()) {
235
+ throw new IllegalArgumentException(Integer.toString(rank));
236
+ }
214
- this.Mark = Mark;
237
+ this.suit = suit;
215
- this.Rank = Rank;
238
+ this.rank = rank;
216
239
  }
217
240
 
218
241
  public int calcScore() {
219
- if (this.Rank > 10) {
220
- return 10;
221
- }
222
- return this.Rank;
242
+ return Math.min(this.rank, 10);
223
243
  }
224
244
 
225
245
  @Override
226
246
  public String toString() {
227
- final String r;
228
- switch (this.Rank) {
229
- case 1:
230
- r = "A";
231
- break;
232
- case 11:
233
- r = "J";
234
- break;
235
- case 12:
236
- r = "Q";
237
- break;
238
- case 13:
239
- r = "K";
240
- break;
241
- default:
242
- r = Integer.toString(this.Rank);
247
+ return this.suit + RANKS.get(this.rank - 1);
243
- break;
244
- }
245
- return this.Mark + r;
246
248
  }
247
249
  }
248
250
 
249
- class Deck {
251
+ class CardDeck {
250
- private final ArrayDeque<Card> cards;
252
+ private final Deque<Card> cards;
251
253
 
252
- public Deck() {
254
+ public CardDeck() {
253
- List<Card> card_list = new ArrayList<>();
255
+ List<Card> card_list = new ArrayList<>(Card.RANKS.size() * Card.SUITS.size());
254
- IntStream.rangeClosed(1, 13).forEach((i) -> {
256
+ IntStream.rangeClosed(1, Card.RANKS.size()).forEach((i) -> {
257
+ for (String suit : Card.SUITS) {
255
- card_list.add(new Card("\u2660", i));
258
+ card_list.add(new Card(suit, i));
256
- card_list.add(new Card("\u2663", i));
259
+ }
257
- card_list.add(new Card("\u2662", i));
258
- card_list.add(new Card("\u2661", i));
259
260
  });
260
-
261
261
  Random rnd = new Random();
262
- // Random#setSeedでshuffleの結果を固定(テスト用)
262
+ // Random#setSeedでshuffleの実行結果を固定(テスト用)
263
263
  // rnd.setSeed(42);
264
264
  Collections.shuffle(card_list, rnd);
265
265
  cards = new ArrayDeque<>(card_list);