Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * fifteen.c
- *
- * CS50 AP
- * Fifteen
- *
- * Implements Game of Fifteen (generalized to d x d).
- *
- * Usage: fifteen d
- *
- * whereby the board's dimensions are to be d x d,
- * where d must be in [DIM_MIN,DIM_MAX]
- *
- * Note that usleep is obsolete, but it offers more granularity than
- * sleep and is simpler to use than nanosleep; `man usleep` for more.
- *
- * Extra features including printing an actual grid to make it look more
- * tile-like, and using ANSI color sequences for some additional customizing
- */
- #define _XOPEN_SOURCE 500
- #include <cs50.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- // constants
- #define DIM_MIN 3
- #define DIM_MAX 9
- // ansi escape sequence to print grid color
- // replace the number beteen [ and m with 31 for red, 32 for green, 33 for brown,
- // 34 for blue, 35 for purple, 36 for cyan, 37 for gray
- #define COLOR "\033[32m"
- // board
- int board[DIM_MAX][DIM_MAX];
- // dimensions
- int d;
- // saved locations of the blank tile
- int blank_row;
- int blank_col;
- // prototypes
- void clear(void);
- void greet(void);
- void init(void);
- void draw(void);
- bool move(int tile);
- bool won(void);
- void swap(int *a, int *b);
- void print_grid_row(int d);
- void print_tile(int tile);
- int main(int argc, string argv[])
- {
- // ensure proper usage
- if (argc != 2)
- {
- printf("Usage: fifteen d\n");
- return 1;
- }
- // ensure valid dimensions
- d = atoi(argv[1]);
- if (d < DIM_MIN || d > DIM_MAX)
- {
- printf("Board must be between %i x %i and %i x %i, inclusive.\n",
- DIM_MIN, DIM_MIN, DIM_MAX, DIM_MAX);
- return 2;
- }
- // open log
- FILE *file = fopen("log.txt", "w");
- if (file == NULL)
- {
- return 3;
- }
- // greet user with instructions
- greet();
- // initialize the board
- init();
- // accept moves until game is won
- while (true)
- {
- // clear the screen
- clear();
- // draw the current state of the board
- draw();
- // log the current state of the board (for testing)
- for (int i = 0; i < d; i++)
- {
- for (int j = 0; j < d; j++)
- {
- fprintf(file, "%i", board[i][j]);
- if (j < d - 1)
- {
- fprintf(file, "|");
- }
- }
- fprintf(file, "\n");
- }
- fflush(file);
- // check for win
- if (won())
- {
- printf("ftw!\n");
- break;
- }
- // prompt for move
- printf("Tile to move: ");
- int tile = get_int();
- // quit if user inputs 0 (for testing)
- if (tile == 0)
- {
- break;
- }
- // log move (for testing)
- fprintf(file, "%i\n", tile);
- fflush(file);
- // move if possible, else report illegality
- if (!move(tile))
- {
- printf("\nIllegal move.\n");
- usleep(500000);
- }
- // sleep thread for animation's sake
- usleep(50000);
- }
- // close log
- fclose(file);
- // success
- return 0;
- }
- /**
- * Clears screen using ANSI escape sequences.
- */
- void clear(void)
- {
- printf("\033[2J");
- printf("\033[%d;%dH", 0, 0);
- }
- /**
- * Greets player.
- */
- void greet(void)
- {
- clear();
- printf("WELCOME TO GAME OF FIFTEEN\n");
- usleep(2000000);
- }
- /**
- * Initializes the game's board with tiles numbered 1 through d*d - 1
- * (i.e., fills 2D array with values but does not actually print them).
- */
- void init(void)
- {
- for (int i = 0; i < d; i++) //loop over board, initialize it
- {
- for (int j = 0; j < d; j++)
- {
- board[i][j] = (d * d - 1) - j - (i * d); //the largest tile - current col - current row * d
- }
- }
- if (d % 2 == 0) //when d is even, flip 2 and 1
- {
- board[d - 1][d - 2] = 2;
- board[d - 1][d - 3] = 1;
- }
- blank_row = d - 1; //assign the blank row
- blank_col = d - 1; //assign the blank col
- }
- /**
- * Prints the board in its current state.
- */
- void draw(void)
- {
- for (int i = 0; i < d; i++) //iterate over the board
- {
- for (int j = 0; j < d; j++)
- {
- printf("%2d ", board[i][j]); //print each tile to fill up to spaces, with a space afterwards
- }
- printf("\n"); //move to the next line
- }
- }
- /**
- * If tile borders empty space, moves tile and returns true, else
- * returns false.
- */
- bool move(int tile)
- {
- //find the row / col of the tile
- int tile_row;
- int tile_col;
- //iterate over board, if the current tile matches tile, set its value to tile_row/col
- for (int i = 0; i < d; i++)
- {
- for (int j = 0; j < d; j++)
- {
- if (board[i][j] == tile)
- {
- tile_row = i;
- tile_col = j;
- }
- }
- }
- //initialize booleans for checking tile movement
- bool oneRowAway = tile_row == blank_row - 1 || tile_row == blank_row + 1; //true if one row away
- bool oneColAway = tile_col == blank_col - 1 || tile_col == blank_col + 1; //true if one col away
- bool sameRow = tile_row == blank_row; //true if same row
- bool sameCol = tile_col == blank_col; //true if same col
- // if row valid and col valid but both row and col are one away at the same time
- if ( ( oneRowAway || (sameRow)) && ( oneColAway || (sameCol)) & !(oneRowAway && oneColAway) )
- {
- //create a temporary variable and set it equal to the tile, flip the values of tile / blank, and reflect these changes on the board
- int temp_row = tile_row;
- int temp_col = tile_col;
- tile_row = blank_row;
- tile_col = blank_col;
- board[tile_row][tile_col] = tile;
- blank_row = temp_row;
- blank_col = temp_col;
- board[blank_row][blank_col] = 0;
- return true; //return that the move worked
- }
- return false; //this means it didn't
- }
- /**
- * Returns true if game is won (i.e., board is in winning configuration),
- * else false.
- */
- bool won(void)
- {
- //there probably could've been a cleener way to do this, but I started doing this and just left it as is
- int previousTile = -1; //used for checking previous tile
- int counter = 0; //counter to make the if statement fail if you're on the last element and it's 0
- //iterate over loop
- for (int i = 0; i < d; i++)
- {
- for (int j = 0; j < d; j++)
- {
- counter++;
- //return false if current tile < the previous one, but don't if you're on the last tile and it is equal to 0
- if (board[i][j] < previousTile && !((board[d - 1 ][d - 2] == d * d - 1 && board[i][j] == 0)
- && counter == d * d))
- {
- return false;
- }
- previousTile = board[i][j];
- }
- }
- return true; // if you get through the loop without returning false, the board has been won.
- }
Advertisement
Add Comment
Please, Sign In to add comment