0

Well, this one has got me good - I just don't see a way round it! I think I've got the init and draw functions working - they work for the first draw anyway, but I've been working on 'move' for days and just can't get my head round it....it seems to need pointers but I don't understand them - we haven't covered them yet (to my knowledge!?)but I've tried to read up on them and have tried to use them as best I can because if I don't then I get the 'incompatible pointer' type errors... I added the '*' s to all of the variables because when I printed out the blank-col variable to check it, it only worked if I added the star. My main problem (I think - though I may have missed other errors) is that I can't seem to identify the positions of the blank and the tile properly. So...the board seems to draw, and you can enter the tile you want to move, but when you press enter it just goes back to a blank space instead of the tile number and nothing happens...can anyone help please? I did originally use a temp variable to change over the blank and tile but then I read because the blank was '0' it simplified the exchange so I thought maybe I could do it as I now have. I would so appreciate some pointers (no pun intended!) as I'm totally at the end of my tether with this one....thank you!

/**
 * 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];
int *blank_row;
int *blank_col;
int *tile_row;
int *tile_col;

// 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)
    //initiate the board to hold between 3 and 9 spaces on each side of the board
    {
   for (int i = (d-1); i > -1; i--)
        {
            for (int j = (d-1); j > -1; j--)
            {
                //populate the board with numbers from d-1 to 0 (zero being the blank space)
                board[i][j] = (i * d) + j;

                //calculate if d is an odd number, and if so swap 2 & 1
                if ( d % 2 == 0 )
                    {
                      board[0][1] = 2;
                      board [0][2] = 1;
                    }


            }
        }
    }

/**
 * Prints the board in its current state.
 */
void draw(void)
{
    //repeat initialisation loop and print results
    for (int i = (d-1); i > -1; i--)
        {
            for (int j = (d-1); j > -1; j--)
            {
                if (board[i][j] == 0)
                {
                    blank_row = board[i];
                    blank_col = board[j];
                    printf("   _");


                }
            else
                {
                    printf( "%4d", board[i][j]);
                }

            }
        printf("\n\n");
        }
}
/**
 * If tile borders empty space, moves tile and returns true, else
 * returns false. 
*/
 bool move(int tile)
{   //declare temp int
    int temp;


    // Search for position of tile
    for (int row = 0; row < d; row++)
        {
            for (int col = 0; col < d; col++)
            {
              if (board[row][col] == tile) 
                {
                 tile_row = board[row];
                 tile_col = board[col];

                //check if it can move up and if so, move
                if (*tile_row > 0)
                {
                    if (board[*tile_row-1][*tile_col] == 0)
                    {
                    board[*blank_row][*blank_col] = board[*tile_row][*tile_col];
                    board[*tile_row][*tile_col] = 0;
                    }
                }

                //check if it can move left and if so, move
                if (*tile_col > 0)
                {
                    if (board [*tile_row][*tile_col-1] == 0)
                    {
                      board[*blank_row][*blank_col] = board[*tile_row][*tile_col];
                    board[*tile_row][*tile_col] = 0;
          }
                }

                //check if it can move right and if so, move
                if (*tile_col < (d-2)) 
                {
                    if (board [*tile_row][*tile_col+1] == 0)
                    {
                          board[*blank_row][*blank_col] = board[*tile_row][*tile_col];
                    board[*tile_row][*tile_col] = 0;
                      }
                }


                //check if it can move down and if so, move
                if (*tile_row < d-2)
                {
                    if (board[*tile_row+1][*tile_col] == 0)
                    {
                    board[*blank_row][*blank_col] = board[*tile_row][*tile_col];
                    board[*tile_row][*tile_col] = 0;
                    }
                }
            }
            return true;
        }
        }
    return false;

}
/**
 * Returns true if game is won (i.e., board is in winning configuration), 
 * else false.
 */
bool won(void)
{
    // TODO
    return false;
}

1 Answer 1

1

First of all, applause for wanting to understand pointers, but they are not needed for this assignment. My suggestion is to remove all *'s or any other pointer references.

When you try to record the position of the blank tile, you are using the following code:

             tile_row = board[row];
             tile_col = board[col];

It's the right idea but the wrong implementation. You're trying to record the positions in the array, but this doesn't work. It's a two dimensional array and this code only has one dimensional index in each line. Even if it had both indexes, it would actually be transferring the value stored in the array element to tile_row or tile_col. What you really want to do is save the values of row and col, not board[row] or board[col].

Next, if (*tile_col < (d-2)) is problematic. Again, the right idea, but it prevents swapping with the right side column. It should either be <= or < d-1. Same for bottom row. I'll let you work out why.

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

2
  • Thank you so much for replying! I got it!!!! So after what you said, I used just the 'row' and the 'col' (I actually changed it back to i/j for ease) and it worked - now I've stored the location of the tile and the blank! Thank you so much!! The only thing is...now it's counting the cols and rows from the bottom right instead of from the top left - whether I start from the length of the array and iterate down or from 0 and iterate up...any hints gratefully received?! Thank you again!
    – CallyB
    Commented Jan 8, 2017 at 1:53
  • Or perhaps it doesn't matter if it's not the correct reference to the position? I just realised that as long as it consistently keeps track of those elements then it doesn't matter how it labels them?
    – CallyB
    Commented Jan 8, 2017 at 1:59

You must log in to answer this question.

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