bonjour
Je partage ici un petit code de jeu de "déminage" où l'utilisateur doit "couper" les fils de la bonne couleur pour interrompre un décompte.
Pour éviter d'avoir à couper réellement des fils, le montage utilise une petite breadboard où les fils de couleurs sont fixes et un 'petit pont' en face du fil de couleur est l'élément à retirer pour déconnecter un fil donné
Il y a trois boutons en plus dans le montage: un bouton plus, un bouton moins et un bouton de validation / OK.
L'interface de ce prototype se fait dans le moniteur série ouvert à 115200 bauds.
Au lancement de l'application, vous verrez
Choisir la Durée: 20 s
Cette valeur provient de la variable dureeInitiale
qui est initialisée à 20s dans le setup.
Un click sur le bouton + augmente cette durée et sur le bouton - la diminue. Il s'agit de définir le temps disponible pour "couper" les bons fils.
Une fois ce temps défini, vous clickez sur le bouton de validation (OK). Par exemple si j'appuie 5 fois sur le bouton + et je valide, je vais avoir dans la console série :
Choisir la Durée: 20 s
Durée: 21 s
Durée: 22 s
Durée: 23 s
Durée: 24 s
Durée: 25 s
Choix effectué, Durée: 25 s
Ensuite le code génère un nombre de fils à couper et vous dit la solution. C'est défini dans la constante nbHotWiresToGuess
et vaut 3 par défaut
Génération combinaison aléatoire
Vert
Rouge
Gris
Appuyez sur OK pour commencer
Cette partie de configuration du jeu donc est à effectuer par un administrateur.
Ensuite l'idée c'est d'avoir un jeu (sans l'arduino) qui permet aux joueurs de déterminer quels sont les trois fils choisis et dans quel ordre il faut les retirer.
Quand une équipe de joueurs pense avoir deviné, ils viennent tester leur choix sur l'arduino.
Un appui sur OK lance le décompte (qui s'affiche dans le moniteur série) et un beep audio qui accélère donne un retour Sonore au joueur.
Le joueur retire les petits strips, une erreur de couleur ou d'ordre et c'est la fin du jeu marqué par une musique adaptée et un message affiché dans le moniteur série:
C'est parti
Durée: 20 s
Durée: 19.00 s
Durée: 18.00 s
Durée: 17.00 s
Durée: 16.00 s
ERREUR: Gris débranché !!!
Vous avez PERDU...
Si les 3 fils sont enlevés dans le bon ordre, un autre musique marque le gain de la partie (et le moniteur série affiche aussi de l'information)
Le câblage est tout simple:
- 8 fils de couleurs (pins 6 à 13) reliés à GND au travers du "petit pont" qui sert à couper la connexion
-
un piezo connecté en pin 5 (+) avec le (-) connecté à GND (par précaution je mets toujours une petite résistance de limitation d'appel de courant de 150Ω)
-
3 boutons momentanés connectés en pins 2, 3 et 4 (pin -- bouton -- GND) qui seront configurés en INPUT_PULLUP donc pas besoin de résistance.
Au final ça ressemble à cela:
Voici le code qui nécessite la librairie de @bricoleau pour la gestion des 3 boutons.
/* ============================================
KEEP THIS INFORMATION IF YOU USE THIS CODE
code is placed under the MIT license
Copyright (c) 2019 J-M-L For the Arduino Forum
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
/* ********* PIN DEFINITION ************
PINS
0 Not connected (reserved for Serial Rx)
1 Not connected (reserved for Serial Tx)
2 OK buton (momentary button connected to GND)
3 + buton (momentary button connected to GND)
4 - buton (momentary button connected to GND)
5 Piezo +, (- going to GND through 150Ω current limiting resistor)
6 hotwire to GND (with removable strip)
7 hotwire to GND (with removable strip)
8 hotwire to GND (with removable strip)
9 hotwire to GND (with removable strip)
10 hotwire to GND (with removable strip)
11 hotwire to GND (with removable strip)
12 hotwire to GND (with removable strip)
13 hotwire to GND (with removable strip)
A0
A1
A2
A3
A4
A5
Libraries
simpleBouton http://forum.arduino.cc/index.php?topic=375232.0
*/
#include <simpleBouton.h>
#include <assert.h>
enum t_etape : byte {Reset, Reglage, Generation, Confirmation, Decompte, Victoire, Echec};
simpleBouton boutonOK(2);
simpleBouton boutonPlus(3);
simpleBouton boutonMoins(4);
const byte piezoPin = 5;
const int totalHotWires = 8;
const byte hotWirePin[] = {6, 7, 8, 9, 10, 11, 12, 13};
const char * hotWireColor[] = {"Gris", "Violet", "Bleu", "Vert", "Jaune", "Orange", "Rouge", "Marron"};
const int nbHotWiresToGuess = 3;
// Vérifications de cohérence
static_assert((totalHotWires == sizeof(hotWireColor) / sizeof(hotWireColor[0])), "hotWireColor: Nombre incorrect de couleurs");
static_assert((totalHotWires == sizeof(hotWirePin) / sizeof(hotWirePin[0])), "hotWirePin: Nombre incorrect de pins");
static_assert((totalHotWires >= nbHotWiresToGuess), "nbHotWiresToGuess: Trop de fils à enlever");
t_etape etape = Reset;
uint32_t deltaT = 1000;
int32_t dureeInitiale;
int32_t dureeRestante;
uint32_t t0, lastChrono;
byte solution[totalHotWires];
byte hotWireState[totalHotWires];
int wireIndexToGuess;
void fisherYatesShuffle(byte* tableau, byte n) {
randomSeed(analogRead(A1));
for (byte i = n - 1; i >= 1; --i) {
byte alea = random(0, i + 1);
byte tmp = tableau[i];
tableau[i] = tableau[alea];
tableau[alea] = tmp;
}
}
inline void tictac() {
static bool tic = false;
tone(piezoPin, tic ? 1000 : 2000, 10);
tic = !tic;
}
void melodiePerte() {
for (int16_t f = 1500; f >= 1; f--) {
tone(piezoPin, f);
delay(1);
}
noTone(piezoPin);
}
void melodieGain() {
uint16_t melody[][2] = {
{262, 250}, {196, 125}, {196, 125}, {220, 250},
{196, 250}, { 0, 250}, {247, 250}, {262, 250},
};
for (byte i = 0; i < 8; i++) {
tone(piezoPin, melody[i][0], melody[i][1]);
delay(melody[i][1] * 1.25);
}
}
inline void readHotWireState() {
for (byte i = 0; i < totalHotWires; i++) hotWireState[i] = digitalRead(hotWirePin[i]);
}
inline void afficherdureeRestante(byte precision = 0) {
Serial.print(F("Durée: "));
Serial.print(dureeRestante / 1000.0, precision);
Serial.println(F(" s"));
}
void gestionEtat() {
switch (etape) {
case Reset:
deltaT = 1000;
dureeInitiale = 20000l; // par défaut 20 secondes
dureeRestante = dureeInitiale;
wireIndexToGuess = 0;
for (byte i = 0; i < totalHotWires; i++) solution[i] = i;
Serial.print(F("Choisir la "));
afficherdureeRestante();
etape = Reglage;
break;
case Reglage:
boutonPlus.actualiser();
if (boutonPlus.vientDEtreEnfonce()) {
tone(piezoPin, 500, 20);
dureeRestante += 1000;
dureeInitiale = dureeRestante;
afficherdureeRestante();
}
boutonMoins.actualiser();
if (boutonMoins.vientDEtreEnfonce()) {
tone(piezoPin, 300, 20);
if (dureeRestante >= 2000) {
dureeRestante -= 1000;
dureeInitiale = dureeRestante;
}
afficherdureeRestante();
}
boutonOK.actualiser();
if (boutonOK.vientDEtreEnfonce()) {
tone(piezoPin, 2500, 20);
Serial.print(F("Choix effectué, "));
afficherdureeRestante();
etape = Generation;
}
break;
case Generation:
Serial.println(F("Génération combinaison aléatoire"));
fisherYatesShuffle(solution, totalHotWires);
for (byte i = 0; i < nbHotWiresToGuess; i++) {
Serial.write('\t');
Serial.println(hotWireColor[solution[i]]);
}
Serial.println(F("Appuyez sur OK pour commencer"));
etape = Confirmation;
break;
case Confirmation:
boutonPlus.actualiser();
boutonMoins.actualiser();
boutonOK.actualiser();
if (boutonPlus.vientDEtreEnfonce() || boutonMoins.vientDEtreEnfonce()) { // on ne veut pas valider
tone(piezoPin, 500, 25); delay(25); tone(piezoPin, 300, 25);
Serial.println(F("Choisir la durée"));
afficherdureeRestante();
etape = Reglage;
} else if (boutonOK.vientDEtreEnfonce()) {
tone(piezoPin, 2500, 20);
t0 = millis();
lastChrono = t0;
Serial.println(F("C'est parti"));
afficherdureeRestante();
etape = Decompte;
}
break;
case Decompte:
{
if (millis() - lastChrono >= deltaT) { // deltaT ms de passé
dureeRestante -= deltaT;
if (dureeRestante < 0) dureeRestante = 0;
lastChrono += deltaT;
afficherdureeRestante(2);
tictac();
if (dureeRestante == 0) {
etape = Echec;
} else if (dureeRestante <= dureeInitiale / 8) deltaT = 100;
else if (dureeRestante <= dureeInitiale / 4) deltaT = 250;
else if (dureeRestante <= dureeInitiale / 2) deltaT = 500;
}
// on regarde l'état des fils
readHotWireState();
// test si situation inchangée
bool situationCorrecte = true;
for (int i = 0; i < wireIndexToGuess ; i++) // ceux là doivent être HIGH (déconnnectés)
if (hotWireState[solution[i]] == LOW) {
Serial.print(F("\tERREUR: "));
Serial.print(hotWireColor[solution[i]]);
Serial.println(F(" rebranché !!!"));
situationCorrecte = false;
break;
}
if (situationCorrecte)
for (int i = wireIndexToGuess + 1; i < totalHotWires; i++) // ceux là doivent être LOW (connectés)
if (hotWireState[solution[i]] == HIGH) {
Serial.print(F("\tERREUR: "));
Serial.print(hotWireColor[solution[i]]);
Serial.println(F(" débranché !!!"));
situationCorrecte = false;
break;
}
if (situationCorrecte) {
if (hotWireState[solution[wireIndexToGuess]] == HIGH) { // on a déconecté le bon
tone(piezoPin, 300); delay(20); tone(piezoPin, 400); delay(20); tone(piezoPin, 300, 20);
Serial.write('\t');
Serial.print(hotWireColor[solution[wireIndexToGuess]]);
Serial.println(F(" est OK !!!"));
wireIndexToGuess++;
if (wireIndexToGuess >= nbHotWiresToGuess) {
etape = Victoire;
}
}
} else { // situation incorrecte
etape = Echec;
}
}
break;
case Victoire:
Serial.println(F("Vous avez GAGNE !!!"));
melodieGain();
etape = Reset;
break;
case Echec:
Serial.println(F("Vous avez PERDU..."));
melodiePerte();
etape = Reset;
break;
}
}
void setup() {
Serial.begin(115200);
pinMode(piezoPin, OUTPUT);
for (byte i = 0; i < totalHotWires; i++) pinMode(hotWirePin[i], INPUT_PULLUP);
}
void loop() {
gestionEtat();
}
Dans les modifications simples:
-
Vous pouvez modifier le code pour câbler en dur les 3 fils à enlever si vous voulez faire un jeu non aléatoire (à mettre l'index des pins dans le tableau
solution
) -
vous pouvez enlever les boutons + et - et ne conserver que le bouton OK pour démarrer la partie
Bon amusement