0

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;
}
  • Have you tried running your code line-by-line in a debugger while monitoring the control flow and the values of all variables, in order to determine in which line your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Andreas Wenzel Apr 12 '23 at 02:08
  • 1
    Tip: You've written the program using a single 2D array that is modified to show the progress of the game... If you want "undo", you will have to save the state of the game (somehow). Since it's likely to be an 8x8 gameboard, maybe you can think about using a single `long long` to represent each ply of the game. Lots of fun with bit shifting and masking. Lots to learn... – Fe2O3 Apr 12 '23 at 02:17
  • 1
    In order to implement an "undo" function that allows you to undo an arbitrary number of moves, you can either save the entire game state after every single move, or you can save only the information necessary to reconstruct the previous game state. I am only vaguely familiar with the rules of Reversi, but my guess is that the latter would require you to store the coordinates of the move as well as a list of all pieces that were flipped, or at least a list of lines of flipped pieces (up to 4 lines, so 8 coordinates). It would probably be simpler to store the entire game state instead. – Andreas Wenzel Apr 12 '23 at 02:27

0 Answers0