回答編集履歴

2

コメントで指摘いただいて間違いを修正

2019/01/05 15:46

投稿

kozuchi
kozuchi

スコア1193

test CHANGED
@@ -1,66 +1,32 @@
1
1
  # 結論
2
2
 
3
- 以下のようにれば、おそらくご期待どおりの動作をすると思われ
3
+ いろいろ間違ったこと書いてせんでした
4
4
 
5
- が、以下のプログラムには明らかな不備があります。
6
-
7
- 具体的には、フィールドの初期化がなされていません。
8
-
9
- それを全修正すると、変更点が多ぎて今回の回答の要点がぼやてしうので、
5
+ 他の方が指摘しるとおりConsole.ReadKey(); を削除るだで済みすね。
10
-
11
- あえて修正していません。
12
6
 
13
7
 
14
8
 
15
- 以下プログラムは、実際上、ぼ期待通りの動作をすると思いますが、
9
+ # そのほ
16
10
 
17
- それ「たあるということをご了承ください
11
+ 今回のご質問と直接関係ない点になりすが、ご参考まで
18
12
 
19
13
 
14
+
15
+ > endがtrueになったら終了するのでfalseにする必要はありません
16
+
17
+
18
+
19
+ であれば、 End フィールドを廃止して、以下のようにしてしまった方が、
20
+
21
+ シンプルかもしれません。
20
22
 
21
23
 
22
24
 
23
25
  ```C#
24
26
 
25
- using System;
26
-
27
-
28
-
29
- namespace RPG経験値計算
30
-
31
- {
32
-
33
- class Program
34
-
35
- {
36
-
37
- string input;
38
-
39
- int Lv;
40
-
41
- int OneUpExp;
42
-
43
- int AllExp;
44
-
45
- bool End;
46
-
47
- bool IntegerIsEntered;
48
-
49
-
50
-
51
- static void Main()
52
-
53
- {
54
-
55
- Program p = new Program();
56
-
57
- while (!p.End)
27
+ while (p.Input())
58
28
 
59
29
  {
60
-
61
- Console.WriteLine("終了したい場合はendを、経験値の計算をしたい場合は整数を入力してください");
62
-
63
- p.Input();
64
30
 
65
31
  if (p.IntegerIsEntered)
66
32
 
@@ -74,372 +40,32 @@
74
40
 
75
41
  }
76
42
 
77
- }
43
+
78
44
 
45
+ // ~ 中略 ~
79
46
 
80
-
81
- void Input()
47
+ bool Input()
82
48
 
83
49
  {
84
50
 
85
- IntegerIsEntered = false;
86
-
87
- End = true;
51
+ bool End;
88
52
 
89
53
 
90
54
 
91
55
  input = Console.ReadLine();
92
56
 
93
- if (input.Contains("end")) End = true;
57
+ IntegerIsEntered = int.TryParse(input, out Lv);
94
58
 
95
- else if (int.TryParse(input, out Lv)) IntegerIsEntered = true;
59
+ End = input.Contains("end");
96
60
 
97
- else
98
61
 
99
- {
100
62
 
101
- Console.WriteLine("endまたは整数を入力してください" );
63
+ if(!( End || IntegerIsEntered )) Console.WriteLine("endまたは整数を入力してください");
102
64
 
103
- IntegerIsEntered = false;
104
65
 
66
+
105
- }
67
+ return !End;
106
68
 
107
69
  }
108
70
 
109
-
110
-
111
- void Calculation()
112
-
113
- {
114
-
115
- AllExp = Lv * Lv * 1000;
116
-
117
- OneUpExp = Lv * Lv * 1000;
118
-
119
- Lv--;
120
-
121
- OneUpExp -= Lv * Lv * 1000;
122
-
123
- }
124
-
125
-
126
-
127
- void Output()
128
-
129
- {
130
-
131
- Console.Write("レベルを1つ上げるために必要な経験値:");
132
-
133
- Console.WriteLine(OneUpExp);
134
-
135
-
136
-
137
- Console.Write("このレベルに達するために必要な経験値");
138
-
139
- Console.WriteLine(AllExp);
140
-
141
- Console.WriteLine("続けるにはenterを押してください");
142
-
143
- Console.ReadKey();
144
-
145
- }
146
-
147
- }
148
-
149
- }
150
-
151
71
  ```
152
-
153
-
154
-
155
- #問題点と変更箇所
156
-
157
- おおざっぱに言うと、二つの問題があります。
158
-
159
-
160
-
161
- 0. メッセージの出力タイミングが不適切
162
-
163
- 0. 判定条件にあてはまらなかった場合の処理がない
164
-
165
-
166
-
167
- それぞれに対応する問題点と修正箇所を書きます
168
-
169
-
170
-
171
- ##問題点1:メッセージの出力タイミングが不適切
172
-
173
- end 以外を入力した場合、再度 Input()関数 を呼んで、入力を読み込むことになりますが、
174
-
175
- 入力を促すメッセージがループの外にあるため、最初の一回しか表示されず、
176
-
177
- 二回目以降、使っている人は「end か 数字を入力する状態」に入ったことをはっきり知ることができません。
178
-
179
- また、Output() 関数の最後で、ReadKey()関数を呼んでいますが、
180
-
181
- 入力を促すメッセージが表示されていません。
182
-
183
- この二つの理由により、
184
-
185
-
186
-
187
- 0.「1」を入力する
188
-
189
- 0.「end」を入力する
190
-
191
-
192
-
193
- といった操作をした場合、Output() 関数の最後で、ReadKey()関数 に endの 「e」
194
-
195
- が読まれてしまい、そのあとでループの先頭に戻ったのちInput() 関数が呼ばれた際には
196
-
197
- 「nd」しか読まれなくなってしまいます。
198
-
199
-
200
-
201
-
202
-
203
- ### 変更箇所1
204
-
205
- 「end か 数字を入力する状態」にあることを示すメッセージをループ内に入れて毎回出るようにします。
206
-
207
-
208
-
209
- #### 変更前
210
-
211
- ```C#
212
-
213
- 17: Console.WriteLine("終了したい場合はendを、経験値の計算をしたい場合は整数を入力してください");
214
-
215
- 18: while (!p.End)
216
-
217
- 19: {
218
-
219
- 20: p.Input();
220
-
221
- 21: if (p.IntegerIsEntered)
222
-
223
- 22: {
224
-
225
- 23: p.Calculation();
226
-
227
- 24: p.Output();
228
-
229
- 25: }
230
-
231
- 26: }
232
-
233
- ```
234
-
235
-
236
-
237
- #### 変更後
238
-
239
- ```C#
240
-
241
- 17: while (!p.End)
242
-
243
- 18: {
244
-
245
- 19: Console.WriteLine("終了したい場合はendを、経験値の計算をしたい場合は整数を入力してください");
246
-
247
- 20: p.Input();
248
-
249
- 21: if (p.IntegerIsEntered)
250
-
251
- 22: {
252
-
253
- 23: p.Calculation();
254
-
255
- 24: p.Output();
256
-
257
- 25: }
258
-
259
- 26: }
260
-
261
- ```
262
-
263
-
264
-
265
- ### 変更箇所2
266
-
267
- Output() 関数の最後で、ReadKey()関数の読み込み状態(何らかのキーが押されるのを待っている状態)
268
-
269
- にあることを示すメッセージを追加します。
270
-
271
-
272
-
273
- #### 変更前
274
-
275
- ```C#
276
-
277
- 53:
278
-
279
- 54: Console.Write("このレベルに達するために必要な経験値");
280
-
281
- 55: Console.WriteLine(AllExp);
282
-
283
- 56: Console.ReadKey();
284
-
285
-
286
-
287
- ```
288
-
289
-
290
-
291
- #### 変更後
292
-
293
- ```C#
294
-
295
- 56:
296
-
297
- 57: Console.Write("このレベルに達するために必要な経験値");
298
-
299
- 58: Console.WriteLine(AllExp);
300
-
301
- 59: Console.WriteLine("続けるにはenterを押してください");
302
-
303
- 60: Console.ReadKey();
304
-
305
- ```
306
-
307
-
308
-
309
- ##問題点2:判定条件にあてはまらなかった場合の処理がない
310
-
311
- Input() 関数で、
312
-
313
-
314
-
315
- - 入力は end か?
316
-
317
- - 入力は数値か?
318
-
319
-
320
-
321
- の判定が行われていますが、それぞれ、「end でなかった場合」「数値でなかった場合」の
322
-
323
- 処理がありません。
324
-
325
- 今回の問題の原因となっている IntegerIsEntered に関して言うと、いったん整数が入力された場合に、IntegerIsEntered を true にしていますが、
326
-
327
- 入力が数値でなかった場合に IntegerIsEntered を false にする処理が無いため
328
-
329
- 一度 ture になった IntegerIsEntered はずっと true のままです。
330
-
331
-
332
-
333
- このため、一度整数を入力するとそのあとは「end」 を入力しても、いちいち Output() が呼ばれるので、
334
-
335
- 意図しない表示が行われ ReadKey() が呼ばれるのですぐには終わりません。
336
-
337
- この動きを回避するためには、欠落している処理を追加する必要があります。
338
-
339
-
340
-
341
- ### 変更箇所
342
-
343
- IntegerIsEntered と End にいったん false を入れる処理を追加し、
344
-
345
- 入力がそれぞれの条件を満たさない場合は対応するフィールドが false になるようにしました。
346
-
347
-
348
-
349
- #### 変更前
350
-
351
- ```C#
352
-
353
- 29: void Input()
354
-
355
- 30: {
356
-
357
- 31: input = Console.ReadLine();
358
-
359
- 32: if (input.Contains("end")) End = true;
360
-
361
- 33: else if (int.TryParse(input, out Lv)) IntegerIsEntered = true;
362
-
363
- 34: else
364
-
365
- 35: {
366
-
367
- 36: Console.WriteLine("endまたは整数を入力してください");
368
-
369
- 37: IntegerIsEntered = false;
370
-
371
- 38: }
372
-
373
- 39: }
374
-
375
- ```
376
-
377
-
378
-
379
- #### 変更後
380
-
381
- ```C#
382
-
383
- 28:
384
-
385
- 29: void Input()
386
-
387
- 30: {
388
-
389
- 31: IntegerIsEntered = false;
390
-
391
- 32: End = true;
392
-
393
- 33:
394
-
395
- 34: input = Console.ReadLine();
396
-
397
- 35: if (input.Contains("end")) End = true;
398
-
399
- 36: else if (int.TryParse(input, out Lv)) IntegerIsEntered = true;
400
-
401
- 37: else
402
-
403
- 38: {
404
-
405
- 39: Console.WriteLine("endまたは整数を入力してください" );
406
-
407
- 40: IntegerIsEntered = false;
408
-
409
- 41: }
410
-
411
- 42: }
412
-
413
- ```
414
-
415
-
416
-
417
- ## そのほかの問題点
418
-
419
- > この問題に関しては上記コードでは対策できていませんので、
420
-
421
- > ご自分でお調べになって対応してください。
422
-
423
- > きわめて基本的なことなので、調べればすぐにたくさんの情報が得られると思います。
424
-
425
-
426
-
427
- フィールドの初期化が全く行われていません。
428
-
429
- このため、起動直後の
430
-
431
- ```C#
432
-
433
- while (!p.End)
434
-
435
- ```
436
-
437
- がどう動くかは厳密には不定(どう動くかは正確には予測できない)です。
438
-
439
- フィールドの初期化はクラスのインスタンスを生成した時点(new した時点)でコンストラクタでなされるべきですが、
440
-
441
- 実際の動作を見る限り、 bool 型のフィールドには false が初期値として入っているようですので、
442
-
443
- 上記コードはとりあえず動くと思いますが、動作に確実を期すためと、今後の機能追加などでの問題の原因とならないようにするために
444
-
445
- 初期化の処理を追加することを強くお勧めします。

1

記述ミスの訂正

2019/01/05 15:46

投稿

kozuchi
kozuchi

スコア1193

test CHANGED
@@ -160,7 +160,7 @@
160
160
 
161
161
  0. メッセージの出力タイミングが不適切
162
162
 
163
- 0. 変数初期化がなされてない
163
+ 0. 判定条件にあてはまらなかった場合処理がない
164
164
 
165
165
 
166
166
 
@@ -306,7 +306,7 @@
306
306
 
307
307
 
308
308
 
309
- ##問題点2:フィールド初期化がなされてない
309
+ ##問題点2:判定条件にあてはまらなかった場合処理がない
310
310
 
311
311
  Input() 関数で、
312
312