daniel_lawson9999

Fifteen Daniel Lawson

Oct 17th, 2017
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.07 KB | None | 0 0
  1. /**
  2.  * fifteen.c
  3.  *
  4.  * CS50 AP
  5.  * Fifteen
  6.  *
  7.  * Implements Game of Fifteen (generalized to d x d).
  8.  *
  9.  * Usage: fifteen d
  10.  *
  11.  * whereby the board's dimensions are to be d x d,
  12.  * where d must be in [DIM_MIN,DIM_MAX]
  13.  *
  14.  * Note that usleep is obsolete, but it offers more granularity than
  15.  * sleep and is simpler to use than nanosleep; `man usleep` for more.
  16.  *
  17.  * Extra features including printing an actual grid to make it look more
  18.  * tile-like, and using ANSI color sequences for some additional customizing
  19.  */
  20.  
  21. #define _XOPEN_SOURCE 500
  22.  
  23. #include <cs50.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27.  
  28. // constants
  29. #define DIM_MIN 3
  30. #define DIM_MAX 9
  31.  
  32. // ansi escape sequence to print grid color
  33. // replace the number beteen [ and m with 31 for red, 32 for green, 33 for brown,
  34. // 34 for blue, 35 for purple, 36 for cyan, 37 for gray
  35. #define COLOR "\033[32m"
  36.  
  37. // board
  38. int board[DIM_MAX][DIM_MAX];
  39.  
  40. // dimensions
  41. int d;
  42.  
  43. // saved locations of the blank tile
  44. int blank_row;
  45. int blank_col;
  46.  
  47. // prototypes
  48. void clear(void);
  49. void greet(void);
  50. void init(void);
  51. void draw(void);
  52. bool move(int tile);
  53. bool won(void);
  54. void swap(int *a, int *b);
  55. void print_grid_row(int d);
  56. void print_tile(int tile);
  57.  
  58. int main(int argc, string argv[])
  59. {
  60.     // ensure proper usage
  61.     if (argc != 2)
  62.     {
  63.         printf("Usage: fifteen d\n");
  64.         return 1;
  65.     }
  66.  
  67.     // ensure valid dimensions
  68.     d = atoi(argv[1]);
  69.     if (d < DIM_MIN || d > DIM_MAX)
  70.     {
  71.         printf("Board must be between %i x %i and %i x %i, inclusive.\n",
  72.                DIM_MIN, DIM_MIN, DIM_MAX, DIM_MAX);
  73.         return 2;
  74.     }
  75.  
  76.     // open log
  77.     FILE *file = fopen("log.txt", "w");
  78.     if (file == NULL)
  79.     {
  80.         return 3;
  81.     }
  82.  
  83.     // greet user with instructions
  84.     greet();
  85.  
  86.     // initialize the board
  87.     init();
  88.  
  89.     // accept moves until game is won
  90.     while (true)
  91.     {
  92.         // clear the screen
  93.         clear();
  94.  
  95.         // draw the current state of the board
  96.         draw();
  97.  
  98.         // log the current state of the board (for testing)
  99.         for (int i = 0; i < d; i++)
  100.         {
  101.             for (int j = 0; j < d; j++)
  102.             {
  103.                 fprintf(file, "%i", board[i][j]);
  104.                 if (j < d - 1)
  105.                 {
  106.                     fprintf(file, "|");
  107.                 }
  108.             }
  109.             fprintf(file, "\n");
  110.         }
  111.         fflush(file);
  112.  
  113.         // check for win
  114.         if (won())
  115.         {
  116.             printf("ftw!\n");
  117.             break;
  118.         }
  119.  
  120.         // prompt for move
  121.         printf("Tile to move: ");
  122.         int tile = get_int();
  123.  
  124.         // quit if user inputs 0 (for testing)
  125.         if (tile == 0)
  126.         {
  127.             break;
  128.         }
  129.  
  130.         // log move (for testing)
  131.         fprintf(file, "%i\n", tile);
  132.         fflush(file);
  133.  
  134.         // move if possible, else report illegality
  135.         if (!move(tile))
  136.         {
  137.             printf("\nIllegal move.\n");
  138.             usleep(500000);
  139.         }
  140.  
  141.         // sleep thread for animation's sake
  142.         usleep(50000);
  143.     }
  144.  
  145.     // close log
  146.     fclose(file);
  147.  
  148.     // success
  149.     return 0;
  150. }
  151.  
  152. /**
  153.  * Clears screen using ANSI escape sequences.
  154.  */
  155. void clear(void)
  156. {
  157.     printf("\033[2J");
  158.     printf("\033[%d;%dH", 0, 0);
  159. }
  160.  
  161. /**
  162.  * Greets player.
  163.  */
  164. void greet(void)
  165. {
  166.     clear();
  167.     printf("WELCOME TO GAME OF FIFTEEN\n");
  168.     usleep(2000000);
  169. }
  170.  
  171. /**
  172.  * Initializes the game's board with tiles numbered 1 through d*d - 1
  173.  * (i.e., fills 2D array with values but does not actually print them).
  174.  */
  175. void init(void)
  176. {
  177.     for (int i = 0; i < d; i++) //loop over board, initialize it
  178.     {
  179.         for (int j = 0; j < d; j++)
  180.         {
  181.             board[i][j] = (d * d - 1) - j - (i * d); //the largest tile - current col - current row * d
  182.         }
  183.     }
  184.     if (d % 2 == 0) //when d is even, flip 2 and 1
  185.     {
  186.         board[d - 1][d - 2] = 2;
  187.         board[d - 1][d - 3] = 1;
  188.     }
  189.     blank_row = d - 1; //assign the blank row
  190.     blank_col = d - 1; //assign the blank col
  191. }
  192.  
  193. /**
  194.  * Prints the board in its current state.
  195.  */
  196. void draw(void)
  197. {
  198.     for (int i = 0; i < d; i++) //iterate over the board
  199.     {
  200.         for (int j = 0; j < d; j++)
  201.         {
  202.             printf("%2d ", board[i][j]); //print each tile to fill up to spaces, with a space afterwards
  203.         }
  204.         printf("\n"); //move to the next line
  205.     }
  206. }
  207.  
  208. /**
  209.  * If tile borders empty space, moves tile and returns true, else
  210.  * returns false.
  211.  */
  212. bool move(int tile)
  213. {
  214.     //find the row / col of the tile
  215.     int tile_row;
  216.     int tile_col;
  217.     //iterate over board, if the current tile matches tile, set its value to tile_row/col
  218.     for (int i = 0; i < d; i++)
  219.     {
  220.         for (int j = 0; j < d; j++)
  221.         {
  222.             if (board[i][j] == tile)
  223.             {
  224.                 tile_row = i;
  225.                 tile_col = j;
  226.             }
  227.         }
  228.     }
  229.     //initialize booleans for checking tile movement
  230.     bool oneRowAway = tile_row == blank_row - 1 || tile_row == blank_row + 1; //true if one row away
  231.     bool oneColAway = tile_col == blank_col - 1 || tile_col == blank_col + 1; //true if one col away
  232.     bool sameRow = tile_row == blank_row; //true if same row
  233.     bool sameCol = tile_col == blank_col; //true if same col
  234.  
  235.     //       if row valid          and      col valid         but    both row and col are one away at the same time
  236.     if ( ( oneRowAway || (sameRow)) && ( oneColAway || (sameCol)) & !(oneRowAway && oneColAway) )
  237.     {
  238.         //create a temporary variable and set it equal to the tile, flip the values of tile / blank, and reflect these changes on the board
  239.         int temp_row = tile_row;
  240.         int temp_col = tile_col;
  241.         tile_row = blank_row;
  242.         tile_col = blank_col;
  243.         board[tile_row][tile_col] = tile;
  244.         blank_row = temp_row;
  245.         blank_col = temp_col;
  246.         board[blank_row][blank_col] = 0;
  247.         return true; //return that the move worked
  248.     }
  249.     return false; //this means it didn't
  250. }
  251.  
  252. /**
  253.  * Returns true if game is won (i.e., board is in winning configuration),
  254.  * else false.
  255.  */
  256. bool won(void)
  257. {
  258.     //there probably could've been a cleener way to do this, but I started doing this and just left it as is
  259.     int previousTile = -1; //used for checking previous tile
  260.     int counter = 0; //counter to make the if statement fail if you're on the last element and it's 0
  261.     //iterate over loop
  262.     for (int i = 0; i < d; i++)
  263.     {
  264.         for (int j = 0; j < d; j++)
  265.         {
  266.             counter++;
  267.             //return false if current tile < the previous one, but don't if you're on the last tile and it is equal to 0
  268.             if (board[i][j] < previousTile && !((board[d  - 1 ][d - 2] == d * d - 1 && board[i][j] == 0)
  269.                                                 && counter == d * d))
  270.             {
  271.                 return false;
  272.             }
  273.             previousTile = board[i][j];
  274.         }
  275.     }
  276.     return true; // if you get through the loop without returning false, the board has been won.
  277. }
Advertisement
Add Comment
Please, Sign In to add comment