Industrie Steckverbinder


Google-Suche auf MEINE-SCHALTUNG.de :





Dauerkalender


Vier Gewinnt
(Strategiespiel mit Arduino Nano)


Vier Gewinnt: Original

Eine im Handel erhältliche "Vier Gewinnt" - Ausgabe.

Vier Gewinnt: Spielfeld

Die selbstgemachte meine-schaltung.de-Version.


Das Spiel „Vier Gewinnt“, das in den 70er-Jahren entstand, ist ein Strategiespiel für zwei Personen. Man könnte sagen, „Vier Gewinnt“ ist ein Zwillingsbruder von „Vier in eine Reihe“ oder „Fünf in eine Reihe“. Die Grundregeln aller dieser Spiele sind nahezu identisch. Der Unterschied bezieht sich lediglich auf den Zugang zu dem Spielfeld. Ist die Frage bei „Vier in eine Reihe“ eher irrelevant, trifft man bei „Vier Gewinnt“ gleich auf eine Einschränkung. Das Spielfeld steht hier normalerweise senkrecht und die Steine, die das Kreuz und Kreis ersetzen, können nur von oben auf das Spielfeld gebracht werden. Auch hier geht es darum, vier eigene Steine in eine Linie zu bringen. Sobald man dies geschafft hat, ist der Gegner geschlagen und das Spiel zu Ende.

Arduino Nano

Arduino Nano


In unserem Versuch wird ein der Spieler von dem Arduino ersetzt. Es kommt der kleine Arduino Nano zum Einsatz. Arduino Nano ist eine der kleinsten Arduino-Platinen und wird überwiegend bei kleinen Projekten eingesetzt. Bei dem Versuch kann man beobachten, dass der Kleine ganz flott mit seinen Aufgaben fertig wird und zusätzlich noch über Reserven verfügt. Die Betriebsspannung von Arduino beträgt 5V, ein Ausgang kann mit bis zu 40 mA belastet werden. Empfohlene Versorgungsspannung beträgt 7-12 VDC.

RGB-Matrix CJMCU

8x8 RGB-Matrix CJMCU


Arduino steuert mit seinem Programm die RGB-Matrix CJMCU an. Die Matrix besteht aus 64 RGB-Dioden, die in acht Reihen und acht Spalten angeordnet sind. Dabei handelt es sich um die WS2812 LEDs, die intern aus drei Leuchtdioden (Rot, Grün, Blau) und einem Controller-Chip bestehen. Damit ist für die Matrix kein externer Treiber notwendig. Die gesamte Matrix wird mit nur einer Datenleitung angesteuert. Auf Empfehlung des Herstellers wird die einfache Schaltung mit einem Kondensator von 1000 µF und einem Widerstand im Wert von 300 Ohm erweitert. Als weitere Komponenten werden an die Eingänge des Arduino fünf Taster angeschlossen. Sie ermöglichen während des Spiels die Kommunikation mit dem Mikrocontroller. Eine separate Leuchtdiode dient als Signalleuchte, die das Ende des Spiels markiert.

Rückseite

Rückseite der Testplatine.


Schaltplan

Schaltplan

Schaltplan (Arduino ohne USB-Anschluss: Vin > 7 V)

Das Programm

Mit den Tasten „ROT“ und „GRÜN“ kann gewählt werden, wer von den Spielern den ersten Zug tätigt. Die Farben sind fest zugeordnet. Arduino spielt mit „ROT“, sein Gegenüber mit „Grün“. Mit den Tasten „Links“ und „Rechts“ kann der Spieler den Cursor auf die gewünschte Spalte bewegen, mit der Taste „Enter“ seinen Zug-Wunsch bestätigen. Nachdem der Spieler seinen Zug absolviert hatte, ist Arduino an der Reihe.
Das Programm (Sketch) untersucht die Felder, die für den nächsten Zug infrage kommen und bewertet sie. Bei jedem Zug werden dem entsprechenden Feld Punkte zugewiesen. Ein Arduino-Zug bringt einem Feld 1 Punkt. Die vom Gegner besetzten Felder werden mit 5 Punkten bewertet. Bei der Untersuchung werden diese Punkte für alle 4er-Kombinationen summiert und verglichen.
Grundsätzlich untersucht das Programm nur eigene Züge. Nur in einem Fall wird Bezug auf die Züge des Gegners genommen (3er Kombination). Somit besteht noch genügend Raum für Erweiterungen und Verbesserungen des Programms. In dem folgenden Kurzvideo wird diese einfache Version des Programms vorgestellt. Das Programm benötigt lediglich 22% des Programmierspeicherplatzes des Mikrocontrollers.
Dank der Kommentare im Programm kann man die Vorgehensweise bei Berechnungen leicht nachvollziehen. Es wird dabei schnell sichtbar, dass das Programm keinen ausgeklügelten Spiel-Strategien folgt. Es wird bei der Feldbewertung lediglich Stellung zu der aktuellen Situation genommen. Und dennoch, diese einfache Vorgehensweise bei der Vergabe der Punkte bewirkt, dass jeder Gelegenheitsspieler beim Spiel mit Sicherheit in Schwierigkeiten gerät.

Bibliothek

Vor der Nutzung des Programms muss die Bibliothek "Adafruit NeoPixel" installiert werden.


// ************************************************************************
// Vier Gewinnt
// Mit RGB-Matrix CJMCU und Arduino Nano
// IDE 1.8.12
// ************************************************************************
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> 
#endif

#define LED_PIN    2
#define LED_COUNT 64

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// Eingänge + Ausgänge ....................................................
int Taste_Links = 7;
int Taste_Rechts = 6;
int Taste_Gegner = 3;
int Taste_Ich = 4;
int Taste_Enter = 5;
int Spielende = 8;

// Variablen ..............................................................
int Spielbrett [15][15];
int Spieler = 0;           // Eröffnung: 1 - Spieler, 2 - Arduino
int Reihe = 0;
int Spalte = 0;
int Feld_Nummer = 0;
int Cursor = 0;
int Game_is_over = 0;
int Zufallszahl;


// SETUP ******************************************************************
void setup() {
  strip.begin();           
  strip.show();            
  strip.setBrightness(20); 
  pinMode(Taste_Links, INPUT_PULLUP);
  pinMode(Taste_Rechts, INPUT_PULLUP);
  pinMode(Taste_Gegner, INPUT_PULLUP);
  pinMode(Taste_Ich, INPUT_PULLUP);
  pinMode(Taste_Enter, INPUT_PULLUP);
  pinMode(Spielende, OUTPUT);

Serial.begin(9600);
}

// HAUPTPROGRAMM **********************************************************
void loop() {
  
  // Zufallszahlen via Schlaufe .............................
  Zufallszahl++;
  if (Zufallszahl > 11) { Zufallszahl = 4; }
  delay (10);
 
  // Rand vorbelegen ........................................
  if (Spielbrett [1][1] == 0) { Rand_vorbelegen(); }
  
  // Eröffnungsentscheidung .................................
  if ( Spieler == 0) {
    if (digitalRead(Taste_Gegner) == LOW) { 
      delay (300); 
      Spieler = 1;  }
    if (digitalRead(Taste_Ich) == LOW) { 
      delay (300);
      Mein_Zufallszug(); } }

  // Spiel ..................................................
  if (Game_is_over == 0) {
    switch (Spieler) {
      case 1: { Spieler_am_Zug(); break; }
      case 2: { Mein_Zug(); break; 
      } } }

  // Spiel zu Ende ..........................................
  if (Game_is_over == 1) {
    do {
      digitalWrite (Spielende, HIGH);
      delay(500);
      digitalWrite (Spielende, LOW);
      delay(500);
    } while (Game_is_over == 0); }
}
// HAUPTPROGRAMM ENDE *****************************************************

// Rand vorbelegen --------------------------------------------------------
void Rand_vorbelegen() {
  int i,j;
  for (i=1; i<15; i++) {
    for (j=1; j<15; j++) {
      Spielbrett [i][j] = 0;
      if ((i < 5) or (i > 11)) {
        Spielbrett [i][j] = -50; }
      if ((j < 4) or (j > 11)) {
        Spielbrett [i][j] = -50; } } } 
}

// Programm Mein_Zufallszug -----------------------------------------------
void Mein_Zufallszug() { 
  Spalte = Zufallszahl;
  for (int i=5; i<12; i++) {
    if ((Spielbrett [i][Spalte] == 0) and (Spielbrett [i+1][Spalte] != 0)) {
      Reihe = i; } }
  Spielbrett [Reihe][Spalte] = 1;
  Zug_ausfueren ();
  Spieler = 1;
}
  
// Spieler am Zug ---------------------------------------------------------
void Spieler_am_Zug() {
  if (Cursor == 0) {
    Cursor = 1;
    Reihe = 4;
    Spalte = 4;
    Cursor_Zeigen(1); }
    
  if (Cursor == 1) {
    if (digitalRead(Taste_Links) == LOW) {
      delay (300);
      Cursor_Zeigen(0);
      Spalte--;
      if (Spalte < 4) { Spalte = 11; }
      Cursor_Zeigen(1); }

    if (digitalRead(Taste_Rechts) == LOW) {
      delay (300);
      Cursor_Zeigen(0);
      Spalte++;
      if (Spalte > 11) { Spalte = 4; }
      Cursor_Zeigen(1); }    
  
    if (digitalRead(Taste_Enter) == LOW) {
      delay (300);
      for (int i=5; i<12; i++) {
        if ((Spielbrett [i][Spalte] == 0) and (Spielbrett [i+1][Spalte] != 0)) {
          Reihe = i; } }
      Spielbrett [Reihe][Spalte] = 5;
      Cursor = 0;
      Spieler = 2;
      Zug_ausfueren ();
      Vier_in_Reihe (20); } }
}

// Cursor Zeigen ----------------------------------------------------------
void  Cursor_Zeigen (int EinAus) {
  Feld_Nummer = (Reihe-4)*8 + (Spalte-3) - 1;
  if (EinAus == 0) { strip.setPixelColor(Feld_Nummer, 0, 0, 0); }
  if (EinAus == 1) { strip.setPixelColor(Feld_Nummer, 0, 0, 255); }
  strip.show();
}  

// Computer am Zug --------------------------------------------------------
void Mein_Zug() {
  int Punkte_horizontal[2];  // 1 Arduino, 2 Gegenspieler
  int Punkte_vertikal[2];
  int Punkte_diagonal_L[2];
  int Punkte_diagonal_R[2];
  int Punkte_Zahl = 0;
  int Best_Punkte = 0;
  int Best_Reihe = 0;
  int Best_Spalte = 0;
  int Punkte_addiert;
  

    // Alle Felder durchsuchen ..............................
    for (Spalte = 4; Spalte < 12; Spalte++) { 
      for (Reihe = 5; Reihe < 12; Reihe++) {
        if ((Spielbrett [Reihe][Spalte] == 0) and (Spielbrett [Reihe+1][Spalte] != 0)) {
          
          // Feldbewertung ..................................                
          Punkte_horizontal[1] = 0;  Punkte_horizontal[2] = 0;
          for (int i=-3; i<1; i++) {
            Punkte_addiert = Summe_Punkte_horizontal (Reihe, Spalte+i);
            if ((Punkte_addiert > Punkte_horizontal[1]) and (Punkte_addiert < 5)) { 
              Punkte_horizontal[1] = Punkte_addiert; }
            if ((Punkte_addiert > Punkte_horizontal[2]) and (Punkte_addiert > 4)) { 
              Punkte_horizontal[2] = Punkte_addiert; } }

          Punkte_vertikal[1] = 0;  Punkte_vertikal[2] = 0;          
          for (int i=-3; i<1; i++) {
            Punkte_addiert = Summe_Punkte_vertikal (Reihe+i, Spalte);
            if ((Punkte_addiert > Punkte_vertikal[1]) and (Punkte_addiert < 5)) { 
              Punkte_vertikal[1] = Punkte_addiert; }
            if ((Punkte_addiert > Punkte_vertikal[2]) and (Punkte_addiert > 4)) { 
              Punkte_vertikal[2] = Punkte_addiert; } }
          
          Punkte_diagonal_L[1] = 0;  Punkte_diagonal_L[2] = 0;          
          for (int i=-3; i<1; i++) {
            Punkte_addiert = Summe_Punkte_diagonal_L (Reihe+i, Spalte+i);
            if ((Punkte_addiert > Punkte_diagonal_L[1]) and (Punkte_addiert < 5)) { 
              Punkte_diagonal_L[1] = Punkte_addiert; }
            if ((Punkte_addiert > Punkte_diagonal_L[2]) and (Punkte_addiert > 4)) { 
              Punkte_diagonal_L[2] = Punkte_addiert; } }
          
          Punkte_diagonal_R[1] = 0;  Punkte_diagonal_R[2] = 0;          
          for (int i=-3; i<1; i++) {
            Punkte_addiert = Summe_Punkte_diagonal_R (Reihe-i, Spalte+i);
            if ((Punkte_addiert > Punkte_diagonal_R[1]) and (Punkte_addiert < 5)) { 
              Punkte_diagonal_R[1] = Punkte_addiert; }
            if ((Punkte_addiert > Punkte_diagonal_R[2]) and (Punkte_addiert > 4)) { 
              Punkte_diagonal_R[2] = Punkte_addiert; } }     

          // Beste Position ermitteln .......................
          Punkte_Zahl = 0;
          // 1 Pixel = 1 Punkt ..............................
          if (Punkte_horizontal[1] == 1) { Punkte_Zahl = 1; }
          if (Punkte_vertikal[1] == 1) { Punkte_Zahl = 1; }
          if (Punkte_diagonal_L[1] == 1) { Punkte_Zahl = 1; }
          if (Punkte_diagonal_R[1] == 1) { Punkte_Zahl = 1; }

          // Kreuzung 1 x 1 Pixel = 2 Punkte ................
          if (Punkte_horizontal[1] == 1 and Punkte_vertikal[1] == 1) { Punkte_Zahl = 2; }
          if (Punkte_horizontal[1] == 1 and Punkte_diagonal_L[1] == 1) { Punkte_Zahl = 2; }
          if (Punkte_horizontal[1] == 1 and Punkte_diagonal_R[1] == 1) { Punkte_Zahl = 2; }
          if (Punkte_vertikal[1] == 1 and Punkte_diagonal_L[1] == 1) { Punkte_Zahl = 2; }
          if (Punkte_vertikal[1] == 1 and Punkte_diagonal_R[1] == 1) { Punkte_Zahl = 2; }
          if (Punkte_diagonal_L[1] == 1 and Punkte_diagonal_R[1] == 1) { Punkte_Zahl = 2; }
            
          // 2 Pixel - 3 Punkte .............................
          if (Punkte_horizontal[1] == 2) { Punkte_Zahl = 3; }
          if (Punkte_vertikal[1] == 2) { Punkte_Zahl = 3; }
          if (Punkte_diagonal_L[1] == 2) { Punkte_Zahl = 3; }
          if (Punkte_diagonal_R[1] == 2) { Punkte_Zahl = 3; }

          // Kreuzung 2 x 1 Pixel = 4 Punkte ................
          if (Punkte_horizontal[1] == 2 and Punkte_vertikal[1] == 1) { Punkte_Zahl = 4; }
          if (Punkte_horizontal[1] == 1 and Punkte_vertikal[1] == 2) { Punkte_Zahl = 4; }
          if (Punkte_horizontal[1] == 2 and Punkte_diagonal_L[1] == 1) { Punkte_Zahl = 4; }
          if (Punkte_horizontal[1] == 1 and Punkte_diagonal_L[1] == 2) { Punkte_Zahl = 4; }
          if (Punkte_horizontal[1] == 2 and Punkte_diagonal_R[1] == 1) { Punkte_Zahl = 4; }
          if (Punkte_horizontal[1] == 1 and Punkte_diagonal_R[1] == 2) { Punkte_Zahl = 4; }
          if (Punkte_vertikal[1] == 2 and Punkte_diagonal_L[1] == 1) { Punkte_Zahl = 4; }
          if (Punkte_vertikal[1] == 1 and Punkte_diagonal_L[1] == 2) { Punkte_Zahl = 4; }
          if (Punkte_vertikal[1] == 2 and Punkte_diagonal_R[1] == 1) { Punkte_Zahl = 4; }
          if (Punkte_vertikal[1] == 1 and Punkte_diagonal_R[1] == 2) { Punkte_Zahl = 4; }
          if (Punkte_diagonal_L[1] == 2 and Punkte_diagonal_R[1] == 1) { Punkte_Zahl = 4; }  
          if (Punkte_diagonal_L[1] == 1 and Punkte_diagonal_R[1] == 2) { Punkte_Zahl = 4; }     

          // Kreuzung 2 x 2 Pixel = 5 Punkte ................
          if (Punkte_horizontal[1] == 2 and Punkte_vertikal[1] == 2) { Punkte_Zahl = 5; }
          if (Punkte_horizontal[1] == 2 and Punkte_diagonal_L[1] == 2) { Punkte_Zahl = 5; }
          if (Punkte_horizontal[1] == 2 and Punkte_diagonal_R[1] == 2) { Punkte_Zahl = 5; }
          if (Punkte_vertikal[1] == 2 and Punkte_diagonal_L[1] == 2) { Punkte_Zahl = 5; }
          if (Punkte_vertikal[1] == 2 and Punkte_diagonal_R[1] == 2) { Punkte_Zahl = 5; }
          if (Punkte_diagonal_L[1] == 2 and Punkte_diagonal_R[1] == 2) { Punkte_Zahl = 5; }  

          // 3 Pixel beim Gegner = 6 Punkte ..................
          if (Punkte_horizontal[2] == 15) { Punkte_Zahl = 6; }
          if (Punkte_vertikal[2] == 15) { Punkte_Zahl = 6; }
          if (Punkte_diagonal_L[2] == 15) { Punkte_Zahl = 6; }
          if (Punkte_diagonal_R[2] == 15) { Punkte_Zahl = 6; }
                
          // 3 Pixel = 7 Punkte ..............................
          if (Punkte_horizontal[1] == 3) { Punkte_Zahl = 7; }
          if (Punkte_vertikal[1] == 3) { Punkte_Zahl = 7; }
          if (Punkte_diagonal_L[1] == 3) { Punkte_Zahl = 7; }
          if (Punkte_diagonal_R[1] == 3) { Punkte_Zahl = 7; }

          // Entscheidung ....................................
          if (Punkte_Zahl > Best_Punkte) { 
            Best_Punkte = Punkte_Zahl; Best_Reihe = Reihe; Best_Spalte = Spalte; }

          // Nichts gefunden .................................
          if (Best_Punkte == 0) { Best_Reihe = Reihe; Best_Spalte = Zufallszahl; } } } }

    Reihe = Best_Reihe;
    Spalte = Best_Spalte;
    Spielbrett [Reihe][Spalte] = 1;
    Zug_ausfueren();
    Spieler = 1;
    Cursor = 0;
    // gewonnen ? .............................................
    Vier_in_Reihe (4);
}

// Nach 4er-Kombination suchen --------------------------------------------
void Vier_in_Reihe (int Wert) {
  int Summe = 0;

  for (int i=-3; i<1; i++) {
    Summe = Summe_Punkte_horizontal (Reihe, Spalte+i);
    if (Summe == Wert) { Game_is_over = 1; } }
        
  for (int i=-3; i<1; i++) {
    Summe = Summe_Punkte_vertikal (Reihe+i, Spalte);
    if (Summe == Wert) { Game_is_over = 1; } }

  for (int i=-3; i<1; i++) {
    Summe = Summe_Punkte_diagonal_L (Reihe+i, Spalte+i);
    if (Summe == Wert) { Game_is_over = 1; } }
      
  for (int i=-3; i<1; i++) {
    Summe = Summe_Punkte_diagonal_R (Reihe-i, Spalte+i);
    if (Summe == Wert) { Game_is_over = 1; } }      
}

// ------------------------------------------------------------------------
int Summe_Punkte_horizontal (int R, int S) {
  int Summe = 0;
  for (int i=S; i<S+4; i++) { Summe = Summe + Spielbrett [R][i]; }
  return Summe;
}

// ------------------------------------------------------------------------
int Summe_Punkte_vertikal (int R, int S) {
  int Summe = 0;
  for (int i=R; i<R+4; i++) { Summe = Summe + Spielbrett [i][S]; }  
  return Summe;
}

// ------------------------------------------------------------------------
int Summe_Punkte_diagonal_L (int R, int S) { 
  int Summe = Spielbrett [R][S] + Spielbrett [R+1][S+1] + Spielbrett [R+2][S+2] + Spielbrett [R+3][S+3];
  return Summe;
}

// ------------------------------------------------------------------------
int Summe_Punkte_diagonal_R (int R, int S) {
  int Summe = Spielbrett [R][S] + Spielbrett [R-1][S+1] + Spielbrett [R-2][S+2] + Spielbrett [R-3][S+3];
  return Summe;
}

// Zug ausführen **********************************************************
void  Zug_ausfueren () {
  for (int i = 4; i < Reihe+1; i++) {
    Feld_Nummer = (i-4)*8 + (Spalte-3) - 1;
    for (int j=1; j<4; j++) {
      strip.setPixelColor(Feld_Nummer, 0, 0, 255);
      strip.show(); delay (50);
      strip.setPixelColor(Feld_Nummer, 0, 0, 0);
      strip.show(); delay(50); } }
  // Rot Arduino  .............................................
  if (Spielbrett [Reihe][Spalte] == 1) { strip.setPixelColor(Feld_Nummer, 255, 0, 0); }
  // Grün Spieler  ............................................
  if (Spielbrett [Reihe][Spalte] == 5) { strip.setPixelColor(Feld_Nummer, 0, 255, 0); }
  strip.show();
  }
      
         


Kurzvideo

Kurzvideo


Spiele


Google-Suche auf MEINE-SCHALTUNG.de :


Home Impressum Datenschutz