Skip to content

Instantly share code, notes, and snippets.

@wkoch
Last active May 23, 2022 17:30
Show Gist options
  • Save wkoch/1c23fd09d9a0974eb2c17297798b5b25 to your computer and use it in GitHub Desktop.
Save wkoch/1c23fd09d9a0974eb2c17297798b5b25 to your computer and use it in GitHub Desktop.
Jogo da Memória
#define entrada(x) pinMode(x, INPUT_PULLUP)
#define saida(x) pinMode(x, OUTPUT)
#define aguarde(x) delay(x)
#define DESLIGA 0 // Usado para controlar LEDs
#define NADA_ESCOLHIDO 0 // Usado para verificar botões
#define VERMELHO (1 << 0)
#define VERDE (1 << 1)
#define AZUL (1 << 2)
#define AMARELO (1 << 3)
#define LED_VERMELHO 10
#define LED_VERDE 3
#define LED_AZUL 13
#define LED_AMARELO 5
// Definições dos pinos de botão
#define BOTAO_VERMELHO 9
#define BOTAO_VERDE 2
#define BOTAO_AZUL 12
#define BOTAO_AMARELO 6
// Definições dos pinos do Buzzer
#define PIEZO1 4
#define PIEZO2 7
// Parâmetros do jogo
#define RODADAS_ATE_SER_CAMPEAO 10 // Número de rodadas para vencer o Jogo.
#define TEMPO_DE_RESPOSTA_JOGADOR 3000 // Tempo para pressionar um botão antes que o jogo acabe. 3 segundos
// Variáveis de estado do jogo
byte tabuleiro[32]; //Salva a combinação de botões à medida que avançamos
byte rodadas = 0; //Conta o número de rodadas de sucesso que o jogador fez
void setup()
{
// Configuração dos pinos de entradas e saídas
entrada(BOTAO_VERMELHO);
entrada(BOTAO_VERDE);
entrada(BOTAO_AZUL);
entrada(BOTAO_AMARELO);
saida(LED_VERMELHO);
saida(LED_VERDE);
saida(LED_AZUL);
saida(LED_AMARELO);
saida(PIEZO1);
saida(PIEZO2);
toqueInicial(); // Ao ligar toque a música vencedor
if (checaBotao() == AMARELO) tocarMusica();
}
void loop()
{
modoAtracao(); // Pisca luzes enquanto aguarda o usuário apertar um botão
// Indique o início do jogo
controlaLEDs(VERMELHO | VERDE | AZUL | AMARELO); // Ativar todos os LEDs
aguarde(1000);
controlaLEDs(DESLIGA); // Desligue os LEDs
aguarde(250);
// Roda o jogo de memória e recebe resultado
if (jogoDaMemoria() == true)
toqueVencedor(); // Ganhou, toca som de vitória
else
toquePerdedor(); // Perdeu, toca som de derrota
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//As seguintes funções estão relacionadas apenas ao jogo
// Jogue o jogo regular da memória
// Retorna false se o jogador perde ou true se o jogador ganhar
boolean jogoDaMemoria(void)
{
randomSeed(millis()); // Semeia o gerador aleatório
rodadas = 0; // Redefinir o jogo para o começo
while (rodadas < RODADAS_ATE_SER_CAMPEAO)
{
adicionaJogada(); // Adicione um botão aos movimentos atuais e reproduza-os
apresentaJogadas(); // Jogue de volta o tabuleiro do jogo atual
// Em seguida, solicite ao jogador que repita a sequência.
for (byte atual = 0 ; atual < rodadas ; atual++)
{
byte opcao = aguardarBotao(); // Veja o botão que o usuário pressiona
if (opcao == 0) return false; // Se a espera expirar, o jogador perde
if (opcao != tabuleiro[atual]) return false; // Se a escolha estiver incorreta, o jogador perde
}
aguarde(1000); // O jogador estava correto, espera antes de jogar
}
return true; // O jogador cumpriu todas as rodadas para ganhar!
}
// Reproduz o conteúdo atual dos movimentos do jogo
void apresentaJogadas(void)
{
for (byte atual = 0 ; atual < rodadas ; atual++)
{
emitirTom(tabuleiro[atual], 150);
// Aguarde algum tempo entre a reprodução do botão
// Encurtar isso para tornar o jogo mais difícil
aguarde(150); // 150 funciona bem. 75 fica rápido.
}
}
// Adiciona um novo botão aleatório à sequência do jogo
void adicionaJogada(void)
{
byte novoBotao = random(0, 4); //min (incluido), max (excluido)
// Temos que converter esse número, 0 até 3, para cor
if(novoBotao == 0) novoBotao = VERMELHO;
else if(novoBotao == 1) novoBotao = VERDE;
else if(novoBotao == 2) novoBotao = AZUL;
else if(novoBotao == 3) novoBotao = AMARELO;
tabuleiro[rodadas++] = novoBotao; // Adicionar este novo botão ao array do jogo
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// As seguintes funções controlam o hardware
// ilumina um determinado LEDs
// Passar em um byte composto de VERMELHO, AMARELO, etc
void controlaLEDs(byte leds)
{
if ((leds & VERMELHO) != 0)
digitalWrite(LED_VERMELHO, HIGH);
else
digitalWrite(LED_VERMELHO, LOW);
if ((leds & VERDE) != 0)
digitalWrite(LED_VERDE, HIGH);
else
digitalWrite(LED_VERDE, LOW);
if ((leds & AZUL) != 0)
digitalWrite(LED_AZUL, HIGH);
else
digitalWrite(LED_AZUL, LOW);
if ((leds & AMARELO) != 0)
digitalWrite(LED_AMARELO, HIGH);
else
digitalWrite(LED_AMARELO, LOW);
}
// Aguarde até que um botão seja pressionado.
// Retorna uma das cores do LED (LED_VERMELHO, etc.) se for bem-sucedida, 0 se expirar
byte aguardarBotao(void)
{
long inicio = millis(); // Lembre-se da hora em que começamos o loop
// Enquanto tempo decorrido desde a definição da variável início for menor que limite do jogo:
while ( (millis() - inicio) < TEMPO_DE_RESPOSTA_JOGADOR) // Faz um loop até que passe o tempo limite
{
byte botao = checaBotao();
if (botao != NADA_ESCOLHIDO)
{
emitirTom(botao, 150); // Reproduzir o botão que o usuário acabou de pressionar
while(checaBotao() != NADA_ESCOLHIDO) ; // Agora vamos esperar que o usuário libere o botão
aguarde(10); // Isso ajuda com toques duplos acidentais
return botao;
}
}
return NADA_ESCOLHIDO; // Se chegarmos aqui, expiramos!
}
// Retorna um bit '1' na posição correspondente a VERMELHO, VERDE, etc.
byte checaBotao(void)
{
if (digitalRead(BOTAO_VERMELHO) == 0) return(VERMELHO);
else if (digitalRead(BOTAO_VERDE) == 0) return(VERDE);
else if (digitalRead(BOTAO_AZUL) == 0) return(AZUL);
else if (digitalRead(BOTAO_AMARELO) == 0) return(AMARELO);
return(NADA_ESCOLHIDO); // Se nenhum botão for pressionado, não retorne nenhum
}
// Acenda um LED e toque o tom
// Vermelho, superior esquerdo: 440Hz - 2.272ms - 1.136ms de pulso
// Verde, superior direito: 880Hz - 1.136ms - pulso de 0.568ms
// Azul, inferior esquerdo: pulso de 587.33Hz - 1.702ms - 0.851ms
// Amarelo, inferior direito: 784Hz - 1,276ms - pulso de 0,638ms
void emitirTom(byte qual, int duracao_milisegundos)
{
controlaLEDs(qual); // Ligue um dado LED
// Reproduz o som associado ao LED fornecido
switch(qual)
{
case VERMELHO:
emitirSom(duracao_milisegundos, 1136);
break;
case VERDE:
emitirSom(duracao_milisegundos, 568);
break;
case AZUL:
emitirSom(duracao_milisegundos, 851);
break;
case AMARELO:
emitirSom(duracao_milisegundos, 638);
break;
}
controlaLEDs(DESLIGA); // Desligue todos os LEDs
}
// Alterna o buzzer a cada pausa_microsegundos, por uma duração de duracao_milisegundos.
void emitirSom(int duracao_milisegundos, int pausa_microsegundos)
{
// Converter tempo total de reprodução de milissegundos para microssegundos
long comprimento_microsegundos = duracao_milisegundos * (long)1000;
// Faz um loop até que o tempo restante de reprodução seja menor que uma única pausa_microsegundos
while (comprimento_microsegundos > (pausa_microsegundos * 2))
{
comprimento_microsegundos -= pausa_microsegundos * 2; // Diminui o tempo de jogo restante
// Alterna a campainha em várias velocidades
digitalWrite(PIEZO1, LOW);
digitalWrite(PIEZO2, HIGH);
delayMicroseconds(pausa_microsegundos);
digitalWrite(PIEZO1, HIGH);
digitalWrite(PIEZO2, LOW);
delayMicroseconds(pausa_microsegundos);
}
}
// Reproduzir o som e as luzes do vencedor
void toqueInicial(void)
{
controlaLEDs(VERDE | AZUL);
somVencedor();
controlaLEDs(VERMELHO | AMARELO);
somVencedor();
controlaLEDs(VERDE | AZUL);
somVencedor();
controlaLEDs(VERMELHO | AMARELO);
somVencedor();
}
void toqueVencedor(void)
{
toqueInicial();
tocarMusica();
}
// Som vencedor
// Este é apenas um som (chato) único que criamos, não há mágica nisso
void somVencedor(void)
{
// Alterna a campainha em várias velocidades
for (byte x = 250 ; x > 70 ; x--)
{
for (byte y = 0 ; y < 3 ; y++)
{
digitalWrite(PIEZO2, HIGH);
digitalWrite(PIEZO1, LOW);
delayMicroseconds(x);
digitalWrite(PIEZO2, LOW);
digitalWrite(PIEZO1, HIGH);
delayMicroseconds(x);
}
}
}
// Toque o som perdedor / luzes
void toquePerdedor(void)
{
controlaLEDs(VERMELHO | VERDE);
emitirSom(255, 1500);
controlaLEDs(AZUL | AMARELO);
emitirSom(255, 1500);
controlaLEDs(VERMELHO | VERDE);
emitirSom(255, 1500);
controlaLEDs(AZUL | AMARELO);
emitirSom(255, 1500);
}
// Mostra uma tela de "modo de atração" enquanto aguarda o usuário pressionar o botão.
void modoAtracao(void)
{
while(true)
{
controlaLEDs(VERMELHO);
aguarde(100);
if (checaBotao() != NADA_ESCOLHIDO) return;
controlaLEDs(AZUL);
aguarde(100);
if (checaBotao() != NADA_ESCOLHIDO) return;
controlaLEDs(VERDE);
aguarde(100);
if (checaBotao() != NADA_ESCOLHIDO) return;
controlaLEDs(AMARELO);
aguarde(100);
if (checaBotao() != NADA_ESCOLHIDO) return;
}
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// As seguintes funções estão relacionadas apenas ao Easter Egg Musical
int numeroDoLed = 0; // Mantém o controle de qual LED estamos ligando durante o ciclo musical
// Não faça nada além de tocar a música
// Esta função é ativada quando o usuário segura o botão inferior direito (amarelo)
void tocarMusica(void)
{
// Notas (frequências) da música.
int notas[] = {
2637, 2637, 0, 2637, 0, 2093, 2637, 0, 3136, 0, 0, 0, 1568, 0, 0, 0,
2093, 0, 0, 1568, 0, 0, 1319, 0, 0, 1760, 0, 1976, 0, 1865, 1760, 0,
1568, 2637, 3136, 3520, 0, 2794, 3136, 0, 2637, 0, 2093, 2349, 1976, 0, 0, 2093,
0, 0, 1568, 0, 0, 1319, 0, 0, 1760, 0, 1976, 0, 1865, 1760, 0, 1568,
2637, 3136, 3520, 0, 2794, 3136, 0, 2637, 0, 2093, 2349, 1976, 0, 0, 262, 523,
220, 440, 233, 466, 0, 0, 262, 523, 220, 440, 233, 466, 0, 0, 175, 349,
147, 294, 156, 311, 0, 0, 175, 349, 147, 294, 156, 311, 0, 0, 311, 277,
294, 277, 311, 311, 208, 196, 277, 262, 370, 349, 165, 466, 440, 415, 311, 247,
233, 220, 208, 0, 0, 0};
// Duração das notas da música
int tempos[] = {
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 9, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 6, 3, 12, 12, 12, 12, 12, 12, 6, 3, 12, 12,
12, 12, 12, 12, 6, 3, 12, 12, 12, 12, 12, 12, 6, 6, 18, 18, 18, 6, 6, 6, 6, 6, 6, 18,
18, 18, 18, 18, 18, 10, 10, 10, 10, 10, 10, 3, 3, 3};
// Ligue o LED inferior direito (amarelo)
controlaLEDs(AMARELO);
emitirTom(AMARELO, 150);
controlaLEDs(VERMELHO | VERDE | AZUL); // Ligue os outros LEDs até você soltar o botão
while(checaBotao() != NADA_ESCOLHIDO) ; // Aguarde até que o usuário pare de pressionar o botão
controlaLEDs(NADA_ESCOLHIDO); // Desligue os LEDs
aguarde(1000); // Espere um segundo antes de tocar música
digitalWrite(PIEZO2, LOW); // configure o lado "PIEZO1" da campainha para ficar baixo, enquanto tocamos o tom no outro pino.
while(checaBotao() == NADA_ESCOLHIDO) // Reproduzir música até você pressionar um botão
{
int limite = sizeof notas / sizeof *notas; // Descobre o tamanho do array
// iterar sobre as notas da melodia:
for (int i = 0; i < limite; i++) {
mudaLED();
int duracao = 1000 / tempos[i]; // Velocidade da música
tone(PIEZO1, notas[i], duracao);
aguarde(duracao * 1.3); // Pausa entre notas
noTone(PIEZO1);
if(checaBotao() != NADA_ESCOLHIDO)
break;
}
}
}
// Cada vez que esta função é chamada, a placa se move para o próximo LED
void mudaLED(void)
{
controlaLEDs(1 << numeroDoLed); // Mude o LED
numeroDoLed++; // Ir para o próximo LED
if(numeroDoLed > 3) numeroDoLed = 0; // Enrole o balcão, se necessário
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment