Vier gewinnt auf dem U 64 LED Matrix Panel

Inzwischen hat sich ein reger Informationsaustausch via Email mit unserem Kunden Herrn Küster, dem wir die Elektronische Sanduhr verdanken, entwickelt. Dieser hat verletzungsbedingt viel Zeit zum Programmieren seines Micro Controllers und diesmal hat er mir das Spiel „Vier gewinnt“ für zwei Spieler auf dem U 64 LED Matrix Panel CJMCU-8 * 8 Modul  mit RGBLEDs geschickt. Für den Versuchsaufbau hatte ich alle Teile zuhause. Also gleich ausprobieren.

Weiter unten finden Sie ein aktuelles Update des Projektes

4 gewinnt

Verwendete Hardware

Anzahl Bauteil
1 Nano V3.0 mit FT232RL Chip und ATmega328
Oder: Nano V3.0 mit Atmega328 CH340
Alternativ: Micro Controller mit ATMEGA 328P
1 U 64 LED Matrix Panel CJMCU-8 * 8 Modul
Steckbrett (Breadboard), 3 Taster und Kabel (Jumper Wire)

Hardware

Für das abgebildete fertige Set benötigen Sie noch:

1 Gehäuse (Pollin)
1 Batterie-Pack
1 LM2596S DC-DC Netzteil Adapter Step down Modul

Hier der Schaltplan:

Schaltplan
Wie so häufig haben sich die Programmierer der New Yorker Firma Adafruit die Mühe gemacht, uns Anwendern den schwierigsten Teil bei der Hardware-nahen Programmierung abzunehmen und eine Bibliothek für das LED-Display entwickelt und auf github bzw. über den Bibliotheksverwalter bereitgestellt. Deshalb wird diese zu Beginn des Sketches mit
#include <Adafruit_NeoPixel.h>   eingefügt. Sofern noch nicht geschehen, bitte im Suchfenster des Bibliotheksverwalters NeoPixel eingeben (bei mir bereits installiert).

Bibliotheksverwalter

NeoPixel ist wie so häufig eine Bibliothek für eine Vielzahl von RGBLED-Displays, die trotz unterschiedlichster Bauformen eines gemeinsam haben: Außer der Spannungsversorgung gibt es eine einzige Datenleitung, die die hintereinander liegenden RGBLEDs ansteuert. Mit den Zeilen

 int anzahl = 64;
 Adafruit_NeoPixel strip(anzahl, 6, NEO_GRB + NEO_KHZ800);

instanziieren wir deshalb unser 8x8 Modul.

Für das Spielfeld stehen acht Spalten und sieben Zeilen zur Verfügung, denn die oberste Zeile wird jeweils für die Positionierung des nächsten „Spielsteins“ benötigt. Rot beginnt. Die oberste, linke LED leuchtet rot und kann mit den zwei Tastern für links (an GPIO9) und rechts (an GPIO10) entsprechend bewegt werden. Der Zug wird mit dem mittleren Taster (an GPIO8) abgeschlossen. Der Leuchtpunkt wandert so weit nach unten, wie freie Felder verfügbar sind. 

Nach der Prüfroutine, ob ein Spieler bereits vier gleichfarbige Felder waagerecht, senkrecht oder diagonal erreicht hat, erscheint oben links eine grüne LED und der zweite Spieler macht seinen Zug in gleicher Weise. Dann sehen wir wieder eine rote LED oben links usw.

Wenn die Prüfroutine zu einem positiven Ergebnis kommt, blinken zunächst die vier RGBLEDs in Reihe, dann das ganze Display in den Farben des Gewinners. Sodann ist der Micro Controller für die nächste Runde bereit. Um das Spiel vorzeitig zu beenden, beide Richtungstaster gleichzeitig drücken.

Hier der Sketch im Ganzen und als Download:

 #include <Adafruit_NeoPixel.h>
 int anzahl = 64;
 Adafruit_NeoPixel strip(anzahl, 6, NEO_GRB + NEO_KHZ800);
 
 long rot = strip.Color(5, 0, 0); long gruen = strip.Color(0, 5, 0); long farbe = 0;
 byte zw1 = 0; int zw2 = 0; // werden in "Ausgabe Spielfeld" benutzt
 byte zw3 = 0; // wird in Absenken der Spielsteine benutzt
 byte zw4 = 0; // Startfeld beim Testen
 byte zw5 = 0; // Zaelwert innere Schleife, testet 4 Felder
 byte zw6 = 0; // Zaelwert mittlere Schleife, testet eine Spalte
 byte zw7 = 0; // Zaelwert außere Schleife, testet alle Spalten
 byte zw8 = 0; // Gefallene Steine
 byte zw9 = 0; // Ausgabe Siegerfarbe
 byte zw10 = 0; //Loeschen Anzeige und Spielfeld
 byte zw11 = 0; //Blinken Siegersteine
 long farbe_1 = 0; long farbe_2 = 0; // Siegerfarbe
 byte position_1 = 0; byte position_2 = 0; byte position_3 = 0; byte position_4 = 0; //Position Gewinnersteine
 
 // 0 -> nicht belegt; 1 -> rot; 2 -> gruen
 byte spielfeld [64] = {
   1, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0
 };
 
 byte rechts = 10; byte links = 9; byte runter = 8; // Nummer der benoetigten Ports
 
 byte richtung = 0 ; // 1 -> rechts; 2 -> links; 3 -> runter
 byte status_start = 1; // 1 -> rot; 2 -> gruen
 byte status_spiel = 1 ; // 1 -> rot; 2 -> gruen
 byte position_0 = 0; // Zeiger fuer Spielfeld
 byte test_rot = 0; byte test_gruen = 0; byte sieger = 0; // Benoetigt zum Ermitteln des Siegers
 
 void setup() {
 
   Serial.begin(9600);
 
   strip.begin();
   strip.show(); // Initialize all pixels to 'off'
 
   pinMode(rechts, INPUT); digitalWrite (rechts, HIGH);
   pinMode(links, INPUT); digitalWrite (links, HIGH);
   pinMode(runter, INPUT); digitalWrite (runter, HIGH);
 
   ausgabe_spielfeld ();
 }
 
 void loop() {
 
   // Abfrage Tastatur und Sprung in entsprechendes Programm
   do {
     
     if (digitalRead(rechts) == LOW && digitalRead(links) == LOW) {
       zw8 = 56;
       test_spielende ();
    };
     if ( digitalRead(rechts) == LOW) {
       richtung = 1; rechts_0 ();
    }
     if ( digitalRead(links) == LOW) {
       richtung = 2; links_0 ();
    }
     if ( digitalRead(runter) == LOW) {
       if (spielfeld [position_0 + 8] == 0) {
         richtung = 3;
         runter_0 (); zw8 ++; // Anzahl Durchlaeufe + 1
         test_spielende ();
      };
    }
  }
   while ( richtung == 0);
   richtung = 0; // Loeschender Richtung
 
 
   ausgabe_spielfeld ();
   delay(300);
 }
 
 // ------------- Test ob es einen Sieger gibt ------------------
 // ---------- Programm wird nach Absenken eines Steines aufgerufen
 void test_spielende () {
 
   // ----------- Test diagonal oben ------------
   // ----------3 verschaltelte Zyklen ----------
 
   zw4 = 32; // Startfeld beim Testen
   sieger = 0; zw7 = 0;
 
   do {
     zw6 = 0;
 
     do {
       zw5 = 0; // Zaelschleife
       test_rot = 0; test_gruen = 0;
 
       // Testen 4 Zellen diegonal oben
       do {
         if ( spielfeld [zw4] == 1) {
           test_rot ++;
        };
         if ( spielfeld [zw4] == 2) {
           test_gruen ++;
        };
 
         // Merken der Position beim Sieg
         if (sieger == 0) {
           if (zw5 == 0) {
             position_1 = zw4;
          };
           if (zw5 == 1) {
             position_2 = zw4;
          };
           if (zw5 == 2) {
             position_3 = zw4;
          };
           if (zw5 == 3) {
             position_4 = zw4;
          };
        };
 
         zw4 = zw4 - 7; zw5++;
      }
       while (zw5 != 4);
 
       if (test_rot == 4) {
         sieger = 1;
      } else {
         test_rot = 0;
      };
       if (test_gruen == 4) {
         sieger = 2;
      } else {
         test_gruen = 0;
      };
       zw4 = zw4 + 36; zw6++;
       if (sieger != 0) {
         zw6 = 4;
      };
    }
     while ( zw6 != 4);
 
     zw4 = zw4 - 31; zw7++;
     if (sieger != 0) {
       zw7 = 5;
    };
  }
   while (zw7 != 5);
 
   // ----------- Test diagonal unten -----------
   // ----------3 verschachtelte Zyklen ----------
 
   zw4 = 8; // Startfeld beim Testen
   zw7 = 0;
 
   do {
     zw6 = 0;
 
     do {
       zw5 = 0; //zaehlschleife
       test_rot = 0; test_gruen = 0;
 
       // Testen 4 Zellen diagonal unten
       do {
         if ( spielfeld [zw4] == 1) {
           test_rot ++;
        };
         if ( spielfeld [zw4] == 2) {
           test_gruen ++;
        };
 
         // Merken der Position beim Sieg
         if (sieger == 0) {
           if (zw5 == 0) {
             position_1 = zw4;
          };
           if (zw5 == 1) {
             position_2 = zw4;
          };
           if (zw5 == 2) {
             position_3 = zw4;
          };
           if (zw5 == 3) {
             position_4 = zw4;
          };
        };
 
         zw4 = zw4 + 9; zw5++;
      }
       while (zw5 != 4);
 
       if (test_rot == 4) {
         sieger = 1;
      } else {
         test_rot = 0;
      };
       if (test_gruen == 4) {
         sieger = 2;
      } else {
         test_gruen = 0;
      };
       zw4 = zw4 - 28; zw6++;
       if (sieger != 0) {
         zw6 = 4;
      };
    }
     while ( zw6 != 4);
 
     zw4 = zw4 - 31; zw7++;
     if (sieger != 0) {
       zw7 = 5;
    };
  }
   while (zw7 != 5);
 
   // ------------ Test senkrecht ---------------
   // ----------3 verschaltelte Zyklen ----------
 
   zw4 = 8; // Startfeld beim Testen
   zw7 = 0;
   do {
     zw6 = 0;
 
     do {
       zw5 = 0; //zaelschleife
       test_rot = 0; test_gruen = 0;
 
       // Testen 4 Zellen senkrecht
       do {
         if ( spielfeld [zw4] == 1) {
           test_rot ++;
        };
         if ( spielfeld [zw4] == 2) {
           test_gruen ++;
        };
 
         // Merken der Position beim Sieg
         if (sieger == 0) {
           if (zw5 == 0) {
             position_1 = zw4;
          };
           if (zw5 == 1) {
             position_2 = zw4;
          };
           if (zw5 == 2) {
             position_3 = zw4;
          };
           if (zw5 == 3) {
             position_4 = zw4;
          };
        };
 
         zw4 = zw4 + 8; zw5++;
      }
       while (zw5 != 4);
 
       if (test_rot == 4) {
         sieger = 1;
      } else {
         test_rot = 0;
      };
       if (test_gruen == 4) {
         sieger = 2;
      } else {
         test_gruen = 0;
      };
       zw4 = zw4 - 24; zw6++;
       if (sieger != 0) {
         zw6 = 4;
      };
    }
     while ( zw6 != 4);
 
     zw4 = zw4 - 31; zw7++;
     if (sieger != 0) {
       zw7 = 8;
    };
  }
   while (zw7 != 8);
 
   // ------------- Test waagerecht --------------
   // ----------3 verschachtelte Zyklen ----------
   zw4 = 8; // Startfeld beim Testen
   zw7 = 0;
   do {
     zw6 = 0;
 
     do {
       zw5 = 0;
       test_rot = 0; test_gruen = 0;
 
       // Testen 4 Zellen waagerecht
       do {
         if ( spielfeld [zw4] == 1) {
           test_rot ++;
        };
         if ( spielfeld [zw4] == 2) {
           test_gruen ++;
        };
 
         // Merken der Position beim Sieg
         if (sieger == 0) {
           if (zw5 == 0) {
             position_1 = zw4;
          };
           if (zw5 == 1) {
             position_2 = zw4;
          };
           if (zw5 == 2) {
             position_3 = zw4;
          };
           if (zw5 == 3) {
             position_4 = zw4;
          };
        };
 
         zw4++; zw5++;
      }
       while (zw5 != 4);
 
       if (test_rot == 4) {
         sieger = 1;
      } else {
         test_rot = 0;
      };
       if (test_gruen == 4) {
         sieger = 2;
      } else {
         test_gruen = 0;
      };
       zw4 = zw4 + 4; zw6++;
       if (sieger != 0) {
         zw6 = 7;
      };
    }
     while ( zw6 != 7);
 
     zw4 = zw4 - 55; zw7++;
     if (sieger != 0) {
       zw7 = 5;
    };
  }
   while (zw7 != 5);
 
   // Festlegen Siegerfarben
   if (sieger == 1) {
     farbe_1 = rot;
     farbe_2 = rot;
     ende (); // Ausgabe Siegerfarbe Rot
  };
   if (sieger == 2) {
     farbe_1 = gruen;
     farbe_2 = gruen;
     ende (); // Ausgabe Siegerfarbe Gruen
  };
   if (zw8 == 56 ) {
     farbe_1 = gruen;
     farbe_2 = rot;
     ende (); // Ausgabe Unentschieden
  };
 
   position_1 = 0; position_2 = 0; position_3 = 0; position_4 = 0;
   test_rot = 0; test_gruen = 0;
 }
 
 // ---------- Ausgabe Siegerfarbe ----------
 
 void ende () {
   zw11 = 0;
 
   if (zw8 != 56 ) {
     do {
       strip.setPixelColor ( position_1, 0, 0, 0);
       strip.setPixelColor ( position_2, 0, 0, 0);
       strip.setPixelColor ( position_3, 0, 0, 0);
       strip.setPixelColor ( position_4, 0, 0, 0);
       strip.show(); delay(200);
       strip.setPixelColor ( position_1, farbe_1);
       strip.setPixelColor ( position_2, farbe_1);
       strip.setPixelColor ( position_3, farbe_1);
       strip.setPixelColor ( position_4, farbe_1);
       strip.show(); delay(200);
       zw11++;
    }
     while ( zw11 != 5);
  }
 
   zw9 = 0;
   do {
     strip.setPixelColor ( zw9, farbe_1); zw9++;
     strip.setPixelColor ( zw9, farbe_2); zw9++;
  }
   while (zw9 != 64);
   strip.show();
 
   delay(2000);
 
   // ---------- Vorbereitung neuer Start -----------
 
   zw10 = 0;
   do {
     strip.setPixelColor ( zw10, 0, 0, 0); spielfeld [zw10] = 0;
     zw10++;
  }
   while ( zw10 != 64);
   strip.show();
 
   spielfeld [0] = 1; ausgabe_spielfeld ();
   zw1 = 0; zw2 = 0; zw3 = 0; zw4 = 0; zw5 = 0; zw6 = 0; zw7 = 0; zw8 = 0; zw9 = 0; zw10 = 0;
   position_1 = 0; position_2 = 0; position_3 = 0; position_4 = 0;
   position_0 = 0;
 
   // Wechsel Start-Spielfarbe
   farbe_1 = 0; farbe_2 = 0; sieger = 0;  
 
   if (status_start == 1) {
     farbe = gruen; status_spiel = 2;status_start=2;
     spielfeld [0] = 2;
  } else {
     farbe = rot;
     spielfeld [0] = 1; status_spiel = 1;status_start=1;
  };
   
   ausgabe_spielfeld ();
 }
 
 // ---------- Ein Schritt nach Links ----------
 void links_0 () {
   if (position_0 != 0) {
     spielfeld [position_0] = 0;
     position_0--;
     spielfeld [ position_0 ] = status_spiel;
  };
 }
 
 // ---------- Ein Schritt nach Rechts ----------
 void rechts_0 () {
   if (position_0 != 7) {
     spielfeld [position_0] = 0;
     position_0++;
     spielfeld [ position_0 ] = status_spiel;
  };
 }
 
 // ---------- Absenken des Spielsteines ----------
 void runter_0 () {
   zw3 = 0;
   do {
     if (spielfeld [position_0 + 8] == 0 ) {
       spielfeld [position_0] = 0; position_0 = position_0 + 8; spielfeld [position_0] = status_spiel;
       zw3++;
       ausgabe_spielfeld (); delay(200);
    }
     else {
       zw3 = 7;
    }
  }
   while (zw3 != 7) ;
   richtung = 0; position_0 = 0;
   if (status_spiel == 1 ) {
     status_spiel = 2;
     spielfeld [position_0] = 2;
  } else {
     status_spiel = 1;
     spielfeld [position_0] = 1;
  };
   ausgabe_spielfeld ();
 }
 
 // ---------- Ausgabe Spielfeld ----------
 void ausgabe_spielfeld () {
   zw1 = 0;
 
   do {
     zw2 = spielfeld [zw1];
     if (zw2 == 0) {
       strip.setPixelColor ( zw1, 0, 0, 0);
    };
     if (zw2 == 1) {
       strip.setPixelColor ( zw1, rot);
    };
     if (zw2 == 2) {
       strip.setPixelColor ( zw1, gruen);
    };
     zw1++;
  }
   while (zw1 != 64);
   strip.show();
 }
 
 // HUK Vier_gewinnt_4.4 27.07.2021

Alternativ können Sie Vier gewinnt auch auf dem Wandgehäuse AZ-Touch spielen. Diese Möglichkeit hatte Jörn Weise in seinem Blog am 3. Juli 2021 vorgestellt.

Beide vorgestellte Versionen sind für zwei Spieler ausgelegt und bieten außer der schönen Anzeige die Prüfroutine, ob bereits ein Spieler gewonnen hat. Wer gegen einen spielstarken Computer spielen möchte, dem sei die Version von Al Sweigart auf dem Raspberry Pi empfohlen. Ich muss zu meiner Schande gestehen, dass ich hin und wieder verliere. Also lieber mit dem Sketch von Herrn Küster auf dem  U 64 LED Matrix Panel CJMCU-8 * 8 Modul gegen meine Enkeltochter spielen?

UPDATE

Es hat unserem Kunden Herrn Küster keine Ruhe gelassen, bis er auch die Option Spieler gegen Mikrcontroller programmiert hat. Man hat die Wahlmöglichkeit zwischen zwei Spielern (linke Richtungstaste) oder Spieler gegen MCU (rechte Richtungstaste).

  • Bei Spieler gegen Spieler wird die Anfangsfarbe bei jedem neuen Spiel gewechselt
  • Bei Spieler gegen Rechner hat der Spieler immer rot und beginnt das erste Spiel. Danach beginnt immer der Verlierer.

Hier der Link zum Download

Viel Spaß beim Nachbauen und Spielen.

DisplaysFür arduinoProjekte für anfänger

7 Kommentare

Andreas Wolter

Andreas Wolter

@René: Wenn auch mit den Testsketches die LED nicht eingeschaltet wird, gehe ich davon aus, dass in dem Modul etwas nicht korrekt verlötet ist. SIe könnten versuchen, einen Testsketch so anzupassen, dass genau diese LED eingeschaltet wird. Wenn diese nicht leuchtet, müssen Sie den Support kontaktieren und das Modul austauschen lassen.

Grüße,
Andreas Wolter
AZ-Delivery Blog

René

René

Hi,
also auch mit einem Test-Sketch/Beispiel Sketch aus der Neopixel Bibliothek bleibt die erste LED dunkel. Keine Ahnung warum das so ist.
Wenn man das 4-Gewinnt Programm startet, dann ist es ja auch so, dass die erste LED dunkel ist und man eben direkt bei der zweiten startet. Also entweder ist das Modul defekt oder irgendein anderer Fehler ist vorhanden.
Habe beides, Board und Matrix bei euch bezogen.

Andreas Wolter

Andreas Wolter

@Renè: haben Sie am Programm änderungen vorgenommen?
Wenn nicht, empfehle ich, ein Testprogramm auf den MC zu laden, um zu sehen, ob die LEDs alle ordnungsgemäß angesprochen werden.

Unser Blogautor Bernd Albrecht hat den Sketch nochmal getestet und er funktioniert so wie er soll.
Ich denke aber, dass wir den Fehler finden werden.

Grüße,
Andreas Wolter
AZ-Delivery Blog

René

René

Ich habe jetzt einen Fehler im Programm:
Beim Start des Arduinos wird nicht das ganz oben, ganz links befindliche LED rot aktiviert sondert immer ganz oben und eins nach rechts.
Hab versucht das zu finden, aber kann es sein, dass die LED Matrix falsch initialisiert wird?

René

René

Super, vielen Dank.

Andreas Wolter

Andreas Wolter

Wir haben den Link zum Gehäuse ergänzt. Es ist kein 3D-Modell für den Drucker.

Außerdem hat uns Herr Küster ein Update zur Verfügung gestellt, das Sie jetzt ebenfalls im Beitrag finden.

Mit freundlichen Grüßen,
Andreas Wolter
AZ-Delivery Blog

René

René

Cooles Projekt, würde ich gern nachbauen aber den Hinweis zum Gehäuse finde ich sehr lustig ;)
Könntet ihr vielleicht erwähnen welches ihr dazu genutzt habt?
Oder noch besser wäre, wenn das eine stl für einen 3D-Druck wäre ;)

Einen Kommentar hinterlassen

Alle Kommentare werden vor der Veröffentlichung moderiert