Desenvolvimento de um Jogo da Velha Simples em C

Abordagem Modular em C para Implementação do Jogo

Para desenvolver um jogo interativo como o da velha em C, é essencial adotar uma estrutura de código modular. Isso envolve a separação em arquivos distintos: um cabeçalho (.h) para declarações e definições de constantes, e dois arquivos de código-fonte (.c) – um para a lógica principal e outro para as funções do jogo. Esta prática melhora a manutenibilidade, facilita a reutilização de código e permite uma melhor organização do projeto.

Estrutura de Arquivos e Declarações

Crie três arquivos: jogo.h (para macros e protótipos), principal.c (para o fluxo do jogo) e funcoes.c (para implementação das funções). No cabeçalho, defina as dimensões do tabuleiro e declare as funções necessárias.

// jogo.h
#ifndef JOGO_H
#define JOGO_H

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

#define TAMANHO_TABULEIRO 3

void inicializar_tabuleiro(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col);
void mostrar_tabuleiro(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col);
void jogada_jogador(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col);
void jogada_computador(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col);
char verificar_vitoria(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col);

#endif

Implementação do Menu Principal

O menu principal utiliza um laço do-while para repetir as opções até que o usuário decida sair. A função switch-case direciona a execução com base na escolha do jogador.

// principal.c
#include "jogo.h"

void menu_principal() {
    printf("==== Jogo da Velha ====\n");
    printf("1. Iniciar partida\n");
    printf("0. Sair\n");
    printf("=======================\n");
}

void iniciar_partida() {
    char tabuleiro[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO];
    inicializar_tabuleiro(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
    mostrar_tabuleiro(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
    
    char resultado = 'C'; // 'C' para continuar
    while (resultado == 'C') {
        jogada_jogador(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
        mostrar_tabuleiro(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
        resultado = verificar_vitoria(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
        if (resultado != 'C') break;
        
        jogada_computador(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
        mostrar_tabuleiro(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
        resultado = verificar_vitoria(tabuleiro, TAMANHO_TABULEIRO, TAMANHO_TABULEIRO);
    }
    
    if (resultado == 'X') printf("Jogador venceu!\n");
    else if (resultado == 'O') printf("Computador venceu!\n");
    else if (resultado == 'E') printf("Empate!\n");
}

int main() {
    srand((unsigned int)time(NULL));
    int opcao;
    do {
        menu_principal();
        printf("Opção: ");
        scanf("%d", &opcao);
        switch (opcao) {
            case 1:
                printf("Iniciando jogo...\n");
                iniciar_partida();
                break;
            case 0:
                printf("Encerrando...\n");
                break;
            default:
                printf("Opção inválida.\n");
        }
    } while (opcao != 0);
    return 0;
}

Inicialização e Exibição do Tabuleiro

A inicialização preenche o tabuleiro com espaços em branco usando memset. A exibição percorre a matrriz bidimensional, imprimindo os símbolos com separadores visuais.

// funcoes.c
#include "jogo.h"

void inicializar_tabuleiro(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col) {
    for (int i = 0; i < lin; i++) {
        for (int j = 0; j < col; j++) {
            tab[i][j] = ' ';
        }
    }
}

void mostrar_tabuleiro(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col) {
    for (int i = 0; i < lin; i++) {
        for (int j = 0; j < col; j++) {
            printf(" %c ", tab[i][j]);
            if (j < col - 1) printf("|");
        }
        printf("\n");
        if (i < lin - 1) {
            for (int k = 0; k < col; k++) {
                printf("---");
                if (k < col - 1) printf("|");
            }
            printf("\n");
        }
    }
}

Lógica das Jogadas

O jogador insere coordenadas (baseadas em 1), que são validadas para garantir que estejam dentro dos limites e em uma posição vazia. O computador gera coordenadas aleatórias até encontrar uma célula livre.

void jogada_jogador(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col) {
    int linha, coluna;
    printf("Jogador - insira linha e coluna (ex: 1 2): ");
    scanf("%d %d", &linha, &coluna);
    while (linha < 1 || linha > lin || coluna < 1 || coluna > col || tab[linha-1][coluna-1] != ' ') {
        printf("Posição inválida. Tente novamente: ");
        scanf("%d %d", &linha, &coluna);
    }
    tab[linha-1][coluna-1] = 'X';
}

void jogada_computador(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col) {
    int l, c;
    printf("Computador jogando...\n");
    do {
        l = rand() % lin;
        c = rand() % col;
    } while (tab[l][c] != ' ');
    tab[l][c] = 'O';
}

Verificação do Resultado

A função verificar_vitoria checa linhas, colunas e diagonais para três símbolos iguais. Retorna 'X' ou 'O' para vitórias, 'E' para empate (tabuleiro cheio) e 'C' para continuação.

char verificar_vitoria(char tab[TAMANHO_TABULEIRO][TAMANHO_TABULEIRO], int lin, int col) {
    // Verificar linhas e colunas
    for (int i = 0; i < lin; i++) {
        if (tab[i][0] != ' ' && tab[i][0] == tab[i][1] && tab[i][1] == tab[i][2])
            return tab[i][0];
        if (tab[0][i] != ' ' && tab[0][i] == tab[1][i] && tab[1][i] == tab[2][i])
            return tab[0][i];
    }
    // Verificar diagonais
    if (tab[0][0] != ' ' && tab[0][0] == tab[1][1] && tab[1][1] == tab[2][2])
        return tab[0][0];
    if (tab[0][2] != ' ' && tab[0][2] == tab[1][1] && tab[1][1] == tab[2][0])
        return tab[0][2];
    // Verificar empate
    for (int i = 0; i < lin; i++) {
        for (int j = 0; j < col; j++) {
            if (tab[i][j] == ' ') return 'C';
        }
    }
    return 'E';
}

Este código demonstra a implementação completa de um jogo da velha em C, destacando a modularidade e a lógica de controle de fluxo.

Tags: C jogo-da-velha programação-modular arrays-2D desenvolvimento-de-jogos

Publicado em 6-3 23:12 por Thomas