In: Computer Science
Complete the project functions for this week. Note that you have two weeks to complete these functions, however you should aim to get most of them done this week so you can focus on your own additions to the project next week. These functions are setup_game(), play_game() and computer_move(). To complete these functions, first remove the library function call from the function in the template (save_game_lib, etc), then replace that with your own code to complete the function. You can test your functions separately from the project by creating a small main() function that calls them (with appropriate inputs), or you can compile the entire project and see if it works.
setup_game(): The setup_game function takes a Game pointer as input, and initialises this structure so that it is ready to play a new game. There are three main tasks that this function needs to achieve. Firstly, it needs to determine whether player 1 and player 2 are human or
computer players. To do this, a prompt should be displayed to the user and they can enter 'h' for human or 'c' for computer for both players. The results of this input should set the "player1" and "player2" fields of the game structure to either 0 for a computer player or 1 for a human player. Next, your function needs to initialise the board to be empty, by filling every square with zeros. Finally, the turn and winner fields of the structure should be set. winner should be set to 0 (since nobody has won yet), and turn should be a randomly chosen as either 1 or 2.
play_game(): This function performs all the actions necessary to play the game. Most of the functionality of the game has already been implemented by other functions, so the main task of the play_game functions is to call these in the correct way. It takes a pointer to a Game as input, and this structure is assumed to be already initialised to either a new game or a game in progress. The function needs to then run the game until either somebody has won, or the board is full (a draw). To do this, on each turn the game needs to display the board, then either (a) get a move from the keyboard for a human player, or (b) determine a computer move for a computer player, then add this move to the board. The turn and winner fields should then be updated to reflect the new state of the game. If a human player enters 's' or 'q' (as indicated by the return value of get_move) then the move isn't added and the turn field is not changed, but instead the game is saved or quit as appropriate. Your play_game function should use the existing functions (get_move, add_move, display_board, board_full, winner, save_game, etc) to perform all the relevant tasks. You can also use the wait_seconds() function to delay the game for a few seconds before the computer moves, in order to stop this happening instantly.
computer_move(): This function is the "artificial intelligence" of the game. It takes the current board array, the player whose turn it is, and the 'level' of the AI as input, and returns a column number (between 1 and COLS) in which the computer will play. This is very similar to the get_move() function, except that rather than asking the player for a move, one is generated by the AI. The 'level' variable determines how 'smart' the AI is. Level 0 should just generate a random column (that isn't full) and return that. Level 1 should look if the computer can win the game in any column, and if so choose that column. If not, a random valid non-full column is chosen. For level 2, the computer should also check if the opponent can win in any column, and choose that column to block them. Level 3 and above do not need to be implemented for this version, so the behaviour should be the same as level 2.
HINT: Create a copy of the board, so that you can 'test' each move in turn (using add_move and winner) to see if it wins, and choose that column if so. If not, you can reset the copy back to the original board and try again.
TEMPLATE FILE:
#include #include #include #include #include #include "connect4.h" int main ( void ){ int option ; Game g ; // intitialise random seed srand(time(NULL)); while (( option = main_menu()) != -1 ){ if ( option == 1 ){ // setup a new game setup_game ( &g ) ; // now play this game play_game ( &g ) ; } else if ( option == 2 ){ // attempt to load the game from the save file if ( load_game ( &g, "game.txt" ) == 0 ){ // if the load went well, resume this game play_game ( &g ) ; } else { printf ( "Loading game failed.\n") ; } } else if ( option == -1 ){ printf ( "Exiting game, goodbye!\n") ; } } }
// WEEK 4-5 TASKS
// setup_game()
// play_game()
// computer_move()
// calcualtes a column for the computer to move to, using
artificial "intelligence"
// The 'level' argument describes how good the computer is, with
higher numbers indicating better play
// 0 indicates very stupid (random) play, 1 is a bit smarter, 2
smarter still, etc..
int computer_move ( int board[COLS][ROWS], int colour, int level
){
// If level 0, this is a 'dumb' opponent, pick a random column that isn't full and return that
// If level 1, this is slightly smarter - if the computer's move can win the game, choose that column, otherwise random
// If level 2, slightly smarter again. If computer can win it will do that, otherwise it will block an opponent's winning move, otherwise random
// Higher levels are up to you!
// Hint - you can copy the board into a 'temporary' board and
trial putting a token in a column, then simply call the winner
function to see
// if that move has won the game. Doing this for the current player
will check if that player can win, doing it for the opponent will
see if the opponent can win next turn
// You can use "lookahead" logic to search for the 'best' move many moves ahead
return computer_move_lib ( board, colour, level ) ;
}
// sets up the game to a new state
// prompts the user if each player should be a human or computer,
and initialises the relevant fields
// of the game structure accordingly
int setup_game ( Game *g ){
// prompt the user to enter whether each player is a human or
computer (h or c)
// set the player1 and player2 fields of the struct accordingly (1
for human, 0 for computer)
// initialise the board to all zeros
// set winner to 0 ( no winner yet!)
// set turn to either 1 or 2 (randomly)
return setup_game_lib ( g ) ;
}
// Starts or resumes playing the Game g. Continues until the game
is over or the user quits.
int play_game ( Game *g ){
return play_game_lib ( g ) ;
}
#ifndef CONNECT4_H #define CONNECT4_H 1 #define ROWS 6 // height of the board #define COLS 7 // width of the board (values of 9 are going to display poorly!!) // These lines detect what sort of compiler you are using. This is used to handle the time delay // function wait() in various operating systems. Most OS will use sleep(), however for windows it is // Sleep() instead. #ifdef _WIN32 #include <windows.h> #else #include <unistd.h> #endif typedef struct { int player1, player2 ; // variables for each player - 1 for human, 0 for computer player int board[COLS][ROWS] ; // the game board. 0 for empty space, 1 for player 1, 2 for player 2 // Note that row 0 is the TOP row of the board, not the bottom! // column 0 is on the left of the board int turn ; // whose turn it is, 1 or 2 int winner ; // who has won - 0 for nobody, 1 for player 1, 2 for player 2 } Game ; // displays the welcome screen and main menu of the game, and prompts the user to enter an option until // a valid option is entered. // Returns 1 for new game, 2 for load game, -1 for quit int main_menu ( void ) ; // displays the board to the screen int display_board ( int[COLS][ROWS] ) ; // sets up the game to a new state // prompts the user if each player should be a human or computer, and initialises the relevant fields // of the game structure accordingly int setup_game ( Game *g ) ; // Returns TRUE if the specified column in the board is completely full // FALSE otherwise // col should be between 1 and COLS int column_full ( int[COLS][ROWS], int col ) ; // plays a game until it is over int play_game ( Game *g ) ; // prompts the user to enter a move, and checks that it is valid // for the supplied board and board size // Returns the column that the user has entered, once it is valid (1-COLS) // note that this value is betweeen 1 and COLS (7), NOT between 0 and 6!! // If the user enters 'S' or 's' the value -1 should be returned, indicating that the game should be saved // If the user enters 'Q' or 'q' the value -2 should be returned, indicating that the game should be abandoned int get_move ( int[COLS][ROWS] ) ; // calcualtes a column for the computer to move to, using artificial "intelligence" // The 'level' argument describes how good the computer is, with higher numbers indicating better play // 0 indicates very stupid (random) play, 1 is a bit smarter, 2 smarter still, etc.. int computer_move ( int[COLS][ROWS], int colour, int level ) ; // adds a token of the given value (1 or 2) to the board at the // given column (col between 1 and COLS inclusive) // Returns 0 if successful, -1 otherwise int add_move ( int b[COLS][ROWS], int col, int colour ) ; // determines who (if anybody) has won. Returns the player id of the // winner, otherwise 0 int winner ( int[COLS][ROWS] ) ; // determines if the board is completely full or not int board_full ( int[COLS][ROWS] ) ; // saves the game to the specified file. The file is text, with the following format // player1 player2 turn winner // board matrix, each row on a separate line // Example: // //1 0 1 0 player 1 human, player 2 computer, player 1's turn, nobody has won //0 0 0 0 0 0 0 board state - 1 for player 1's moves, 2 for player 2's moves, 0 for empty squares //0 0 0 0 0 0 0 //0 0 0 2 0 0 0 //0 0 0 2 0 0 0 //0 2 1 1 1 0 0 //0 2 2 1 1 2 1 int save_game ( Game g, char filename[] ) ; // loads a saved game into the supplied Game structure. Returns 0 if successfully loaded, -1 otherwise. int load_game ( Game *g, char filename[] ) ; // waits for s seconds - platform specific! THIS FUNCTION IS INCLUDED IN THE LIBRARY, NO NEED TO WRITE IT! void wait_seconds ( int s ) ; // library versions of functions. Exactly the same behaviour done by course staff. Please just call these if you have not completed your version as yet. int display_board_lib ( int[COLS][ROWS] ) ; int setup_game_lib ( Game *g ) ; int column_full_lib ( int[COLS][ROWS], int col ) ; int play_game_lib ( Game *g ) ; int get_move_lib ( int[COLS][ROWS] ) ; int add_move_lib ( int b[COLS][ROWS], int col, int colour ) ; int winner_lib ( int[COLS][ROWS] ) ; int board_full_lib ( int[COLS][ROWS] ) ; int computer_move_lib ( int[COLS][ROWS], int colour, int level ) ; int save_game_lib ( Game g, char filename[] ) ; int load_game_lib ( Game *g, char filename[] ) ; int main_menu_lib ( void ) ;
#ifndef FT_H
# define FT_H
void ft_putchar(char c);
void ft_putstr(char *str);
void ft_swap(int *a, int *b);
int ft_strcmp(char *s1, char *s2);
int ft_strlen(char *str);
#endif
///02////////////////
#ifndef FT_BOOLEAN_H
# define FT_BOOLEAN_H
# include <unistd.h>
# define TRUE 1
# define FALSE 0
# define SUCCESS 0
# define EVEN_MSG "I have a pair number of arguments.\n"
# define ODD_MSG "I have an impair number of arguments.\n"
# define EVEN(x) (!(x % 2))
typedef int t_bool;
#endif
#include "ft_boolean.h"
void ft_putstr(char *str)
{
while (*str)
write(1, str++, 1);
}
t_bool ft_is_even(int nbr)
{
return ((EVEN(nbr)) ? TRUE : FALSE);
}
int main(int argc, char **argv)
{
(void)argv;
if (ft_is_even(argc - 1) == TRUE)
ft_putstr(EVEN_MSG);
else
ft_putstr(ODD_MSG);
return (SUCCESS);
}
#ifndef FT_ABS_H
# define FT_ABS_H
# define ABS(Value) ((Value < 0) ? (-Value) : (Value))
#endif
#ifndef FT_POINT_H
# define FT_POINT_H
typedef struct s_point
{
int x;
int y;
} t_point;
#endif
#include "ft_point.h"
void set_point(t_point *point)
{
point->x = 42;
point->y = 21;
}
int main(void)
{
t_point point;
set_point(&point);
return (0);
}
#include "ft_stock_par.h"
char *ft_strdup(char *src)
{
int i;
int src_size;
char *new_str;
i = 0;
src_size = 0;
while (src[src_size])
src_size++;
new_str = (char*)malloc(sizeof(*new_str) * (src_size));
if (new_str == NULL)
return (NULL);
while (i < src_size)
{
new_str[i] = src[i];
i++;
}
new_str[src_size] = '\0';
return (new_str);
}
struct s_stock_par *ft_param_to_tab(int ac, char **av)
{
t_stock_par *stock;
int i;
int j;
i = 0;
stock = malloc(sizeof(t_stock_par) * (ac + 1));
while (i < ac)
{
j = 0;
while (av[i][j])
j++;
stock[i].size_param = j;
stock[i].str = av[i];
stock[i].copy = ft_strdup(av[i]);
stock[i].tab = ft_split_whitespaces(av[i]);
i++;
}
stock[i].str = 0;
return (stock);
}
#include "ft_stock_par.h"
void ft_show_tab(struct s_stock_par *par)
{
par = 0;
}
#ifndef FT_STOCK_PAR_H
# define FT_STOCK_PAR_H
# include <stdlib.h>
typedef struct s_stock_par
{
int size_param;
char *str;
char *copy;
char **tab;
} t_stock_par;
void ft_show_tab(struct s_stock_par *par);
char **ft_split_whitespaces(char **str);
#endif
#include "ft_stock_par.h"
void ft_putnbr(int nb)
{
if (nb >= 10)
{
ft_putnbr(nb / 10);
ft_putnbr(nb % 10);
}
else
ft_putchar(48 + nb);
}
void ft_putstr(char *str)
{
int i;
i = 0;
while (str[i])
{
ft_putchar(str[i]);
i++;
}
}
void ft_show_tab(struct s_stock_par *par)
{
int i;
int j;
i = 0;
while (par[i].str)
{
ft_putstr(par[i].copy);
ft_putchar('\n');
ft_putnbr(par[i].size_param);
ft_putchar('\n');
j = 0;
while (par[i].tab[j])
{
ft_putstr(par[i].tab[j]);
ft_putchar('\n');
j++;
}
i++;
}
}
#include "ft_stock_par.h"
char *ft_strdup(char *src)
{
int i;
int src_size;
char *new_str;
i = 0;
src_size = 0;
while (src[src_size])
src_size++;
new_str = (char*)malloc(sizeof(*new_str) * (src_size));
if (new_str == NULL)
return (NULL);
while (i < src_size)
{
new_str[i] = src[i];
i++;
}
new_str[src_size] = '\0';
return (new_str);
}
struct s_stock_par *ft_param_to_tab(int ac, char **av)
{
t_stock_par *stock;
int i;
int j;
i = 0;
stock = malloc(sizeof(t_stock_par) * (ac + 1));
while (i < ac)
{
j = 0;
while (av[i][j])
j++;
stock[i].size_param = j;
stock[i].str = av[i];
stock[i].copy = ft_strdup(av[i]);
stock[i].tab = ft_split_whitespaces(av[i]);
i++;
}
stock[i].str = 0;
return (stock);
}
#ifndef FT_STOCK_PAR_H
# define FT_STOCK_PAR_H
# include <stdlib.h>
typedef struct s_stock_par
{
int size_param;
char *str;
char *copy;
char **tab;
} t_stock_par;
void ft_putchar(char c);
void ft_putstr(char *str);
void ft_putnbr(int nb);
void ft_show_tab(struct s_stock_par *par);
struct s_stock_par *ft_param_to_tab(int ac, char **av);
char **ft_split_whitespaces(char *str);
char *ft_strdup(char *src);
#endif