Advertisement
Guest User

Untitled

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