I am in an adventure trying to test my C language programming skills and I am re-developing a simple game code based on the board game called REVERSI. I want the game to be between the user/player playing against an Artificial Inteligence player and I want to make it possible to undo both the player's and AI player moves in the board. Struggling to develop the code for this (using linked structures and dynamic memory).
I tried to write those but I am not getting it right. The undo function is not working at all. One way I thought about is to display an updated board after both players possible valid moves, and the actual move made(in the case of the AI player for better testing) but I can not get it to undo the main player's and the AI player's moves.
Below I have provided my code with what I have managed to do until now:
#define VAZIO '.'
#define PRETO 'X'
#define BRANCO 'O'
#define JOGADA_VALIDA '#'
#define SIZE_TABULEIRO 8
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
/**********************************************************************************/
/* Inicializa o tabuleiro com as peças nas posições iniciais */
void inicializa_tabuleiro(int tabuleiro[SIZE_TABULEIRO][SIZE_TABULEIRO])
{
    int i, j;
    for (i = 0; i < SIZE_TABULEIRO; i++)
    {
        for (j = 0; j < SIZE_TABULEIRO; j++)
        {
            tabuleiro[i][j] = VAZIO;
        }
    }
    tabuleiro[3][3] = BRANCO;
    tabuleiro[4][4] = BRANCO;
    tabuleiro[3][4] = PRETO;
    tabuleiro[4][3] = PRETO;
}
/***********************************************************************************/
/* Exibe o tabuleiro com as coordenadas de 0-7 em cima e na esquerda */
void mostra_tabuleiro(int tabuleiro[SIZE_TABULEIRO][SIZE_TABULEIRO])
{
    int i;
    printf("  ");
    /* Imprime as coordenadas na linha superior */
    for (i = 0; i < SIZE_TABULEIRO; i++)
    {
        printf("%d ", i);
    }
    printf("\n");
    /* Imprime as peças e as coordenadas nas demais linhas */
    for (i = 0; i < SIZE_TABULEIRO; i++)
    {
        printf("%d ", i);
        printf("\n");
    }
}
/***********************************************************************************************/
int movimento_valido(int tabuleiro[SIZE_TABULEIRO][SIZE_TABULEIRO], int linha, int coluna, char jogador)
{
    int i, j, x, y, tem_oponente;
    int oponente = (jogador == PRETO) ? BRANCO : PRETO;
    /* Verifica se a célula está vazia */
    if (tabuleiro[linha][coluna] != VAZIO) {
        return 0;
    }
    /* Verifica em todas as direções se há peças do oponente que podem ser capturadas */
    for (i = -1; i <= 1; i++) {
        for (j = -1; j <= 1; j++) {
            /* Ignora a própria posição e verifica apenas as direções */
            if (i == 0 && j == 0) {
                continue;
            }
            x = linha + i;
            y = coluna + j;
            tem_oponente = 0;
            while (x >= 0 && x < SIZE_TABULEIRO && y >= 0 && y < SIZE_TABULEIRO && tabuleiro[x][y] == oponente) {
                x += i;
                y += j;
                tem_oponente = 1;
            }
            if (tem_oponente && x >= 0 && x < SIZE_TABULEIRO && y >= 0 && y < SIZE_TABULEIRO && tabuleiro[x][y] == jogador) {
                return 1;
            }
        }
    }
    return 0;
}
/************************************************************************************************/
void marca_movimentos_validos(int tabuleiro[SIZE_TABULEIRO][SIZE_TABULEIRO], char jogador)
{
    int i, j;
    for (i = 0; i < SIZE_TABULEIRO; i++)
    {
        for (j = 0; j < SIZE_TABULEIRO; j++)
        {
            if (tabuleiro[i][j] == VAZIO && movimento_valido(tabuleiro, i, j, jogador))
            {
                tabuleiro[i][j] = JOGADA_VALIDA;
            }
        }
    }
}
/*************************************************************************************************/
void mostra_tabuleiro_com_movimentos_validos(int tabuleiro[SIZE_TABULEIRO][SIZE_TABULEIRO], char jogador)
{
    int i, j;
    marca_movimentos_validos(tabuleiro, jogador);
    printf("  ");
    /* Imprime as coordenadas na linha superior */
    for (i = 0; i < SIZE_TABULEIRO; i++)
    {
        printf("%d ", i);
    }
    printf("\n");
    for (i = 0; i < SIZE_TABULEIRO; i++)
    {
        printf("%d ", i);
        for (j = 0; j < SIZE_TABULEIRO; j++)
        {
            switch (tabuleiro[i][j])
            {
                case VAZIO:
                    printf(". ");
                    break;
                case PRETO:
                    printf("X ");
                    break;
                case BRANCO:
                    printf("O ");
                    break;
                case JOGADA_VALIDA:
                    printf("# ");
                    break;
            }
        }
        printf("\n");
    }
}
/*************************************************************************************************/
void jogada(int tabuleiro[SIZE_TABULEIRO][SIZE_TABULEIRO], char jogador) {
    int linha, coluna, i, j, x, y, oponente, tem_oponente;
    /* Marca as jogadas válidas no tabuleiro */
    marca_movimentos_validos(tabuleiro, jogador);
    while (true) {
        /* Solicita as coordenadas da jogada ao jogador */
        printf("\nJogador %c, insira a linha e a coluna da sua jogada separadas por um espaco: ", jogador);
        if (scanf("%d %d", &linha, &coluna) != 2) {
            printf("Coordenadas invalidas. Tente novamente.\n");
            /* Limpa o buffer do scanf no caso de entrada inválida */
            while (getchar() != '\n') {}
            continue;
        }
        /* Verifica se as coordenadas da jogada são válidas */
        if (linha < 0 || linha >= SIZE_TABULEIRO || coluna < 0 || coluna >= SIZE_TABULEIRO) {
            printf("Coordenadas invalidas. Tente novamente.\n");
            continue;
        }
        if (tabuleiro[linha][coluna] != JOGADA_VALIDA) {
            printf("Jogada invalida. Tente novamente.\n");
            continue;
        }
        /* Executa a jogada no tabuleiro */
        tabuleiro[linha][coluna] = jogador;
        oponente = (jogador == PRETO) ? BRANCO : PRETO;
        /* Verifica em todas as direções se há peças do oponente que podem ser capturadas */
        for (i = -1; i <= 1; i++) {
            for (j = -1; j <= 1; j++) {
                /* Ignora a própria posição e verifica apenas as direções */
                if (i == 0 && j == 0) {
                    continue;
                }
                x = linha + i;
                y = coluna + j;
                tem_oponente = 0;
                while (x >= 0 && x < SIZE_TABULEIRO && y >= 0 && y < SIZE_TABULEIRO && tabuleiro[x][y] == oponente) {
                    x += i;
                    y += j;
                    tem_oponente = 1;
                }
                if (tem_oponente && x >= 0 && x < SIZE_TABULEIRO && y >= 0 && y < SIZE_TABULEIRO && tabuleiro[x][y] == jogador) {
                    /* Gira as peças do oponente */
                    x -= i;
                    y -= j;
                    while (tabuleiro[x][y] == oponente) {
                        tabuleiro[x][y] = jogador;
                        x -= i;
                        y -= j;
                    }
                }
            }
        }
        /* Troca a vez para o oponente */
        jogador = oponente;
        /* Mostra o tabuleiro atualizado */
    mostra_tabuleiro_com_movimentos_validos(tabuleiro, jogador);
    }
    /* Mostra o tabuleiro final */
    mostra_tabuleiro_com_movimentos_validos(tabuleiro, jogador);
    printf("Jogadas validas marcadas com '#' \n");
}
/************************************************************************************************/
int main()
{
    char jogador;
    int tabuleiro[SIZE_TABULEIRO][SIZE_TABULEIRO];
    printf("Bem vindo ao jogo Reversi :) \n");
    printf("Escolha uma peca para jogar: X ou O? \n");
    scanf(" %c", &jogador);
    printf("\n");
    while(jogador != 'X' && jogador != 'O')
        {
        printf("Peca invalida. Escolha novamente: X ou O? \n");
        scanf(" %c", &jogador);
        }
    /* Inicializa o tabuleiro */
    inicializa_tabuleiro(tabuleiro);
    mostra_tabuleiro_com_movimentos_validos(tabuleiro, jogador);
    printf("\n");
    printf("Jogadas validas estao marcadas com '#' \n");
    jogada(tabuleiro, jogador); /* ou jogada(tabuleiro, BRANCO); */
    return 0;
}
