1

Dear StackExchange users,

My name is Samuel and I'm 14 years old. I am completing Problem Set 3 but am stuck on fifteen.c. My program compiles and runs. When I run the program, I get the normal message: "WELCOME TO THE GAME OF FIFTEEN". Then, I have nothing on the screen except when it asks for a tile. Also, every move is an illegal move. Can anyone help?

Thank you,:)

From, Samuel

 /**
 * fifteen.c
 *
 * 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.
 */

 #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

 // board
 int board[DIM_MAX][DIM_MAX];

 // dimensions
 int d;

 // prototypes
 void clear(void);
 void greet(void);
 void init(void);
 void draw(void);
 bool move(int tile);
 bool won(void);

 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(500000);
}

// 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)
{

int board [d][d];

for (int i = 0; i < d; i++)
{
    for (int j = 0; j < d; j++)
    {
        board [i][j] = (d*d) - ((i * 3) + (j + 1));
    }
}

if (d % 2 == 0)
{
    int swap = board[d - 1][d - 2];
    board[d - 1][d - 3] = board[d - 1][d - 2];
    board[d - 1][d - 3] = swap;
}
printf("i\n");
}

/**
* Prints the board in its current state.
*/
void draw(void)
{

int board [d][d];
int counter = 0;
for (int i = 0; i < d; i++)
{
    for (int j = 0; j < d; j++)
    {
        if (board [i][j] == board [d][d])
        {
            printf(" _");
        }

        while (counter != board [i][j])
        {
            counter++;
        }
        if (counter >= 10)
        {
            printf("%i", board [i][j]);
        }
        else
        {
        printf("%i", board [i][j]);
        }
    }
printf("\n");
printf("j\n");
}
}

/**
* If tile borders empty space, moves tile and returns true, else
* returns false. 
*/
bool move(int tile)
{
int blank_space=0, temp;

if (tile == 0)
{
    return false;
}
for (int i = 0; i < d; i++)
{
    for (int j = 0; j < d; j++)
    {
        if (board[i][j] == tile)
        {
            if (j > 0)
            {
                if (board[i-0][j-1] == blank_space)
                {
                    temp = board[i][j];
                    blank_space = board[i-0][j-1];
                    board[i][j] = temp;
                    return true;
                }
            }
            if (j > d-1)
            {
                if (board[i-1][j-0] == blank_space)
                {
                    temp = board[i][j];
                    blank_space = board[i-1][j-0];
                    board[i][j] = temp;
                    return true;
                }
            }
            if (i < 0)
            {
                if (board[i+0][j+1] == blank_space)
                {
                    temp = board[i][j];
                    blank_space = board[i+0][j+1];
                    board[i][j] = temp;
                    return true;
                }
            }
            if (i < d-1)
            {
                if (board[i+1][j+0] == blank_space)
                {
                    temp = board[i][j];
                    blank_space = board[i+1][j+0];
                    board[i][j] = temp;
                    return true;
                }
            }
        }
    }
}
return false;
printf("k\n");
}

/**
* Returns true if game is won (i.e., board is in winningconfiguration), 
* else false.
*/
bool won(void)
{
for (int i = 0; i < d; i++)
{
    for (int j = 0; j < d; j++)
    {
        if (board[i][j] == (d*d) - ((i+1) *(j + (i+1))))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}
return false;
printf("l\n");
}
1

Welcome to CS50x!

There are a number of issues in the code, so I'll point out a couple of the major errors to get you going and to give you the chance to find the rest on your own.

First, the code is creating something called a shadow variable in two places, one in init() and the other in draw(). The shadow variable is the board[][] array. When there is an existing variable (in this case, the board[][] array), and another variable is created with the same name by redeclaring it, then the new variable takes over and masks or hides the original variable. The new, shadow var takes precedence locally and everything is done to that variable, while the var that is hidden remains untouched. When the shadow var goes out of scope (in this case, when the function ends) then the shadow variable will cease to exist and the original var will reappear with whatever content it had when it was masked.

In this case, the statement int board[d][d]; that appears at the beginning of each of the two functions is creating the shadow arrays in those functions. The board[][] array already exists as a global array. It does not need to be redeclared and shouldn't be. This is the biggest problem.

Next, in draw, the code compares array elements to board[d][d]. board[d][d] is outside of the valid part of the array. The array indexes should not exceed d-1 or they are off the edge of the board. In this case the comparison should be to 0.

Also in draw, the while loop is unnecessary. I'm not sure what the purpose of that loop is, but it looks like it can and usually does cause an infinite loop.

The print statements that follow appear to be designed to handle one vs. two digit numbers, but the print formatting is the same. Either one needs to be changed appropriately, or the whole sequence of if/else and print statements can be replaced with a single printf statement that contains the appropriate formatting code that says how many digits to print.( I'll leave it to you to figure it out. Hint: google printf format.)

Finally, the won() function needs some work. As written, it will only check one tile. Also, the formula is checking that the board is in the initial configuration, not the won configuration. (And how does it check for the 0 tile?)

You have a good start and these corrections will get you going. Attack each issue one at a time and you'll get through it! If you have questions on these issues, leave a comment. New problems get a new question. Happy coding! ;-)

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

1
  • Thank you for your answer, I understand everything except for why all the moves I enter are illegal. I think it has something to do with the "move" function. – Samuel Hanssen Jan 12 '17 at 16:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .