Click here to Skip to main content
15,400,381 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi. I'm making a tic tac toe game and I've been looking online for tutorial on how I can make a save game function for loading the game later. Up until now I've had no luck with this. See the code for the game below. I'd like some help and insight on how I can achieve this. Cheers.

The code is running fine for me, it's just that I'm very confused as to how I would achieve making the save and load game function. Any help or advice would be very much appreciated.

The problem now is I'm getting two errors saying the load and save identifier cant be found would anyone have a solution to this I will paste the code I have done down below

What I have tried:

#include <stdio.h>
char box[10] = { 'o','1','2','3','4','5','6','7','8','9' };// This is to Initialise the board
int checkWin();// This will be used to check for the win
void board();

int main() {
	
	int player = 1, i, choice;
	char xOrO; // X,O
	
	if (!save(box, player))
	{
		fprintf(stderr, "Save function failed!\n");
		//TODO: handle failure
	}

	if (!load(box, &player))
	{
		fprintf(stderr, "Load function failed!\n");
		//TODO: handle failure
	}
	
	do {
		board();
		player = (player % 2) ? 1 : 2;
		printf("Player %d, enter the choice : ", player);
		scanf("%d", &choice);
		xOrO = (player == 1) ? 'X' : 'O';
		if (choice == 1 && box[1] == '1')
			box[1] = xOrO;
		else if (choice == 2 && box[2] == '2')
			box[2] = xOrO;
		else if (choice == 3 && box[3] == '3')
			box[3] = xOrO;
		else if (choice == 4 && box[4] == '4')
			box[4] = xOrO;
		else if (choice == 5 && box[5] == '5')
			box[5] = xOrO;
		else if (choice == 6 && box[6] == '6')
			box[6] = xOrO;
		else if (choice == 7 && box[7] == '7')
			box[7] = xOrO;
		else if (choice == 8 && box[8] == '8')
			box[8] = xOrO;
		else if (choice == 9 && box[9] == '9')
			box[9] = xOrO;

		else {
			printf("Invalid option !");
			player--;
			getchar();
		}
		i = checkWin();
		player++;

	} while (i == -1);

	board();
	if (i == 1) {
		printf("==>Player %d won", --player);
	}
	else {
		printf("==>Game draw");
	}
	getchar();
	return 0;

}
int checkWin() {
	if (box[1] == box[2] && box[2] == box[3])/**/
		return 1;
	else if (box[4] == box[5] && box[5] == box[6])
		return 1;
	else if (box[7] == box[8] && box[8] == box[9])
		return 1;
	else if (box[1] == box[4] && box[4] == box[7])
		return 1;
	else if (box[2] == box[5] && box[5] == box[8])
		return 1;
	else if (box[3] == box[6] && box[6] == box[9])
		return 1;
	else if (box[1] == box[5] && box[5] == box[9])
		return 1;
	else if (box[3] == box[5] && box[5] == box[7])
		return 1;
	else if (box[1] != '1' && box[2] != '2' && box[3] != '3' && box[4] != '4' && box[5] != '5' && box[6] != '6' && box[7] != '7' && box[8] != '8' && box[9] != '9')
		return 0;
	else
		return -1;
}

void board() {
	printf("\n\n\t Tic Tac Toe \n\n");
	printf("Player1 (X) - Player2 (O) \n\n\n");
	printf("     |     |     \n");
	printf("  %c  |  %c  |  %c  \n", box[1], box[2], box[3]);
	printf("_____|_____|_____\n");
	printf("     |     |     \n");
	printf("  %c  |  %c  |  %c  \n", box[4], box[5], box[6]);
	printf("_____|_____|_____\n");
	printf("     |     |     \n");
	printf("  %c  |  %c  |  %c  \n", box[7], box[8], box[9]);
	printf("     |     |     \n");
}

//this function returns whether the save operation was successful
bool save(char board_array[10], int player)
{
	FILE* fp;

	//open file
	fp = fopen("savefile.txt", "wt");
	if (fp == NULL)
	{
		fprintf(stderr, "Error opening file\n");
		return false;
	}

	//save player's turn to file
	if (fputc(player == 1 ? '1' : '2', fp) == EOF)
	{
		fprintf(stderr, "Error writing to file\n");
		fclose(fp);
		return false;
	}

	//save board to file
	if (fwrite(board_array, 10, 1, fp) != 1)
	{
		fprintf(stderr, "Error writing to file\n");
		fclose(fp);
		return false;
	}

	//cleanup
	fclose(fp);

	return true;
}

//this function returns whether the load operation was successful
bool load(char board_array[10], int* player)
{
	FILE* fp;

	//open file
	fp = fopen("savefile.txt", "rt");
	if (fp == NULL)
	{
		fprintf(stderr, "Error opening file\n");
		return false;
	}

	//read player's turn from file
	switch (fgetc(fp))
	{
	case EOF:
		fprintf(stderr, "Error reading from file\n");
		fclose(fp);
		return false;
		break;
	case '1':
		*player = 1;
		break;
	case '2':
		*player = 2;
		break;
	default:
		fprintf(stderr, "Unexpected character found in file!\n");
		fclose(fp);
		return false;
	}

	//read board from file
	if (fread(board_array, 10, 1, fp) != 1)
	{
		fprintf(stderr, "Error reading from file\n");
		fclose(fp);
		return false;
	}

	//cleanup
	fclose(fp);

	return true;
}
Posted
Updated 22-Aug-21 6:59am
v2
Comments
Afzaal Ahmad Zeeshan 22-Aug-21 8:56am
   
And what is the problem with this?
akeem jokosenumi 22-Aug-21 9:05am
   
The probelem is I keep getting the message load and save identifier cannot be found which makes it unable to open the file

You need to place your Main() function at the bottom in C so everything else is declared first.

Another option would be to use Function Prototypes[^]
   
v2
C is an old language: it does not "look ahead" to see what sunctionsmight be declared later.

So since your save and load functions are only declared at the bottom of the file, when you try to call them from main it doesn't understand what you mean as it hasn't encountered the names before.

The solution is to use forward references: put these two lines above your main function:
bool save(char board_array[10], int player);
bool load(char board_array[10], int* player);


I'd also reverse the parameters when you save the data - change:
if (fwrite(board_array, 10, 1, fp) != 1)
To
if (fwrite(board_array, 1, 10, fp) != 1)

as the array "element" is one byte wide (a char) and you have ten of them.
   
v2
Comments
Rick York 22-Aug-21 12:32pm
   
If you tell fwrite to write ten items it will return 10 if is successful.
akeem jokosenumi 22-Aug-21 12:59pm
   
Hi I changed this now its working my question now is how would this load at the start of the because I'm now getting error writing to the file would anyone have clue as to why this is as I'm so close to finishing off this project
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>

void reset_game(char board[3][3], bool* player);
bool save(char board[3][3], bool player);
bool load(char board[3][3], bool* player);
int  check_win(char board[3][3]);
void print_board(char board[3][3]);
int  get_int_from_user(const char* prompt, ...);
bool get_YN_from_user(const char* prompt, ...);

int main()
{
    //array which holds the board contents
    char board[3][3];

    //this variable specifies whether it is the first player's turn
    bool first_player;

    //this variable will store the user's input
    int choice;

    //initialize the game state
    reset_game(board, &first_player);

    for (;;) //infinite loop, equivalent to while(true)
    {
        print_board(board);

        //read input from user
        choice = get_int_from_user(
            "Enter a number 1 to 9 to select a field, or\n"
            "the number 10 to save the game, or\n"
            "the number 11 to load the game, or\n"
            "the number 12 to quit the game.\n"
            "Player %d, enter your choice :\n",
            first_player ? 1 : 2
        );

        //handle user input
        switch (choice)
        {
        case 10:
            //save game
            if (save(board, first_player))
            {
                printf("Save successful.\n");
            }
            else
            {
                printf("Save failed!\n");
            }
            break;
        case 11:
            //load game
            if (load(board, &first_player))
            {
                printf("Load successful.\n");
            }
            else
            {
                printf("Load failed!\n");
                printf("Resetting game, as the game may now be in a corrupt state.\n");
                reset_game(board, &first_player);
            }
            break;
        case 12:
            //quit game
            printf("Bye!\n");
            exit(EXIT_SUCCESS);
        default:
            if (1 <= choice && choice <= 9)
            {
                //user selected a field

                int i;

                //calculate corresponing row and column
                i = choice - 1;
                int row = i / 3;
                int column = i % 3;

                //make sure field is not already occupied
                if (board[row][column] != 'E')
                {
                    printf("Invalid choice! The specified field is not empty!\n");
                    break;
                }

                //make the move
                board[row][column] = first_player ? 'X' : 'O';

                i = check_win(board);

                if (i != -1)
                {
                    print_board(board);
                    if (i == 1)
                        printf("==>Player %d won\n", first_player ? 1 : 2);
                    else
                        printf("==>Game draw\n");
                    if (get_YN_from_user("Do you want to play again? (y/n)\n"))
                    {
                        reset_game(board, &first_player);
                        continue;
                    }
                    else
                        exit(EXIT_SUCCESS);
                }

                //change the player's turn
                first_player = !first_player;
            }
            else
            {
                printf("Invalid choice! Choice must be a number between 1 and 12.\n");
            }
        }
    }
}

void reset_game(char board[3][3], bool* first_player)
{
    //set all fields of the board to contain 'E', which stands for "empty"
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            board[i][j] = 'E';

    //make it the first player's turn
    *first_player = true;
}


int check_win(char board[3][3])
{
    //check for horizontal win
    for (int i = 0; i < 3; i++)
    {
        char c = board[i][0];

        if (c != 'E' && board[i][1] == c && board[i][2] == c)
            return 1;
    }

    //check for vertical win
    for (int i = 0; i < 3; i++)
    {
        char c = board[0][i];

        if (c != 'E' && board[1][i] == c && board[2][i] == c)
            return 1;
    }

    //check for diagonal win
    for (int i = 0; i < 3; i++)
    {
        char c;

        //check for top-left to bottom-right win
        c = board[0][0];
        if (c != 'E' && board[1][1] == c && board[2][2] == c)
            return 1;

        //check for bottom-left to top-right win
        c = board[2][0];
        if (c != 'E' && board[1][1] == c && board[0][2] == c)
            return 1;
    }

    //check for draw
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            if (board[i][j] == 'E')
                return -1;

    return 0;
}

void print_board(char board[3][3])
{
    printf("\n\n      Tic Tac Toe \n\n");
    printf("Player1 (X) - Player2 (O) \n\n\n");

    for (int i = 0; i < 3; i++)
    {
        printf("        |     |     \n");

        printf(
            "     %c  |  %c  |  %c  \n",
            board[i][0] == 'E' ? '1' + i * 3 : board[i][0],
            board[i][1] == 'E' ? '2' + i * 3 : board[i][1],
            board[i][2] == 'E' ? '3' + i * 3 : board[i][2]
        );

        if (i != 2)
            printf("   _____|_____|_____\n");
        else
            printf("        |     |     \n");
    }

    printf("\n");
}

//this function returns whether the save operation was successful
bool save(char board[3][3], bool first_player)
{
    FILE* fp;

    fp = fopen("savefile.txt", "wt");
    if (fp == NULL)
    {
        fprintf(stderr, "Error opening file\n");
        return false;
    }

    if (fputc(first_player ? '1' : '2', fp) == EOF)
    {
        fprintf(stderr, "Error writing to file\n");
        fclose(fp);
        return false;
    }

    if (fwrite(board, 9, 1, fp) != 1)
    {
        fprintf(stderr, "Error writing to file\n");
        fclose(fp);
        return false;
    }

    fclose(fp);

    return true;
}

///this function returns whether the load operation was successful
bool load(char board[3][3], bool* first_player)
{
    FILE* fp;

    //open file
    fp = fopen("savefile.txt", "rt");
    if (fp == NULL)
    {
        fprintf(stderr, "Error opening file\n");
        return false;
    }

    //read player's turn from file
    switch (fgetc(fp))
    {
    case EOF:
        fprintf(stderr, "Error reading from file\n");
        fclose(fp);
        return false;
        break;
    case '1':
        *first_player = true;
        break;
    case '2':
        *first_player = false;
        break;
    default:
        fprintf(stderr, "Unexpected character found in file!\n");
        fclose(fp);
        return false;
    }
    //read board from file
    if (fread(board, 9, 1, fp) != 1)
    {
        fprintf(stderr, "Error reading from file\n");
        fclose(fp);
        return false;
    }

    //cleanup
    fclose(fp);

    return true;
}

int get_int_from_user(const char* prompt, ...)
{
    for (;;) //loop forever until user enters a valid number
    {
        char buffer[1024], * p;
        va_list vl;
        long l;

        va_start(vl, prompt);
        vprintf(prompt, vl);
        va_end(vl);

        if (fgets(buffer, sizeof buffer, stdin) == NULL)
        {
            fprintf(stderr, "unrecoverable error reading from input\n");
            exit(EXIT_FAILURE);
        }

        //make sure that entire line was read in (i.e. that
        //the buffer was not too small)
        if (strchr(buffer, '\n') == NULL)
        {
            int c;

            printf("line input was too long!\n");

            //discard remainder of line
            do
            {
                c = getchar();

                if (c == EOF)
                {
                    fprintf(stderr, "unrecoverable error reading from input\n");
                    exit(EXIT_FAILURE);
                }

            } while (c != '\n');

            continue;
        }

        errno = 0;
        l = strtol(buffer, &p, 10);

        if (p == buffer)
        {
            printf("error converting string to number\n");
            continue;
        }

        if (errno == ERANGE || l < INT_MIN || l > INT_MAX)
        {
            printf("number out of range error\n");
            continue;
        }

        //make sure remainder of line contains only whitespace,
        //so that input such as "12dfghoh" gets rejected
        for (; *p != '\0'; p++)
        {
            if (!isspace((unsigned char)*p))
            {
                printf("unexpected input encountered!\n");

                //cannot use `continue` here, because that would go to
                //the next iteration of the innermost loop, but we
                //want to go to the next iteration of the outer loop
                goto next_outer_loop_iteration;
            }
        }

        return l;

    next_outer_loop_iteration:
        continue;
    }
}


//this function will ask the user a yes/no question
bool get_YN_from_user(const char* prompt, ...)
{
    for (;;) //loop forever until user enters a valid number
    {
        char buffer[1024];
        va_list vl;

        va_start(vl, prompt);
        vprintf(prompt, vl);
        va_end(vl);

        if (fgets(buffer, sizeof buffer, stdin) == NULL)
        {
            fprintf(stderr, "unrecoverable error reading from input\n");
            exit(EXIT_FAILURE);
        }

        //make sure that entire line was read in (i.e. that
        //the buffer was not too small)
        if (strchr(buffer, '\n') == NULL)
        {
            int c;

            printf("line input was too long!\n");

            //discard remainder of line
            do
            {
                c = getchar();

                if (c == EOF)
                {
                    fprintf(stderr, "unrecoverable error reading from input\n");
                    exit(EXIT_FAILURE);
                }

            } while (c != '\n');

            continue;
        }

        return toupper((unsigned char)buffer[0]) == 'Y';
    }
}
   
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900