forked from TheCSharpAcademy/CodeReviews.Console.MathGame
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.cs
325 lines (285 loc) · 9.26 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/** Requirements
1. You need to create a Math game containing the 4 basic operations
2. The divisions should result on INTEGERS ONLY and dividends should go from 0 to 100. Example: Your app shouldn't present the division 7/2 to the user, since it doesn't result in an integer.
3. Users should be presented with a menu to choose an operation
4. You should record previous games in a List and there should be an option in the menu for the user to visualize a history of previous games.
5. You don't need to record results on a database. Once the program is closed the results will be deleted
*/
/** Challenges
1. Try to implement levels of difficulty.
2. Add a timer to track how long the user takes to finish the game.
3. Create a 'Random Game' option where the players will be presented with questions from random operations
*/
List<HighscoreEntry> highscores = new List<HighscoreEntry>();
int menuSelection;
Console.WriteLine("Welcome to the Math Game app.");
do
{
Console.WriteLine("\nSelect an option:");
Console.WriteLine("1. Start a new game");
Console.WriteLine("2. See Highscores (session)");
Console.WriteLine("0. Exit");
menuSelection = ReadUserInput();
Console.Clear();
switch (menuSelection)
{
case 1:
ShowNewGameMenu();
break;
case 2:
ShowHighscores();
break;
case 0:
Console.WriteLine("Goodbye!");
break;
default:
Console.WriteLine("Invalid option.");
break;
}
} while (menuSelection != 0);
void ShowHighscores()
{
if (highscores.Count == 0)
System.Console.WriteLine("Nothing here yet...");
else
{
// Order highscores
List<HighscoreEntry> ordered = highscores.OrderByDescending(t => t.Score).ThenBy(t => t.ElapsedTime).ToList();
for (int i = 0; i < highscores.Count; i++)
{
Console.WriteLine($"{(i + 1).ToString().PadLeft(2)}. {ordered[i]}");
}
}
Console.WriteLine("Press enter to continue.");
Console.ReadLine();
}
void ShowNewGameMenu()
{
int menuSelection;
do
{
// Game options:
Console.WriteLine("Select a game:");
Console.WriteLine("1. Addition");
Console.WriteLine("2. Subtraction");
Console.WriteLine("3. Multiplication");
Console.WriteLine("4. Division");
Console.WriteLine("5. Random");
Console.WriteLine("0. Main Menu");
menuSelection = ReadUserInput();
Console.Clear();
switch (menuSelection)
{
case 1:
StartGame(MathOperation.Addition);
break;
case 2:
StartGame(MathOperation.Subtraction);
break;
case 3:
StartGame(MathOperation.Multiplication);
break;
case 4:
StartGame(MathOperation.Division);
break;
case 5:
StartGame(MathOperation.Random);
break;
case 0:
break;
default:
Console.WriteLine("Invalid option.");
break;
}
} while (menuSelection != 0);
}
GameDifficulty GetGameDifficulty()
{
// Game difficulties:
Console.WriteLine("Select a difficulty:");
Console.WriteLine("1. Easy");
Console.WriteLine("2. Medium");
Console.WriteLine("3. Hard");
int difficultySelection = ReadUserInput();
GameDifficulty selectedDifficulty = GameDifficulty.Easy;
bool validOption = false;
do
{
switch (difficultySelection)
{
case 1:
selectedDifficulty = GameDifficulty.Easy;
validOption = true;
break;
case 2:
selectedDifficulty = GameDifficulty.Medium;
validOption = true;
break;
case 3:
selectedDifficulty = GameDifficulty.Hard;
validOption = true;
break;
default:
Console.WriteLine("Invalid option.");
break;
}
} while (!validOption);
return selectedDifficulty;
}
/** This function cannot return MathOperation.Random */
MathOperation GetMathOperation()
{
int option = new Random().Next(1, 5);
switch (option)
{
case 1: return MathOperation.Addition;
case 2: return MathOperation.Subtraction;
case 3: return MathOperation.Multiplication;
case 4: return MathOperation.Division;
}
throw new ArgumentOutOfRangeException("Invalid option");
}
void StartGame(MathOperation gameOption)
{
GameDifficulty gameDifficulty = GetGameDifficulty();
Console.Clear();
int score = 0;
bool continueGame = true;
int userResponse, correctResponse;
MathOperation mathOperation = gameOption;
var start = DateTime.Now;
while (continueGame)
{
if (gameOption == MathOperation.Random)
mathOperation = GetMathOperation();
(int, int) terms = GetOperationTerms(mathOperation, gameDifficulty);
Console.WriteLine($"How much is {terms.Item1}{GetGameOperator(mathOperation)}{terms.Item2}?");
userResponse = ReadUserInput();
correctResponse = ApplyMathOperation(mathOperation, terms.Item1, terms.Item2);
if (correctResponse == userResponse)
score += CalcScore(mathOperation, gameDifficulty);
else
{
Console.WriteLine($"The right answer was {correctResponse}");
continueGame = false;
}
}
var end = DateTime.Now;
TimeSpan delta = end - start;
Console.WriteLine($"Game finished after {delta.TotalSeconds} seconds! Score: {score}");
// TODO Update Highscores
Console.WriteLine("Insert player name");
string? userNameInput = Console.ReadLine();
string userName = userNameInput == null ? "Anonymous" : userNameInput;
highscores.Add(new HighscoreEntry(score, gameDifficulty, userName, delta));
}
(int, int) GetOperationTerms(MathOperation mathOperation, GameDifficulty gameDifficulty)
{
Random rnd = new Random();
int term1, term2;
int difficulty = (int)gameDifficulty;
// Term 1
term1 = rnd.Next(difficulty);
// Term 2
if (mathOperation == MathOperation.Division)
// If operation is Division, then avoid 0 as the denominator.
// Also, avoid terms that don't produce integer results
do
{
term2 = rnd.Next(1, difficulty);
} while (term1 % term2 != 0);
else
term2 = rnd.Next(difficulty / 5);
// If Subtracting, then make the result a positive value
if (mathOperation == MathOperation.Subtraction && term1 < term2)
return (term2, term1);
else
return (term1, term2);
}
int ReadUserInput()
{
string? readResult;
bool parseSuccess = false;
int userInput = -1;
do
{
readResult = Console.ReadLine();
if (readResult != null)
{
parseSuccess = int.TryParse(readResult, out userInput);
}
} while (!parseSuccess);
return userInput;
}
int CalcScore(MathOperation mathOperation, GameDifficulty gameDifficulty)
{
int operationScore = (int)mathOperation + 1;
switch (gameDifficulty)
{
case GameDifficulty.Easy: return operationScore * 2;
case GameDifficulty.Medium: return operationScore * 3;
case GameDifficulty.Hard: return operationScore * 4;
}
throw new ArgumentOutOfRangeException("gameDifficulty is not valid");
}
int ApplyMathOperation(MathOperation mathOperation, int leftNumber, int rightNumber)
{
switch (mathOperation)
{
case MathOperation.Addition:
return leftNumber + rightNumber;
case MathOperation.Subtraction:
return leftNumber - rightNumber;
case MathOperation.Multiplication:
return leftNumber * rightNumber;
case MathOperation.Division:
return leftNumber / rightNumber;
default:
throw new ArgumentOutOfRangeException("GameOption is not valid: " + mathOperation);
}
}
string GetGameOperator(MathOperation mathOperation)
{
switch (mathOperation)
{
case MathOperation.Addition:
return "+";
case MathOperation.Subtraction:
return "-";
case MathOperation.Multiplication:
return "*";
case MathOperation.Division:
return "/";
default:
throw new ArgumentOutOfRangeException("GameOption is not valid: " + mathOperation);
}
}
enum MathOperation
{
Addition,
Subtraction,
Multiplication,
Division,
Random,
}
public enum GameDifficulty
{
Easy = 50,
Medium = 100,
Hard = 500,
}
public struct HighscoreEntry
{
public HighscoreEntry(int score, GameDifficulty selectedDifficulty, string playerName, TimeSpan elapsedTime)
{
Score = score;
SelectedDifficulty = selectedDifficulty;
PlayerName = playerName;
ElapsedTime = elapsedTime;
}
public double Score { get; }
public GameDifficulty SelectedDifficulty { get; }
public string PlayerName { get; }
public TimeSpan ElapsedTime { get; }
public override string ToString() => $"{PlayerName.PadRight(20)} -- {Score.ToString().PadLeft(5)} ({SelectedDifficulty}) -- {ElapsedTime:mm':'ss}";
}