Italo Info


Jogo da velha

Quem nunca jogou algum jogo de videogame? Talvez na infância ou, mesmo, depois de adulto. É difícil encontrar alguém que nunca tenha jogado um jogo eletrônico. Então, ao pensar sobre esses joguinhos, pode surgir a questão: Como é feito um jogo de videogame? Nesse texto escrito, exponho os códigos fonte de um jogo da velha que fiz em linguagem de programação “C”. Também estão disponíveis para download o mesmo jogo produzido em “Java” e outra versão produzida para dispositivos android. Veja abaixo as imagens do jogo da velha:

Jogo da velha
Jogo da velha
Batalha estrelar
Jogo da velha - empate
Jogo da velha O ganhou
Jogo da velha - O venceu...

Um pouco sobre formas básicas:

As linguagens de programação disponibilizam funções (ou métodos de classes) para o desenho de formas geométricas básicas como: ponto, linha, retângulo, circulo, elipse, etc.

Para desenhar formas geométricas através de uma linguagem de programação é preciso calcular coordenadas e dimensões. Os sistemas de coordenadas das linguagens de programação têm semelhança com o sistema de coordenadas cartesianas. Porém, com a diferença que a coordenada (0, 0) inicia-se no canto superior esquerdo, variando de (0, 0) até (largura da tela de pintura, altura da tela de pintura). Ou seja, em uma janela com tela de pintura de dimensões: 800px por 600px, a menor coordenada é à posição (0, 0) e a maior coordenada é à posição (799, 599).

Para desenhar, por exemplo, um círculo, é necessário: coordenadas centrais (X, Y), raio e cor (isso pode variar conforme as funções ou métodos oferecidos pelas linguagens de programação).

Para os exemplos seguintes:

Assuma a variável TELA_LARGURA como a largura da tela de pintura igual a 300px;

Assuma a variável TELA_ALTURA como a altura da tela de pintura igual a 200px;

Assuma "*" igual a um sinal de multiplicação e "/" igual a um sinal de divisão;

Para centralizar um circulo de raio igual a 50px pode-se fazer algo semelhante a:


circulo_x = TELA_LARGURA / 2;
circulo_y = TELA_ALTURA  / 2;	

ou 

circulo_x = 300 / 2;
circulo_y = 200 / 2;

Assim, o circulo pode ser desenhado da seguinte forma:


set_cor(  COR_RGB );
desenha_circulo( circulo_x, circulo_y, raio );

A cor pode ser representada da seguinte forma:

COR_RGB = { 0, 0, 255 };

Isso é a cor de pintura representada em RGB ( Red, Green, Blue ) onde as cores primárias são misturadas, e variam de 0 a 255 ( 255 representa 100% da cor ). Nesse exemplo, a quantidade de cor vermelha a ser misturada é igual a 0, a quantidade de cor verde é 0 e a quantidade de cor azul é 255, logo a cor de valor RGB {0, 0, 255} é azul.

Algumas linguagens de programação desenham o circulo como elipse. Sendo necessário informar os valores de um retângulo que representa as dimensões do circulo, ao invés de coordenadas centrais e raio. Por exemplo:

Em linguagem “Java”, o circulo pode ser desenhado do seguinte modo (diferentemente do método anterior):

g.setColor( Color.BLUE ); // o mesmo que g.setColor( new RGB( 0, 0, 255 ) ); g.drawArc( circulo_x, circulo_y, circulo_largura, circulo_altura, 0, 360 );

Onde, para centralizar o circulo na tela de pintura em Java pode-se calcular como a seguir:


circulo_x = ( LARGURA_TELA - circulo_largura ) / 2;
circulo_y = ( ALTURA_TELA  - circulo_altura  ) / 2;

Os valores 0 e 360 são ângulos que indicam um corte no círculo de acordo com esses valores. Por exemplo, para desenhar um personagem pacman pode-se utilizar os valores: 45, 270 ao invés de 0, 360;

g.drawArc( circulo_x, circulo_y, circulo_largura, circulo_altura, 45, 270 );

O Jogo da Velha (Linguagem C)

Para produzir o Jogo da Velha foram necessários, primeiramente, alguns cálculos. As jogadas, tando do jogador quanto do computador, são armazenadas em uma matriz conforme mostrado a seguir:

char jogadas[3][3] = { {' ', ' ', 'O'}, {' ', 'X', ' '}, {' ', ' ', ' '} };

No exemplo acima, jogadas[2][0] é iqual a 'O' (Jogada do computador) e jogadas[1][1] é iqual a 'X' (Jogada do jogador) e jogadas[1][2] é iqual a '  ' (Posição livre para jogada). O jogo é iniciado com todas as posições de jogadas livres, isto é, iquais a '  '.

Abaixo os calculos da dimensão e coordenadas do tabuleiro e o desenho das linhas que dividem as posições de jogada:

		
tabuleiro_dim = quadrado_dim * 3;                   // Isso porque o tabuleiro tem 3 quadrados de largura e 3 quadrados de altura ( tabuleiro_dim = 150 );		
tabuleiro_x = ( LARGURA_TELA - tabuleiro_dim ) / 2;
tabuleiro_y = ( ALTURA_TELA  - tabuleiro_dim ) / 2;
	
desenha_linha( 
	tabuleiro_x + quadrado_dim, 
	tabuleiro_y, 
	tabuleiro_x + quadrado_dim,
	tabuleiro_y + tabuleiro_dim
);

desenha_linha(
	tabuleiro_x + ( 2 * quadrado_dim ),
	tabuleiro_y,
	tabuleiro_x + ( 2 * quadrado_dim ),
	tabuleiro_y + td
);
	
desenha_linha(
	tabuleiro_x,
	tabuleiro_y + quadrado_dim,
	tabuleiro_x + tabuleiro_dim,
	tabuleiro_y + quadrado_dim
);

desenha_linha(
	tabuleiro_x,
	tabuleiro_y + ( 2 * quadrado_dim ),
	tabuleiro_x + tabuleiro_dim,
	tabuleiro_y + ( 2 * quadrado_dim )
);			

Como detectar o quadrado em que o usuário clicou?

Vamos assumir que os indices da jogada efetuada pelo jogador são as variáveis: posX e posY. Por exemplo, se posX = 1 e posY = 1 então jogadas[ posX ][ posY ] é igual a jogadas[1][1] que é igual a 'X', conforme a matriz de jogadas definida anteriormente.

Mais adiante, como são calculados os indices (posX e posY) da matriz de jogadas. Para o cálculo, assuma que:

Variável x representa a coordenada x da posição clicada e pode variar de 0 até ( LARGURA_TELA - 1 ).

Variável y representa a coordenada y da posição clicada e pode variar de 0 até ( ALTURA_TELA - 1 ).

As variável posX e posY representam indices na matriz de jogadas conforme já explicado e podem variar de 0 a 2. Isso porque a matriz de jogadas tem apenas 3 linhas e 3 colunas e os indices da matriz (em linguagem C) começam na posição 0 (não na posição 1).

Após um clique com mouse, os valores das variáveis (x e y) são convertidos em (posX, posY) conforme mostrado a seguir.

tx = tabuleiro_x; ty = tabuleiro_y; td = tabuleiro_dim; qd = quadrado_dim; if ( x >= tx && x < tx + td && y >= ty && y < ty + td ) { // condição que verifica se o usuário clicou dentro do tabuleiro posX = ( x - tx ) / qd; posY = ( y - ty ) / qd; ... }

A matriz de jogadas é utilizada também no desenho dos Xis e Bolas.

Abaixo, o calculo das coordenadas de um quadrado de indices "posX" e "posY". Lembre-se de que posX e posY são indices para a matriz de jogadas. É necessário associar as jogadas as posições do tabuleiro.

quadrado_x = tabuleiro_x + ( posX * quadrado_dim ); // posX pode variar de 0 a 2. Onde, 0 representa o primeiro quadrado e 2 o terceiro; quadrado_y = tabuleiro_y + ( posY * quadrado_dim ); // calculo semelhante ao do <b>quadrado_x</b>;

Abaixo os cálculos e desenho do circulo que representa a jogada do computador:

circulo_x = quadrado_x + ( quadrado_dim / 2 ); circulo_y = quadrado_y + ( quadrado_dim / 2 ); circulo_raio = ( quadrado_dim / 2 ) - borda; desenha_circulo( circulo_x, circulo_y, circulo_raio );

Abaixo os cálculos e desenho do xis que representa a jogada do jogador:


xis_x1 = quadrado_x + borda; xis_y1 = quadrado_y + borda; xis_x2 = quadrado_x + quadrado_dim - borda; xis_y2 = quadrado_y + quadrado_dim - borda; desenha_linha( xis_x1, xis_y1, xis_x2, xis_y2 ); desenha_linha( xis_x1, xis_y2, xis_x2, xis_y1 );

A função "draw_circle"

A implementação da função draw_circle foi necessária porque não encontrei a função pronta utilizando a biblioteca gráfica SDL. Por isso, precisei implementá-la. Abaixo como fiz:


void draw_circle( SDL_Renderer* pintor, int cx, int cy, int r ) { double a; for( a = -M_PI; a < M_PI; a+= 0.01 ) { int x = cx + r * cos( a ); int y = cy + r * sin( a ); SDL_RenderDrawPoint( pintor, x, y ); } }

Para o Jogo da Velha é preciso também desenvolver funções para verificar se um determinado jogador venceu, além de função que verifica se houve empate.

Os seguintes passos são necessários para verificar se algum jogador venceu ( X ou O ):

  • Verificar as tres linhas horizontais para saber se em uma das três linhas tem marcações somente de "X" ou somente de "O";

  • Verificar as tres linhas verticais para saber se em uma das três linhas tem marcações somente de "X" ou somente de "O".

  • Verificar os quadrados das diagonais, isto é, quadrados de posição = { (0, 0), (1, 1), (2, 2) } e { (0, 2), (1, 1), (2, 0) } para saber se em uma das duas diagonais tem marcações somente de "X" ou somente de "O".

No programa principal, foi implantado o seguinte algoritmo:


inicializa

enquanto a janela não for fechada fazer {
	
	verificar_se_alguem_venceu
	verificar_se_houve_empate
					
	verificar_eventos {
		Se mouse clicado, detectar quadrado clicado {
			Se ninguem venceu nem houve empate {
				efetuar jogada do jogador
				determinar e efetuar jogada do computador
			} Se não {
				reiniciar_jogo
			}
		} se não, se tecla precionada {
			se alguém venceu ou houve empate {
				reiniciar_jogo
			}
		}
		
	}		

	pintar_jogo_na_tela	
	
}

finaliza	

Outra função necessária ao jogo da velha é uma função que calcule a jogada do jogador computador. Onde se faz necessária a implantação de um algoritmo que dote o jogo de inteligência artificial. O método onde está o código que dá inteligência ao joguinho é o calcula_jogada_comp. Você pode dar uma olhada na função no código fonte da versão feito em "C" que pode ser baixado logo no final desse artigo. O código fonte do jogo da velha escrito em C tem o nome "jogodavelha.c". Baixe o arquivo e estude-o!. Obs: O Jogo da Velha foi feito para o jogador nunca ganhar! Peço que, caso alguém jogue e consiga vencer, me notifique ou deixe um comentário para eu melhorar o algoritmo.

As partes mais complicadas que representam a lógica do jogo, preferi não comentar agora, pois, o texto cresceria muito. Quem quiser saber mais sobre como desenvolver o Jogo da Velha, pode analisar os códigos fontes disponíveis para download e/ou me enviar comentário com dúvidas ou sugestões. (Eu recebo os comentários postados nesse site por e-mail).


Downloads

Atenção: Os jogos disponíveis para download, com exceção da versão pra android, só podem ser testados em um computador comum. As versões do jogo produzidas em linguagem C, necessitam ser executados em sistema operacional Windows. A versão produzida em Java pode ser executada em qualquer sistema operacional com o JRE instalado. O JRE é popularmente conhecido por, apenas, Java que é uma máquina virtual e, também, linguagem de programação.

Para jogar o jogo da velha feito em C, basta, após o download, descompactar o arquivo jogodavelha-x86_64.rar ou o arquivo jogodavelha-i686.rar e dar dois cliques no arquivo jogodavelha.exe.

Download de jogodavelha-x86_64.rar
Download de jogodavelha-i686.rar

Para jogar o Jogo da Velha (Versão Android) é preciso baixar o arquivo jogodavelha.apk do seu celular ou tablet android e, então, instalá-lo. Após o download, procure pelo arquivo jogodavelha.apk em seu sistema de arquivos (Provavelmente na pasta Downloads), dê dois cliques no arquivo e aceite a instalação. Se seu dispositivo bloquear a instalação é porque você deve configurar o dispositivo para aceitar a instalação de softwares de fontes desconhecidas, isso porque eu assinei digitalmente o programa, mas, não tenho certificado digital registrado. Não publiquei o programa no google playstore!

Download de jogodavelha.apk

Para jogar jogo da velha feito em Java, é necessário, após o download, dar dois cliques no arquivo jogodavelha.jar.

Download de JogoDaVelha.jar

Abaixo os codigos fonte para download

Download de jogodavelha.c
Download de JogoDaVelha.java

Escrevi sobre e disponibilizei para download um jogo da velha produzido em C++. Acesse a página do projeto clicando aqui.


Atenção: O código fonte em java do Jogo da Velha foi colocado todo em apenas um arquivo por questões didáticas para que ficasse o mais simples possível de ser entendido. Também por questões didáticas, não foram aplicados padrões de projeto para separar, por exemplo, a lógica do sistema da interface gráfica.

É só isso pessoal, até o próximo!

Se quiser deixe um comentário com dúvidas ou sugestões que eu recebo notificação por e-mail. Pretendo escrever sobre como compilar o codigo fonte em C com biblioteca SDL ou sobre como desenvolver a lógica da inteligência do jogador computador. Mas, só pretendo escrever sobre esses assuntos se alguém se interessar.