Sicherheitsmodule von Pilz


Google-Suche auf MEINE-SCHALTUNG.de :





Dauerkalender


Vier in eine Reihe


Spielfeld


„Vier in eine Reihe“ ist ein Kreis-Kreuz-Strategiespiel für zwei Personen. Man könnte sagen, bei dem Spiel handelt es sich um eine erweiterte Version des Klassikers Tic-Tac-Toe oder um eine abgespeiste Version des Spiels „Fünf in einer Reihe, das auch unter den Namen Gomoku bekannt ist. In dem Beispiel konstruieren wir das Spiel so, dass einer der Spieler durch einen Mikrocontroller (hier Arduino Nano) ersetzt wird. Die Regeln bleiben erhalten. Jedem Spieler wird ein bestimmtes Zeichen (Kreuz oder Kreis) zugeordnet. Abwechselnd platzieren die Spieler ihre Kreuze und Kreise auf dem Spielbrett (hierzu wird meistens kariertes Papier verwendet), bis es einem gelingt, vier seiner Zeichen in einer Reihe zu bekommen. Damit wird er zum Gewinner und das Spiel ist beendet. Bei der nächsten Runde werden meistens die Rollen getauscht und diesmal eröffnet der zweite Spieler mit seinem Zeichen das Spiel.

RGB-Matrix CJMMU

8x8 RGB-Matrix CJMMU


Ein solches Vorhaben kann schnell zu einer anspruchsvollen und aufwendigen Angelegenheit werden. In dem Beispiel wird allerdings nur das notwendigste gemacht. Der Spieler Mensch soll einen gewöhnlichen Spieler als Gegner bekommen, der gelegentlich auch verlieren kann. Auf jedem Fall soll sichergestellt werden, dass der Mensch, sollte er während des Spiels nicht mit Herz und Seele dabei sein, gnadenlos niedergeschmettert wird.

Testschaltung

Testschaltung auf Platine (Frontansicht)


Die Schaltung samt Programm stellt nur einen Grundriss für die Ausführung eines solchen Spiels dar. Wir verzichten hier auf eine Reihe von Zusatzfunktionen, die das Spiel sicher interessanter und attraktiver machen würden. Man könnte die Schaltung z.B. um die Funktion „Wer beginnt“ oder „Farbenauswahl“ erweitern. Auch die Punkte-Vergabe bei internen Berechnungen könnte man ohne Weiteres weiter verfeinern. In dem Beispiel bezieht sich das Programm ausschließlich auf seine eigenen Züge. Das reicht jedoch, um für ausreichend Verwirrung auf dem Spielbrett zu sorgen, vollkommen aus. Alle möglichen Erweiterungen, Verbesserungen und Optimierungen des Programms oder gar einen Ausbau zu dem großen Bruder „Fünf in eine Reihe“ kann jeder begeisterte Hobby-Programmierer selbst in Angriff nehmen.

Rückseite

Rückseite. Verdrahtungsaufwand ist überschaubar.


Für die erforderliche Schaltung sind nur wenige Komponenten notwendig. Als Spielbrett dient eine 8x8 RGB-Matrix (CJMMU). Den beiden Spielern werden nicht wie gewöhnlich Kreuz und Kreis zugeordnet, sondern Farben. In dem Beispiel spielt Arduino mit der roten Farbe, der Gegenspieler bekommt die grüne Farbe. Das „Denken“ übernimmt Arduino Nano. Beide Komponenten sind für kleine Geldbeträge im Handel erhältlich. Zusätzlich muss man für eine stabile und leistungsfähige Spannungsversorgung sorgen. Jede RGB-Diode kann bei voller Ansteuerung einen Strom von bis zu 50 mA ziehen. Hier kommt ein fertiges Spannungsregler-Modul zum Einsatz, der bei Bedarf 3A liefern kann.
Alle Teile kann man für Testzwecke auf einer Platine montieren.

Schaltplan

Schaltplan

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

Das Programm

Grundsätzlich besteht das Programm (in der Welt des Arduino Sketch genannt) aus zwei Hauptteilen. In dem ersten Teil bekommt der Gegenspieler die Möglichkeit, seinen Zug zu absolvieren. In dem zweiten Teil wird über die angemessene Antwort „nachgedacht“.
Den ersten Zug führt der Computer aus. Eine andere Möglichkeit in dieser Grundausführung gibt es nicht. Eine Erweiterung des Programms wäre hier durchaus sinnvoll. Sobald der Zug ausgeführt wurde, ist der Gegenspieler am Zug. Mit Cursortasten kann er den Cursor auf eine beliebige Stelle des Spielbrettes führen und dort, indem er die Enter-Taste betätigt, seinen Zug bestätigen.
Nachdem der Zug ausgeführt wurde, beginnt das Programm die Überlegungen über seine Antwort. Im Hintergrund arbeitet das Programm mit einer 14x14 Matrix. Dank dessen gibt es keine Kollisionen bei Berechnungen, die auch außerhalb des eigentlichen Spielfeldes stattfinden.
Das Programm durchsucht alle Felder und nimmt sich diese vor, die frei sind und mindestens an ein besetztes Feld angrenzen. Für jedes Feld werden alle 4er-Kombinationen, an welchen es teilnehmen könnte, untersucht. Anschließend werden die Ergebnisse, auch unter Berücksichtigung möglicher Kreuzungen, miteinander verglichen. Als Ergebnis bekommt das gerade untersuchte Feld eine Wertung. Diese Wertung entscheidet dann schließlich, ob ein Zug auf diesem Feld stattfindet oder nicht.
In dem Verfahren werden ausschließlich eigene Züge berücksichtigt. Mit einem zusätzlichen Programmierungsaufwand könnte man das Programm erweitern und bei der Wertung auch die Züge des Gegners berücksichtigen.

Bibliothek

Damit das Programm funktioniert, muss die Bibliothek "Adafruit NeoPixel" V1.4.0 installiert werden.


// ************************************************************************
// Vier in eine Reihe
// Mit RGB-Matrix CJMCU und Arduino Nano
// IDE 1.8.12
// (Grundstock)
// ************************************************************************
#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_Rauf = 6;
int Taste_Rechts = 3;
int Taste_Runter = 4;
int Taste_Enter = 5;
int Spielende = 8;

// Variablen ..............................................................
int Spielbrett [14][14];
int Spieler = 0;
int Reihe = 0;
int Spalte = 0;
int Feld_Nummer = 0;
int Cursor = 0;
int CursorReihe = 0;
int CursorSpalte = 0;
int Game_is_over = 0;

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

// HAUPTPROGRAMM **********************************************************
void loop() {

  if (Game_is_over == 0) {
    switch (Spieler) {
      case 0: { Ich_beginne(); break; }
      case 1: { Spieler_am_Zug(); break; }
      case 2: { Mein_Zug(); break; } }
  }
  Spielbrett_Anzeigen();
  if (Game_is_over == 1) {
    do {
      digitalWrite (Spielende, HIGH);
      delay(500);
      digitalWrite (Spielende, LOW);
      delay(500);
    } while (Game_is_over == 0); }
}

// Programm Start ---------------------------------------------------------
void Ich_beginne() { 
  Spielbrett [8][8] = 1;
  Spieler = 1;
}

// Spielbrett anzeigen ----------------------------------------------------
void Spielbrett_Anzeigen() {
  for (Reihe = 4; Reihe < 12; Reihe++) { 
    for (Spalte = 4; Spalte < 12; Spalte++) {
      Feld_Nummer = (Reihe-4)*8 + (Spalte-3) - 1;
      // Leer (Aus)
      if (Spielbrett [Reihe][Spalte] == 0) { strip.setPixelColor(Feld_Nummer, 0, 0, 0); }
      // Rot Arduino
      if (Spielbrett [Reihe][Spalte] == 1) { strip.setPixelColor(Feld_Nummer, 255, 0, 0); }
      // Grün Spieler
      if (Spielbrett [Reihe][Spalte] == -10) { strip.setPixelColor(Feld_Nummer, 0, 255, 0); }
      // Blau Cursor
      if (Spielbrett [Reihe][Spalte] == 100) { strip.setPixelColor(Feld_Nummer, 0, 0, 255); } }}
  strip.show();  
}

// Spieler am Zug ---------------------------------------------------------
void Spieler_am_Zug() {
  if (Cursor == 0) {
    do {
      Reihe = random (4,12);
      Spalte = random (4,12);  
    } while (Spielbrett [Reihe][Spalte] != 0);
    Cursor = 1;
    Spielbrett [Reihe][Spalte] = 100;
    CursorReihe = Reihe;
    CursorSpalte = Spalte;
  }
  if (Cursor == 1) {
    if (digitalRead(Taste_Links) == LOW) {
      delay (300);
      for (int i = CursorSpalte; i > 3; i--) {
        if (Spielbrett [CursorReihe][i] == 0) {
          Spielbrett [CursorReihe][CursorSpalte] = 0;
          Spielbrett [CursorReihe][i] = 100;
          CursorSpalte = i;
          break; } }
    }

    if (digitalRead(Taste_Rechts) == LOW) {
      delay (300);
      for (int i = CursorSpalte; i < 12; i++) {
        if (Spielbrett [CursorReihe][i] == 0) {
          Spielbrett [CursorReihe][CursorSpalte] = 0;
          Spielbrett [CursorReihe][i] = 100;
          CursorSpalte = i;
          break; } }
    }    

    if (digitalRead(Taste_Rauf) == LOW) {
      delay (300);
      for (int i = CursorReihe; i > 3; i--) {
        if (Spielbrett [i][CursorSpalte] == 0) {
          Spielbrett [CursorReihe][CursorSpalte] = 0;
          Spielbrett [i][CursorSpalte] = 100;
          CursorReihe = i;
          break; } }
    }    

    if (digitalRead(Taste_Runter) == LOW) {
      delay (300);
      for (int i = CursorReihe; i < 12; i++) {
        if (Spielbrett [i][CursorSpalte] == 0) {
          Spielbrett [CursorReihe][CursorSpalte] = 0;
          Spielbrett [i][CursorSpalte] = 100;
          CursorReihe = i;
          break; } }
    }    

    if (digitalRead(Taste_Enter) == LOW) {
      delay (500);
      Spielbrett [CursorReihe][CursorSpalte] = -10;
      Cursor = 2;
      Spieler = 2;
      Vier_in_Reihe (CursorReihe, CursorSpalte, -40);
    }    
  }
}

// Computer am Zug --------------------------------------------------------
void Mein_Zug() {
  int Punkte_horizontal;
  int Punkte_vertikal;
  int Punkte_diagonal_L;
  int Punkte_diagonal_R;
  int Punkte_Zahl = 0;
  int Best_Punkte = 0;
  int Best_Reihe = 0;
  int Best_Spalte = 0;
  int Punkte_addiert;
  
  
    // Alle Felder durchsuchen ............................................
    for (Reihe = 4; Reihe < 12; Reihe++) { 
      for (Spalte = 4; Spalte < 12; Spalte++) {
        // nur Freie Plätze suchen ........................................
        if (Spielbrett [Reihe][Spalte] == 0) {
          // Nachbarschaft prüfen .........................................
          int Nachbarschaft = Spielbrett [Reihe][Spalte - 1] +
                            Spielbrett [Reihe][Spalte + 1] +
                            Spielbrett [Reihe - 1][Spalte] +
                            Spielbrett [Reihe - 1][Spalte - 1] +
                            Spielbrett [Reihe - 1][Spalte + 1] +
                            Spielbrett [Reihe + 1][Spalte] +
                            Spielbrett [Reihe + 1][Spalte - 1] +
                            Spielbrett [Reihe + 1][Spalte + 1];
          // Feldbewertung ................................................
          if (Nachbarschaft != 0) {                   
            Punkte_horizontal = 0;
            Punkte_addiert = Summe_Punkte_horizontal (Reihe, Spalte-3);
            if (Punkte_addiert > Punkte_horizontal) { Punkte_horizontal = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_horizontal (Reihe, Spalte-2);
            if (Punkte_addiert > Punkte_horizontal) { Punkte_horizontal = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_horizontal (Reihe, Spalte-1);
            if (Punkte_addiert > Punkte_horizontal) { Punkte_horizontal = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_horizontal (Reihe, Spalte);
            if (Punkte_addiert > Punkte_horizontal) { Punkte_horizontal = Punkte_addiert; }

            Punkte_vertikal = 0;
            Punkte_addiert = Summe_Punkte_vertikal (Reihe-3, Spalte);
            if (Punkte_addiert > Punkte_vertikal) { Punkte_vertikal = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_vertikal (Reihe-2, Spalte);
            if (Punkte_addiert > Punkte_vertikal) { Punkte_vertikal = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_vertikal (Reihe-1, Spalte);
            if (Punkte_addiert > Punkte_vertikal) { Punkte_vertikal = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_vertikal (Reihe, Spalte);
            if (Punkte_addiert > Punkte_vertikal) { Punkte_vertikal = Punkte_addiert; }

            Punkte_diagonal_L = 0;
            Punkte_addiert = Summe_Punkte_diagonal_L (Reihe-3, Spalte-3);
            if (Punkte_addiert > Punkte_diagonal_L) { Punkte_diagonal_L = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_diagonal_L (Reihe-2, Spalte-2);
            if (Punkte_addiert > Punkte_diagonal_L) { Punkte_diagonal_L = Punkte_addiert; }            
            Punkte_addiert = Summe_Punkte_diagonal_L (Reihe-1, Spalte-1);
            if (Punkte_addiert > Punkte_diagonal_L) { Punkte_diagonal_L = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_diagonal_L (Reihe, Spalte);
            if (Punkte_addiert > Punkte_diagonal_L) { Punkte_diagonal_L = Punkte_addiert; }
            
            Punkte_diagonal_R = 0;
            Punkte_addiert = Summe_Punkte_diagonal_R (Reihe+3, Spalte-3);
            if (Punkte_addiert > Punkte_diagonal_R) { Punkte_diagonal_R = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_diagonal_R (Reihe+2, Spalte-2);
            if (Punkte_addiert > Punkte_diagonal_R) { Punkte_diagonal_R = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_diagonal_R (Reihe+1, Spalte-1);
            if (Punkte_addiert > Punkte_diagonal_R) { Punkte_diagonal_R = Punkte_addiert; }
            Punkte_addiert = Summe_Punkte_diagonal_R (Reihe, Spalte);
            if (Punkte_addiert > Punkte_diagonal_R) { Punkte_diagonal_R = Punkte_addiert; }          
            
            // Beste Position ermitteln ...................................
            Punkte_Zahl = 0;
            // 1 Pixel = 1 Punkt ..........................................
            if (Punkte_horizontal == 1) { Punkte_Zahl = 1; }
            if (Punkte_vertikal == 1) { Punkte_Zahl = 1; }
            if (Punkte_diagonal_L == 1) { Punkte_Zahl = 1; }
            if (Punkte_diagonal_R == 1) { Punkte_Zahl = 1; }

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

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

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

            // 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 = Spalte; }
            
          } // Feldbewertung abgeschlossen ...............................
        }   // Suche nach leeren Plätzen abgeschlossen ...................               
    } }     // komplette Durchsuchung abgeschlossen
    // Feld belegen ......................................................
    Spielbrett [Best_Reihe][Best_Spalte] = 1;
    Spieler = 1;
     Cursor = 0;
    // Haben wir etwa gewonnen ? .........................................
    Vier_in_Reihe (Best_Reihe, Best_Spalte, 4);
}

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

  Summe = Summe_Punkte_horizontal (PosReihe, PosSpalte-3);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_horizontal (PosReihe, PosSpalte-2);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_horizontal (PosReihe, PosSpalte-1);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_horizontal (PosReihe, PosSpalte);
  if (Summe == Wert) { Game_is_over = 1; }

  Summe = Summe_Punkte_vertikal (PosReihe-3, PosSpalte);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_vertikal (PosReihe-2, PosSpalte);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_vertikal (PosReihe-1, PosSpalte);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_vertikal (PosReihe, PosSpalte);
  if (Summe == Wert) { Game_is_over = 1; }
  
  Summe = Summe_Punkte_diagonal_L (PosReihe-3, PosSpalte-3);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_diagonal_L (PosReihe-2, PosSpalte-2);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_diagonal_L (PosReihe-1, PosSpalte-1);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_diagonal_L (PosReihe, PosSpalte);
  if (Summe == Wert) { Game_is_over = 1; }

  Summe = Summe_Punkte_diagonal_R (PosReihe+3, PosSpalte-3);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_diagonal_R (PosReihe+2, PosSpalte-2);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_diagonal_R (PosReihe+1, PosSpalte-1);
  if (Summe == Wert) { Game_is_over = 1; }
  Summe = Summe_Punkte_diagonal_R (PosReihe, PosSpalte);
  if (Summe == Wert) { Game_is_over = 1; }         
}

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

// ------------------------------------------------------------------------
int Summe_Punkte_vertikal (int R, int S) {
  int Summe = Spielbrett [R][S] + Spielbrett [R+1][S] + Spielbrett [R+2][S] + Spielbrett [R+3][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;
}        


Kurzvideo

Kurzvideo


Spiele


Google-Suche auf MEINE-SCHALTUNG.de :


Home Impressum Datenschutz