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