Werte in Arrays vergleichen

Hallo liebe Community,

ich bin gerade dabei ein 4Gewinnt zu programmieren. Nun habe ich aber ein Problem, und zwar möchte ich die Leds in ein Array eintragen und dann vergleichen

int spalte1[] = {0, 0, 0, 0, 0, 0, 0, 0};

spalte1[x1]=1;

if (spalte1[x1]==spalte1[x1-1]==spalte1[x1-2])
{
pixels.setPixelColor(27,pixels.Color(brightness,0,brightness));
}

doch so wie ich glaube, dass es stimmt funktioniert es nicht.
wisst ihr woran es liegen könnte.
mit freundlichen Grüßen SparZan

Und ich kann nicht erkennen, was es werden soll.

memcmp() suchst du nicht? Oder?

if (spalte1[x1]==spalte1[x1-1]==spalte1[x1-2])

Zuerst würde ich mal ein 2 dimensionales Array für die ganze Spielfläche anlegen.

Viergewinnt = [7][6]; mit dem Orsprung (0,0) links unten.

Dann ist ein Vergleichen in 4 Richtungen notwendig: Waagerecht (x ändern) Senkrecht (y ändern) diagonal aufsteigend (x und y änden sich positiv) und diagonal absteigend (x ändert sich positiv, y negativ)

Sagen wir daß 0 ein unbelegtes Feld ist, 1 ist der erste Spieler und 2 der 2.Spieler.
Du fängst links unten an und schaust ob nicht 0 ist.
Ist dort 1 oder 2 kontrollierst Du ob die benachbarten Felder 1 bzw 2 sind. Benachbart zu pos(x,y) sind pos (x+1,y), pos(x,y+1) pos(x+1,y+1) pos(x+1,y-1) sofern die Werte im Spielfeld (0,0), (0,6), (5,0) und (5,6) nicht überschritten wird.

Wenn Du mehrere Werte vergleichen willst dann mußt Du das über logische Verküpfungen machen (&& || und !) und nicht über mehrmaliges ==
also nicht a==b==c sondern (a==b)&& (a==c)

Grüße Uwe

Hi

Auch musst Du nicht immer das ganze Spielfeld prüfen - es reicht völlig, ob der aktuell gesetzte Stein eine 4-er Reihe (oder mehr) bildet.
Dafür vom gesetzten Stein in beide Richtungen (je Richtung) die Anzahl an Steine zählen, Die die gleiche Farbe haben.
Bei Waagerecht zähle ich also nach Links, bis ein Feld kommt, daß nicht in meiner Farbe ist (oder das Ende des Spielfeld erreicht), nach links das Gleiche.
Wenn die Anzahl in die eine Richtung + die Anzahl in die andere Richtung + 1 >= 4 ist, habe ich gewonnen.
Das Auszählen kann man schön in eine Funktion auslagern, Die Dir die maximal zusammenhängenden Steine zurück gibt, dafür übergibst Du Dieser die aktuelle Stein-Position.
Intern rennt Diese dann alle 4 Richtungen beidseitig ab, das Maximum wird gemerkt und am Schluss zurück gegeben.

Das könnte man sogar so bauen, daß man damit auch das Spielfeld füllt - Rückgabe 0 wäre 'Feld ist bereits vom Gegner besetzt' - Alles oberhalb sind 'x Steine in Reihe'.

MfG

Hallo, erstmal ein reisen großes Dankeschön, dass ich so schnell so viele Antworten bekommen hab.
ich habe schon nach memcmp() geschaut und komplett den Überblick verloren. Also denke ich, ich habe das mit den Logischen Verknüpfungen vollig falsch gemacht und bedanke mich deswegen bei unserem Moderator. nur verstehe ich noch nicht ganz wie ich von einer 7*8 matrix auf ein zweidimensionales array kommen soll?

Eine 7*8 Matrix ist bereits ein zweidimensionales Array.

byte matrix[zeilen][spalten]

Wenn Du negative Werte brauchst, nimm anstelle von byte char.

Gruß Tommy

Hi

Genau so :slight_smile:
Du speicherst die Steine in einem Feld[7][8];
Eine Klammer ist X, die Andere Y.

So kannst Du auch 'durch die Positionen gehen' - indem Du eben die Werte für X/Y veränderst.
Bei Waagerecht würde Y gleich bleiben und X würde herunter gezählt, bis ein Feld nicht in meiner Farbe gefunden wird und danach von der Steinposition hoch gezählt.

MfG

Da dies nun mein erstes mal ist das ich mit einem zweidimensionalen Array programmiere wollte ich fragen ob es so stimmt was ich gemacht hab. dies ist bis jetzt nur der Befehl das er die LEDs runterfallen lässt (funktioniert einwandfrei) und das er die in das Array einträgt

int s1=0;
int s2=16;
int s3=15;
int s4=32;
int s5=31;
int s6=48;
int s7=47;


int y=7;
int x=6;


byte spielfeld[8][7] = {
  {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},
  };


void Spieler1spielt()
{
  if (tasterGedrueckt(taster1))
{
  spielfeld[y][1] = 1;
  for(int i = 7; i > s1; i--)
  {
    pixels.setPixelColor(i, pixels.Color(0,brightness,0)); 
    pixels.setPixelColor(i+1, pixels.Color(0,0,0)); 
    pixels.show(); 
    delay (100);
  if (i==s1)
    {
    pixels.setPixelColor(i,pixels.Color(0,brightness,0)); 
    }
    continue;
    }
  zustand = Spieler2;  
  s1=s1+1;
  y=y-1;
}




if (tasterGedrueckt(taster2))
{
    spielfeld[y][2] = 1;
    for(int i = 8; i < s2; i++)
  {
    pixels.setPixelColor(i, pixels.Color(0,brightness,0)); 
    pixels.setPixelColor(i-1, pixels.Color(0,0,0)); 
    pixels.show(); 
    delay (100);
    
  if (i==s2)
    {
    pixels.setPixelColor(i,pixels.Color(0,brightness,0));   
    }
    continue;
  }
  zustand = Spieler2;
  s2 = s2-1;
  y=y-1;
}

Hi

So ganz ohne Kommentar sehe ich Da - mit Mühe - 7 Reihen oder Spalten - was mir die Zahlen sagen sollen, vermag ich aber nicht zu verstehen.
Auffällig 16,32,48 und jeweils 'Einer Weniger' - Was Das aber bezwecken soll, ist mir völlig schleierhaft.

Gewöhne Dir an, Kommentare zu schreiben.
NICHT, was Da steht
also s3 den Wert 15 zuweisen ... Das ist ein schlechter Kommentar - DAS sehe ich selber!
Was Du mit der Zuweisung bezweckst gehört in den Kommentar.

Dann noch - s1...s7 sind durchnummerierte Variablen - Das ist zumindest 'unschön'.
Wird INT benötigt? (-32768...32767)
byte s[]={0,16,16,32,31,48,47};
Da kannst Du mit s[0]...s[6] drauf zugreifen - sollten wir diese 's' brauchen.

MfG

Habe ich das mit dem Eingeben in das Zweidimensionale Array richtig gemacht?

byte s[]={0,16,15,32,31,48,47};       //Variablen für das "herrunterfallen" der LEDs


int y=7;                                          //Höhe des Spielfelds
int x=6;                                          //Breite des Spielfelds, eins weniger da das Array bei 0 anfängt zu zählen


int brightness=255; //helligkeit der Farbe

byte spielfeld[8][7] = {    //Spielfeld als Array
  {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},
  };


  if (tasterGedrueckt(taster1))
{
  spielfeld[y][1] = 1;                 //wo in dem Arrray muss Spieler 1 eingetragen werden
  for(int i = 7; i > s[0]; i--)       //herrunterfallen der LED, zahlt bis zum Ende der Reihe
  {
    pixels.setPixelColor(i, pixels.Color(0,brightness,0)); 
    pixels.setPixelColor(i+1, pixels.Color(0,0,0));         //hintere LED ausschalten "Drop-Effekt"
    pixels.show(); 
    delay (100);
  if (i==s[0])                        //LED leuchten lassen wennn diese unten angekommen ist
    {
    pixels.setPixelColor(i,pixels.Color(0,brightness,0)); 
    }
    continue;                         //for-Schleife beenden
    }
  zustand = Spieler2;     // anderer Spieler ist an der Reihe --> zustand wechseln
  s[0]=s[0]+1;            //Die "Länge" des spielfeldes um 1 verringern, da dort eine Led ist
  y=y-1;                  //Die "Länge" des spielfeldes um 1 verringern, da dort eine Led ist für des zweidimensionale Array
}

Globale Variablen müssen nicht mit 0 initialisiert werden. Es ist nicht falsch, aber das geschieht automatisch

Hallo, eine Frage noch, würde dass so eventuell funktionieren?? Und wenn nicht wie dann?!

if ((spielfeld[y][1]==spielfeld[y-1][1])&&(spielfeld[y][1]==spielfeld[y-2][1])&&(spielfeld[y][1]==spielfeld[y-3][1]))
{
  Gewinner ausgeben
}

Hi

Das ist mir zu kompliziert!
Dein Code oben ist SO bestimmt nicht komplett - Du musst Dich Da bereits innerhalb einer Funktion befinden, sonst kannst Du nicht mit den Variablen arbeiten.

Was spricht gegen meinen Weg weiter oben?
Gegeben X/Y des aktuellen Spielstein (also schon nach Unten gefallen).
Diese Position ist Deine Start-Position.
Ab hier zählst Du für alle 4 Möglichkeiten, wie viele Steine 'am Stück' liegen.
Für jede der 4 Möglichkeiten (Senkrecht, Waagerecht, Diagonal steigend, Diagonal fallend) zählst Du in beide Richtungen, ob Da Steine gleicher Farbe liegen.
Wenn Ja -> +1
Wenn Nein -> hier fertig

Du übergibst Deiner Prüf-Funktion die aktuelle Position des Spielstein und die Such-Richtung.
byte anzahl=count(byte x,byte y,char xp,char yp,byte farbe);
Wobei x/y die Koordinaten sind und xp/yp die Increments - für Waagerecht wäre XP=1, YP=0.
Die Funktion prüft, ob das Feld x/y leer ist, wenn nicht, wird 0 zurück gegeben - ungültiger Zug.
Wenn das Feld leer war, ist Es Jetzt besetzt :slight_smile:
Nun prüfst Du in der Richtung XP/YP, ob dieses Feld ebenfalls in der eigenen Farbe ist - so lange, bis Du aus dem Spielfeld heraus kommst, oder eine andere Farbe (oder leeres Feld) findest.
Dann das Ganze mit negativen XP/YP - also in die andere Richtung.
Beide Male wirst Du eine Anzahl an gleicher Steine finden - oder eben nicht.
Die Zahlen reichen von 0 (in dieser Richtung ist kein weiterer Stein) bis 7 (viel mehr Felder gibt's halt nicht).
Diese beiden Anzahlen addierst Du und erhöhst um 1 - der aktuelle Stein wurde ja zuvor noch nicht mitgezählt.
So bekommst Du von der Funktion einen Wert im Bereich 0...7 zurück - wenn der Wert 0 ist, ist's ein ungültiger Zug - das Feld gehört schon jemandem!
Bei <4 hat man noch nicht gewonnen.
Bei >3 hat man soeben gewonnen.

Bin gerade dabei, meine VM zur IDE zu exportieren ... die virtuelle Platte ist zu klein geworden ... sonst hätte ich Das in etwas Code gegossen ...

MfG

Hi

Etwas Code wäre nicht schlecht,wenn du es noch hinbekommst, denn ich bin mit so viel Text als Anfänger ein bisschen überfordert.

Ich danke Dir auf jeden Fall jetzt schon für die Mühe die du dir machst um mir bei meinem Problem Hilfe zu leisten. Ist es in Ordnung für dich, wenn ich dich in meiner Danksagung erwähne, da du bis jetzt schon sehr viel geholfen hast.

Mfg

Hi

//Forensketch
//Beitrag https://forum.arduino.cc/index.php?topic=692819.msg4657591#msg4657591
//4-Gewinnt

enum farbe {frei = 0, Spieler_1, Spieler_2};
const byte Spielfeldbreite = 7;
const byte Spielfeldhoehe = 8;

byte spielfeld[Spielfeldbreite][Spielfeldhoehe]; //das Spielfeld wird mit 0=frei initialisiert

void setup() {
  // put your setup code here, to run once:
  Serial.begin(57600);
  char counter = 0;
  Serial.println("Spieler 1 setzt 5/7");
  counter = count(5, 7, 0, 1, Spieler_1); //Spieler 1 setzt Stein 5/7 -> 1 - Prüfung senkrecht
  printnummer(counter);
  Serial.println(" Steine senkrecht");
  counter = count(5, 7, 1, 0, Spieler_1); //Spieler 1 setzt Stein 5/7 -> -1 - Prüfung waagerecht
  printnummer(counter);
  Serial.println(" Steine waagerecht");
  counter = count(5, 7, 1, 1, Spieler_1); //Spieler 1 setzt Stein 5/7 -> -1 - Prüfung diagonal
  printnummer(counter);
  Serial.println(" Steine diagonal 1");
  counter = count(5, 7, -1, 1, Spieler_1); //Spieler 1 setzt Stein 5/7 -> -1 - Prüfung diagonal, andere Richtung
  printnummer(counter);
  Serial.println(" Steine diagonal 2");
  //negative Rückgabe, da das Startfeld bereits gesetzt war

  Serial.println("Spieler 2 setzt 5/7");
  counter = count(5, 7, 0, 1, Spieler_2); //Spieler 2 setzt Stein 5/7 -> 0 Spielfeld ist bereits vom Gegner besetzt
  printnummer(counter);
  Serial.println(" 0-> Feld bereits besetzt");
  Serial.println("Spieler 2 setzt 6/7");
  counter = count(6, 7, 0, 1, Spieler_2); //Spieler 2 setzt Stein 6/7 -> 1 - Prüfung senkrecht
  printnummer(counter);
  Serial.println(" Steine senkrecht");
  //... andere prüfungen für Spieler 2

  Serial.println("Spieler 1 setzt 4/7");
  counter = count(4, 7, 0, 1, Spieler_1); //Spieler 1 setzt Stein 4/7 -> 1 - Prüfung senkrecht
  printnummer(counter);
  Serial.println(" Steine senkrecht");
  counter = count(4, 7, 1, 0, Spieler_1); //Spieler 1 setzt Stein 4/7 -> -2 - Prüfung waagerecht
  printnummer(counter);
  Serial.println(" Steine waagerecht");
  counter = count(4, 7, 1, 1, Spieler_1); //Spieler 1 setzt Stein 4/7 -> -1 - Prüfung diagonal
  printnummer(counter);
  Serial.println(" Steine diagonal 1");
  counter = count(4, 7, -1, 1, Spieler_1); //Spieler 1 setzt Stein 4/7 -> -1 - Prüfung diagonal, andere Richtung
  printnummer(counter);
  Serial.println(" Steine diagonal 2");
  //Bei der Prüfung waagerecht kam als Maximum '-2' raus - der Spieler hat 2 Steine 'am Stück'
}

void loop() {
  // put your main code here, to run repeatedly:
}


//Funktion zählt ab übergebenem Punkt in die Richtung XP/YP
//bzw. Deren Gegenrichtung die Anzahl der von uns besetzten Felder
//Rückgaben:
//0 Feld ist dem Gegner
//1...127 Anzahl an zusammenhängenden Spielsteinen, Feld eingenommen
//-1...-127 Anzahl an zusammenhängenden Spielsteinen, Feld war bereits uns
char count(byte x, byte y, char xp, char yp, farbe spielerfarbe) {
  //Funktion zählt ab x/y in den Richtungen
  //senkrecht/waagerecht/diagonal steigend/fallend
  //die Anzahl an gleicher Farben auf den Spielfeldern
  char counter = 0;
  if (spielfeld[x][y] == 0 || spielfeld[x][y] == spielerfarbe) {
    //Das Spielfeld ist noch unbesetzt
    //oder bereits in unserem besitz - hier wird das Ergebnis negiert

    //in Richtung xp/yp Felder prüfen
    //Abbruch: wenn XP/YP außerhalb des Spielfeld
    //oder: Farbe unglweich Spielerfarbe
    char a; //lokale Hilfs-Variablen
    char b;
    for (byte durchgang = 0; durchgang < 2; durchgang++) {
//      Serial.print("Durchgang:");
//      Serial.println(durchgang);
      //1.ter Durchgang XP/YP unangetastet
      //2.ter Durchgang XP/YP negiert (= Gegenrichtung)
      if (durchgang) {
        xp = -xp;
        yp = -yp;
      }
      a = x; b = y; //Hilfsvariablen auf aktuellen Punkt setzen
      bool weiter = true; //Abbruch-Variable
      while (weiter) {
        a += xp;
        b += yp;
        Serial.print("Teste (");
        Serial.print((byte)a);
        Serial.print('/');
        Serial.print((byte)b);
        Serial.print(")= ");

        //Abbruch, wenn außerhalb des Spielfeld, oder Farbe falsch
        if (a < 0 || b < 0 || a >= Spielfeldbreite || b >= Spielfeldhoehe) {
          weiter = false;
          Serial.print("ausserhalb Spielfeld");
        } else {
          if ( spielfeld[(byte)a][(byte)b] == spielerfarbe) {
            //sonst Counter erhöhen
            Serial.print("unser Feld");
            counter++;
          } else {
            Serial.print("nicht uns");
            weiter = false;
          }
        }
        Serial.println();
      };
    }
    counter++;  //um 1 erhöhen, da das Startfeld ja ebenfalls uns ist
    if (spielfeld[x][y] == spielerfarbe) {
      //wenn das Spielfeld zuvor schon uns gehörte, Counter negieren
      //Das zeigt beim Aufruf dieser Funktion, daß das Spielfeld NICHT gesetzt wurde
      //man kann mit der Funktion also auch 'nur' Zählen
      counter = -counter;
    } else {
      //sonst Spielfeld einnehmen
      spielfeld[x][y] = spielerfarbe;
    }
  }
  return counter;
}

void printnummer(char nummer) {
  if (nummer < 0) {
    Serial.print('-');
    nummer = -nummer;
  }
  Serial.print((byte)nummer);
}

Uno/Nano:
Der Sketch verwendet 2570 Bytes (8%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 478 Bytes (23%) des dynamischen Speichers, 1570 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Viel Spaß beim Durchkauen :slight_smile:

MfG

PS: Tantiemen sind natürlich immer willkommen feix
Hoffe ja mehr, daß ich von Dir keine Voodoo-Puppe spendiert bekomme :wink:

Hi
vielen dank für den code und dein engagment mir zu helfen
MFG

PS: mit der Voodoo-Puppe bin ich noch am überlegen, oder wie wärs mit elefantenscheiße. HAHA ne spaß, ich überleg mir was.:wink:

Hi
was genau macht der Code, ich komm nicht ganz da hinter

  char counter = 0;
  Serial.println("Spieler 1 setzt 5/7");
  counter = count(5, 7, 0, 1, Spieler_1); //Spieler 1 setzt Stein 5/7 -> 1 - Prüfung senkrecht
  printnummer(counter);

MFG

Hi

  1. die Variable counter wird lokal erzeugt und mit 0 initialisiert (ZWINGEND - der Speicherplatz kann jeden Wert aufweisen)
  2. Ausgabe für mich, daß ich meiner Funktion sagem daß Spieler 1 das Feld 5/7 einnehmen will
  3. Die Funktion count(x,y,xp,yp,farbe) prüft
  • ist das aktuelle Feld leer? (dann nehmen wir Das ein)
  • ist das aktuelle Feld von mir besetzt? (dann wird das Ergebnis negativ zurück gegeben als 'uns, aber nicht neu gesetzt)
  • ist das aktuelle Feld vom Gegner besetzt? (dann wird 0 zurück gegeben)
    In den ersten zwei Fällen wird also gezählt, wie viele Spielsteine wir jetzt in Reihe haben.
    Die Suchrichtung gibt xp und yp (x-plus / y-plus) vor.
    In diesem Fall xp=0 -> also keine Veränderung von X
    yp=1 -> Y wird hochgezählt.
    Nun wird immer x+=xp;y+=yp; gerechnet, bis das erreichte Feld NICHT mehr unsere Farbe hat oder außerhalb der Spielfeld liegt.
    Im 2.ten Durchgang wird die Suchrichtung umgedreht (Durchgang==1).
    Also xp bleibt 0, yp wird zu -1.
    Jetzt gehen wir die Spielfelder in Gegenrichtung ab, wieder so lange, bis die Farbe NICHT Unserer entspricht oder wir außerhalb des Spielfeld kommen.
    Dann wird noch +1 gerechnet, da das aktuelle Feld in der Zählerei nicht vorkommt, Dieses aber uns ist (wenn's zuvor leer oder uns war - aber anders wären wir nicht 'hier').
    Nun haben wir also die Anzahl der zusammenhängenden Spielsteine in dieser Richtung (und Gegenrichtung) gezählt.
    Nun wird noch geprüft, ob das Feld leer ist - ja, dann setzen wir das Feld in unserer Farbe.
    Nein? Dann ist das Feld bereits uns - das gezählte Ergebnis wird negiert als Zeichen dafür, daß das Feld bereits uns war und wir hier 'nur' gezählt haben.

In der letzten Zeile wird der Wert als Zahl ausgegeben - hier erweist Es Sich als blöd, daß char NICHT als Zahlen ausgegeben werden - ein char(0) ist das Leerzeichen ASCII-Code 0, erst ab 32 kommen Da druckbare Zeichen raus - deshalb die Zusatz-Funktion, Die ein Minus ausgibt, wenn der char-Wert <0 ist und dann den char-Wert als Byte (cast) ausgeben lässt - Bytes werden als Zahlen ausgegeben, deshalb der Cast.

Die vier Prüfungen könnte man noch auslagern und nur das Setzen des Feld übergeben, aka

char setzeFeld(byte x,byte y,farbe spielerFarbe){
   char ergebnis =count(x,y,0,1,spielerFarbe); //senkrecht
   bool neu=false;
   if (ergebnis){
      //das Ergebnis ist != 0, also das Feld ist (spätestens JETZT) uns
      if (ergebnis>0){
         ergebnis=-ergebnis; //umdrehen zum Vergleich
         neu=true;
      }
      char ergebnis2=count(x,y,1,0,spielerFarbe); //waagerecht - ergibt negativen Wert
      ergebnis=min(ergebnis,ergebnis2);
      ergebnis2=count(x,y,1,0,spielerFarbe); //waagerecht
      ergebnis=min(ergebnis,ergebnis2);
      ergebnis2=count(x,y,1,1,spielerFarbe); //diagonal 2
      ergebnis=min(ergebnis,ergebnis2);
      ergebnis2=count(x,y,1,-1,spielerFarbe); //diagonal 2
      ergebnis=min(ergebnis,ergebnis2);
      if (neu) ergebnis=-ergebnis;  //wenn das Feld neu besetzt wurde, wieder 'umdrehen'
   }
   return ergebnis;
}
//Die Rückgabe wäre jetzt 0, wenn das Feld vom Feind besetzt ist
//>0, wenn wir das Feld neu besetzt haben
//<0, wenn wir das Feld schon besetzt hatten
//beim normalen Spielverlauf muß diese Rückgabe also Positiv sein,
//da Jeder nur auf noch freie Felder setzen darf

MfG

Edit 1x xp->yp (typo)

Hi
perfekt danke jetzt wird mir einiges klarer
MFG

ZWINGEND - der Speicherplatz kann jeden Wert aufweisen

Die zweite Hälfte ist zwar richtig, aber ...
Der Wert von counter wird erstmals mit dem Ergebnis der Funktion count(...) beschrieben und vorher nicht verwendet. Der Compiler wird also die ÜBERFLÜSSIGE Initialisierung =0 ignorieren.

:slight_smile: