CMSC 15200 - Summer 2013

Homework #6 (Short) Due: Friday August 23th, 2013 @ 11:59 pm

In this homework, you will build off your lab from this week. You will build a GUI game called Animal Match. The object of the game is to match all pairs within the grid of animals. You will gain experience using the GTK library for this assignment.

You will need to connect to a cs machine in order to see your GUI application. Instructions on how to connect to a CS machine was explained in Lab #4 .

You wrote the majority of the GUI development in lab; therefore, you will use those same code (to a degree) in order to convert it into a working game.

You will do all your coding in a file called hw6.c .


Game Implementation

The game is to be implemented as follows:

  1. Create a 4x5 grid of buttons that will display images of various animals. Each button, will display a picture of an animal, which is specified in an file that needs to be read in from the command line. This will be the only command line agrument for this assignment. At the beginning of the game, all the animals are hidden. You need to use the hidden.jpg image file as the hide image. For example:

    Download the zip file of the animal images from here: animals.zip

    If you are remotely connected to the a CS machine you can download the images using the wget command inside the terminal window

    wget http://www.classes.cs.uchicago.edu/archive/2013/summer/15200-91/labs/lab4_files/animals.zip unzip animalz.zip

    Keep all images in this animals directory and make sure to commit this directory when submitting your homework.

    This file read from the command line should be formated as follows: ANIMAL_NAME FILE_PATH_TO_IMAGE ROW COL .

    The ANIMAL_NAME is the name of an animal defined in your animals directory. FILE_PATH_TO_IMAGE is the relative path to the image file for the animal. ROW and COL are the board indices of where to place the animal.

    For example, lets say we had a file called board.txt. An example format is shown below.

     
    parrot animals/parrot.jpg 0 0 
    loin animals/loin.jpg 0 1
    eagle animals/eagle.jpg 0 2
    koala animals/koala.jpg 0 3
    owl animals/owl.jpg 0 4
    cat animals/cat.jpg 1 0
    chipmunk animals/chipmunk.jpg 1 1
    moose animals/moose.jpg 1 2
    parrot animals/parrot.jpg 1 3
    dog animals/dog.jpg 1 4
    duck animals/duck.jpg 2 0
    dog animals/dog.jpg 2 1
    loin animals/loin.jpg 2 2
    owl animals/owl.jpg 2 3
    chipmunk animals/chipmunk.jpg 2 4
    moose animals/moose.jpg 3 0
    eagle animals/eagle.jpg 3 1
    cat animals/cat.jpg 3 2
    duck animals/duck.jpg 3 3
    koala animals/koala.jpg 3 4
    
    Thus, if we were to reavel all the animals on the board then the placement of each animal in the file board.txt should look like the following:
  2. When an animal button is clicked, the game needs to reveal the animal image of the clicked button. When a second animal button has been clicked (i.e. we clicked on two buttons), you need to check to see if the second animal matches the first animal clicked. If they are the same then the second animal needs to be revealed to the player. If they are not a match then the game should hide the first animal again. You should not show the second card to the player if there is not a match (trust me it's a little bit more work to make this happen so do not worry about it).
  3. If all the animals have been matched then you need to display "All pairs found in the game" in an label at the bottom of the screen.

To compile the GTK library with your hw6.c file you will need to run the following command:

gcc hw6.c -o hw6 `pkg-config --cflags --libs gtk+-2.0`

Required Code

Inside your hw6.c file, you will need to paste in the following code and implement the functions.
 
#include <gtk/gtk.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAX_ROWS 4
#define MAX_COLS 5

struct animalItem { 
    GtkWidget * button;   /* A pointer to the button that displays this animal */
    char name[20];       /* the name of the animal (e.g. "lion") */ 
    char animalFilename[80];  /* the relative path for the image (e.g. "animals/loin.jpg") */
}; 

typedef struct animalItem AnimalItem_t; 

struct gamestate { 
    int gameState[MAX_ROWS][MAX_COLS];  /* Keeps track of which indicies have been matched correctly. 
                                           This array should only be filled with booleans (i.e. 1 for
                                          true or 0 for false) */
    	                                /* Think about how you might want to use this in the game... */ 
                                            
    AnimalItem_t * board[MAX_ROWS][MAX_COLS]; /* a 2D array of AnimalItem_t pointers (i.e. the game board) */  
    
    GtkWidget *table;  /* A pointer to the table for the game window */ 
    
    GtkWidget *label; /* A pointer to the label at the bottom of the window */ 
    
    int prevRow;      /* the row index of the previous animal clicked (i.e. row of the first clicked animal) */
    
    int prevCol;    /* the col index of the previous animal clicked (i.e. col of the first clicked animal) */
    
    int clickedCount;  /*The number times we clicked the mouse button */ 
}; 

typedef struct gamestate GameState; 

void readInBoard(char * filename, GameState * state); 
int gameComplete(GameState * state); 
void findButton(GameState * state, GtkButton *button, int * btnRow, int * btnCol); 

/* All of the game logic should be implemented within the animalClicked function */ 
static void animalClicked (GtkButton *button,
                         gpointer   user_data)
{
   GameState * state = (GameState *)user_data;  /* Each button should pass in the game state */ 
   /* Implement function code */ 
}

static void destroy( GtkWidget *widget,
                     gpointer   data )
{
    gtk_main_quit ();
}
int main( int   argc,
          char *argv[] )
{
    GtkWidget *window;
    GameState * state = (GameState *)malloc(sizeof(GameState)); 

    gtk_init (&argc, &argv);

    if(argc == 2){
    
        /* implement the code for the main function */ 
        
        gtk_widget_show_all (window);

        g_signal_connect (window, "destroy",
		      G_CALLBACK (destroy), NULL);

      

        gtk_main();
    }else {
        printf("Error you need to provide the board setup file\n"); 
        return 1; 
    }

    return 0;
} 
/* readInBoard should setup the board by reading from the fileaname */ 
void readInBoard(char * filename, GameState * state){ 

 	/* implement the code for the readInBoard function */ 
} 

/* gameComplete should read through the 2D array field (state->gameState) and check to 
	see if any of the elements is zero. If any of the elements is zero then return 0, 
    otherwise return 1. */ 
int gameComplete(GameState * state) { 

 	/* implement the code for the gameComplete function */ 

}
/* findButton should read through the game board (i.e. state->board) to find the location (i.e. the row and col) of 
   the parameter "button". The function will store the row and col inside the 
	parameters btnRow and btnCol. Hint: This function should use the == operator because 
    GtkButton * button is a pointer so the function only need to compare the addresses. */ 
void findButton(GameState * state, GtkButton *button, int * btnRow, int * btnCol) { 

	/* implement the code for the findButton function */ 

}

Really this is all you need in order to impelement the match game. Ask questions on Piazza if anything seems confusing!

Extra Credit

The extra credit will be added to this current homework assignment.
  • (Earn up to 10%): Add a command line option "-r" that randomly generates the game board instead of reading the board from a file. If the player enters in a board file with the "-r" option then it should ignore reading in the file and generate a random game board. Make sure the board is valid (i.e. each animal generated has a match somewhere else on the board.).
  • (Earn up to 10%): Add a mechanism (i.e. the ability) to the game GUI that allows the player to choose between playing a random game or loading another board file. This means that you need to have a working version of the previous extra credit problem. You will also have to ask the player to give you the path to the board file if they choose to load a new game from a file. This can be done any way you like; although, more points will be given to an implementation that uses a menu bar.

Helpful Links


Style

At the top of your hw6.c file, write a comment with your name, etc., in the following form:

              /* Jane Doe, jdoe */
              /* CS152, Summer 2013 */
              /* Homework 6: Animal Match */
              
This information is not strictly necessary, since your files are already identified by their names and the repository they reside in. Nevertheless, the redundancy is a helpful convenience for us when we are browsing and/or grading your work.

Comments, where they occur, should be helpful and precise. Omit superfluous comments:

              int a = b + c; /* I'm adding b and c and naming it a! */
              
Yes, we can see that.

Your code should be no more than 80 columns wide.

Do not write more than one statement on a line.

Do not submit code that does not compile. If a function is broken, and makes compilation impossible, comment out that function and submit the rest. Non-compiling code will receive little to no credit.


Submitting Your Work

Save and commit your files in YOUR-REPOSITORY/hw6. Recall that you will need to add your work before you commit it. (Also, notice that in the -m message you include at commit time, -m is simply a command-line option.)

Commit your work early and often. We do not grade intermediate commits, only the work as it stands at the deadline. If you have any issues with subversion, not only your instructors but your classmates can help you. Most of the students in this class have at least one full quarter of experience running subversion.

If, for any reason, perhaps due to a late add, you do not have a CS repository, save your work somewhere you can easily get it and send mail to Adam. We'll get you set up with a repository in time to make the deadline.