//Basic libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <stdbool.h>
#include <time.h>

#define Empty 0
#define P1 1
#define P2 2
#define Height 6
#define Width 7

int board[Height][Width];
char gamestr[41];

void show_game_list(){
    //Open game file for reading
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("games.txt", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);
    //Print the available games id in creation order
    printf("ORDER     ID\n");
    int count = 1;
    while ((read = getline(&line, &len, fp)) != -1) {
        char c[9];
        for (int i = 0; i < 10; i++){
            c[i] = line[i];
        }
        printf("%d.        ", count);
        printf("%s\n", c);
        count++;
    }
    //Close file
    fclose(fp);
    if (line)
        free(line);
}
void select_game(){
    //Player input choice
    printf("Select game order number... ");
    int choice;
    scanf("%d", & choice);
    //Open game file for reading
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("games.txt", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);
    //Assign the game format to a variable
    int count = 1;
    while ((read = getline(&line, &len, fp)) != -1) {
        if (count == choice){
            for (int i = 10; i < 52; i++)
                gamestr[i - 10] = line[i];
        }
        count++;
    }
    fclose(fp);
    if (line)
        free(line);
}
void menu(){
    printf("Enter 1 to PLAY NEW GAME\nEnter 2 to LOAD SAVED GAME\n... ");
    int choice;
    scanf("%d", & choice);
    system("cls");
    if (choice == 1){
        board_setup();
    }
    else {
        show_game_list();
        select_game();
        load_game();
    }

}
void board_setup(){
    //All the board values set to empty
    for (int h = 0; h < Height; h++)
        for (int w = 0; w < Width; w++)
            board[w][h] = Empty;
}
void board_print(){
    system("cls");
    //Iterate trough the board and print state
    for (int h = 0; h < Height; h++){
        for (int w = 0; w < Width; w++){
            if (board[w][h] == P1)
                printf("\033[0;31m");
            else if (board[w][h] == P2)
                printf("\033[0;34m");
            else if (board[w][h] == 3)
                printf("\033[1;32m");
            else
                printf("\033[0;33m");
            printf("  %d", board[w][h]);
            printf("\033[0;37m");
        }
        printf("\n");
    }
}
bool valid_location(int column){
    //If number is out of range
    if (!(column >= 0 && column <= 6))
        return false;
    //If there is no free space
    if (board[column][0] != Empty)
        return false;
    return true;
}
void board_insert(int player, int column){
    //Iterate the selected column down to top
    //Player peace inserted only in first free space
    for(int h = Height - 1; h >= 0; h--){
        if (board[column][h] != Empty)
            continue;
        board[column][h] = player;
        break;
    }
}
bool win_condition(int player){
    //Check horizontal locations for win
    for (int h = 0; h < Height; h++)
        for (int w = 0; w < Width - 3; w++)
            if (board[w][h] == player && board[w+1][h] == player && board[w+2][h] == player && board[w+3][h] == player){
                board[w][h]   = 3;
                board[w+1][h] = 3;
                board[w+2][h] = 3;
                board[w+3][h] = 3;
                return true;
            }
    //Check vertical locations for win     
    for (int h = 0; h < Height - 3; h++)
        for (int w = 0; w < Width; w++)
            if (board[w][h] == player && board[w][h+1] == player && board[w][h+2] == player && board[w][h+3] == player){
                board[w][h] = 3;
                board[w][h+1] = 3;
                board[w][h+2] = 3;
                board[w][h+3] = 3;
                return true;
            }
    //Check positively sloped diagonals for win
    for (int h = 0; h < Height - 3; h++)
        for (int w = 0; w < Width - 3; w++)
            if (board[w][h] == player && board[w+1][h+1] == player && board[w+2][h+2] == player && board[w+3][h+3] == player){
                board[w][h] = 3;
                board[w+1][h+1] = 3;
                board[w+2][h+2] = 3;
                board[w+3][h+3] = 3;
                return true;
            }
    //Check negatively sloped diagonals for win
    for (int h = 3; h < Height; h++)
        for (int w = 0; w < Width - 3; w++)
            if (board[w][h] == player && board[w+1][h-1] == player && board[w+2][h-2] == player && board[w+3][h-3] == player){
                board[w][h] = 3;
                board[w+1][h-1] = 3;
                board[w+2][h-2] = 3;
                board[w+3][h-3] = 3;
                return true;
            }
    return false;
}
int get_input(int player){
    printf("Enter 0 to save game...\nPlayer %d, select column (1 - 7): ", player);
    int choice;
    scanf("%d", & choice);
    choice -= 1;
    return choice;
}
int next_player(int player){
    if (player == P1) return P2;
    return P1;
}
void save_game(){
    //Translate the game into a string format
    //e.g. 000000000000001000000120000012000001200000
    char c[51];
    int count = 0;
    for (int h = 0; h < Height; h++){
        for (int w = 0; w < Width; w++){
            c[count] = board[w][h] + '0';
            count++;
        }
    }
    //Open game file for appending
    FILE *f = fopen("games.txt", "a");
    if (f == NULL)
    {
        printf("Error opening file!\n");
        exit(1);
    }
    //The game id is the actual time
    fprintf(f, "%d", time(0));
    fprintf(f, "%s\n", c);
}
void load_game(){
    //We go backwards assigning each part of the board the correct value
    int count = 0;
    for (int h = 0; h < Height; h++){
        for (int w = 0; w < Width; w++){
            char *pChar = malloc(sizeof(char));
            *pChar = gamestr[count];
            board[w][h] = atoi(pChar);
            count++;
        }
    }
}
int main(){
    menu();
    int current_player = P1;
    while (true){
        board_print();
        int ci = get_input(current_player); //ci defined as current input from player [-1 - 6]
        //if input -1 game is saved and turn restarted
        if (ci == -1){
            save_game();
            system("cls");
            continue;
        }
        //in case invalid move, turn restarted
        if (!valid_location(ci)){ 
            system("cls");
            continue;
        }
        //Insert piece and pass turn
        board_insert(current_player, ci);
        if (win_condition(current_player)){
            break;
        }
        current_player = next_player(current_player);
    }
    board_print();
    printf("Congratulations player %d for winning!\n\nPress any key to exit...", current_player);
    getch();
}

Recommended Answers

All 2 Replies

There are already functions for saving games and loading saves in the code, so I assume that there is some problem with those functions. Could you please explain what is actually happening?

Does the program fail to compile, or compile with warnings? Is the program crashing when you try to save and/or load? Does it save, but incorrectly? Does loading fail restart the game at the saved point? Are there any error messages?

BTW, <conio.h> is not a standard C library, it is specific to a few older Windows compilers such as Turbo C. I would recommend avoiding it, even if your intention is to run purely on Windows. Similarly, you are using the ANSI character set for extended and control characters, which will only work properly with certain settings even under Windows. I would recommend the windows port of NCurses instead, as that should work in all circumstances; or conversely, moving out of the console entirely and writing the program as a Windows application. Finally, using system() presents a number of security holes, and is best avoided as well.

You already have save and load functionality, although what you've done with select_game() and load_game() feels unnecessarily messy.
I can see a couple obvious bugs
First:

#define Height 6
#define Width 7
int board[Height][Width];
char gamestr[41];

board will be 6*7 = 42 bytes, gamestr is one byte too small to hold the entire board state (gotcha: at size 42, the addressable indices will be 0 to 41).
Honestly, it reads like you're using the gamestr variable for no real reason, since you can already write everything to board as you're reading it from the file (and, if you know how to allocate a contiguous memory block for your board state, you could just read/write the byte values to it straight from the file without having to play around with converting them to/from text).

Second:
What you're saving here...

//The game id is the actual time
fprintf(f, "%d", time(0));
fprintf(f, "%s\n", c);

Is not what you're loading there:

while ((read = getline(&line, &len, fp)) != -1) {
    if (count == choice){
        for (int i = 10; i < 52; i++)
            gamestr[i - 10] = line[i];
    }
    count++;
}

When you save, you first write the timestamp and then the game state. When you load, you load everything into the game state, even though the first few bytes of the save will actually contain the timestamp.

Third:
You're expecting your player to know the position of the saved game state in the save file based on... what exactly? The player won't know the information you're asking of them - it might be best to just have a single save per file and give the player ability to choose a file name to load.

commented: can you edit it for me , cause that's what i learnt , and i didn't like the result +0
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.