Implementação do Jogo de Campo Minado em C

O jogo de campo minado envolve uma grade onde o jogador deve revelar células sem acionar minas. A implementação em C requer a definição de estruturas de dados para o tabuleiro, lógica para posicionamento aleatório de minas e interação do jogador.

Inicialmente, define-se um menu para o usuário escolher entre jogar ou sair. O menu é implementado com uma função que exibe opções e um loop do-while para controlar o fluxo do programa.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void exibir_menu() {
    printf("********** 1. Iniciar Jogo **********\n");
    printf("********** 0. Sair        **********\n");
}

int main() {
    int escolha = 0;
    srand((unsigned int)time(NULL));
    do {
        exibir_menu();
        printf("Selecione uma opcao: ");
        scanf("%d", &escolha);
        switch (escolha) {
            case 1:
                iniciar_jogo();
                break;
            case 0:
                printf("Encerrando o programa.\n");
                break;
            default:
                printf("Opcao invalida. Tente novamente.\n");
        }
    } while (escolha != 0);
    return 0;
}

A função iniciar_jogo encapsula a lógica principal. Define-se um tabuleiro de 9x9 com bordas adicionais para evitar acessos inválidos, usando constantes para as dimensões.

#define LINHAS 9
#define COLUNAS 9
#define LINHAS_TOTAL (LINHAS + 2)
#define COLUNAS_TOTAL (COLUNAS + 2)
#define TOTAL_MINAS 10

Duas matrizes de caracteres são criadas: uma para armazenar a posição das minas (com '0' para vazio e '1' para mina) e outra para exibir ao jogador (com '*' para células ocultas).

void iniciar_jogo() {
    char tabuleiro_minas[LINHAS_TOTAL][COLUNAS_TOTAL] = {0};
    char tabuleiro_visivel[LINHAS_TOTAL][COLUNAS_TOTAL] = {0};
    inicializar_matriz(tabuleiro_minas, LINHAS_TOTAL, COLUNAS_TOTAL, '0');
    inicializar_matriz(tabuleiro_visivel, LINHAS_TOTAL, COLUNAS_TOTAL, '*');
    posicionar_minas(tabuleiro_minas, LINHAS, COLUNAS);
    exibir_tabuleiro(tabuleiro_visivel, LINHAS, COLUNAS);
    jogador_interagir(tabuleiro_minas, tabuleiro_visivel, LINHAS, COLUNAS);
}

A inicialização da matriz utiliza uma função genérica para preencher todos os elementos com um caractere especificado, iterando com laços aninhados.

void inicializar_matriz(char matriz[LINHAS_TOTAL][COLUNAS_TOTAL], int linhas, int colunas, char valor) {
    for (int i = 0; i < linhas; i++) {
        for (int j = 0; j < colunas; j++) {
            matriz[i][j] = valor;
        }
    }
}

O posicionamento aleatório de minas emprega a biblioteca rand para gerar coordenadas dentro dos limites do tabuleiro, garantindo que não haja sobreposição.

void posicionar_minas(char tabuleiro[LINHAS_TOTAL][COLUNAS_TOTAL], int linhas, int colunas) {
    int minas_restantes = TOTAL_MINAS;
    while (minas_restantes > 0) {
        int linha = rand() % linhas + 1;
        int coluna = rand() % colunas + 1;
        if (tabuleiro[linha][coluna] == '0') {
            tabuleiro[linha][coluna] = '1';
            minas_restantes--;
        }
    }
}

A exibição do tabuleiro inclui índices de linhas e colunas para facilitar a navegação, percorrendo apanas as áreas internas do tabuleiro.

void exibir_tabuleiro(char matriz[LINHAS_TOTAL][COLUNAS_TOTAL], int linhas, int colunas) {
    printf("  ");
    for (int i = 1; i <= colunas; i++) {
        printf("%d ", i);
    }
    printf("\n");
    for (int i = 1; i <= linhas; i++) {
        printf("%d ", i);
        for (int j = 1; j <= colunas; j++) {
            printf("%c ", matriz[i][j]);
        }
        printf("\n");
    }
}

A interação do jogador ocorre em um loop até que todas as células sem minas sejam reveladas ou uma mina seja acionada. O cálculo de minas adjacentes soma os valores dos oito vizinhos e subtrai o caractere '0' para obter a contagem numérica.

int contar_minas_adjacentes(char tabuleiro[LINHAS_TOTAL][COLUNAS_TOTAL], int linha, int coluna) {
    return (tabuleiro[linha-1][coluna] + tabuleiro[linha-1][coluna-1] + tabuleiro[linha][coluna-1] +
            tabuleiro[linha+1][coluna] + tabuleiro[linha][coluna+1] + tabuleiro[linha+1][coluna+1] +
            tabuleiro[linha+1][coluna-1] + tabuleiro[linha-1][coluna+1] - 8 * '0');
}

void jogador_interagir(char minas[LINHAS_TOTAL][COLUNAS_TOTAL], char visivel[LINHAS_TOTAL][COLUNAS_TOTAL], int linhas, int colunas) {
    int x, y;
    int celulas_reveladas = 0;
    int total_celulas_seguras = linhas * colunas - TOTAL_MINAS;
    while (celulas_reveladas < total_celulas_seguras) {
        printf("Digite as coordenadas (linha coluna): ");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= linhas && y >= 1 && y <= colunas) {
            if (minas[x][y] == '1') {
                printf("Voce acionou uma mina! Fim de jogo.\n");
                exibir_tabuleiro(minas, linhas, colunas);
                break;
            } else {
                int minas_proximas = contar_minas_adjacentes(minas, x, y);
                visivel[x][y] = '0' + minas_proximas;
                exibir_tabuleiro(visivel, linhas, colunas);
                celulas_reveladas++;
            }
        } else {
            printf("Coordenadas invalidas. Tente novamente.\n");
        }
    }
    if (celulas_reveladas == total_celulas_seguras) {
        printf("Parabens! Voce completou o jogo.\n");
    }
}

A separação em arquivos de cabeçalho e implementação promove modularidade, com declarações em jogo.h e definições em jogo.c.

Tags: campo minado algoritmo estrutura de dados Desenvolvimento de Jogos

Publicado em 7-2 19:09