Advertisement
Guest User

Untitled

a guest
Mar 28th, 2020
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.95 KB | None | 0 0
  1. // Assignment 1 20T1 COMP1511: Minesweeper
  2. // minesweeper.c
  3. //
  4. // This program was written by z5312070
  5. // on 11/3/2020
  6. //
  7. // Version 1.0.0 (2020-03-08): Assignment released.
  8. // Version 1.0.1 (2020-03-08): Fix punctuation in comment.
  9. // Version 1.0.2 (2020-03-08): Fix second line of header comment to say minesweeper.c
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13.  
  14. // Possible square states.
  15. #define VISIBLE_SAFE 0
  16. #define HIDDEN_SAFE 1
  17. #define HIDDEN_MINE 2
  18.  
  19. // The size of the starting grid.
  20. #define SIZE 8
  21.  
  22. // The possible command codes.
  23. #define DETECT_ROW 1
  24. #define DETECT_COL 2
  25. #define DETECT_SQUARE 3
  26. #define REVEAL_SQUARE 4
  27. #define GAMEPLAY_MODE 5
  28. #define DEBUG_MODE 6
  29. #define REVEAL_RADIAL 7
  30.  
  31. // Add any extra #defines here.
  32. #define GAME_ALIVE 0
  33. #define GAME_OVER 1
  34. #define GAME_WON 2
  35.  
  36. #define REVEAL_SQUARE_SIZE 3
  37. #define MAX_HINTS 3
  38. #define COORD_SIZE 4
  39.  
  40. void initialise_field(int minefield[SIZE][SIZE]);
  41. void print_debug_minefield(int minefield[SIZE][SIZE]);
  42.  
  43. void placeMine(int minefield[SIZE][SIZE], int row, int column, int squareState);
  44. void detect_row(int minefield[SIZE][SIZE], int row);
  45. void detect_column(int minefield[SIZE][SIZE], int col);
  46.  
  47. void detect_square(int minefield[SIZE][SIZE], int row, int column, int size);
  48. int reveal_square(int minefield[SIZE][SIZE], int row, int column);
  49. void set_3x3square_visible_safe(int minefield[SIZE][SIZE], int coords[COORD_SIZE]);
  50. int count_in_square(int minefield[SIZE][SIZE], int row, int column, int size, int squareState);
  51.  
  52. void handle_hints(int minefield[SIZE][SIZE], int mineOption, int *hintsUsed);
  53. void draw_status(int status);
  54. void print_gameplay_minefield(int minefield[SIZE][SIZE], int gameStatus);
  55. void print_minefield(int minefield[SIZE][SIZE], int row, int col, int incrementer, int gameStatus);
  56.  
  57. int reveal_radial(int minefield[SIZE][SIZE], int row, int column);
  58. void shift_grid(int minefield[SIZE][SIZE], int row, int column);
  59.  
  60. void math_clamp(int min, int max, int *x);
  61. void math_clamp_array(int min, int max, int arraySize, int *array);
  62.  
  63. int main(void) {
  64. // declare variables
  65. int hintsUsed = 0;
  66. int numberOfMinesToAdd = 0;
  67. int mineOption = 0;
  68. int roundsPlayed = 0; // doesn't include hints
  69. int gameStatus = GAME_ALIVE;
  70. int gameMode = DEBUG_MODE;
  71. int minefield[SIZE][SIZE];
  72.  
  73. initialise_field(minefield);
  74. printf("Welcome to minesweeper!\n");
  75. printf("How many mines? ");
  76. scanf("%d", &numberOfMinesToAdd);
  77. printf("Enter pairs:\n");
  78.  
  79.  
  80. // gets user input for the position of mine(s)
  81. int numberOfPairs = 0;
  82. while (numberOfPairs < numberOfMinesToAdd) { // cycle through the amount of mines
  83. int row, col;
  84. scanf("%d %d", &row, &col);
  85. placeMine(minefield, row, col, HIDDEN_MINE);
  86. numberOfPairs++;
  87. }
  88.  
  89. printf("Game Started\n");
  90. print_debug_minefield(minefield);
  91.  
  92. // check for valid input and continuous loop
  93. while (scanf("%d", &mineOption) == 1) {
  94. int row = 0;
  95. int column = 0;
  96. handle_hints(minefield, mineOption, &hintsUsed);
  97.  
  98. if (mineOption == REVEAL_SQUARE) {
  99. scanf("%d %d", &row, &column);
  100. gameStatus = reveal_square(minefield, row, column);
  101. roundsPlayed++;
  102. } else if (mineOption == GAMEPLAY_MODE) {
  103. printf("Gameplay mode activated\n");
  104. gameMode = GAMEPLAY_MODE;
  105. } else if (mineOption == DEBUG_MODE) {
  106. printf("Debug mode activated\n");
  107. gameMode = DEBUG_MODE;
  108. } else if (mineOption == REVEAL_RADIAL) {
  109. scanf("%d %d", &row, &column);
  110. gameStatus = reveal_radial(minefield, row, column);
  111. roundsPlayed++;
  112. }
  113.  
  114. // safe first turn
  115. if (roundsPlayed == 1 && gameStatus == GAME_OVER) {
  116. shift_grid(minefield, row, column);
  117.  
  118. // run revealer again after shift
  119. if (mineOption == REVEAL_SQUARE) {
  120. gameStatus = reveal_square(minefield, row, column);
  121. } else if (mineOption == REVEAL_RADIAL) {
  122. gameStatus = reveal_radial(minefield, row, column);
  123. }
  124.  
  125.  
  126. } else {
  127. if (gameStatus == GAME_OVER) {
  128. printf("Game over \n");
  129. } else if (gameStatus == GAME_WON) {
  130. printf("Game Won! \n");
  131. }
  132. }
  133.  
  134. if (gameMode == GAMEPLAY_MODE) {
  135. print_gameplay_minefield(minefield, gameStatus);
  136. } else {
  137. print_debug_minefield(minefield);
  138. }
  139.  
  140.  
  141. }
  142. return 0;
  143. }
  144. // runs hints
  145. void handle_hints(int minefield[SIZE][SIZE], int mineOption, int *hintsUsed) {
  146. int row, col, size;
  147. if (mineOption == DETECT_ROW) {
  148. scanf("%d", &row);
  149. if (*hintsUsed < MAX_HINTS) {
  150. detect_row(minefield, row);
  151. *hintsUsed = *(hintsUsed) + 1;
  152. } else {
  153. printf("Help already used\n");
  154. }
  155. } else if (mineOption == DETECT_COL) {
  156. scanf("%d", &col);
  157. if (*hintsUsed < MAX_HINTS) {
  158. detect_column(minefield, col);
  159. *hintsUsed = *(hintsUsed) + 1;
  160. } else {
  161. printf("Help already used\n");
  162. }
  163.  
  164. } else if (mineOption == DETECT_SQUARE) {
  165. scanf("%d %d %d", &row, &col, &size);
  166. if (*hintsUsed < MAX_HINTS) {
  167. detect_square(minefield, row, col, size);
  168. *hintsUsed = *(hintsUsed) + 1;
  169. } else {
  170. printf("Help already used\n");
  171. }
  172. }
  173. }
  174.  
  175. // Places mine on the minefield
  176. void placeMine(int minefield[SIZE][SIZE], int row, int column, int squareState) {
  177. // check if they the user input is in the bounds of the minefield
  178. if (row < SIZE && column < SIZE && row >= 0 && column >= 0) {
  179. // pass it into location storage
  180. minefield[row][column] = squareState;
  181. }
  182. }
  183.  
  184. // Set the entire minefield to HIDDEN_SAFE.
  185. void initialise_field(int minefield[SIZE][SIZE]) {
  186. int row = 0;
  187. while (row < SIZE) {
  188. int col = 0;
  189. while (col < SIZE) {
  190. placeMine(minefield, row, col, HIDDEN_SAFE);
  191. col++;
  192. }
  193. row++;
  194. }
  195. }
  196.  
  197. // Print out the actual values of the minefield.
  198. void print_debug_minefield(int minefield[SIZE][SIZE]) {
  199. int row = 0;
  200. while (row < SIZE) {
  201. int col = 0;
  202. while (col < SIZE) {
  203. printf("%d ", minefield[row][col]);
  204. col++;
  205. }
  206. printf("\n");
  207. row++;
  208. }
  209. }
  210.  
  211. // Prints the number of lines in a row
  212. void detect_row(int minefield[SIZE][SIZE], int row) {
  213. int totalMines = 0;
  214. int i = 0;
  215. while (i < SIZE) {
  216. if (minefield[row][i] == HIDDEN_MINE) {
  217. totalMines++;
  218. }
  219. i++;
  220. }
  221. printf("There are %d mine(s) in row %d \n", totalMines, row);
  222. }
  223.  
  224. // Prints the number of lines in a column
  225. void detect_column(int minefield[SIZE][SIZE], int col) {
  226. int totalMines = 0;
  227. int i = 0;
  228. while (i < SIZE) {
  229. if (minefield[i][col] == HIDDEN_MINE) {
  230. totalMines++;
  231. }
  232. i++;
  233. }
  234. printf("There are %d mine(s) in column %d \n", totalMines, col);
  235. }
  236.  
  237. // Counts the number of mines in a specific area box
  238. // returns the number of mines found
  239. int count_in_square(int minefield[SIZE][SIZE], int row, int column, int size, int squareState) {
  240. int round = size / 2;
  241. int coords[COORD_SIZE] = {
  242. row - round, // start row position
  243. column - round, // start column position
  244. row + round, // end row position
  245. column + round // end column position
  246. };
  247.  
  248. math_clamp_array(0, SIZE, COORD_SIZE, coords);
  249.  
  250. int numberOfMines = 0;
  251. int startRowPosReset = coords[0];
  252. while (startRowPosReset <= coords[2]) {
  253. int startColPosReset = coords[1];
  254. while (startColPosReset <= coords[3]) {
  255. if (minefield[startRowPosReset][startColPosReset] == squareState) {
  256. numberOfMines++;
  257. }
  258. startColPosReset++;
  259. }
  260. startRowPosReset++;
  261. }
  262.  
  263. return numberOfMines;
  264. }
  265.  
  266. // Prints the number of lines in a specific area
  267. void detect_square(int minefield[SIZE][SIZE], int row, int column, int size) {
  268. int numberOfMines = count_in_square(minefield, row, column, size, HIDDEN_MINE);
  269. printf("There are %d mine(s) in the square centered at row %d, column %d of size %d \n", numberOfMines, row, column, size);
  270.  
  271. }
  272.  
  273. // reveals content of the square
  274. // returns 0:alive | 1:hits bomb | 2:won
  275. int reveal_square(int minefield[SIZE][SIZE], int row, int column) {
  276. // calculates the radius and rounds down
  277. int radius = REVEAL_SQUARE_SIZE / 2;
  278. int coords[COORD_SIZE] = {
  279. row - radius, // start row position
  280. column - radius, // start column position
  281. row + radius, // end row position
  282. column + radius // end column position
  283. };
  284.  
  285. // checks if the coordinate is valid
  286. math_clamp_array(0, SIZE, COORD_SIZE, coords);
  287.  
  288. if (minefield[row][column] == HIDDEN_MINE) { // check if user reveals a mine
  289. return GAME_OVER;
  290. } else {
  291. //check if mine is in the vicinity
  292. int numberOfMinesInSquare = count_in_square(minefield, row, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  293. if (numberOfMinesInSquare != 0) { // if it contains mines
  294. // set the user input to VISIBLE_SAFE
  295. placeMine(minefield, row, column, VISIBLE_SAFE);
  296. } else { // if it doesn't contain mines
  297. // set 3x3 square VISIBLE_SAFE
  298. set_3x3square_visible_safe(minefield, coords);
  299. }
  300. }
  301.  
  302. // check if every square has been searched
  303. int hiddenSafeCounter = count_in_square(minefield, row, column, SIZE, HIDDEN_SAFE);
  304. if (hiddenSafeCounter == 0) {
  305. return GAME_WON;
  306. }
  307.  
  308. return GAME_ALIVE;
  309. }
  310.  
  311. // set 3x3 square to visible safe
  312. void set_3x3square_visible_safe(int minefield[SIZE][SIZE], int coords[COORD_SIZE]) {
  313. int startRowPosReset = coords[0];
  314. while (startRowPosReset <= coords[2]) { // loop through rows
  315. int startColPosReset = coords[1];
  316. while (startColPosReset <= coords[3]) { // loop through columns
  317. placeMine(minefield, startRowPosReset, startColPosReset, VISIBLE_SAFE);
  318. startColPosReset++;
  319. }
  320. startRowPosReset++;
  321. }
  322. }
  323. // draws happy or sad face
  324. void draw_status(int status) {
  325. if (status == GAME_OVER) { // dead
  326. printf("xx\n");
  327. printf("/\\\n");
  328.  
  329. } else { // alive or won
  330. printf("..\n");
  331. printf("\\/\n");
  332. }
  333. }
  334. // draws the minefield with mines hidden
  335. void print_gameplay_minefield(int minefield[SIZE][SIZE], int gameStatus) {
  336. draw_status(gameStatus);
  337.  
  338. int totalSizeRow = SIZE + 3;
  339. int totalSizeCol = SIZE + 20 ;
  340. int lastRowArray = totalSizeRow - 1;
  341. int lastColArray = totalSizeCol - 1;
  342.  
  343. int row = 0;
  344. while (row < totalSizeRow) {
  345. int col = 0;
  346. int incrementer = 1;
  347. while (col < totalSizeCol) {
  348. // draw top numbers
  349. if (row == 0) {
  350. if (col < 4) { // draw white space at the start
  351. printf(" ");
  352. } else {
  353. if (col == (1 + 3 * incrementer)) {
  354. int tensColumn = (incrementer / 10) % 10;
  355. printf("%d", tensColumn);
  356. } else if (col == (2 + 3 * incrementer)) {
  357. int lastDigit = (incrementer - 1) % 10; //-1 to start a 0
  358. printf("%d", lastDigit);
  359. } else {
  360. printf(" "); // draws the spaces between the numbers
  361. }
  362. }
  363. } else if (row == 1 || row == lastRowArray) { // draw top line and bottom
  364. if (col < 3) {
  365. printf(" ");
  366. } else {
  367. printf("-");
  368. }
  369. } else {
  370. if (col == 0) { // draw side axis
  371. int tensRow = ((row - 2) / 10) % 10;
  372. printf("%d", tensRow);
  373. } else if (col == 1) { // draw side axis
  374. int lastDigit = (row - 2) % 10; // -2 because of the spacer at top
  375. printf("%d", lastDigit);
  376. } else if (col == 3 || col == lastColArray) { // draw the side lines
  377. printf("|");
  378. } else if (col == 2 || (col == 3 + 3 * incrementer)) { // between mines
  379. printf(" ");
  380. } else {
  381. print_minefield(minefield, row, col, incrementer, gameStatus);
  382. }
  383. }
  384. if (col == (3 + 3 * incrementer)) { // gap between mine
  385. incrementer++;
  386. }
  387. col++;
  388. }
  389. printf("\n");
  390. row++;
  391. }
  392. }
  393. // draws the gameplay minefield from array
  394. void print_minefield(int minefield[SIZE][SIZE], int row, int col, int incrementer, int gameStatus) {
  395. int fieldRow = row - 2; // -2 to account for gap in the top corner
  396. int fieldCol = incrementer - 1; // -1 because first array starts a 0
  397. int isSecondPosition = 0;
  398.  
  399. if (col == (2 + 3 * incrementer)) { // second minefield position
  400. isSecondPosition = 1;
  401. }
  402.  
  403. if (minefield[fieldRow][fieldCol] == VISIBLE_SAFE) { // if it has been explored
  404. int adjacentMines = count_in_square(minefield, fieldRow, fieldCol, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  405. if (adjacentMines > 0) { // has mine next to it
  406.  
  407. if (isSecondPosition) {
  408. printf("%d", adjacentMines);
  409. } else {
  410. int tensColumn = adjacentMines / 10;
  411. printf("%d", tensColumn);
  412. }
  413.  
  414. } else { // is explored and contains no mine or no mines next to it
  415. printf(" ");
  416. }
  417.  
  418. } else if (gameStatus == GAME_OVER && minefield[fieldRow][fieldCol] == HIDDEN_MINE) {
  419. // reveal mines if game is over
  420. if (isSecondPosition) {
  421. printf(")");
  422. } else {
  423. printf("(");
  424. }
  425. } else { // not explored yet
  426. printf("#");
  427. }
  428. }
  429.  
  430. void shift_grid(int minefield[SIZE][SIZE], int row, int column) {
  431. while (minefield[row][column] == HIDDEN_MINE ) {
  432. int tempLastRow[SIZE];
  433. int colInc = 0;
  434.  
  435. // store bottom row
  436. while (colInc < SIZE) {
  437. tempLastRow[colInc] = minefield[SIZE - 1][colInc];
  438. colInc++;
  439. }
  440.  
  441. // shift everything down
  442. int rowInc = 0;
  443. while (rowInc < SIZE) {
  444. int colInc2 = 0;
  445. int tempRowBefore[SIZE];
  446.  
  447. while (colInc2 < SIZE) {
  448. int temp[SIZE];
  449.  
  450. // set first row to last row
  451. if (rowInc == 0) {
  452. tempRowBefore[colInc2] = minefield[rowInc][colInc2];
  453. minefield[rowInc][colInc2] = tempLastRow[colInc2];
  454. } else { // set row to previous row
  455. temp[colInc2] = minefield[rowInc][colInc2];
  456. minefield[rowInc][colInc2] = tempRowBefore[colInc2];
  457. tempRowBefore[colInc2] = temp[colInc2];
  458. }
  459. colInc2++;
  460. }
  461. rowInc++;
  462. }
  463. }
  464. }
  465.  
  466. int reveal_radial(int minefield[SIZE][SIZE], int row, int column) {
  467. if (minefield[row][column] == HIDDEN_MINE) { // check if user reveals a mine
  468. return GAME_OVER;
  469. } else {
  470. //check if mine is in the vicinity
  471. int numberOfMinesInSquare = count_in_square(minefield, row, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  472. if (numberOfMinesInSquare != 0) { // if it contains mines
  473. // set the center to VISIBLE_SAFE only
  474. placeMine(minefield, row, column, VISIBLE_SAFE);
  475.  
  476. } else { // if it doesn't contain mines
  477.  
  478. // middle top
  479. int i1 = row;
  480. while (i1 >= 0) {
  481. if (minefield[i1][column] != HIDDEN_MINE) {
  482. placeMine(minefield, i1, column, VISIBLE_SAFE);
  483. }
  484. int mines = count_in_square(minefield, i1, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  485. if (mines > 0) {
  486. i1 = -1;
  487. }
  488. i1--;
  489. }
  490.  
  491. // middle bottom
  492. int i2 = row;
  493. while (i2 < SIZE) {
  494. if (minefield[i2][column] != HIDDEN_MINE) {
  495. placeMine(minefield, i2, column, VISIBLE_SAFE);
  496. }
  497. int mines = count_in_square(minefield, i2, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  498. if (mines > 0) {
  499. i2 = SIZE;
  500. }
  501. i2++;
  502. }
  503.  
  504. // middle left
  505. int j3 = column;
  506. while (j3 >= 0) {
  507. if (minefield[row][j3] != HIDDEN_MINE) {
  508. placeMine(minefield, row, j3, VISIBLE_SAFE);
  509. }
  510. int mines = count_in_square(minefield, row, j3, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  511. if (mines > 0) {
  512. j3 = -1;
  513. }
  514. j3--;
  515. }
  516.  
  517. // middle right
  518. int j4 = column;
  519. while (j4 < SIZE) {
  520. if (minefield[row][j4] != HIDDEN_MINE) {
  521. placeMine(minefield, row, j4, VISIBLE_SAFE);
  522. }
  523. int mines = count_in_square(minefield, row, j4, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  524. if (mines > 0) {
  525. j4 = SIZE;
  526. }
  527. j4++;
  528. }
  529.  
  530. // top left diagonal
  531. int i5 = row;
  532. int j5 = column;
  533. while (i5 >= 0 && j5 >= 0) {
  534. if (minefield[i5][j5] != HIDDEN_MINE) {
  535. placeMine(minefield, i5, j5, VISIBLE_SAFE);
  536. }
  537. int mines = count_in_square(minefield, i5, j5, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  538. if (mines > 0) {
  539. i5 = -1;
  540. }
  541. i5--;
  542. j5--;
  543. }
  544.  
  545. // top right diagonal
  546. int i6 = row;
  547. int j6 = column;
  548. while (i6 >= 0 && j6 < SIZE) {
  549. if (minefield[i6][j6] != HIDDEN_MINE) {
  550. placeMine(minefield, i6, j6, VISIBLE_SAFE);
  551. }
  552. int mines = count_in_square(minefield, i6, j6, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  553. if (mines > 0) {
  554. i6 = -1;
  555. }
  556. i6--;
  557. j6++;
  558. }
  559.  
  560. // bottom left diagonal
  561. int i7 = row;
  562. int j7 = column;
  563. while (i7 < SIZE && j7 >= 0) {
  564. if (minefield[i7][j7] != HIDDEN_MINE) {
  565. placeMine(minefield, i7, j7, VISIBLE_SAFE);
  566. }
  567. int mines = count_in_square(minefield, i7, j7, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  568. if (mines > 0) {
  569. i7 = SIZE;
  570. }
  571. i7++;
  572. j7--;
  573. }
  574.  
  575. // bottom right diagonal
  576. int i8 = row;
  577. int j8 = column;
  578. while (i8 < SIZE && j8 < SIZE) {
  579. if (minefield[i8][j8] != HIDDEN_MINE) {
  580. placeMine(minefield, i8, j8, VISIBLE_SAFE);
  581. }
  582. int mines = count_in_square(minefield, i8, j8, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
  583. if (mines > 0) {
  584. i8 = SIZE;
  585. }
  586. i8++;
  587. j8++;
  588. }
  589.  
  590. }
  591.  
  592. }
  593.  
  594. // check if every square has been searched
  595. int hiddenSafeCounter = count_in_square(minefield, row, column, SIZE, HIDDEN_SAFE);
  596. if (hiddenSafeCounter == 0) {
  597. return GAME_WON;
  598. }
  599.  
  600. return GAME_ALIVE;
  601. }
  602.  
  603. // clamp coords
  604. void math_clamp(int min, int max, int *x) {
  605. if (*x <= min) {
  606. *x = min;
  607. } else if (*x >= max) {
  608. *x = max - 1; // need to -1 because to account for 0 index for array
  609. }
  610. }
  611.  
  612. // clamp coords in an array
  613. void math_clamp_array(int min, int max, int arraySize, int *array) {
  614. int i = 0;
  615. while (i < arraySize) {
  616. math_clamp(0, SIZE, array);
  617. array++;
  618. i++;
  619. }
  620. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement