0
Here is my code 
    /**
 * fifteen.c
 *
 * Computer Science 50
 * Problem Set 3
 *
 * 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 = GetInt();

        // 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)
{
    // TODO initiate the board
    int MAX_TILE = d*d - 1; 
    for (int i = 0; i < d; i++)
    {
        for (int j = 0; j< d; j++)
        {
            board[i][j] = MAX_TILE - i * d - j;
        }
    }

    // swap the last two numbers if d is odd
    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 print out the 2D grid 
    for (int i = 0; i < d; i++)
    {
        for (int j = 0; j < d; j++)
        {
            if (board[i][j] != 0)
            {
                printf("%2i ", board[i][j]);
            }
            else
            {
                printf("%2c ", (char)95);
            }
        }
        printf("\n");
    }

    printf("%i\n", board[d-1][d-1]);

}

/**
 * If tile borders empty space, moves tile and returns true, else
 * returns false. 
 */
bool move(int tile)
{
    // TODO move the tile if it is beside the empty space

    int count = 0;
    for (int i = 0; i < d; i++)
    {
        for (int j = 0; j < d; j++)
        {
            if (board[i][j] == 0)
            {
                if (j - 1 >= 0 && board[i][j-1] == tile)
                {
                    board[i][j] = tile;
                    board[i][j-1] = 0;

                    count++;
                }

                else if (j+1 <= d-1 && board[i][j+1] == tile)
                {
                    //int temp = board[i][j];

                    board[i][j] = tile;
                    board[i][j+1] = 0;

                    count++;
                }
                /**
                else if ((j + 1 <= d-1) && (board[i][j+1] == tile))
                {
                    board[i][j] = tile;
                    board[i][j+1] = 0;

                    count++;
                } 
                **/
                else if (i - 1 >= 0 && board[i-1][j] == tile)
                {
                    board[i][j] = tile;
                    board[i-1][j] = 0;

                    count++;
                } 
                else if ((i + 1 <= d-1) && (board[i+1][j] == tile))
                {
                    board[i][j] = tile;
                    board[i+1][j] = 0;

                    count++;
                }

            }
        }
    }
    if (count > 0)
    return true;
    else 
    return false;

}

/**
 * Returns true if game is won (i.e., board is in winning configuration), 
 * else false.
 */
bool won(void)
{
    // TODO
    int count = 0;
    if (board[d-1][d-1] != 0)
    {
        return false;
    }
    else 
    {
        for (int i = 0; i < d; i++)
        {
            for (int j = 0; j < d; j++)
            {
                if (board[i][j] != i * d + j + 1)
                {
                    count++;
                }
            }
        }

        if (count > 1)
        return false;
        else 
        return true;
    }
}

everything looks all right for me, except when I do test, it can't move to right or down, which are the j+1 and i+1 scenario. No error message. just keep asking for tile number and no action on the grid. I even try to assign other numbers to board[i][j] and board[i][j+1], and it did show the value correctly on the grid. But not work when board[i][j] = j; board[i][j+1]. Same thing for i+1 scenario.

Thanks advance for any help.

0

Actually, it is making the move. What you're not seeing is a second move that is executing, returning the board to its original state. This is a case of unintended consequences.

The problem is that as soon as the move is made, instead of terminating, the code continues to execute the for loops. Once the move is made, the board is in a new state. As the for loops continue to exit, the test conditions for another move are met with the new state, and the code makes another move, swapping tile and 0 back to their original state.

This would be easily fixed by adding a return statement to each of the 4 blocks of code that executes a move, thus ending processing as soon as a move is executed. This would also simplify the code slightly, as you could delete the count code that you use to confirm that a move has occurred.

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

  • Thanks Cliff. That answers my question perfectly. – michael zhang Sep 22 '16 at 3:01
  • Thanks Cliff. That answers my question perfectly. Based on your suggestion I modified the code and it works fine. The reason is also that I don't have a clear understanding of return statement. will it break out of the loop after return true? The concern I have earlier is the loop will continue checking and also it will go to the return false statement at last row. Will this cause conflicts? Seems not per testing... – michael zhang Sep 22 '16 at 3:07
  • When a return statement is encountered, it will immediately stop processing any code in the function (or main) and return control to the calling code (or the operating system). It will also return any value that is part of the return statement. But most important, nothing further will be processed in the current function. Nothing! No looping, no assignments, nothing at all. – Cliff B Sep 22 '16 at 3:14
  • That's clear enough! Thanks Cliff. – michael zhang Sep 23 '16 at 7:32

You must log in to answer this question.

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