// // ############################### // # JEU DE LA COURSE A 20 # // # Exemplaire avec une horloge # // ############################### // # Guy Magli 16.02.2020 # // ############################### // # Conception, cablages # // # mises a jour, # // # contact... # // # www.magli.fr # // ############################### // // ! ======================== ! // ! LIBRAIRIES ET PARAMETRES ! // ! ======================== ! // // Afin d'eviter les problemes d'affichage et d'impression les signes diacritiques // ont ete retires des commentaires et des chaines de caracteres. // #include // Pour le servo moteur. // // ! ================================================= ! // ! VARIABLES GLOBALES, CONSTANTES ET INITIALISATIONS ! // ! ================================================= ! // // Pour les boutons. // uint8_t buttons = 0; // // Pour les messages. // char cAfficheur[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Les afficheurs sont vides String cTexte; // Ligne a afficher sur les LED. String cFin = " "; // Serie d'espaces pour la fin des lignes affichees. char cChar; // Extraction d'un caractere des chaines a afficher. // // : ------ : // : Divers : // : ------ : // int t; // Pour les boucles diverses. // // : -------------------------- : // : Pour le jeu proprement dit : // : -------------------------- : // int iNombreTotalDeMinutes = 20; // Nombre total de minutes (course a 20). int iNombreDeMinutesDejaPassees = 0; // Minutres deja passees par les deux joueurs. int iNombreDeMinutesAAvancer = 0; // Minutes a passer pour ce coup de jeu. int iNombreDeMinutesQuOnPeutAvancer = 2; // Minutes qu'on peut faire passer a chaque tour. int iNombreDePositionsGagnantes = 0; // Combien y a-t-il de positions gagnantes. int iPositionsGagnantes[20]; // Quelles sont toutes les positions gagnantes ? int iEnCours = 0; // Position qu'on est en train d'examiner ou de jouer. String cCommence = ""; // Doit contenir 'B' pour le boitier ou 'J' pour le joueur. int iCommence = 0; // Doit contenir 1 pour le JOUeur et 2 pour le BOItier. bool bJeuFini = false; // A-t-on atteint ou meme depasse la derniere minute ? int iDelai = 3000; // Temps d'attente. // // Parametres pour l'afficheur a LED. // Les chiffres correspondent aux adresses 0xc0 0xc2 0xc4 0xc6 0xc8 0xca 0xcc 0xce. // const int strobe = 8; // STB de l'afficheur a 8 LED const int clock = 9; // CLK ... const int data = 10; // DIO ... #define SEGMENT_A 0x01 // A #define SEGMENT_B 0x02 // --- #define SEGMENT_C 0x04 // F : : B #define SEGMENT_D 0x08 // -G- #define SEGMENT_E 0x10 // E : : C #define SEGMENT_F 0x20 // --- #define SEGMENT_G 0x40 // D // // Les chiffres. // const unsigned char cChiffres[] = { SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F, // 0 SEGMENT_B + SEGMENT_C, // 1 SEGMENT_A + SEGMENT_B + SEGMENT_G + SEGMENT_E + SEGMENT_D, // 2 SEGMENT_A + SEGMENT_B + SEGMENT_G + SEGMENT_C + SEGMENT_D, // 3 SEGMENT_F + SEGMENT_G + SEGMENT_B + SEGMENT_C, // 4 SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_C + SEGMENT_D, // 5 SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_E + SEGMENT_C + SEGMENT_D, // 6 SEGMENT_A + SEGMENT_B + SEGMENT_C, // 7 SEGMENT_A + SEGMENT_F + SEGMENT_B + SEGMENT_G + SEGMENT_E + SEGMENT_C + SEGMENT_D, // 8 SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_F + SEGMENT_G + SEGMENT_D, // 9 }; // // Les lettres. // const unsigned char cLettreA = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_G; // Comme le R const unsigned char cLettreB = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F + SEGMENT_G; const unsigned char cLettreC = SEGMENT_A + SEGMENT_F + SEGMENT_E + SEGMENT_D; const unsigned char cLettreD = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F; // Comme le O et le Q const unsigned char cLettreE = SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_E + SEGMENT_D; const unsigned char cLettreF = SEGMENT_A + SEGMENT_F + SEGMENT_E + SEGMENT_G; const unsigned char cLettreG = SEGMENT_A + SEGMENT_F + SEGMENT_E + SEGMENT_D + SEGMENT_C; // Comme le N const unsigned char cLettreH = SEGMENT_F + SEGMENT_E + SEGMENT_G + SEGMENT_B + SEGMENT_C; const unsigned char cLettreI = SEGMENT_B + SEGMENT_C; const unsigned char cLettreJ = SEGMENT_B + SEGMENT_C + SEGMENT_D; // Pas de K const unsigned char cLettreL = SEGMENT_F + SEGMENT_E + SEGMENT_D; const unsigned char cLettreM = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C; // Comme le N const unsigned char cLettreN = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C; // Comme le M const unsigned char cLettreO = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F; // Comme le D et le Q const unsigned char cLettreP = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_G; const unsigned char cLettreQ = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F; // Comme le D et le 0 const unsigned char cLettreR = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_G; // Comme le A const unsigned char cLettreS = SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_C + SEGMENT_D; const unsigned char cLettreT = SEGMENT_F + SEGMENT_E + SEGMENT_G; // en minuscule const unsigned char cLettreU = SEGMENT_F + SEGMENT_E + SEGMENT_D + SEGMENT_C + SEGMENT_B; // Comme le V const unsigned char cLettreV = SEGMENT_F + SEGMENT_E + SEGMENT_D + SEGMENT_C + SEGMENT_B; // Comme le U // Pas de W // Pas de X const unsigned char cLettreY = SEGMENT_F + SEGMENT_G + SEGMENT_B + SEGMENT_C + SEGMENT_D; // Pas de Z // // La ponctuation // const unsigned char cEspace = 0x00; const unsigned char cPoint = 0x80; const unsigned char cApostrophe = SEGMENT_F; const unsigned char cTraitDUnion = SEGMENT_G; // // // Le moteur. // Servo sMoteur; int iAnciennePosition = 0; // // ! ===== ! // ! Setup ! // ! ===== ! // void setup() { // // : --------------- : // : Initialisations : // : --------------- : // // Initialisation des nombres aleatoires. // randomSeed(analogRead(0)); // initialise le generateur de nombre aleatoire. // // Affiche le generique. // // Indispensable pour les afficheur a LED. // pinMode(strobe, OUTPUT); pinMode(clock, OUTPUT); pinMode(data, OUTPUT); SendCommand(0x8f); Reset(); SendCommand(0x44); // // Pour le moteur. // sMoteur.attach(7); // Broches du moteur. sMoteur.write(0); // Remise a zero (en haut de l'horloge). } // // ! ==== ! // ! Loop ! // ! ==== ! // void loop() { // // Tant que l'Arduino est branchee, on joue, il n'y a pas de sortie possible, c'est une machine dediee apres tout ! // // : --------- : // : Generique : // : --------- : // cTexte = "EN 2020 A EVIAN ON JOUE A LA COURSE A 20" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } // // : ------------------------------ : // : On demande qui commence le jeu : // : ------------------------------ : // cTexte = "QUI COMMENCE" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } // // On attend qu'un bouton soit presse sur l'afficheur a 8 LED while ((buttons != 1) && (buttons != 128)) { buttons = litBoutons(); } if (buttons == 1) { cCommence = "J"; // C'est le joueur qui commence. iCommence = 1; cTexte = "TU COMMENCES" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } } if ((buttons == 8) || (buttons == 128)) { cCommence = "B"; // C'est le boitier qui commence. iCommence = 2; cTexte = "LE BOITIER COMMENCE" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } } buttons = litBoutons(); afficheLeTotal(); DebuterLeJeu(); // if (cCommence == "B") { FaireJouerLeBoitier(); } // C'est le boitier qui commence. bJeuFini = false; while (bJeuFini == false) { if (bJeuFini == false) { FaireJouerLeJoueur(); } if (bJeuFini == false) { FaireJouerLeBoitier(); } } } // // ! ========== ! // ! Procedures ! // ! ========== ! // // : -------------- : // : Debuter le jeu : // : -------------- : // void DebuterLeJeu() { // // On cherche les positions gagnantes. // // On efface les positions gagnantes memorisees precedemment. // iNombreDePositionsGagnantes = 0; for (t = 0; t < iNombreDePositionsGagnantes; t++) // On efface les anciennes positions gagnantes. { iPositionsGagnantes[t] = 0; } // // La derniere bille est egalement une position gagnante, il convient de ne pas l'oublier ! // iNombreDePositionsGagnantes++; iPositionsGagnantes[iNombreDePositionsGagnantes] = iNombreTotalDeMinutes; // // On memorise les positions gagnantes. // iEnCours = iNombreTotalDeMinutes; // On examinera toutes les positions gagnantes en commencant par la fin. while (iEnCours >= (iNombreDeMinutesQuOnPeutAvancer + 1)) { iNombreDePositionsGagnantes++; iPositionsGagnantes[iNombreDePositionsGagnantes] = (iEnCours - 1 - iNombreDeMinutesQuOnPeutAvancer); iEnCours = iPositionsGagnantes[iNombreDePositionsGagnantes]; } // // On demarre et on initialise. // iNombreDeMinutesDejaPassees = 0; } // // : ---------------------- : // : Faire jouer le boitier : // : -----------------------: // void FaireJouerLeBoitier() { // // On cherche la prochaine position gagnante. // for (t = 1; t <= iNombreDePositionsGagnantes; t++) { // // Il faut que la position gagnante soit superieure au nombre de Billes deja allumees. // if (iPositionsGagnantes[t] > iNombreDeMinutesDejaPassees) { // // Il ne faut pas allumer plus de Billes que ce qui est autorise. // if ((iPositionsGagnantes[t] - iNombreDeMinutesDejaPassees) <= iNombreDeMinutesQuOnPeutAvancer) { iNombreDeMinutesAAvancer = iPositionsGagnantes[t] - iNombreDeMinutesDejaPassees; } } } // // Si les positions gagnantes sont trop loin, on joue un nombre au hasard, dans les limites autorisees. // if ((iNombreDeMinutesAAvancer == 0) || (iNombreDeMinutesAAvancer > iNombreDeMinutesQuOnPeutAvancer)) { iNombreDeMinutesAAvancer = random(1, iNombreDeMinutesQuOnPeutAvancer + 1); } // // On redige le message sur l'ecran. // if (iNombreDeMinutesAAvancer == 1) { cTexte = "LE BOITIER AJOUTE 1 MINUTE" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } iNombreDeMinutesDejaPassees = iNombreDeMinutesDejaPassees + 1; faitBougerLAiguille(); } else { cTexte = "LE BOITIER AJOUTE 2 MINUTES" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } iNombreDeMinutesDejaPassees = iNombreDeMinutesDejaPassees + 2; faitBougerLAiguille(); } afficheLeTotal(); // // C'est peut-etre la fin du jeu. // if (iNombreDeMinutesDejaPassees >= iNombreTotalDeMinutes) { bJeuFini = true; iNombreDeMinutesDejaPassees = 0; cTexte = "TU AS PERDU HELAS HELAS HELAS HELAS HELAS " + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } sMoteur.write(0); delay(30); } } // // : ---------------------- : // : Faire jouer le joueur : // : ---------------------- : // void FaireJouerLeJoueur() { // // On demande combien de minutes le joueur ajoute. // // Sur l'ecran. // cTexte = "A TOI" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } // On attend qu'un bouton soit presse sur l'afficheur a 8 LED while ((buttons != 1) && (buttons != 128)) { buttons = litBoutons(); } if (buttons == 1) { cTexte = "TU AJOUTES 1 MINUTE" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } iNombreDeMinutesDejaPassees = iNombreDeMinutesDejaPassees + 1; faitBougerLAiguille(); } if ((buttons == 8) || (buttons == 128)) { cTexte = "TU AJOUTES 2 MINUTES" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } iNombreDeMinutesDejaPassees = iNombreDeMinutesDejaPassees + 2; faitBougerLAiguille(); } buttons = litBoutons(); // // Est-ce la fin ? // if (iNombreDeMinutesDejaPassees >= iNombreTotalDeMinutes) { // // Message de victoire du joueur sur l'ecran LCD. // bJeuFini = true; iNombreDeMinutesDejaPassees = 0; cTexte = "TU AS GAGNE BRAVO BRAVO BRAVO BRAVO BRAVO" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } sMoteur.write(0); delay(30); } } // // : ------------------ : // : Recommencer le jeu : // : ------------------ : // void RecommencerLeJeu() { iNombreDeMinutesAAvancer = 0; iNombreDeMinutesDejaPassees = 0; iNombreDePositionsGagnantes = 0; iAnciennePosition = 0; } // // : ------------------------------------- : // : Efface totalement l'afficheur a 8 LED : // : ------------------------------------- : // void effaceTout() { digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc0); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc2); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc4); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc6); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc8); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xca); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xcc); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xce); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); } // // : ------------------------------------------ : // : Decale vers la gauche les afficheurs a LED : // : ------------------------------------------ : // void decale() { int t; for (t = 0; t < 7; t++) { cAfficheur[t] = cAfficheur[t + 1]; } } // // : ------------------- : // : Affiche sur les LED : // : ------------------- : // void affiche(char cChar) { switch ((cChar)) { case 'A': cAfficheur[7] = cLettreA; break; case 'B': cAfficheur[7] = cLettreB; break; case 'C': cAfficheur[7] = cLettreC; break; case 'D': cAfficheur[7] = cLettreD; break; case 'E': cAfficheur[7] = cLettreE; break; case 'F': cAfficheur[7] = cLettreF; break; case 'G': cAfficheur[7] = cLettreG; break; case 'H': cAfficheur[7] = cLettreH; break; case 'I': cAfficheur[7] = cLettreI; break; case 'J': cAfficheur[7] = cLettreJ; break; case 'L': cAfficheur[7] = cLettreL; break; case 'M': cAfficheur[7] = cLettreM; break; case 'N': cAfficheur[7] = cLettreN; break; case 'O': cAfficheur[7] = cLettreO; break; case 'P': cAfficheur[7] = cLettreP; break; case 'Q': cAfficheur[7] = cLettreQ; break; case 'R': cAfficheur[7] = cLettreR; break; case 'S': cAfficheur[7] = cLettreS; break; case 'T': cAfficheur[7] = cLettreT; break; case 'U': cAfficheur[7] = cLettreU; break; case 'V': cAfficheur[7] = cLettreV; break; case 'Y': cAfficheur[7] = cLettreY; break; case ' ': cAfficheur[7] = cEspace; break; case '.': cAfficheur[7] = cPoint; break; case '-': cAfficheur[7] = cTraitDUnion; break; case '/': cAfficheur[7] = cApostrophe; break; case '1': cAfficheur[7] = cChiffres[1]; break; case '2': cAfficheur[7] = cChiffres[2]; break; case '3': cAfficheur[7] = cChiffres[3]; break; case '4': cAfficheur[7] = cChiffres[4]; break; case '5': cAfficheur[7] = cChiffres[5]; break; case '6': cAfficheur[7] = cChiffres[6]; break; case '7': cAfficheur[7] = cChiffres[7]; break; case '8': cAfficheur[7] = cChiffres[8]; break; case '9': cAfficheur[7] = cChiffres[9]; break; case '0': cAfficheur[7] = cChiffres[0]; break; } digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc0); shiftOut(data, clock, LSBFIRST, cAfficheur[0]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc2); shiftOut(data, clock, LSBFIRST, cAfficheur[1]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc4); shiftOut(data, clock, LSBFIRST, cAfficheur[2]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc6); shiftOut(data, clock, LSBFIRST, cAfficheur[3]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc8); shiftOut(data, clock, LSBFIRST, cAfficheur[4]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xca); shiftOut(data, clock, LSBFIRST, cAfficheur[5]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xcc); shiftOut(data, clock, LSBFIRST, cAfficheur[6]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xce); shiftOut(data, clock, LSBFIRST, cAfficheur[7]); digitalWrite(strobe, HIGH); } // // : ------------------------------------- : // : Initialisation de l'afficheur digital : // : ------------------------------------- : // void SendCommand(uint8_t value) { digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, value); digitalWrite(strobe, HIGH); } // void Reset() { SendCommand(0x40); // set auto increment mode digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc0); for (uint8_t i = 0; i < 16; i++) { shiftOut(data, clock, LSBFIRST, 0x00); } digitalWrite(strobe, HIGH); } // // : -------------------------------- : // : Verifie si on a presse un bouton : // : -------------------------------- : // unsigned int litBoutons() { uint8_t buttons = 0; digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0x42); pinMode(data, INPUT); for (uint8_t i = 0; i < 4; i++) { uint8_t v = shiftIn(data, clock, LSBFIRST) << i; buttons |= v; } pinMode(data, OUTPUT); digitalWrite(strobe, HIGH); return (int) buttons; } // // : ------------------------------ // : Affiche le total des minutes : // : ------------------------------ // void afficheLeTotal() { if (iNombreDeMinutesDejaPassees < 2) { cTexte = "TOTAL " + String(iNombreDeMinutesDejaPassees) + " MINUTE" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } } else { cTexte = "TOTAL " + String(iNombreDeMinutesDejaPassees) + " MINUTES" + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(150); decale(); } } } // // : ---------------------- : // : Fait bouger l'aiguille : // : ---------------------- : // void faitBougerLAiguille() { for (int position = iAnciennePosition; position <= (iNombreDeMinutesDejaPassees * 6.32); position++) { sMoteur.write(position); delay(30); } iAnciennePosition = iNombreDeMinutesDejaPassees * 6; delay(1000); }