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.
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) |
Für das abgebildete fertige Set benötigen Sie noch:
1 | Gehäuse |
---|---|
1 | Batterie-Pack |
1 | LM2596S DC-DC Netzteil Adapter Step down Modul |
Hier der 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).
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:
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?
Viel Spaß beim Nachbauen und Spielen.