-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.cs
387 lines (349 loc) · 19 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
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
using System;
namespace Minesweeper
{
/*
CLASS CELL: The single grid cell
PARAMETERS:
- NUM: Defines the type of the cell, -1 means uninitialized, 0 means nothing, 9 means bomb, any other number is the surrounding bomb count
- FLAG: 0 means nothing, 1 means flag, 2 means question mark
- MANTLED: TRUE means mantled, FALSE means dismantled
*/
class Cell
{
public int num = -1, flag = 0;
public bool mantled = true;
}
/*
CLASS COORDINATE: A data structure for coordinate pairs
PARAMETERS:
- X, Y: Together they make the coordinates of the cursor
*/
class Coordinate
{
public int x = 0, y = 0;
}
class Program
{
static void ConsoleSetColor(ConsoleColor fg, ConsoleColor bg = ConsoleColor.Black)
{
Console.ForegroundColor = fg;
Console.BackgroundColor = bg;
}
static void Main()
{
/* ======== RUNTIME VARIABLES ======== */
string[] main_menu = { "Play", "Options", "Quit" };
int grid_height = 10, grid_width = 15, bombs = 20;
bool cont = true;
ConsoleKey key; // Used to handle user key input
int choice; // Used to store user selection
/* ======== PROGRAM LOOP ======== */
while (cont)
{
// Menu loop
choice = 0;
do
{
// Print menu
Console.Clear();
Console.WriteLine(
"Main Menu\n" +
"========="
);
for (int i = 0; i < main_menu.Length; i++)
{
if (i == choice) ConsoleSetColor(Console.BackgroundColor, Console.ForegroundColor);
Console.WriteLine(main_menu[i]);
if (i == choice) Console.ResetColor();
}
// Read user input
key = Console.ReadKey(false).Key;
switch (key)
{
case ConsoleKey.UpArrow:
if (choice > 0) choice--;
break;
case ConsoleKey.DownArrow:
if (choice < main_menu.Length) choice++;
break;
}
} while (key != ConsoleKey.Enter);
switch (main_menu[choice])
{
case "Quit":
cont = false;
break;
case "Options":
// Print settings
Console.Clear();
Console.WriteLine(
"Options\n" +
"========"
);
Console.Write("Grid width: ");
grid_width = Convert.ToInt32(Console.ReadLine());
Console.Write("Grid height: ");
grid_height = Convert.ToInt32(Console.ReadLine());
do
{
Console.Write("Bomb count: ");
bombs = Convert.ToInt32(Console.ReadLine());
if (bombs >= grid_width * grid_height) Console.WriteLine("Too Many bombs!");
} while (bombs >= grid_width * grid_height);
break;
case "Play":
/* ======== GAME RUNTIME VARIABLES ======== */
ConsoleColor[] numcolors = new ConsoleColor[] {
ConsoleColor.Blue,
ConsoleColor.Green,
ConsoleColor.Red,
ConsoleColor.DarkBlue,
ConsoleColor.DarkRed,
ConsoleColor.Cyan,
ConsoleColor.White,
ConsoleColor.DarkGray
};
Cell[,] grid = new Cell[grid_width, grid_height];
Coordinate cursor = new Coordinate();
bool playing = true;
Random r = new Random();
/* ======== GAME FUNCTIONS ======== */
/*
FUNTION PRINTGRID: Prints the grid and puts values parameter MAP in the corresponding cells
PARAMETERS:
- MAP: A two-dimensional char array containing the contents of the grid
*/
void PrintGrid(Cell[,] grid, Coordinate cursor)
{
int w = grid.GetLength(0);
int h = grid.GetLength(1);
Console.SetCursorPosition(0, 0);
Console.CursorVisible = false;
// For each row
for (int y = 0; y < h; y++)
{
// If top
if (y == 0)
for (int x = 0; x < w; x++)
{
if (x == 0) Console.Write("╔═");
else Console.Write("╤═");
if (cursor.y == 0 && x == cursor.x) Console.Write("╤═");
else Console.Write("══");
if (x == w - 1) Console.Write("╗\n");
}
// Else if in middle
else
for (int x = 0; x < w; x++)
{
if (x == 0) Console.Write("╟─");
else Console.Write("┼─");
if (cursor.y == y && cursor.x == x) Console.Write("┬─");
else if (cursor.y + 1 == y && cursor.x == x) Console.Write("┴─");
else Console.Write("──");
if (x == w - 1) Console.Write("╢\n");
}
for (int x = 0; x < w; x++)
{
// If left
if (x == 0 && cursor.x == 0 && cursor.y == y) Console.Write("╟");
else if (x == 0) Console.Write("║");
// Else if in middle
else if (x == cursor.x && y == cursor.y) Console.Write("├");
else if (x == cursor.x + 1 && y == cursor.y) Console.Write("┤");
else Console.Write("│");
if (grid[x, y].mantled)
{
Console.Write("▐");
ConsoleSetColor(Console.BackgroundColor, Console.ForegroundColor);
switch (grid[x, y].flag)
{
case 0:
Console.Write(" ");
break;
case 1:
Console.Write("!");
break;
case 2:
Console.Write("?");
break;
}
Console.ResetColor();
Console.Write("▌");
}
else
switch (grid[x, y].num)
{
case 0:
Console.Write(" ");
break;
case 9:
Console.Write(" X ");
break;
default:
ConsoleSetColor(numcolors[grid[x, y].num - 1]);
Console.Write(String.Format(" {0} ", grid[x, y].num));
Console.ResetColor();
break;
}
// Else if right
if (x == w - 1 && cursor.x == w - 1 && cursor.y == y) Console.Write("╢\n");
else if (x == w - 1) Console.Write("║\n");
}
// If bottom
if (y == h - 1)
for (int x = 0; x < w; x++)
{
if (x == 0) Console.Write("╚═");
else Console.Write("╧═");
if (cursor.y == h - 1 && x == cursor.x) Console.Write("╧═");
else Console.Write("══");
if (x == w - 1) Console.Write("╝\n");
}
}
}
/*
FUNCTION DISMANTLE: Dismantles the selected cell (and calls itself for blank cells)
PARAMETERS:
- X, Y: The coordinates for the cell to dismantle
*/
void Dismantle(int x, int y)
{
grid[x, y].mantled = false;
if (grid[x, y].num == 0)
for (int ry = -1; ry <= 1; ry++)
for (int rx = -1; rx <= 1; rx++)
if (
x + rx >= 0 &&
x + rx < grid_width &&
y + ry >= 0 &&
y + ry < grid_height &&
grid[x + rx, y + ry].mantled
) Dismantle(x + rx, y + ry);
}
/* ======== SETUP ======== */
// Fill grid with cells
for (int y = 0; y < grid.GetLength(1); y++)
for (int x = 0; x < grid.GetLength(0); x++)
grid[x, y] = new Cell();
/* ======== GAME LOOP ======== */
Console.Clear();
while (playing)
{
Cell cell = grid[cursor.x, cursor.y];
PrintGrid(grid, cursor);
// Await user input
key = Console.ReadKey(true).Key;
switch (key)
{
case ConsoleKey.UpArrow:
if (cursor.y > 0) cursor.y--;
break;
case ConsoleKey.RightArrow:
if (cursor.x < grid_width - 1) cursor.x++;
break;
case ConsoleKey.DownArrow:
if (cursor.y < grid_height - 1) cursor.y++;
break;
case ConsoleKey.LeftArrow:
if (cursor.x > 0) cursor.x--;
break;
case ConsoleKey.Spacebar:
// If the cell is uninitialized
if (cell.num == -1)
{
/* ======== SETUP ======== */
// Initialize cells
for (int y = 0; y < grid_height; y++)
for (int x = 0; x < grid_width; x++)
grid[x, y].num++;
// Place bombs
for (int i = 0; i < bombs; i++)
{
int x, y;
// If possible, place bombs not adjacent to first clicked cell
if (i < grid_width * grid_height - 9)
{
bool adjacent;
do
{
x = r.Next(grid_width);
y = r.Next(grid_height);
adjacent = false;
for (int ry = -1; ry <= 1; ry++)
for (int rx = -1; rx <= 1; rx++)
if (x == cursor.x + rx && y == cursor.y + ry)
adjacent = true;
}
while (grid[x, y].num == 9 || adjacent);
}
else
{
do
{
// x = cursor.x + 1 OR -1
x = cursor.x + 1 - 2 * r.Next(1);
y = cursor.y + 1 - 2 * r.Next(1);
}
while (grid[x, y].num == 9);
}
grid[x, y].num = 9;
}
// For each cell, count and store the number of adjacent bombs
for (int y = 0; y < grid.GetLength(1); y++)
for (int x = 0; x < grid.GetLength(0); x++)
if (grid[x, y].num != 9)
for (int ry = -1; ry <= 1; ry++)
for (int rx = -1; rx <= 1; rx++)
if (
x + rx >= 0 &&
x + rx < grid_width &&
y + ry >= 0 &&
y + ry < grid_height &&
grid[x + rx, y + ry].num == 9
) grid[x, y].num++;
}
// If the cell is unflagged
if (cell.flag == 0)
{
Dismantle(cursor.x, cursor.y);
// If the cell is a bomb
if (cell.num == 9)
{
for (int y = 0; y < grid_height; y++)
for (int x = 0; x < grid_width; x++)
grid[x, y].mantled = false;
PrintGrid(grid, cursor);
Console.WriteLine("Game Over!");
playing = false;
}
}
// Check if won (if mantled cells == bomb count)
int mantled = 0;
for (int y = 0; y < grid_height; y++)
for (int x = 0; x < grid_width; x++)
if (grid[x, y].mantled)
mantled++;
if (mantled == bombs)
{
for (int y = 0; y < grid_height; y++)
for (int x = 0; x < grid_width; x++)
grid[x, y].mantled = false;
PrintGrid(grid, cursor);
Console.WriteLine("You Won!");
playing = false;
}
break;
case ConsoleKey.Enter:
cell.flag++;
if (cell.flag == 3) cell.flag = 0;
break;
}
}
Console.ReadKey();
break;
}
}
}
}
}