Goals for this homework

  • Practice with multi-dimensional arrays
  • Practice using pointers

Updates

You are expected to complete this assignment individually. If you need help, you are invited to come to office hours and/or ask questions on piazza. Clarification questions about the assignments may be asked publicly. Once you have specific bugs related to your code, make the posts private.

This homework has several exercises. We are also providing you with some resources on printf and error handling for this assignment.

You should submit several files for this assignment ( tictactoe_funcs.h, tictactoe_funcs.c, othello_funcs.h, othello_funcs.c, tictactoe.c, othello.c and Makefile) in your subversion repository as directed below.

Set Up

Because you are adding a second set of files to your directory, you need to add a second target to your Makefile. In your makefile, add another two lines (with a space between these and the ones already there).

tictactoe: tictactoe_funcs.h tictactoe_funcs.c tictactoe.c
	clang -Wall tictactoe_funcs.c tictactoe.c -o tictactoe

othello: othello_funcs.h othello_funcs.c othello.c
	clang -Wall othello_funcs.c othello.c -o othello

Remember to make skeleton code so that your code will minimally execute. You must do this in case you do not complete your assignment. Our testing infrastructure needs to compile and execute even if you did not complete the entire assignment.

  • Step 1: Create all of the .h files
    Start with the standard preprocessor guards to make sure the .h file is not read twice:
    #ifndef FILENAME_H
    #define FILENAME_H

    End with the end preprocessor guard.
    #endif

    Add prototypes for all functions in this file, the function header comments, as described below.
  • Step 2: Create all of the .c files. For each function, implement the function with a single line - return with the right type. For any functions already implemented in the warmup, copy those over. For example:
    double surface_area_cylinder(double height, double radius)
    {
    	// you may put an fprintf stating it's not implemented yet here.
    	return 0.0;
    }
    
  • In othello_funcs.c, fill in the following implementation:
    void print_othello_board( char board[8][8] )
    {
            unsigned int i, j;
            for(i=0;i<8;i++)
            {
                    for(j=0;j<8;j++)
                    {
                            printf("%c ",board[i][j]);
                    }
                    printf("\n");
            }
    }
    
  • Step 3: Create the main files. For each function, put in a single function call. For example:
    int main()
    {
    	surface_area_cylinder(1.0, 5.0);
    	// add the rest of the function calls here
    }
    
First get this compiling and running. It won't print out anything, but this will mean that your code will compile and execute with our infrastructure. This must work in order to get any points in this course. Do this first, not last.

Exercise 1: Tic-Tac-Toe

In this exercise, you will complete the code to implement tic-tac-toe. You will write individual functions as specified, as well as a play loop. All of those files will go into tictactoe-funcs.c. Then you will write a main function with both tests for each individual function as well as a call to the play loop to test the entire function.

For the play loop, you are implementing two humans playing against each other. This is the only configuration you will offer. You will see below that you will implement a computer player, and you will test that separately. However, you won't put that in the main play loop. You can write your own testing function for it (which an be in the form of an interactive play loop or explicit test function calls).

First copy over the following functions from the warmup:

  • void print_tic_tac_toe_board( char board[3][3] );
  • void init_board(char board[3][3]);
  • unsigned int place_piece(char board[3][3], char player, unsigned int row, unsigned int col);
You will then implement the following functions:
int player_won(char board[3][3], char player, unsigned int row, unsigned int col);

In this function, player has just placed its piece in location row, col. Check to see if this makes player win the game. If the player has won, return 1. If not, return 0.


int computer_move(char board[3][3], char player, unsigned int *row, unsigned int *col);

In this function, you, playing as the computer, decide upon a move. You are provided the board and what player you are playing for. You place one player character in an empty space, hopefully a space that will go towards winning the game. row and col are output parameters. Fill those variables in with the row and column of your move. Return 1 if you made a move, 0 if not (e.g. the board is full). It is up to you how sophisticated you make this - see how smart you can make it! You will not be graded on the sophistication of the computer moves - it is merely personal satisfaction if yours is awesome. If we can, we'll try to have a tournament of computers playing each other and determine a winner in the class with a prize. But no guarantees.


void play_tic_tac_toe();

This is your game loop. Implement it with the following details:

  • There are two players: 'O' and 'X'.
  • Rows and columns always start with 0.
  • The first piece is placed by 'X'.
  • Use the following print messages for the game. Exit when a win is detected.
  • After every move, print out the board again.
  • Once a player wins, congratulate, print out board, and return.

printf("Player %c, in what row (0-2) will you place your next piece? ",...);
scanf("%u",...);
printf("Player %c, that is not a valid row. Try again. "...); // ask for row again
printf("Player %c, in what column (0-2) will you place your next piece? ",...);
scanf("%u",...);
printf("Player %c, that is not a valid column. Try again. "...); // ask for column again
printf("That is not a valid move. Try again. "...); // go back and ask for row again
printf("Congratulations! Player %c won!",...);
printf("Tie game!",...);

Exercise 2: Othello

In this exercise, you will complete the code to implement Othello. You will write individual functions as specified, as well as a play loop. All of those files will go into othello_funcs.c. Then you will write a main function with both tests for each individual function as well as a call to the play loop to test the entire function.


void init_board(char board[8][8]);

Initialize the board to the starting configuration. Most of the spaces should be '*' indicating that they are empty. The middle four slots are taken with white on the top left and bottom right and black in the bottom left and top right. See the game rules for a diagram.


unsigned int place_piece(char board[8][8], char player, unsigned int row, unsigned int col);

In this function, check to see if it is a valid move. To be valid:

  • The spot must be empty.
  • The piece must be the next piece in a horizontal, vertical, or diagonal line from existing pieces.
  • Placing it must flip pieces of the opposite color.
If it is a valid move, put the character in that spot and returns the number of tiles added to the board (1 for the tile, x for the flipped ones). If not, leave the board unchanged, and return 0.


unsigned int flip_pieces(char board[8][8], unsigned int row, unsigned int col);

This is the crux of play. A piece has just been placed at row, col. You must go through all diagonals and rows aligned with that spot and flip over any pieces of the other color that need to be flipped. See the rules of Othello for when to flip pieces. Count how many pieces were flipped.

This function is called as the last check in place_piece - once it is determined that the move is valid in every other respect, then it places the piece and finds out how many pieces have been flipped. If the number is 0, then place_piece will remove the piece again and report an invalid move.


char player_won(char board[8][8]);

Upon the conclusion of the game, determine who won the game (the player with the most pieces on the board). Return the character of the winner. If it is a tie, return '*'.


int computer_move(char board[8][8], char player, unsigned int *row, unsigned int *col);

In this function, you, playing as the computer, decide upon a move. You are provided the board and what player you are playing for. You need to make a single valid move. It is up to you how intelligent to make your computer. Return 1 if you made a move, 0 if not (e.g. the board is full). row and col are output parameters - put the row and column of your move into those variables.

You will not be graded on the sophistication of the computer moves - it is merely personal satisfaction if yours is awesome. If we can, we'll try to have a tournament of computers playing each other and determine a winner in the class with a prize. But no guarantees.


void play_othello();

This is your game loop. Implement it with the following details:

  • There are two players: 'W' and 'B'.
  • Rows and columns always start with 0.
  • The first move is made by 'B'.
  • A player either enters the row and column of the next piece or, if they do not see a valid move, enters -1, -1.
  • Play continues until all space on the board have been filled or there are no valid plays for either player right in a row.
  • After every move, print out the board again followed by how many pieces each player has on the baord.
  • Upon game ending, congratulate the winner and return.
Use the following print messages for the game:
printf("Player %c, in what row (0-2) will you place your next piece? ",...);
scanf("%d",...);
printf("Player %c, that is not a valid row. Try again.\n"...); // ask for row again
printf("Player %c, in what column (0-2) will you place your next piece? ",...);
scanf("%d",...);
printf("Player %c, that is not a valid column. Try again.\n"...); // ask for column again
printf("That is not a valid move. Try again.\n"...); // go back and ask for row again
printf("White: %u tiles, Black: %u tiles\n",...
printf("Congratulations! Player %c won!\n",...);
printf("Tie game!\n",...);

Submit

At this point, you should have done the following:
  • Created several files and filled in the proper information: tictactoe_funcs.c, tictactoe_funcs.h, tictactoe.c, othello_funcs.c, othello_funcs.h, othello.c inside your hw3 directory.
  • $ svn added all of them (you only ever have to do this once for each file) 
    	
  • Implemented all of your functions. If not, you at least need skeletons of your functions so that our automated tests will compile for the functions you did write.
  • Compiled your executable manually and with the Makefile
  • Implemented your test cases
  • Executed your code
  • Debugged your code
  • $ svn commit -m "hw3 complete"