aula 166

JOGO DA VELHA com funções e procedimentos

Nesta aula, fechando esta parte do nosso curso de programação C, vamos desenvolver o jogo da velha com funções e procedimentos.

Primeiro vamos criar algumas variáveis globais. A matriz que usaremos no jogo e duas variáveis inteiras que serão usadas para acessar nossa matriz jogo.

// variáveis globais
char jogo[3][3]; // matriz do jogo
int l, c; // índices para linha e coluna

Na sequência temos o que considero a parte mais trabalhosa, o procedimento para imprimir nosso jogo na tela. Esta etapa é realmente na tentativa e erro, fazendo, testando e ajustando até atingir o resultado desejado.

// procedimento para imprimir o jogo na tela
void imprimir(){
    printf("\n\n\t 0   1   2\n\n"); // imprime os índices das colunas
    for(l = 0; l < 3; l++){
        for(c = 0; c < 3; c++){
            if(c == 0) // se for início da linha
                printf("\t"); // imprime uma tabulação (espaço)
            printf(" %c ", jogo[l][c]); // imprime o caracter da posição l c
            if(c < 2) // se não for a última posição da linha
                printf("|"); // imprime a barra de divisão das colunas
            if(c == 2) // se for a última coluna
                printf("   %d", l); // imprime os índices das linhas à direita
        }
        printf("\n");
        if(l < 2) // se não for a última linha
            printf("\t-----------\n"); // imprime a linha tracejada dividindo as linhas
    }
}

A seguir temos uma função que verifica se um determinado jogador ganhou em uma determinada linha. Perceba que, para tornar a função mais genérica e útil para os dois jogadores, é recebido como parâmetro um caracter que identifica o jogador (0 ou X) e um valor inteiro que indica qual a linha será verificada.

/*
    função para verificar vitória do jogador c na linha l
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorLinha(int l, char c){
    if(jogo[l][0] == c && jogo[l][1] == c && jogo[l][2] == c)
        return 1;
    else
        return 0;
}

A função a seguir verifica todas as linhas para um determinado jogador. O jogador (0 ou X) é recebido por parâmetro e uma repetição é feita chamando a função anterior para verificar cada linha.

/*
    função para verificar vitória do jogador c nas linhas
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorLinhas(char c){
    int ganhou = 0;
    for(l = 0; l < 3; l++){
        ganhou += ganhouPorLinha(l, c);
    }
    return ganhou;
}

Agora fazemos o mesmo processo para as colunas. Esta função verifica se o jogador j venceu na coluna c.

/*
    função para verificar vitória do jogador j na coluna c
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorColuna(int c, char j){
    if(jogo[0][c] == j && jogo[1][c] == j && jogo[2][c] == j)
        return 1;
    else
        return 0;
}

E esta função verifica se um jogador j venceu por linhas. Uma repetição é feita para chamar a função anterior para cada linha da matriz.

/*
    função que verifica vitória do jogador j por colunas
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorColunas(char j){
    int ganhou = 0;
    for(c = 0; c < 3; c++){
        ganhou += ganhouPorColuna(c, j);
    }
    return ganhou;
}

A seguir temos a função que verifica se o jogador c venceu na diagonal principal.

/*
    função para verificar vitória do jogador c na diagonal principal
    1 - vitória
    0 - não ganhou
*/
int ganhouPorDiagPrin(char c){
    if(jogo[0][0] == c && jogo[1][1] == c && jogo[2][2] == c)
        return 1;
    else
        return 0;
}

E a função que verifica se o jogador c venceu na diagonal secundária.

/*
    função para verificar vitória do jogador c na diagonal secundária
    1 - vitória
    0 - não ganhou
*/
int ganhouPorDiagSec(char c){
    if(jogo[0][2] == c && jogo[1][1] == c && jogo[2][0] == c)
        return 1;
    else
        return 0;
}

A função a seguir é extremamente importante. Dada uma coordenada digitada pelo jogador, ela nos diz se é uma coordenada válida ou não. Perceba que uma coordenada apenas é válida se os índices de linha e coluna digitados estiverem entre 0 e 2 e a posição estiver vazia, ou seja, possuir um espaço.

/*
    função que diz se uma coordenada é válida ou não
    1 - é válida
    0 - não é válida
*/
int ehValida(int l, int c){
    if(l >= 0 && l < 3 && c >= 0 && c < 3 && jogo[l][c] == ' ')
        return 1;
    else
        return 0;
}

A seguir temos o procedimento que faz a leitura da coordenada digitada e, por meio da função anterior, verifica se é válida ou não para o jogador j (0 ou X).

// procedimento para ler as coordenadas digitadas pelo jogador
void lerCoordenadas(char j){
    int linha, coluna;

    printf("Digite linha e coluna: ");
    scanf("%d%d", &linha, &coluna);

    while(ehValida(linha, coluna) == 0){
        printf("Coordenadas invalidas! Digite outra linha e coluna: ");
        scanf("%d%d", &linha, &coluna);
    }
    jogo[linha][coluna] = j;
}

É comum o jogo da velha terminar sem um vencedor. Para identificar o fim do jogo sem vitória precisamos saber quantas posições vazias ainda existem. Isso é feito com a função a seguir.

// função que retorna a quantidade de posições ainda vazias (não jogadas)
int quantVazias(){
    int quantidade = 0;

    for(l = 0; l < 3; l++){
        for(c = 0; c < 3; c++)
            if(jogo[l][c] == ' ')
                quantidade++;
    }
    return quantidade;
}

Agora que já temos todas as funções necessárias, podemos escrever o procedimento para realizar o loop (repetição) do nosso jogo. É este procedimento que ficará lendo coordenadas e verificando vitória até que um dos jogadores ganhe ou o jogo termine sem vitória.

// procedimento jogar com o loop (repetição) principal do jogo
void jogar(){
    int jogador = 1, vitoriaX = 0, vitoria0 = 0;
    char jogador1 = 'X', jogador2 = '0';

    do{
        imprimir();
        if(jogador == 1){
            lerCoordenadas(jogador1);
            jogador++;
            vitoriaX += ganhouPorLinhas(jogador1);
            vitoriaX += ganhouPorColunas(jogador1);
            vitoriaX += ganhouPorDiagPrin(jogador1);
            vitoriaX += ganhouPorDiagSec(jogador1);
        }
        else{
            lerCoordenadas(jogador2);
            jogador = 1;
            vitoria0 += ganhouPorLinhas(jogador2);
            vitoria0 += ganhouPorColunas(jogador2);
            vitoria0 += ganhouPorDiagPrin(jogador2);
            vitoria0 += ganhouPorDiagSec(jogador2);
        }
    }while(vitoriaX == 0 && vitoria0 == 0 && quantVazias() > 0);

    imprimir();

    if(vitoria0 == 1)
        printf("\nParabens Jogador 2. Voce venceu!!!\n");
    else if(vitoriaX == 1)
        printf("\nParabens Jogador 1. Voce venceu!!!\n");
    else
        printf("\nQue pena. Perderam!!!\n");
}

Agora, precisamos apenas controlar nosso jogo na função main. Ao final de uma rodada, é perguntado se desejam jogar novamente, caso seja digitado 1, então uma nova partida é iniciada.

int main(){
    int opcao;

    do{
        inicializarMatriz();
        jogar();

        printf("\nDigite 1 para jogar novamente: ");
        scanf("%d", &opcao);
    }while(opcao == 1);

    return 0;
}

Código completo em C para o Jogo da Velha com funções e procedimentos

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

/*
        Aula 166: Jogo da velha com funções e procedimentos

        Escrito por Wagner Gaspar
        Março de 2021
*/

// variáveis globais
char jogo[3][3]; // matriz do jogo
int l, c; // índices para linha e coluna

// procedimento para inicializar todas as posições da matriz com um espaço
void inicializarMatriz(){
    for(l = 0; l < 3; l++){
        for(c = 0; c < 3; c++)
            jogo[l][c] = ' ';
    }
}

// procedimento para imprimir o jogo na tela
void imprimir(){
    printf("\n\n\t 0   1   2\n\n");
    for(l = 0; l < 3; l++){
        for(c = 0; c < 3; c++){
            if(c == 0)
                printf("\t");
            printf(" %c ", jogo[l][c]);
            if(c < 2)
                printf("|");
            if(c == 2)
                printf("   %d", l);
        }
        printf("\n");
        if(l < 2)
            printf("\t-----------\n");
    }
}

/*
    função para verificar vitória do jogador c na linha l
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorLinha(int l, char c){
    if(jogo[l][0] == c && jogo[l][1] == c && jogo[l][2] == c)
        return 1;
    else
        return 0;
}

/*
    função para verificar vitória do jogador c nas linhas
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorLinhas(char c){
    int ganhou = 0;
    for(l = 0; l < 3; l++){
        ganhou += ganhouPorLinha(l, c);
    }
    return ganhou;
}

/*
    função para verificar vitória do jogador j na coluna c
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorColuna(int c, char j){
    if(jogo[0][c] == j && jogo[1][c] == j && jogo[2][c] == j)
        return 1;
    else
        return 0;
}

/*
    função que verifica vitória do jogador j por colunas
    1 - ganhou
    0 - não ganhou ainda
*/
int ganhouPorColunas(char j){
    int ganhou = 0;
    for(c = 0; c < 3; c++){
        ganhou += ganhouPorColuna(c, j);
    }
    return ganhou;
}

/*
    função para verificar vitória do jogador c na diagonal principal
    1 - vitória
    0 - não ganhou
*/
int ganhouPorDiagPrin(char c){
    if(jogo[0][0] == c && jogo[1][1] == c && jogo[2][2] == c)
        return 1;
    else
        return 0;
}

/*
    função para verificar vitória do jogador c na diagonal secundária
    1 - vitória
    0 - não ganhou
*/
int ganhouPorDiagSec(char c){
    if(jogo[0][2] == c && jogo[1][1] == c && jogo[2][0] == c)
        return 1;
    else
        return 0;
}

/*
    função que diz se uma coordenada é válida ou não
    1 - é válida
    0 - não é válida
*/
int ehValida(int l, int c){
    if(l >= 0 && l < 3 && c >= 0 && c < 3 && jogo[l][c] == ' ')
        return 1;
    else
        return 0;
}

// procedimento para ler as coordenadas digitadas pelo jogador
void lerCoordenadas(char j){
    int linha, coluna;

    printf("Digite linha e coluna: ");
    scanf("%d%d", &linha, &coluna);

    while(ehValida(linha, coluna) == 0){
        printf("Coordenadas invalidas! Digite outra linha e coluna: ");
        scanf("%d%d", &linha, &coluna);
    }
    jogo[linha][coluna] = j;
}

// função que retorna a quantidade de posições ainda vazias (não jogadas)
int quantVazias(){
    int quantidade = 0;

    for(l = 0; l < 3; l++){
        for(c = 0; c < 3; c++)
            if(jogo[l][c] == ' ')
                quantidade++;
    }
    return quantidade;
}

// procedimento jogar com o loop (repetição) principal do jogo
void jogar(){
    int jogador = 1, vitoriaX = 0, vitoria0 = 0;
    char jogador1 = 'X', jogador2 = '0';

    do{
        imprimir();
        if(jogador == 1){
            lerCoordenadas(jogador1);
            jogador++;
            vitoriaX += ganhouPorLinhas(jogador1);
            vitoriaX += ganhouPorColunas(jogador1);
            vitoriaX += ganhouPorDiagPrin(jogador1);
            vitoriaX += ganhouPorDiagSec(jogador1);
        }
        else{
            lerCoordenadas(jogador2);
            jogador = 1;
            vitoria0 += ganhouPorLinhas(jogador2);
            vitoria0 += ganhouPorColunas(jogador2);
            vitoria0 += ganhouPorDiagPrin(jogador2);
            vitoria0 += ganhouPorDiagSec(jogador2);
        }
    }while(vitoriaX == 0 && vitoria0 == 0 && quantVazias() > 0);

    imprimir();

    if(vitoria0 == 1)
        printf("\nParabens Jogador 2. Voce venceu!!!\n");
    else if(vitoriaX == 1)
        printf("\nParabens Jogador 1. Voce venceu!!!\n");
    else
        printf("\nQue pena. Perderam!!!\n");
}

int main(){
    int opcao;

    do{
        inicializarMatriz();
        jogar();

        printf("\nDigite 1 para jogar novamente: ");
        scanf("%d", &opcao);
    }while(opcao == 1);

    return 0;
}

Deixe um comentário

um × dois =

Wagner Gaspar

Capixaba de São Gabriel da Palha, Espírito Santo. Bacharel em Ciência da Computação pela Universidade Federal do Amazonas e mestre em informática pela Universidade Federal do Espírito Santo.