
The Game of Fifteen is a puzzle played on a square, two-dimensional board with numbered tiles that slide. The goal of this puzzle is to arrange the board’s tiles from smallest to largest, left to right, top to bottom, with an empty space in board’s bottom-right corner.
/**
* fifteen.c
*
* Computer Science 50
* Problem Set 3
*
* Implements the 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 [MIN,MAX]
*
* Note that usleep is obsolete, but it offers more granularity than
* sleep and is simpler to use than nanosleep; `man usleep` for more.
*/
#define _XOPEN_SOURCE 500
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// board's minimal dimension
#define MIN 3
// board's maximal dimension
#define MAX 9
// board, whereby board[i][j] represents row i and column j
int board[MAX][MAX];
// board's dimension
int d;
// initialize global variables
int tile;
int blankspace;
int x;
int y;
int i;
int j;
// prototypes
void clear(void);
void greet(void);
void init(void);
void draw(void);
bool move(int tile);
bool won(void);
void save(void);
/**
* Main function - sets up how game will operate.
*/
int main(int argc, string argv[])
{
// greet player
greet();
// ensure proper usage
if (argc != 2)
{
printf("Usage: ./fifteen d\n");
return 1;
}
// ensure valid dimensions
d = atoi(argv[1]);
if (d < MIN || d > MAX)
{
printf("Board must be between %i x %i and %i x %i, inclusive.\n",
MIN, MIN, MAX, MAX);
return 2;
}
// initialixing x and y here so 0 does not reset every time you call move function
else
{
x = (d - 1);
y = (d - 1);
}
// initialize the board
init();
// accept moves until game is won
while (true)
{
// clear the screen
clear();
// draw the current state of the board
draw();
// saves the current state of the board (for testing)
save();
// check for win
if (won())
{
printf("ftw!\n");
break;
}
// prompt for move
printf("Tile to move: ");
int tile = GetInt();
// move if possible, else report illegality
if (!move(tile))
{
printf("\nIllegal move.\n");
usleep(500000);
}
// sleep for animation's sake
usleep(500000);
}
// that's all folks
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("GAME OF FIFTEEN\n");
usleep(2000000);
}
/**
* Initializes the game's board with tiles numbered 1 through d*d - 1,
* (i.e., fills board with values but does not actually print them),
* whereby board[i][j] represents row i and column j.
*/
void init(void)
{
// TODO
int dsquared = (d * d);
int n = 0;
// two for loops to iterate through 2d array - rows/columns
for (int i = 0; i < d; i++)
{
for (int j = 0; j < d; j++)
{
// this will initialize the array counting from largest number down to d * d - 1
// n is used as a counter so we are subtracting by one more each time
n = n + 1;
board[i][j] = (dsquared - n);
}
}
// if d is even and the tiles on board odd, swap 1 and 2 so game can be won
if ((d % 2) == 0)
{
int temp = board[d - 1][d - 2];
board[d - 1][d - 2] = board[d - 1][d - 3];
board[d - 1][d - 3] = temp;
}
}
/**
* Prints the board in its current state.
*/
void draw(void)
{
// TODO nested loops to draw board initialized above
// initialize variables
int n = 0;
// iterate over rows
for (int i = 0; i < d; i++)
{
// iterate over columns
for (int j = 0; j < d; j++)
{
// subtract by one more each time
n = (n + 1);
// print the number of the tile except for the 0 tile
if (board[i][j] > 0)
{
printf("| %2d ", board[i][j]);
}
// for 0 tile, print the space for tiles to move
if (board[i][j] == 0)
{
printf("| __ ");
}
}
// print two lines after each row to make board
printf("|\n\n");
}
}
/**
* If tile borders empty space, moves tile and returns true, else
* returns false.
*/
bool move(int tile)
{
// TODO
// search board for user tile
// iterate through rows to find tile
for (int i = 0; i < d; i++)
{
// iterate through columns to find tile
for (int j = 0; j < d; j++)
{
// if user entered tile that exists on the board
if(tile == board[i][j])
{
// initialize variable for 0
int blankspace = 0;
// test if tile is adjacent to blankspace
if (((x == (i - 1)) && (j == y)) || ((x == (i + 1)) && (j == y)) ||
((i == x) && (y == (j - 1))) || ((i == x) && (y == (j + 1))))
{
// printf("before: tile %d, blankspace %d\n", tile, blankspace)
// swap tile with blankspace if tile is adjacent to blankspace
board[x][y] = tile;
board[i][j] = blankspace;
x=i;
y=j;
// printf("The position of the tile is board[%d][%d] = %2d. Tile is %d\n", i, j, board[i][j], tile);
// printf("Blankspace position is: board[%d][%d] = %d\n", x, y, blankspace);
return true;
}
}
}
}
return false;
}
/**
* Returns true if game is won (i.e., board is in winning configuration),
* else false.
*/
bool won(void)
{
// TODO
// initializes variables
int n = -1;
// iterates through board
for (int i = 0; i < d; i++)
{
for (int j = 0; j < d; j++)
{
// creates counter
n = n + 1;
// if any tile != counter, counting from 0, return false
if (board[i][j] != n)
{
return false;
}
}
}
// otherwise, all tiles count up from 0, game won
return true;
}
/**
* Saves the current state of the board to disk (for testing).
*/
void save(void)
{
// log
const string log = "log.txt";
// delete existing log, if any, before first save
static bool saved = false;
if (!saved)
{
unlink(log);
saved = true;
}
// open log
FILE* p = fopen(log, "a");
if (p == NULL)
{
return;
}
// log board
fprintf(p, "{");
for (int i = 0; i < d; i++)
{
fprintf(p, "{");
for (int j = 0; j < d; j++)
{
fprintf(p, "%i", board[i][j]);
if (j < d - 1)
{
fprintf(p, ",");
}
}
fprintf(p, "}");
if (i < d - 1)
{
fprintf(p, ",");
}
}
fprintf(p, "}\n");
// close log
fclose(p);
}
Start:

FTW!:

Latest posts by Koren Leslie Cohen (see all)
- PM Career Story - April 28, 2022
- How to Transition into Product Management - December 26, 2017
- What I’ve Learned in My First Few Months as a Product Manager - October 14, 2015
I have a querry.
Why did you write x and y = (d – 1)? I want to understand it. And
In move function, you wrote x = i and y = j, why that
Please explain me 🙂
I used x and y variables for the blankspace and later for the swap.
x and y are originally both set to d-1 to represent the blankspace. For example, if someone chose 3 for d, meaning the board has 3 rows (0, 1, 2) and 3 columns (0, 1, 2), as pictured above, the blankspace (represented by x, y) would initially be set to [2][2] on the board, or [d-1][d-1].
In the move function, I measure whether a square is adjacent to the blankspace by measuring i and j as related to x and y, and if adjacent, swapping the tile for the blankspace.
Thank you 😀
Why does the init function have:
n = n + 1;
and the draw function have:
n = (n+1);
I am still a novice at programming, but I must say your code is beautiful to look at. I wish all code was written this way, and with this site’s colour scheme, I wish I could read non-fiction like this. Beautiful!
Hey, i liked your code and used very similar structure myself.
The only difference between your code and mine was that i declared the type and value of x and y in the same line. This caused the function “move” to see x and y as undeclared variables.
Why is it that when you declare the variable type and value in different lines, that the code works?
actually the implementation of this game is not entirely correct, since it is stated in the pset that board only fulfills win condition if the blank is on the bottom right. (you kinda also said it yourself)
you also initialized int n in draw() which wasn’t used! XP
on the otherhand gr8 job on completing the pset!