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; }