-
Das war jetzt böse. 
Ooooh nein, ich war bööööse!
Jetzt musst du mich bestimmt bestrafen. Aber warte… erst musst du mich fangen! Bäääh! 
Er braucht Dich nicht zu fangen. Du weisst ja jetzt, was er mit Artikeln von Dir macht 
-
Hallo Coder-Gemeinde
Ich bin ein "4 gewinnt" auf einem ESP8266 (ESP-12E) mit Arduino IDE (C++) am programmieren.
Für den Computergegner will ich den minimax Algorithmus verwenden.
Aber iwie schaffe ich es nicht. Der landet immer in einem Loop.
Codeschnipsel:
- const byte SPALTEN = 7;
- const byte ZEILEN = 6;
- const byte LEER = 0;
- const byte SPIELER = 1;
- const byte COMPUTER = 2;
- byte spielfeld[SPALTEN][ZEILEN] = {0}; // 2D-Feld für Spielsteine
- byte pfeilPos = SPALTEN / 2; // Startposition des Pfeils in der Mitte
- bool spielerDran = true; // Wechselt nach jedem Zug
- int tiefe = 5; // Maximale Tiefe des Minimax
- ...
- ...
- void vierGewinntLoop() {
- while(true) {
- //zeichneSpielfeld();
- zeichnePfeil(pfeilPos);
-
- if (spielerDran) {
- if (!spielerEingabe()) {
- return;
- }
- } else {
- computerZug();
- }
-
- if (pruefeGewinn(SPIELER)) {
- Serial.println(F("Spieler gewinnt!"));
- return;
- } else if (pruefeGewinn(COMPUTER)) {
- Serial.println(F("Computer gewinnt!"));
- return;
- }
-
- spielerDran = !spielerDran; // Nächster Zug
- }
- }
- bool spielerEingabe() {
- zeichnePfeil(pfeilPos);
- char key;
- while (true) {
- autoPowerOff();
- key = scanKeypad();
- if (key == 'A') {
- return false;
- }
- if (key == '4') {
- pfeilPos = (pfeilPos + SPALTEN - 1) % SPALTEN;
- zeichnePfeil(pfeilPos);
- } else if (key == '6') {
- pfeilPos = (pfeilPos + 1) % SPALTEN;
- zeichnePfeil(pfeilPos);
- } else if (key == '5') {
- if (setzeStein(pfeilPos)) {
- return true;
- }
- }
- delay(100); // Entprellung
- }
- }
- void computerZug() {
- int bestScore = -10000;
- byte bestMove = -1;
- for (int spalte = 0; spalte < SPALTEN; spalte++) {
- for (int zeile = ZEILEN - 1; zeile >= 0; zeile--) {
- if (spielfeld[spalte][zeile] == LEER) {
- spielfeld[spalte][zeile] = COMPUTER; // Setze Zug
- int score = minimax(spielfeld, tiefe, false, -10000, 10000);
- spielfeld[spalte][zeile] = LEER; // Rückgängig machen
- if (score > bestScore) {
- bestScore = score;
- bestMove = spalte;
- }
- }
- }
- }
- // Setze den besten Zug
- for (byte zeile = ZEILEN - 1; zeile >= 0; zeile--) {
- if (spielfeld[bestMove][zeile] == LEER) {
- spielfeld[bestMove][zeile] = COMPUTER;
- zeichneStein(bestMove, zeile);
- zeichnePfeil(bestMove);
- Serial.print(F("Computer setzt in Spalte "));
- Serial.println(bestMove);
- delay(1000);
- break;
- }
- }
- }
- bool setzeStein(byte spalte) {
- for (byte zeile = ZEILEN - 1; zeile >= 0; zeile--) {
- if (spielfeld[spalte][zeile] == LEER) {
- spielfeld[spalte][zeile] = SPIELER;
- zeichneStein(spalte, zeile);
- Serial.print(F("Spieler hat gesetzt! Spalte "));
- Serial.println(spalte);
- return true;
- }
- }
- return false;
- }
- bool pruefeGewinn(byte spieler) {
- // Horizontale Prüfung
- for (int spalte = 0; spalte < SPALTEN; spalte++) {
- for (int zeile = 0; zeile <= ZEILEN - 4; zeile++) {
- if (spielfeld[spalte][zeile] == spieler &&
- spielfeld[spalte][zeile + 1] == spieler &&
- spielfeld[spalte][zeile + 2] == spieler &&
- spielfeld[spalte][zeile + 3] == spieler) {
- return true;
- }
- }
- }
- // Vertikale Prüfung
- for (int zeile = 0; zeile < ZEILEN; zeile++) {
- for (int spalte = 0; spalte <= SPALTEN - 4; spalte++) {
- if (spielfeld[spalte][zeile] == spieler &&
- spielfeld[spalte + 1][zeile] == spieler &&
- spielfeld[spalte + 2][zeile] == spieler &&
- spielfeld[spalte + 3][zeile] == spieler) {
- return true;
- }
- }
- }
- // Diagonale Prüfung (↘ von links unten nach rechts oben)
- for (int zeile = 0; zeile <= ZEILEN - 4; zeile++) {
- for (int spalte = 0; spalte <= SPALTEN - 4; spalte++) {
- if (spielfeld[spalte][zeile] == spieler &&
- spielfeld[spalte + 1][zeile + 1] == spieler &&
- spielfeld[spalte + 2][zeile + 2] == spieler &&
- spielfeld[spalte + 3][zeile + 3] == spieler) {
- return true;
- }
- }
- }
- // Diagonale Prüfung (↙ von links oben nach rechts unten)
- for (int zeile = 3; zeile < ZEILEN; zeile++) {
- for (int spalte = 0; spalte <= SPALTEN - 4; spalte++) {
- if (spielfeld[spalte][zeile] == spieler &&
- spielfeld[spalte + 1][zeile - 1] == spieler &&
- spielfeld[spalte + 2][zeile - 2] == spieler &&
- spielfeld[spalte + 3][zeile - 3] == spieler) {
- return true;
- }
- }
- }
- return false;
- }
- int minimax(byte spielfeld[SPALTEN][ZEILEN], int tiefe, bool maximierer, int alpha, int beta) {
- // Sofortige Gewinnprüfung
- if (pruefeGewinn(SPIELER)) return -1000; // Verlust für den Computer
- if (pruefeGewinn(COMPUTER)) return 1000; // Gewinn für den Computer
- // Wenn keine Züge mehr möglich sind (Unentschieden)
- bool unentschieden = true;
- for (int spalte = 0; spalte < SPALTEN; spalte++) {
- for (int zeile = 0; zeile < ZEILEN; zeile++) {
- if (spielfeld[spalte][zeile] == LEER) {
- unentschieden = false;
- }
- }
- }
- if (unentschieden) return 0; // Unentschieden
- Serial.print(F("tiefe: "));
- Serial.println(tiefe);
- if (tiefe <= 0) return 0; // Maximale Rekursionstiefe erreicht
- byte zugReihenfolge[SPALTEN] = {3, 2, 4, 1, 5, 0, 6}; // Reihenfolge: Mitte zuerst
- if (maximierer) {
- Serial.println(F("maximierer"));
- int maxEval = -10000;
- for (int x = 0; x < SPALTEN; x++) {
- int spalte = zugReihenfolge[x];
- for (int zeile = ZEILEN - 1; zeile >= 0; zeile--) {
- if (spielfeld[spalte][zeile] == LEER) {
- spielfeld[spalte][zeile] = COMPUTER; // Setze Zug
- int eval = minimax(spielfeld, tiefe - 1, false, alpha, beta);
- spielfeld[spalte][zeile] = LEER; // Rückgängig machen
- maxEval = max(maxEval, eval);
- alpha = max(alpha, eval);
- if (beta <= alpha) break; // Beta pruning
- }
- }
- }
- Serial.print(F("maxEval: "));
- Serial.println(maxEval);
- return maxEval;
- } else { // Minimierer (Spieler)
- Serial.println(F("minimierer"));
- int minEval = 10000;
- for (int x = 0; x < SPALTEN; x++) {
- int spalte = zugReihenfolge[x];
- for (int zeile = ZEILEN - 1; zeile >= 0; zeile--) {
- if (spielfeld[spalte][zeile] == LEER) {
- spielfeld[spalte][zeile] = SPIELER; // Setze Zug
- int eval = minimax(spielfeld, tiefe - 1, true, alpha, beta);
- spielfeld[spalte][zeile] = LEER; // Rückgängig machen
- minEval = min(minEval, eval);
- beta = min(beta, eval);
- if (beta <= alpha) break; // Alpha pruning
- }
- }
- }
- Serial.print(F("minEval: "));
- Serial.println(minEval);
- return minEval;
- }
- }
- // Funktion, um einen Spielstein in der gegebenen x, y Koordinate zu zeichnen
- void zeichneStein(byte spalte, byte zeile) {
- // Berechne die Display-Positionen basierend auf den Spielfeld-Koordinaten
- byte x = xStart + spalte * xStep;
- byte y = yStart + zeile * yStep;
- // Wähle die Farbe des Spielsteins basierend darauf, welcher Spieler dran ist
- uint16_t steinFarbe;
- if (spielerDran) {
- steinFarbe = ST77XX_RED; // Spieler - Roter Stein
- } else {
- steinFarbe = ST77XX_YELLOW; // Computer - Gelber Stein
- }
- // Zeichne den gefüllten Kreis (Spielstein) an der gegebenen Position
- tft.fillCircle(x, y, radius, steinFarbe);
- }
- void zeichnePfeil(byte x) {
- //byte x = xStart + pfeilPos * xStep;
- uint16_t pfeilFarbe;
- tft.fillRect(0, 0, 159, 10, 0);
- if (spielerDran) {
- pfeilFarbe = ST77XX_RED; // Spieler - Roter Stein
- } else {
- pfeilFarbe = ST77XX_YELLOW; // Computer - Gelber Stein
- }
- tft.drawBitmap((xStart + x * xStep)-3, 1, downBitmap, 8, 8, pfeilFarbe);
- }
Display More
Der serial Monitor zeigt nach dem ersten Spielzug:
- 04:54:58.103 -> Spieler hat gesetzt! Spalte 3
- 04:54:58.136 -> tiefe: 5
- 04:54:58.136 -> minimierer
- 04:54:58.136 -> tiefe: 4
- 04:54:58.136 -> maximierer
- 04:54:58.136 -> tiefe: 3
- 04:54:58.136 -> minimierer
- 04:54:58.136 -> tiefe: 2
- 04:54:58.136 -> maximierer
- 04:54:58.136 -> tiefe: 1
- 04:54:58.136 -> minimierer
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.136 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> minEval: 0
- 04:54:58.169 -> tiefe: 1
- 04:54:58.169 -> minimierer
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> minEval: 0
- 04:54:58.169 -> tiefe: 1
- 04:54:58.169 -> minimierer
- 04:54:58.169 -> tiefe: 0
- 04:54:58.169 -> tiefe: 0
- ...
Display More
Der log geht ewig so weiter (Loop). Iwie kehrt der nicht zurück, wenn Tiefe 0 erreicht ist.
Sieht jemand, was ich falsch mache?
-
Jetzt sollte ich das Spiel selbst noch begreiffen.
Hab zwar die Anleitung gelesen, aber meine alten grauen Zellen ...
-
Endlich mal mit dem Aufbau begonnen 


Display More
Wieder etwas weiter.
Display More
Und weiter geht's
Nun ist alles gerichtet.
Konnte analoge und digitale hochpräzisions Wasserwaagen von der Firma benutzen.
Auch eine "Brücke", um den noch nicht plangefrästen Tisch zu überbrücken (um zu messen).
Aber es hat noch viele offene Punkte.
Display More
Die ersten Teile 
Sorry, aber ich kann weder rar noch 7z Parts hier hochladen!
- www.xup.
- in/dl,10249077/seitenwand2.mp4/
- in/dl,14189562/kunststoff_fraesen1.mp4/
- in/dl,17426263/kunststoff_fraesen2.mp4/
-
treki
Du hast nicht zufällig deinen Feuerbutton auf die SPACE Taste gemapt
?
Das wars!
Vielen Dank 
-
Steht im vorherigen Post 
-
treki hast du schon eine andere Vice Version ausprobiert?
Nein, weil diese die offizielle in den Paketquellen von Linux Mint 22.1 ist.
Ich will da nicht rum pfuschen 
-
Hast du die PRG oder die D64 gestartet? Mit der PRG musst du nichts eingeben, die sollte so starten. Du bist der erste, der das meldet und ich kann den Fehler hier nicht nachvollziehen (Vice, CCS64). Auch bei den ganzen Videomachern scheint es ja gut zu funktionieren.
Ich attache die d64. Dann LOAD"$",8
LIST zeigt (siehe Screenshot)

Also gebe ich ein: LOAD"*",8

Jetzt RUN
Es erscheint ohne Sound:

Hier ist Ende. Nichts geht mehr.
-
Es spielt keine Musik 
Und welche Version von VICE verwendest du?
3.9 ist die aktuellste.
Funktionieren alle anderen Spiele immer zuverlässig?
3.7.1
(GTK3 3.24.41, GLib 2.80.0, Cairo 1.18.0, Pango 1.52.1)
Linux 6.8.0-53-generic
#55-Ubuntu SMP PREEMPT_DYNAMIC Fri Jan 17 15:37:52 UTC 2025
x86_64
Hab zuletzt PUPU gespielt. Das funktioniert.
-
Bekomme das Titelbild. Aber weiter komme ich nicht 
Nutze VICE (C64SC).
LOAD"*",8
RUN
Was mache ich falsch?
Display More
Welche Version hast du denn?
Habs soeben mit GTK Windows 3.9 am Laufen
Wenn die Musik spielt, kannst du schon ziehen.
Display More
Es spielt keine Musik 
laxiteer
Habe Spacebar und Firebutton versucht.
-
Ein paar Impressionen von meinem Bartop 
Sorry, aber was mich daran stört ist der 16:9 Monitor, den kann man doch nie voll nutzen.
Jein. Hab zumindest einen Scanline Generator eingebaut.
Und 4:3 Bilder werden auch als 4:3 dargestellt.
PS:
Ist Deiner nicht auch 16:9? Sieht so aus 
-
Ein paar Impressionen von meinem Bartop 
-
-
56x45cm reicht!
Hmm 100x170mm kommt da wohl nicht ran.
-
Nicht wirklich gebastelt, eher ausprobiert. Mein neues Spielzeug, ein Dye-Sub Fotodrucker mit Plotter Funktion aus einer Kickstarter Aktion.

Mein erster Druck damit und das Ergebnis ist fantastisch.
könntest da auch folien herstellen für einen bartop zu bekleben?
dann hätt ich ernsthaft interesse.
werde bald das holz (MDF) für so kisten herstellen.
folien kann ich noch nicht herstellen.
-
Mal die ersten Tests auf dem Steckbrett für mein ESP Taschenspiel.
Es basiert auf einem ESP8266 (ESP-12E) mit Wlan.
Es sollen verschiedene Games drauf kommen, wie Master Mind, 4 gewinnt usw. (weitere Ideen sind willkommen).
Es wird auch Sound erhalten (ich staune, wie der kleine 23mm Lautsprecher brüllt
) und einen 18650 Akku.
1.9" Farb TFT Display und 16 Tasten Tastatur.


Display More
Othello (Reversi) und Minesweeper sind auch noch in der Pipeline 
Öffentliche Anleitung zum Nachbauen am Schluss ist dann natürlich selbstverständlich.
PS:
Es ist auch vorgesehn, die Hi-Scores im littleFS zu speichern 
Und wenn mal alles läuft, ev noch Schach gegen einen online Gegner (Roboter).
Warum nicht ein Raspberry? Ganz einfach, weil ein MC wie der ESP viel kastrierter ist und eher an die C64 Ära hinkommt. Auf Speicherplatz achten usw... das macht Spass.
-
Mal die ersten Tests auf dem Steckbrett für mein ESP Taschenspiel.
Es basiert auf einem ESP8266 (ESP-12E) mit Wlan.
Es sollen verschiedene Games drauf kommen, wie Master Mind, 4 gewinnt usw. (weitere Ideen sind willkommen).
Es wird auch Sound erhalten (ich staune, wie der kleine 23mm Lautsprecher brüllt
) und einen 18650 Akku.
1.9" Farb TFT Display und 16 Tasten Tastatur.


-
Bekomme das Titelbild. Aber weiter komme ich nicht 
Nutze VICE (C64SC).
LOAD"*",8
RUN
Was mache ich falsch?
-
Letzter Leerlauf vor Produktion (Spritzschutzwände sind bald fertig).
Genauigkeit: ca 0.03mm
Bearbeitungsfläche: 600x500mm
-
Heute hatte ich (endlich) mal wieder Clients in meinem "GALAXIS Electronic" Game.
Hatte die schon mal. Ein ausgewanderter Deutscher, welcher in Brasilien lebt und mit seinem Sohn mein Game spielt.
Sie waren heute geschlagene 5.5h dauernd am gamen.
Das ist der Beweis... meine Game-Umsetzung macht süchtig.
Link: https://ltspicer.itch.io/galaxis-electronic