Jogo da velha com PIC (que pode virar um jogo de dados)

Um trabalho da faculdade me deixou com três LEDs bicolor fosco sobrando. Juntando eles com mais seis novos, um PIC16F628A que tinha parado aqui e mais alguns poucos componentes surgiu um jogo da velha bem simples e que pode ser bem legal pra passar o tempo com alguém. De bônus, o mesmo circuito ainda pode ser usado, adaptando apenas o código, em um dado eletrônico!


O vídeo a seguir mostra um pouco da ideia de funcionamento do jogo.



Basicamente temos um jogador sendo a cor verde e outro a vermelha. Um botão é dedicado a mover o cursor, que você usa para escolher onde marcar sua posição, para a próxima posição, e o outro botão marca a posição com a cor do jogador atual. Quando um dos jogadores ganhar, a matriz inteira se acende com a cor do ganhador e o cursor pisca na posição da jogada que o fez ganhar. Se "der velha", a matriz se apaga e o jogo recomeça.

Circuito

O circuito é bem simples como vocês podem ver no esquema abaixo:


Como eu queria algo compacto, acabei optando por usar multiplexação nos LEDs: ao invés de gastar 18 pinos de saída (2 por cada LED), gasto apenas nove (seis colunas mais três linhas). Poderia ainda ter sido empregado um shift register, reduzindo para seis pinos utilizados (olha aí a aplicação do post anterior!).
LD1 a LD9 formam a matriz 3x3 de LEDs. Q1 a Q3 ativarão cada linha por vez. É importante ressaltar que com este projeto não devemos acionar mais de duas linhas ao mesmo tempo, pois assim excederíamos a corrente máxima dos pinos do PIC. No código que escrevi, nunca ativo mais de uma linha ao mesmo tempo.
S2 é o botão de seleção e S1 o de movimentar o cursor.

Código


Desta vez não irei explicar detalhadamente cada linha do código, mas a ideia geral apenas.
Para conseguir organizar os LEDs, utilizaremos 3 matrizes (vetores de duas dimensões) 3 x 3, ou seja, cada posição na matriz representa um LED. Duas matrizes armazenam as informações das posições marcadas por cada jogador (matriz verde e vermelho) e uma para gerenciar a posição do cursor na matriz real (matriz cursor).
Para transformar a variável posição em índices para a matriz e simplificar o código, veja que usei "posicao/3" para as linhas e "posicao%3" para as colunas. Isto porque quando dividimos um numero inteiro por outro inteiro, o programa arredondará o valor resultante para baixo nos retornando sempre um inteiro que é o que precisamos, já que a matriz não aceita índices decimais. O operador % nos retorna o resto da divisão de "posicao" por 3, ou seja, sempre 0, 1 ou 2. Quando "posicao" for, por exemplo, 3, a divisão por 3 dará 1 e o resto 0, ou seja, estou na primeira coluna da segunda linha.
O print a seguir mostra um exemplo em C desta lógica funcionando pra deixar as coisas um pouco mais claro:

A parte preta mostra a saída no terminal. A orientação é a mesma do programa: [linha][coluna]

A variável cor serve pra controlar qual será o jogador a jogar na rodada atual.
Na nossa rotina de interrupção temos basicamente quatro tarefas sendo executadas:
  1. Limpar o PORTB, apagando as colunas, e ativar as linhas correspondentes à variável "linha";
  2. Ativar ou não a saída de cada pino do PORTB correspondente a cada coluna em função da linha;
  3. fazer a contagem do tempo e, baseado nesta, controlar a variável responsável por fazer o LED do cursor piscar;
  4. Limpar a interrupção e recarregar o Timer0 para que a interrupção ocorra no tempo desejado.
A lógica para acender cada LED é a seguinte:
  1. Acende o LED se naquela posição atual da matriz há uma jogada feita OU ("|");
  2. Acende o LED se o cursor está na posição atual E ("&") a variável pisca é diferente de zero E a cor é a correta para a matriz atual (cor = 0 significa verde e cor = 1 significa vermelho).
Para saber se alguém ganhou, temos a rotina "testa_ganhou". Nela o programa verifica se existe uma linha inteira, uma coluna inteira ou uma diagonal inteira preenchida naquela cor informada. Veja que a rotina pede uma matriz para analisar e retorna o valor um se alguém ganhou ou zero se não.
Para testar se "deu velha", a rotina "testa_velha" pega ambas as matrizes e soma o valor de cada posição. Se todas as posições estiverem marcadas, esta soma terá que dar nove, afinal, temos nove posições valendo um ou zero. Assim como a outra rotina, esta retorna o valor um ou zero.

Montagem

O circuito foi montado na protoboard mesmo, porém, a matriz de LEDs, juntamente aos resistores e transistores, foram montados em uma placa da SchmartBoard que eu havia recebido a tempo. Se você desejar, todo o circuito pode ser montado em uma placa perfurada ou até mesmo fazer uma PCI para isto. O circuito foi projetado para trabalhar com 5 V mas pode ser alimentado a partir de 3 V. Eu recomendaria utilizar um cabo USB e um carregador portátil se desejar levar o circuito para algum lugar.
E fecho o post de hoje com fotos do meu circuito montado na protoboard!
Até a próxima e um abraço!



Comentários