Arduino Mathe-Rätsel

Vor einem Jahr habe ich einen Geocache gefunden der vermutlich mit einem Arduino gebaut wurde.
Auf einer 8x8 LED-Matrix leuchteten beim einschalten 64 LED's, die von Außen nach Innen der Reihe nach aus gingen. Dann startete das Spiel mit einer zufälligen Anzahl von 59 bis 64 leuchtenden LED's. Unter der Matrix befanden sich 3 Button. Drückte man Button 1 ging eine LED aus, mit dem Button 2 zwei LED's und mit Button 3 drei LED's.
Nach jedem betätigen eines Button war der "Arduino" am Zug und löschte 1, 2 oder 3 LED's aus. Das Spiel endet wenn die Letzte LED erlischt. Hatte "Arduino" den letzten Zug kam eine Meldung auf der Matrix das man es noch mal versuchen kann. Das Spiel startet wieder von vorn. Hatte der Spieler den letzten Zug, ging eine Klappe auf und man konnte sich im Logbuch eintragen.
Jetzt habe ich vor solch einen Sketch zu schreiben.
Der Start mit den nacheinander ausgehenden LED's habe ich schon mal hin bekommen. Nun habe ich aber keinen Plan wie ich mit den Button's die LED's steuern kann. Könnt ihr mir helfen?

Hi

Du musst Dir doch eigentlich nur merken, wie viele und//oder welche LEDs noch an sind.
Je nach betätigtem Button wird 1/2/3x eine beliebige LED ausgeschaltet.

Wenn Keine mehr leuchtet, ist das Spiel vorbei - je nachdem, Wer am Zug war, Klappe oder Anzeige.

Würde wohl ein Bit-Array machen (also 8 Byte) und dort meine leuchtenden LEDs eintragen.
Zum Löschen gibt's eine Funktion, Die genau EINE LED löscht.
Wenn Das die Letzte war, wird TRUE zurück gegeben.
In der Lösch-Funktion wird eine Zufalls-Zahl 1-64 gezogen und in dem Bit-Array das x'te vorhandene Bit gesucht (sprich die zugehörige LED), das Bit gelöscht und die LED abgeschaltet.
Dabei wird auch die Anzahl der noch leuchtenden LEDs um 1 vermindert, wenn = Null, dann 'TRUE' als Returnwert.

Eine nette Idee - was man mit einer 8x8er Matrix doch Alles machen kann!

MfG

riesadiver1:
Der Start mit den nacheinander ausgehenden LED's habe ich schon mal hin bekommen.

Dann zeige den doch mal, dann können wir einschätzen, wo Du stehst.

Dein Thema könnte zunächst Tastenentprellung sein.

Wenn man das Thema Mathe-Rätsel ernst nimmt, ist ja die Frage eher nach der Gewinn-Strategie

Hi

Naja - Das Gleiche gab's früher hüstel schon in der Schule - denke, mit einer Stunde und Google wäre recht schnell klar, was man tippen muß (meine mich erinnern zu können, daß die Summe beider Züge immer identisch sein muß - da man 1-3 tippen kann, wohl 4.
Wenn der Arduino sich an diese Regel hält, hast Du keine Chance - also dürfte auf der µC-Seite eher RND Verwendung finden - wenn bei 10 Spielen 0 gewonnen wurden, bekommt der Arduino wieder einen LED-Stripe 'zum Spielen' - jetzt schon von einem 8-Biter veralbern lassen, wa? :wink:

MfG

postmaster-ino:
denke, mit einer Stunde und Google wäre recht schnell klar, was man tippen muß (meine mich erinnern zu können, daß die Summe beider Züge immer identisch sein muß - da man 1-3 tippen kann, wohl 4.

AFAIR stimmt das bis auf den letzten Zug.

riesadiver1:
Der Start mit den nacheinander ausgehenden LED's habe ich schon mal hin bekommen. Nun habe ich aber keinen Plan wie ich mit den Button's die LED's steuern kann. Könnt ihr mir helfen?

3 Buttons jeder an einem PIN, gegen GND
interne Pull-Up aktivieren ist vermutlich die einfachste Variante.

Wenn der Arduino sich an diese Regel hält, hast Du keine Chance

Gerechterweise kann man es ja so gestalten, dass der Mensch gewinnt, wenn er richtig spielt.

die Entprellerei hat mich nicht so interessiert, aber ich hab mal ein Muster mit 3 KI’s

/* *******************************************************************
  Drei streichen

  // noiasca:

  Software

  Libraries & Credits

  Hardware

  Credits

  Short
  - Computer wählt eine Zufallszahl
  - Spieler und Computer müssen abwechselnd 1-3 Punkte streichen
  - der Spieler der den letzten Punkt streicht, gewinnt

***************************************************************** */

const byte buttonPins[] = {4, 5, 6, 7};   // PIN Definition of the buttons
const byte startLower = 59;
const byte startUpper = 64;

//const byte startLower = 30;
//const byte startUpper = 40;


byte ki_defense(byte current) // defense: KI tries to win asap
{
  byte player2 = 0;
  if (current > 4 )
  {
    byte remainder = current % 4;
    if (remainder) player2 = remainder; else player2 = random(1, 4);
  }
  else if (current == 4 )  // KI knows she could loose next round
  {
    player2 = random(1, 4);
  }
  else player2 = current;
  return player2;
}

byte ki(byte current) // fun: KI tries to win when in low points
{
  byte player2 = 0;
  if (current > 7 )
  {
    player2 = random(1, 4);
  }
  else if (current > 4)
  {
    player2 = current - 4;
  }
  else if (current == 4 )  // KI knows she could loose next round
  {
    player2 = random(1, 4);
  }
  else player2 = current;

  return player2;
}

byte ki_dumm(byte current)
{
  byte player2 = 0;
  if (current > 3)
  {
    player2 = random(1, 4); // das ist keine Intelligenz für den Computer!!!
  }
  else player2 = current;

  return player2;
}


void do_game()
{
  // startzahl festlegen
  byte availablePoints = random(startLower, startUpper);
  Serial.print(F("Start with ")); Serial.println(availablePoints);

  while (availablePoints > 0)
  {
    // Auf Bedienereingabe warten
    Serial.println(F("Player 1: Choose 1, 2 or 3 "));

    // warten bis wieder alle buttons high sind
    while (!(digitalRead(buttonPins[0]) && digitalRead(buttonPins[1]) && digitalRead(buttonPins[2])))
    {
    }
    delay(50);

    while (digitalRead(buttonPins[0]) && digitalRead(buttonPins[1]) && digitalRead(buttonPins[2]))
    {
    }
    delay(50);
    byte player1 = 0;
    if (!digitalRead(buttonPins[0]))  player1 = 1;
    else if (!digitalRead(buttonPins[1]))  player1 = 2;
    else if (!digitalRead(buttonPins[2]))  player1 = 3;
    // warten bis wieder alle buttons high sind
    while (!(digitalRead(buttonPins[0]) && digitalRead(buttonPins[1]) && digitalRead(buttonPins[2])))
    {
    }
    delay(50);

    // Spiel aus?
    if (player1 >= availablePoints)
    {
      Serial.println(F("Player 1: wins"));
      availablePoints = 0;
    }
    else
    {
      // Computer ziehen lassen
      Serial.print(F("Player 1: ")); Serial.print (availablePoints);
      Serial.print(F(" - ")); Serial.print (player1);
      availablePoints -= player1;
      Serial.print(F(" = ")); Serial.println(availablePoints);
      byte player2 = ki(availablePoints);
      //Serial.print(F("Player 2: ")); Serial.println(availablePoints);
      if (player2 == availablePoints)
      {
        Serial.print(F("Player 2: chooses ")); Serial.print(player2); Serial.println(F(" and wins"));
        availablePoints = 0;
      }
      else
      {
        Serial.print(F("Player 2: ")); Serial.print (availablePoints);
        Serial.print(F(" - ")); Serial.print (player2);
        availablePoints -= player2;
        Serial.print(F(" = ")); Serial.println(availablePoints);
      }
    }
  }
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(F("Drei streichen"));

  for (auto &j : buttonPins) {
    pinMode(j, INPUT_PULLUP);
  }
  randomSeed(analogRead(0));
}

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

Die Spiel-KI ist prinzipiell einfach und man kommt auch ohne Google bald drauf. Wenn man den Computer aber das von Anfang an machen lässt ist es bald durchschaut.

hier mal mit der zweiten “fun” KI ein Ablauf wo ich (Spieler 1) auch mal Fehler gemacht habe.

Player 1: Choose 1, 2 or 3 
Player 1: 60 - 1 = 59
Player 2: 59 - 3 = 56
Player 1: Choose 1, 2 or 3 
Player 1: 56 - 1 = 55
Player 2: 55 - 1 = 54
Player 1: Choose 1, 2 or 3 
Player 1: 54 - 1 = 53
Player 2: 53 - 2 = 51
Player 1: Choose 1, 2 or 3 
Player 1: 51 - 1 = 50
Player 2: 50 - 2 = 48
Player 1: Choose 1, 2 or 3 
Player 1: 48 - 1 = 47
Player 2: 47 - 1 = 46
Player 1: Choose 1, 2 or 3 
Player 1: 46 - 1 = 45
Player 2: 45 - 1 = 44
Player 1: Choose 1, 2 or 3 
Player 1: 44 - 1 = 43
Player 2: 43 - 1 = 42
Player 1: Choose 1, 2 or 3 
Player 1: 42 - 1 = 41
Player 2: 41 - 3 = 38
Player 1: Choose 1, 2 or 3 
Player 1: 38 - 1 = 37
Player 2: 37 - 1 = 36
Player 1: Choose 1, 2 or 3 
Player 1: 36 - 1 = 35
Player 2: 35 - 3 = 32
Player 1: Choose 1, 2 or 3 
Player 1: 32 - 1 = 31
Player 2: 31 - 2 = 29
Player 1: Choose 1, 2 or 3 
Player 1: 29 - 1 = 28
Player 2: 28 - 2 = 26
Player 1: Choose 1, 2 or 3 
Player 1: 26 - 2 = 24
Player 2: 24 - 2 = 22
Player 1: Choose 1, 2 or 3 
Player 1: 22 - 2 = 20
Player 2: 20 - 1 = 19
Player 1: Choose 1, 2 or 3 
Player 1: 19 - 3 = 16
Player 2: 16 - 3 = 13
Player 1: Choose 1, 2 or 3 
Player 1: 13 - 1 = 12
Player 2: 12 - 2 = 10
Player 1: Choose 1, 2 or 3 
Player 1: 10 - 2 = 8
Player 2: 8 - 3 = 5
Player 1: Choose 1, 2 or 3 
Player 1: 5 - 1 = 4
Player 2: 4 - 2 = 2
Player 1: Choose 1, 2 or 3 
Player 1: wins

Die Entprellerei ist hässlich und mit Delay, aber ich lass das mal so.

Hi

Da man hier nicht auf die ms achten muß und der Spieler ja auch noch Was von der Anzeige sehen will, habe ich hier überhaupt kein Problem mit delay().
Wäre ja blöd, wenn der Arduino zeigt, wie schnell und gut Er ist und beim ersten prellenden Tastendruck die nächsten 10 Züge gegen mich verwendet werden - und am Schlimmsten: Ich davon noch nicht Mal was sehe!!
Einzig, daß das Display dann leer ist und ich (wieder Mal) verloren habe :wink:

MfG

Wie kann ich euch meinen Sketch zeigen. Wollte ihn hier einfügen und hochladen. Meldung kam 9000 Zeichen überschritten! Bin halt ein Neuling.

ich versteh' zwar nicht ganz wie du 9000 Zeichen für einen halben Sketch verballert hast, aber mach halt ein ZIP und lade es hoch.
Wichtig ist - dass du zu allen verwendeten Libraries entsprechende LINKS setzt, ein Bild wie du es verdrahtet hast und beschreibst was jetzt nicht funktioniert wie es soll

So jetzt noch mit bisserl LED geblinke (4 mal 8x8 Modul mit Max7219)

/* *******************************************************************
  Drei streichen

  // noiasca:

  Libraries & Credits
  - LedControl https://www.arduinolibraries.info/libraries/led-control

  Hardware
  - 8x8 LED Matrix with MAX7219

  Credits

  Short
  - Computer wählt eine Zufallszahl
  - Spieler und Computer müssen abwechselnd 1-3 Punkte streichen
  - der Spieler der den letzten Punkt streicht, gewinnt

***************************************************************** */

#include "LedControl.h"  // LED Control 

const byte buttonPins[] = {4, 5, 6, 7};      // PIN Definition of the buttons
const byte DIN_PIN = 3;                      // Data in
const byte CLK_PIN = 8;                      // Clock
const byte CS_PIN = 9;                       // CS/LOAD
const byte LED_MODULES = 4;                  // ich habe 4 Module - verwendet wird aber nur das erste!!!
const byte startLower = 59;
const byte startUpper = 64 + 1;              // upper end is EXCLUDED!!!
const uint16_t delayAfterTurn = 1 * 1000UL;  // wait n Seconds after each turn
const uint16_t delayAfterGame = 5 * 1000UL;  // wait n Seconds between games

LedControl lc = LedControl(DIN_PIN, CLK_PIN, CS_PIN, LED_MODULES); //(DIN,CLK,CS,modules)

byte logic_offence(byte current) // offence: computer tries to win asap
{
  byte player2 = 0;
  if (current > 4 )
  {
    byte remainder = current % 4;
    if (remainder) player2 = remainder; else player2 = random(1, 4);
  }
  else if (current == 4 )  // computer knows she could loose next round
  {
    player2 = random(1, 4);
  }
  else player2 = current;
  return player2;
}

byte logic(byte current) // fun: computer tries to win when in low points
{
  byte player2 = 0;
  if (current > 7 )
  {
    player2 = random(1, 4);
  }
  else if (current > 4)
  {
    player2 = current - 4;
  }
  else if (current == 4 )  // KI knows she could loose next round
  {
    player2 = random(1, 4);
  }
  else player2 = current;

  return player2;
}

byte logic_null(byte current)
{
  byte player2 = 0;
  if (current > 3)
  {
    player2 = random(1, 4); // no intelligence for Computer!!!
  }
  else player2 = current;

  return player2;
}


void do_game()
{
  // startzahl festlegen
  byte availablePoints = random(startLower, startUpper);
  Serial.print(F("Start with ")); Serial.println(availablePoints);

  led_show(availablePoints);

  while (availablePoints > 0)
  {
    // Auf Bedienereingabe warten
    Serial.println(F("Player 1: Choose 1, 2 or 3 "));

    // warten bis wieder alle buttons high sind
    while (!(digitalRead(buttonPins[0]) && digitalRead(buttonPins[1]) && digitalRead(buttonPins[2])))
    {
    }
    delay(50);

    while (digitalRead(buttonPins[0]) && digitalRead(buttonPins[1]) && digitalRead(buttonPins[2]))
    {
    }
    delay(50);
    byte player1 = 0;
    if (!digitalRead(buttonPins[0]))  player1 = 1;
    else if (!digitalRead(buttonPins[1]))  player1 = 2;
    else if (!digitalRead(buttonPins[2]))  player1 = 3;
    // warten bis wieder alle buttons high sind
    while (!(digitalRead(buttonPins[0]) && digitalRead(buttonPins[1]) && digitalRead(buttonPins[2])))
    {
    }
    delay(50);

    // Spiel aus?
    if (player1 >= availablePoints)
    {
      Serial.println(F("Player 1: wins"));
      availablePoints = 0;
      led_you_win(); delay(delayAfterGame);
    }
    else
    {

      Serial.print(F("Player 1: ")); Serial.print (availablePoints);
      Serial.print(F(" - ")); Serial.print (player1);
      availablePoints -= player1;
      Serial.print(F(" = ")); Serial.println(availablePoints);
      led_show(availablePoints);
      delay(delayAfterTurn);
      // Computer ziehen lassen
      byte player2 = logic(availablePoints);
      //Serial.print(F("Player 2: ")); Serial.println(availablePoints);
      if (player2 == availablePoints)
      {
        Serial.print(F("Player 2: chooses ")); Serial.print(player2); Serial.println(F(" and wins"));
        availablePoints = 0;
        led_you_loose(); delay(delayAfterGame);
      }
      else
      {
        Serial.print(F("Player 2: ")); Serial.print (availablePoints);
        Serial.print(F(" - ")); Serial.print (player2);
        availablePoints -= player2;
        Serial.print(F(" = ")); Serial.println(availablePoints);
        led_show(availablePoints);
        delay(delayAfterTurn);
      }
    }
  }
}

void led_setup()
{
  lc.shutdown(0, false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0, 8);
  /* and clear the display */

  for (byte i = 0; i < LED_MODULES; i++)
  {
    lc.clearDisplay(i);
  }
}

void led_show(byte actual)
{
  lc.clearDisplay(0);
  byte current = 0;

  for (byte row = 0; row < 8; row++) {
    for (byte col = 0; col < 8; col++) {
      current = (row) * 8 + (col);
      //Serial.print(F("D172 current="));Serial.println(current);
      if ( current < actual)
        lc.setLed(0, row, col, true);
      else
        lc.setLed(0, row, col, false);
    }
  }
}

void led_you_win()
{
  lc.setRow(0, 7, 0b00111100); // we start in the last row - otherwise the smily is up side down ;-)
  lc.setRow(0, 6, 0b01000010);
  lc.setRow(0, 5, 0b10100101);
  lc.setRow(0, 4, 0b10000001);
  lc.setRow(0, 3, 0b10100101);
  lc.setRow(0, 2, 0b10011001);
  lc.setRow(0, 1, 0b01000010);
  lc.setRow(0, 0, 0b00111100);
}

void led_you_loose()
{
  lc.setRow(0, 7, 0b00111100);
  lc.setRow(0, 6, 0b01000010);
  lc.setRow(0, 5, 0b10100101);
  lc.setRow(0, 4, 0b10000001);
  lc.setRow(0, 3, 0b10011001);
  lc.setRow(0, 2, 0b10100101);
  lc.setRow(0, 1, 0b01000010);
  lc.setRow(0, 0, 0b00111100);
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(F("Drei streichen"));

  for (auto &j : buttonPins) {
    pinMode(j, INPUT_PULLUP);
  }
  led_setup();
  randomSeed(analogRead(0));
}

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

Überraschender Weise (für mich) lässt sich das nun noch einfacher spielen, einfach zeilenweise leer machen (nichts mehr rechnen).
Damit die Smileys passen habe ich sie einfach von unten nach oben gezeichnet, aber ich lass das mal so ;-).

Ich habe meinen Sketch total falsch angefangen. Und ich glaube das ist noch kein Projekt für einen Anfänger wie mich.
Den Sketch den du geschrieben hast, ist schon fast wie das Original. Beim Geocache musste der erste Zug auf eine durch 4 teilbare Zahl sein. Wenn man dann immer wieder auf eine durch 4 teilbare Zahl zieht öffnete sich am Ende die Klappe. Wenn der erste Zug, oder zwischendurch ein Zug falsch war, hatte man definitiv verloren und musste noch einmal von vorn anfangen.
Doch jetzt habe ich noch ne Frage zum Sketch. Für was ist der 4. Button?

const byte buttonPins = {4, 5, 6, 7}; // PIN Definition of the buttons

das ist nur ein Überbleibsel aus einem anderen Sketch wo ich 4 Buttons hatte. Ich dachte ich brauch etwas zum schwindeln. Habs aber dann doch nicht gemacht.

Hehe

Ein Cheater-Button :wink:
Mal schauen, ob ich mir Deine Kreation gleich nicht Mal auf einen Nano brtzel.

MfG