Hi everyone,
I’m trying to run my Arduino code on Tinkercad Circuits, but I keep getting the error message:
Invalid header file
I’ve double-checked my includes and syntax, but I can’t figure out what’s wrong.
Unfortunately, I can’t use the Arduino IDE right now, so I have to do everything in Tinkercad.
Could someone please help me understand what this error means and how to fix it?
Any hints or examples would be really appreciated!
Thanks in advance
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ====== PIN KONFIGURATION ======
const int PIN_CALL_BUTTON = 2;
const int PIN_FOLD_BUTTON = 3;
const int PIN_ENTER_BUTTON = 4;
const int PIN_POTENTIOMETER = A0;
// ====== DISPLAY KONFIGURATION ======
const int LCD_COLS = 26;
const int LCD_ROWS = 2;
// ====== I2C ADRESSEN FÜR LCD DISPLAYS ======
const int LCD_POT_ADDR = 0x27;
const int LCD_PLAYER_ADDR = 0x26;
const int LCD_CENTER_ADDR = 0x25;
// ====== LCD OBJEKTE (26x2) ======
LiquidCrystal_I2C lcdPot(LCD_POT_ADDR, LCD_COLS, LCD_ROWS);
LiquidCrystal_I2C lcdPlayer(LCD_PLAYER_ADDR, LCD_COLS, LCD_ROWS);
LiquidCrystal_I2C lcdCenter(LCD_CENTER_ADDR, LCD_COLS, LCD_ROWS);
// ====== SPIEL KONFIGURATION ======
const int START_CHIPS = 100;
const int MIN_RAISE = 5;
const int RAISE_STEP = 5;
const long ENTER_HOLD_TIME = 3000;
// ====== SPIELVARIABLEN ======
int spielerChips = START_CHIPS;
int botChips = START_CHIPS;
int pot = 0;
int spielerEinsatz = 0;
int botEinsatz = 0;
int aktuellerRaiseBetrag = 0;
int min_call_amount = 0;
String aktionsStatus = "";
// ====== KARTENDECK & PHASEN ======
struct Karte {
byte wert; // 2-14
byte farbe; // 0-3
};
Karte deck[52];
int deckIndex = 0;
Karte spielerHand[2];
Karte botHand[2];
Karte gemeinschaftsKarten[5];
int anzahlGemeinschaftsKarten = 0;
unsigned long enterPressedTime = 0;
bool enterPressed = false;
enum GamePhase {
PHASE_WAIT_START,
PHASE_PRE_FLOP,
PHASE_FLOP,
PHASE_TURN,
PHASE_RIVER,
PHASE_SHOWDOWN
};
GamePhase currentPhase = PHASE_WAIT_START;
// ====== HAND RANKINGS ======
enum HandRank {
HIGH_CARD = 0,
ONE_PAIR = 1,
TWO_PAIR = 2,
THREE_KIND = 3,
STRAIGHT = 4,
FLUSH = 5,
FULL_HOUSE = 6,
FOUR_KIND = 7,
STRAIGHT_FLUSH = 8,
ROYAL_FLUSH = 9
};
// ====== HAND EVALUATION STRUKTUR ======
struct HandEvaluation {
HandRank rank;
int primaryValue; // Hauptwert (z.B. Drilling-Wert)
int secondaryValue; // Nebenwert (z.B. Paar bei Full House)
int kickers[5]; // Kicker-Karten
int score; // Gesamtscore für Vergleich
};
// ====== VORWÄRTSDEKLARATIONEN ======
String wertZuChar(byte wert);
String farbeZuChar(byte farbe);
String karteZuString(Karte k);
void spielerCall();
void spielerRaise(int totalBet);
void botCall();
void botRaise(int totalBet);
void aktualisiereAlleDisplays();
void fehlerPiep(String meldung);
void spielerGewinntHand();
void botGewinntHand();
bool pruefeGameOver();
void ermittleGewinner();
void spielAbbrechen();
void spielerGewinntShowdown();
void botGewinntShowdown();
void splitPot();
bool frageWeiterspielen();
void warteAufStart();
void startCountdown();
void neueHandStarten();
void mischeDeck();
Karte zieheKarte();
void teileHoleCardsAus();
bool bettingRunde();
void zeigeFlop();
void zeigeTurn();
void zeigeRiver();
void showdown();
void handPause();
int spielerAktion();
// ====== NEUE BOT KI FUNKTIONEN ======
HandEvaluation evaluiereHand(Karte hand[2], Karte community[], int commCount);
int berechneHandScore(HandEvaluation eval);
bool hatPaar(Karte karten[], int count, int &paarWert);
bool hatZweiPaar(Karte karten[], int count, int &hoeheresPaar, int &niedrigeresPaar);
bool hatDrilling(Karte karten[], int count, int &drillingWert);
bool hatStraight(Karte karten[], int count, int &hoechsteKarte);
bool hatFlush(Karte karten[], int count, int &hoechsteKarte);
bool hatFullHouse(Karte karten[], int count, int &drilling, int &paar);
bool hatVierling(Karte karten[], int count, int &vierlingWert);
bool hatStraightFlush(Karte karten[], int count, int &hoechsteKarte);
int botEntscheidungIntelligent();
float berechnePotOdds(int callAmount);
float berechneHandEquity(HandEvaluation eval, int phase);
bool sollBotBluffen(HandEvaluation eval);
int berechneOptimalenEinsatz(HandEvaluation eval, float equity);
// ====== HILFSFUNKTIONEN FÜR KARTEN-DARSTELLUNG ======
String wertZuChar(byte wert) {
if (wert == 14) return "A";
if (wert == 13) return "K";
if (wert == 12) return "Q";
if (wert == 11) return "J";
if (wert == 10) return "T";
return String(wert);
}
String farbeZuChar(byte farbe) {
if (farbe == 0) return "K";
if (farbe == 1) return "C";
if (farbe == 2) return "P";
return "H";
}
String karteZuString(Karte k) {
return wertZuChar(k.wert) + farbeZuChar(k.farbe);
}
// ====== SETUP ======
void setup() {
Serial.begin(9600);
pinMode(PIN_CALL_BUTTON, INPUT_PULLUP);
pinMode(PIN_FOLD_BUTTON, INPUT_PULLUP);
pinMode(PIN_ENTER_BUTTON, INPUT_PULLUP);
randomSeed(analogRead(A1));
systemInitialisierung();
warteAufStart();
}
// ====== MAIN LOOP ======
void loop() {
if (pruefeGameOver()) {
return;
}
neueHandStarten();
teileHoleCardsAus();
aktualisiereAlleDisplays();
currentPhase = PHASE_PRE_FLOP;
if (!bettingRunde()) {
goto hand_ende;
}
zeigeFlop();
currentPhase = PHASE_FLOP;
if (!bettingRunde()) {
goto hand_ende;
}
zeigeTurn();
currentPhase = PHASE_TURN;
if (!bettingRunde()) {
goto hand_ende;
}
zeigeRiver();
currentPhase = PHASE_RIVER;
if (!bettingRunde()) {
goto hand_ende;
}
showdown();
hand_ende:
handPause();
if (!frageWeiterspielen()) {
spielerChips = START_CHIPS;
botChips = START_CHIPS;
warteAufStart();
}
}
// ====== DISPLAYS AKTUALISIEREN ======
void aktualisiereAlleDisplays() {
int call_betrag_live = max(0, botEinsatz - spielerEinsatz);
int anzuzeigender_betrag_live = max(call_betrag_live, aktuellerRaiseBetrag);
Serial.println("==================================================");
Serial.print("PHASE: "); Serial.println(currentPhase);
Serial.print("POT: "); Serial.println(pot);
Serial.print("Spieler Chips: "); Serial.println(spielerChips);
Serial.print("Bot Chips: "); Serial.println(botChips);
Serial.print("Spieler Einsatz: "); Serial.println(spielerEinsatz);
Serial.print("Bot Einsatz: "); Serial.println(botEinsatz);
Serial.println("==================================================");
lcdPot.clear();
lcdPot.setCursor(0, 0);
if (currentPhase != PHASE_WAIT_START && currentPhase != PHASE_SHOWDOWN) {
lcdPot.print("POT: ");
lcdPot.print(pot);
lcdPot.setCursor(0, 1);
lcdPot.print(aktionsStatus);
} else {
lcdPot.print("POKER TIME");
lcdPot.setCursor(0, 1);
lcdPot.print(aktionsStatus);
}
lcdPlayer.clear();
if (currentPhase >= PHASE_PRE_FLOP) {
lcdPlayer.setCursor(0, 0); lcdPlayer.print(farbeZuChar(spielerHand[0].farbe));
lcdPlayer.setCursor(0, 1); lcdPlayer.print(wertZuChar(spielerHand[0].wert));
lcdPlayer.setCursor(2, 0); lcdPlayer.print(farbeZuChar(spielerHand[1].farbe));
lcdPlayer.setCursor(2, 1); lcdPlayer.print(wertZuChar(spielerHand[1].wert));
lcdPlayer.setCursor(5, 0);
lcdPlayer.print("R:");
if (min_call_amount == 0 && aktuellerRaiseBetrag == 0) {
lcdPlayer.print("CHECK");
} else {
int anzuzeigender_betrag = max(min_call_amount, aktuellerRaiseBetrag);
lcdPlayer.print(anzuzeigender_betrag);
}
lcdPlayer.setCursor(5, 1);
lcdPlayer.print("G:");
lcdPlayer.print(spielerChips);
} else {
lcdPlayer.setCursor(0, 0);
lcdPlayer.print("Warte auf Karten");
lcdPlayer.setCursor(0, 1);
lcdPlayer.print("G:");
lcdPlayer.print(spielerChips);
}
lcdCenter.clear();
int cardPositions[] = {1, 4, 7, 10, 13};
for (int i = 0; i < 5; i++) {
if (i < anzahlGemeinschaftsKarten) {
lcdCenter.setCursor(cardPositions[i], 0);
lcdCenter.print(farbeZuChar(gemeinschaftsKarten[i].farbe));
lcdCenter.setCursor(cardPositions[i], 1);
lcdCenter.print(wertZuChar(gemeinschaftsKarten[i].wert));
} else {
lcdCenter.setCursor(cardPositions[i], 0);
lcdCenter.print("-");
lcdCenter.setCursor(cardPositions[i], 1);
lcdCenter.print("-");
}
}
}
// ====== SPIELER AKTION ======
int spielerAktion() {
min_call_amount = max(0, botEinsatz - spielerEinsatz);
aktuellerRaiseBetrag = min_call_amount;
aktualisiereAlleDisplays();
int lastPotiValue = analogRead(PIN_POTENTIOMETER);
bool poti_moved = false;
while (true) {
if (digitalRead(PIN_FOLD_BUTTON) == LOW) {
delay(200);
while (digitalRead(PIN_FOLD_BUTTON) == LOW) delay(10);
aktuellerRaiseBetrag = 0;
return 0;
}
if (digitalRead(PIN_CALL_BUTTON) == LOW) {
delay(200);
while (digitalRead(PIN_CALL_BUTTON) == LOW) delay(10);
spielerCall();
aktuellerRaiseBetrag = 0;
return 1;
}
int potiValue = analogRead(PIN_POTENTIOMETER);
if (abs(potiValue - lastPotiValue) > 5) {
poti_moved = true;
}
if (poti_moved) {
int max_setzbarer_gesamtbetrag = spielerChips + spielerEinsatz;
int raise_range = max(0, max_setzbarer_gesamtbetrag - min_call_amount);
int poti_raise_diff = map(potiValue, 0, 1023, 0, raise_range / RAISE_STEP) * RAISE_STEP;
int poti_total_bet = min_call_amount + poti_raise_diff;
poti_total_bet = constrain(poti_total_bet, min_call_amount, max_setzbarer_gesamtbetrag);
aktuellerRaiseBetrag = poti_total_bet;
if (abs(poti_total_bet - lastPotiValue) >= RAISE_STEP || lastPotiValue == -1) {
aktualisiereAlleDisplays();
lastPotiValue = poti_total_bet;
}
}
if (digitalRead(PIN_ENTER_BUTTON) == LOW && !enterPressed) {
delay(200);
int max_chips = spielerChips + spielerEinsatz;
int min_raise_to = min_call_amount + MIN_RAISE;
if (aktuellerRaiseBetrag == min_call_amount) {
spielerCall();
aktuellerRaiseBetrag = 0;
return 1;
}
if (aktuellerRaiseBetrag < min_raise_to && aktuellerRaiseBetrag != max_chips) {
fehlerPiep("MIN R:");
lcdPot.setCursor(0, 1);
lcdPot.print("MIN RAISE ERROR");
delay(1000);
aktualisiereAlleDisplays();
continue;
}
spielerRaise(aktuellerRaiseBetrag);
aktuellerRaiseBetrag = 0;
return 2;
}
if (digitalRead(PIN_ENTER_BUTTON) == LOW) {
if (!enterPressed) {
enterPressed = true;
enterPressedTime = millis();
} else if (millis() - enterPressedTime >= ENTER_HOLD_TIME) {
aktuellerRaiseBetrag = 0;
return -1;
}
} else {
enterPressed = false;
}
delay(50);
}
}
// ====== SYSTEM INITIALISIERUNG ======
void systemInitialisierung() {
lcdPot.init(); lcdPot.backlight();
lcdPlayer.init(); lcdPlayer.backlight();
lcdCenter.init(); lcdCenter.backlight();
lcdPot.clear(); lcdPot.setCursor(0, 0); lcdPot.print("POKER GAME");
lcdPlayer.clear(); lcdPlayer.setCursor(0, 0); lcdPlayer.print("Initializing...");
lcdCenter.clear(); lcdCenter.setCursor(0, 0); lcdCenter.print("Texas Hold'em");
lcdCenter.setCursor(0, 1); lcdCenter.print("Smart Bot AI");
delay(2000);
}
// ====== WARTE AUF START ======
void warteAufStart() {
currentPhase = PHASE_WAIT_START;
aktionsStatus = "Press ENTER";
aktualisiereAlleDisplays();
lcdCenter.clear();
lcdCenter.setCursor(0, 0);
lcdCenter.print("Press ENTER");
lcdCenter.setCursor(0, 1);
lcdCenter.print("to Start Game");
while (digitalRead(PIN_ENTER_BUTTON) == HIGH) {
delay(50);
}
startCountdown();
}
// ====== START COUNTDOWN ======
void startCountdown() {
for (int i = 3; i > 0; i--) {
aktionsStatus = "Start in " + String(i);
aktualisiereAlleDisplays();
lcdCenter.clear();
lcdCenter.setCursor(7, 0);
lcdCenter.print(i);
delay(1000);
}
aktionsStatus = "LET'S PLAY!";
aktualisiereAlleDisplays();
lcdCenter.clear();
lcdCenter.print("LET'S PLAY!");
delay(1000);
}
// ====== NEUE HAND STARTEN ======
void neueHandStarten() {
mischeDeck();
pot = 0;
spielerEinsatz = 0;
botEinsatz = 0;
anzahlGemeinschaftsKarten = 0;
aktuellerRaiseBetrag = 0;
aktionsStatus = "NEW HAND";
}
// ====== DECK MISCHEN / KARTE ZIEHEN / HOLE CARDS AUSTEILEN ======
void mischeDeck() {
int index = 0;
for (int farbe = 0; farbe < 4; farbe++) {
for (int wert = 2; wert <= 14; wert++) {
deck[index].wert = wert;
deck[index].farbe = farbe;
index++;
}
}
for (int i = 51; i > 0; i--) {
int j = random(0, i + 1);
Karte temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
deckIndex = 0;
}
Karte zieheKarte() {
return deck[deckIndex++];
}
void teileHoleCardsAus() {
spielerHand[0] = zieheKarte();
spielerHand[1] = zieheKarte();
botHand[0] = zieheKarte();
botHand[1] = zieheKarte();
}
// ====== PRÜFE GAME OVER / GEWINNER ERMITTELN ======
bool pruefeGameOver() {
if (spielerChips <= 0 || botChips <= 0) {
ermittleGewinner();
return true;
}
return false;
}
void ermittleGewinner() {
lcdCenter.clear();
lcdCenter.setCursor(0, 0);
aktionsStatus = "";
if (spielerChips > botChips) {
lcdCenter.print("PLAYER WINS!");
aktionsStatus = "PLAYER WINS GAME!";
} else if (botChips > spielerChips) {
lcdCenter.print("BOT WINS!");
aktionsStatus = "BOT WINS GAME!";
} else {
lcdCenter.print("TIE!");
aktionsStatus = "GAME TIE!";
}
aktualisiereAlleDisplays();
lcdCenter.setCursor(0, 1);
lcdCenter.print("P:");
lcdCenter.print(spielerChips);
lcdCenter.print(" B:");
lcdCenter.print(botChips);
while (true) {
delay(1000);
}
}
void spielAbbrechen() {
aktionsStatus = "GAME ABORTED";
aktualisiereAlleDisplays();
lcdCenter.clear();
lcdCenter.print("GAME ABORTED");
delay(2000);
ermittleGewinner();
}
// ====== WEITERSPIELEN ABFRAGE ======
bool frageWeiterspielen() {
aktionsStatus = "Next? CALL/FOLD";
aktualisiereAlleDisplays();
lcdCenter.clear();
lcdCenter.setCursor(0, 0);
lcdCenter.print("CALL: Next Hand");
lcdCenter.setCursor(0, 1);
lcdCenter.print("FOLD: Quit Game");
while (true) {
if (digitalRead(PIN_CALL_BUTTON) == LOW) {
delay(200);
while (digitalRead(PIN_CALL_BUTTON) == LOW) delay(10);
return true;
}
if (digitalRead(PIN_FOLD_BUTTON) == LOW) {
delay(200);
while (digitalRead(PIN_FOLD_BUTTON) == LOW) delay(10);
return false;
}
delay(50);
}
}
// ====== BETTING RUNDE ======
bool bettingRunde() {
spielerEinsatz = 0;
botEinsatz = 0;
if (spielerEinsatz == 0 && botEinsatz == 0) {
aktionsStatus = "BOT ACTION";
aktualisiereAlleDisplays();
int botAction = botEntscheidungIntelligent();
if (botAction == 0) {
spielerGewinntHand();
return false;
}
}
while (true) {
aktionsStatus = "PLAYER ACTION";
aktualisiereAlleDisplays();
int playerAction = spielerAktion();
if (playerAction == -1) {
spielAbbrechen();
return false;
}
if (playerAction == 0) {
botGewinntHand();
return false;
}
if (spielerEinsatz == botEinsatz) {
return true;
}
aktionsStatus = "BOT ACTION";
aktualisiereAlleDisplays();
int botAction = botEntscheidungIntelligent();
if (botAction == 0) {
spielerGewinntHand();
return false;
}
if (spielerEinsatz == botEinsatz) {
return true;
}
}
}
// ====== SPIELER CALL / RAISE ======
void spielerCall() {
int differenz = botEinsatz - spielerEinsatz;
differenz = max(0, differenz);
int tatsaechlicherEinsatz = min(differenz, spielerChips);
spielerEinsatz += tatsaechlicherEinsatz;
spielerChips -= tatsaechlicherEinsatz;
pot += tatsaechlicherEinsatz;
if (tatsaechlicherEinsatz == 0) {
aktionsStatus = "P CHECK";
} else if (tatsaechlicherEinsatz < differenz) {
aktionsStatus = "P ALL-IN";
} else {
aktionsStatus = "P CALL";
}
aktualisiereAlleDisplays();
delay(1500);
}
void spielerRaise(int totalBet) {
int einsatzDifferenz = totalBet - spielerEinsatz;
spielerEinsatz = totalBet;
spielerChips -= einsatzDifferenz;
pot += einsatzDifferenz;
aktionsStatus = "P RAISE";
aktualisiereAlleDisplays();
delay(1500);
}
void fehlerPiep(String meldung) {
delay(500);
}
// ====== BOT CALL / RAISE ======
void botCall() {
int differenz = spielerEinsatz - botEinsatz;
differenz = max(0, differenz);
int tatsaechlicherEinsatz = min(differenz, botChips);
botEinsatz += tatsaechlicherEinsatz;
botChips -= tatsaechlicherEinsatz;
pot += tatsaechlicherEinsatz;
if (tatsaechlicherEinsatz == 0) {
aktionsStatus = "B CHECK";
} else if (tatsaechlicherEinsatz < differenz) {
aktionsStatus = "B ALLIN";
} else {
aktionsStatus = "B CALL";
}
aktualisiereAlleDisplays();
delay(1500);
}
void botRaise(int totalBet) {
int einsatzDifferenz = totalBet - botEinsatz;
einsatzDifferenz = min(einsatzDifferenz, botChips);
totalBet = botEinsatz + einsatzDifferenz;
botEinsatz = totalBet;
botChips -= einsatzDifferenz;
pot += einsatzDifferenz;
aktionsStatus = "B RAISE " + String(einsatzDifferenz);
aktualisiereAlleDisplays();
delay(1500);
}
// **********************************************
// ******** INTELLIGENTE BOT KI - NEU **********
// **********************************************
// ====== HAND EVALUIERUNG ======
HandEvaluation evaluiereHand(Karte hand[2], Karte community[], int commCount) {
HandEvaluation eval;
Karte alleKarten[7];
for(int i = 0; i < 2; i++) alleKarten[i] = hand[i];
for(int i = 0; i < commCount; i++) alleKarten[i+2] = community[i];
int totalCards = 2 + commCount;
// Sortiere Karten nach Wert (absteigend)
for(int i = 0; i < totalCards-1; i++) {
for(int j = i+1; j < totalCards; j++) {
if(alleKarten[j].wert > alleKarten[i].wert) {
Karte temp = alleKarten[i];
alleKarten[i] = alleKarten[j];
alleKarten[j] = temp;
}
}
}
// Prüfe Hände von stärkster bis schwächster
int hoechste;
if(hatStraightFlush(alleKarten, totalCards, hoechste)) {
eval.rank = (hoechste == 14) ? ROYAL_FLUSH : STRAIGHT_FLUSH;
eval.primaryValue = hoechste;
eval.score = berechneHandScore(eval);
return eval;
}
int vierling;
if(hatVierling(alleKarten, totalCards, vierling)) {
eval.rank = FOUR_KIND;
eval.primaryValue = vierling;
eval.score = berechneHandScore(eval);
return eval;
}
int drilling, paar;
if(hatFullHouse(alleKarten, totalCards, drilling, paar)) {
eval.rank = FULL_HOUSE;
eval.primaryValue = drilling;
eval.secondaryValue = paar;
eval.score = berechneHandScore(eval);
return eval;
}
if(hatFlush(alleKarten, totalCards, hoechste)) {
eval.rank = FLUSH;
eval.primaryValue = hoechste;
eval.score = berechneHandScore(eval);
return eval;
}
if(hatStraight(alleKarten, totalCards, hoechste)) {
eval.rank = STRAIGHT;
eval.primaryValue = hoechste;
eval.score = berechneHandScore(eval);
return eval;
}
if(hatDrilling(alleKarten, totalCards, drilling)) {
eval.rank = THREE_KIND;
eval.primaryValue = drilling;
eval.score = berechneHandScore(eval);
return eval;
}
int paar1, paar2;
if(hatZweiPaar(alleKarten, totalCards, paar1, paar2)) {
eval.rank = TWO_PAIR;
eval.primaryValue = paar1;
eval.secondaryValue = paar2;
eval.score = berechneHandScore(eval);
return eval;
}
if(hatPaar(alleKarten, totalCards, paar)) {
eval.rank = ONE_PAIR;
eval.primaryValue = paar;
eval.score = berechneHandScore(eval);
return eval;
}
// High Card
eval.rank = HIGH_CARD;
eval.primaryValue = alleKarten[0].wert;
eval.score = berechneHandScore(eval);
return eval;
}
// ====== HAND SCORE BERECHNUNG ======
int berechneHandScore(HandEvaluation eval) {
int baseScore = eval.rank * 1000;
baseScore += eval.primaryValue * 10;
baseScore += eval.secondaryValue;
return baseScore;
}
// ====== HAND ERKENNUNGS-FUNKTIONEN ======
bool hatPaar(Karte karten[], int count, int &paarWert) {
for(int i = 0; i < count-1; i++) {
for(int j = i+1; j < count; j++) {
if(karten[i].wert == karten[j].wert) {
paarWert = karten[i].wert;
return true;
}
}
}
return false;
}
bool hatZweiPaar(Karte karten[], int count, int &hoeheresPaar, int &niedrigeresPaar) {
int gefundenePaare = 0;
int paare[2] = {0, 0};
for(int i = 0; i < count-1; i++) {
for(int j = i+1; j < count; j++) {
if(karten[i].wert == karten[j].wert) {
bool schonGefunden = false;
for(int k = 0; k < gefundenePaare; k++) {
if(paare[k] == karten[i].wert) schonGefunden = true;
}
if(!schonGefunden && gefundenePaare < 2) {
paare[gefundenePaare++] = karten[i].wert;
}
}
}
}
if(gefundenePaare >= 2) {
hoeheresPaar = max(paare[0], paare[1]);
niedrigeresPaar = min(paare[0], paare[1]);
return true;
}
return false;
}
bool hatDrilling(Karte karten[], int count, int &drillingWert) {
for(int i = 0; i < count-2; i++) {
int gleiche = 1;
for(int j = i+1; j < count; j++) {
if(karten[i].wert == karten[j].wert) gleiche++;
}
if(gleiche >= 3) {
drillingWert = karten[i].wert;
return true;
}
}
return false;
}
bool hatStraight(Karte karten[], int count, int &hoechsteKarte) {
if(count < 5) return false;
// Entferne Duplikate
int einzigartigeWerte[7];
int einzigartigeCount = 0;
for(int i = 0; i < count; i++) {
bool schonVorhanden = false;
for(int j = 0; j < einzigartigeCount; j++) {
if(einzigartigeWerte[j] == karten[i].wert) {
schonVorhanden = true;
break;
}
}
if(!schonVorhanden) {
einzigartigeWerte[einzigartigeCount++] = karten[i].wert;
}
}
// Sortiere absteigend
for(int i = 0; i < einzigartigeCount-1; i++) {
for(int j = i+1; j < einzigartigeCount; j++) {
if(einzigartigeWerte[j] > einzigartigeWerte[i]) {
int temp = einzigartigeWerte[i];
einzigartigeWerte[i] = einzigartigeWerte[j];
einzigartigeWerte[j] = temp;
}
}
}
// Prüfe auf 5 aufeinanderfolgende Karten
for(int i = 0; i <= einzigartigeCount-5; i++) {
bool straight = true;
for(int j = 0; j < 4; j++) {
if(einzigartigeWerte[i+j] - einzigartigeWerte[i+j+1] != 1) {
straight = false;
break;
}
}
if(straight) {
hoechsteKarte = einzigartigeWerte[i];
return true;
}
}
// Prüfe A-2-3-4-5 (Wheel)
if(einzigartigeCount >= 5) {
bool hasAce = false, hasTwo = false, hasThree = false, hasFour = false, hasFive = false;
for(int i = 0; i < einzigartigeCount; i++) {
if(einzigartigeWerte[i] == 14) hasAce = true;
if(einzigartigeWerte[i] == 2) hasTwo = true;
if(einzigartigeWerte[i] == 3) hasThree = true;
if(einzigartigeWerte[i] == 4) hasFour = true;
if(einzigartigeWerte[i] == 5) hasFive = true;
}
if(hasAce && hasTwo && hasThree && hasFour && hasFive) {
hoechsteKarte = 5;
return true;
}
}
return false;
}
bool hatFlush(Karte karten[], int count, int &hoechsteKarte) {
if(count < 5) return false;
for(int farbe = 0; farbe < 4; farbe++) {
int anzahl = 0;
int hoechste = 0;
for(int i = 0; i < count; i++) {
if(karten[i].farbe == farbe) {
anzahl++;
if(karten[i].wert > hoechste) hoechste = karten[i].wert;
}
}
if(anzahl >= 5) {
hoechsteKarte = hoechste;
return true;
}
}
return false;
}
bool hatFullHouse(Karte karten[], int count, int &drilling, int &paar) {
if(count < 5) return false;
// Finde Drilling
bool hatDrill = false;
for(int i = 0; i < count-2; i++) {
int gleiche = 1;
for(int j = i+1; j < count; j++) {
if(karten[i].wert == karten[j].wert) gleiche++;
}
if(gleiche >= 3) {
drilling = karten[i].wert;
hatDrill = true;
break;
}
}
if(!hatDrill) return false;
// Finde Paar (nicht gleicher Wert wie Drilling)
for(int i = 0; i < count-1; i++) {
if(karten[i].wert == drilling) continue;
for(int j = i+1; j < count; j++) {
if(karten[j].wert == drilling) continue;
if(karten[i].wert == karten[j].wert) {
paar = karten[i].wert;
return true;
}
}
}
return false;
}
bool hatVierling(Karte karten[], int count, int &vierlingWert) {
for(int i = 0; i < count-3; i++) {
int gleiche = 1;
for(int j = i+1; j < count; j++) {
if(karten[i].wert == karten[j].wert) gleiche++;
}
if(gleiche >= 4) {
vierlingWert = karten[i].wert;
return true;
}
}
return false;
}
bool hatStraightFlush(Karte karten[], int count, int &hoechsteKarte) {
if(count < 5) return false;
// Prüfe jede Farbe separat
for(int farbe = 0; farbe < 4; farbe++) {
Karte gleicheFarbe[7];
int farbCount = 0;
for(int i = 0; i < count; i++) {
if(karten[i].farbe == farbe) {
gleicheFarbe[farbCount++] = karten[i];
}
}
if(farbCount >= 5) {
if(hatStraight(gleicheFarbe, farbCount, hoechsteKarte)) {
return true;
}
}
}
return false;
}
// ====== POT ODDS BERECHNUNG ======
float berechnePotOdds(int callAmount) {
if(callAmount <= 0) return 999.0;
if(pot == 0) return 0.0;
return (float)pot / (float)callAmount;
}
// ====== HAND EQUITY BERECHNUNG (Vereinfacht) ======
float berechneHandEquity(HandEvaluation eval, int phase) {
float baseEquity = 0.0;
// Basis-Equity basierend auf Hand-Rank
switch(eval.rank) {
case ROYAL_FLUSH:
case STRAIGHT_FLUSH: baseEquity = 0.99; break;
case FOUR_KIND: baseEquity = 0.95; break;
case FULL_HOUSE: baseEquity = 0.90; break;
case FLUSH: baseEquity = 0.80; break;
case STRAIGHT: baseEquity = 0.70; break;
case THREE_KIND: baseEquity = 0.60; break;
case TWO_PAIR: baseEquity = 0.50; break;
case ONE_PAIR:
if(eval.primaryValue >= 10) baseEquity = 0.40;
else baseEquity = 0.30;
break;
case HIGH_CARD:
if(eval.primaryValue == 14) baseEquity = 0.25;
else if(eval.primaryValue >= 12) baseEquity = 0.20;
else baseEquity = 0.15;
break;
}
// Anpassung basierend auf Phase (je früher, desto unsicherer)
switch(phase) {
case PHASE_PRE_FLOP: baseEquity *= 0.7; break;
case PHASE_FLOP: baseEquity *= 0.85; break;
case PHASE_TURN: baseEquity *= 0.95; break;
case PHASE_RIVER: break; // Volle Equity
}
return constrain(baseEquity, 0.0, 1.0);
}
// ====== BLUFF ENTSCHEIDUNG ======
bool sollBotBluffen(HandEvaluation eval) {
// Bluffe nur mit schwachen Händen
if(eval.rank > TWO_PAIR) return false;
// 15% Bluff-Chance bei schwacher Hand
if(random(100) < 15) {
Serial.println("Bot beschließt zu bluffen!");
return true;
}
return false;
}
// ====== OPTIMALEN EINSATZ BERECHNEN ======
int berechneOptimalenEinsatz(HandEvaluation eval, float equity) {
int maxEinsatz = botChips + botEinsatz;
int potGroesse = pot;
// Starke Hand: Aggressives Value Betting
if(eval.rank >= STRAIGHT) {
int betSize = potGroesse * 0.75;
return min(betSize, maxEinsatz);
}
// Mittelstarke Hand: Moderates Betting
if(eval.rank >= TWO_PAIR) {
int betSize = potGroesse * 0.5;
return min(betSize, maxEinsatz);
}
// Schwache Hand mit Potential: Kleine Bets
if(equity > 0.3) {
int betSize = potGroesse * 0.33;
return min(betSize, maxEinsatz);
}
// Sehr schwache Hand: Minimum Bet
return MIN_RAISE;
}
// **********************************************
// ******* INTELLIGENTE BOT ENTSCHEIDUNG *******
// **********************************************
int botEntscheidungIntelligent() {
delay(500);
// Evaluiere Bot's Hand
HandEvaluation botEval = evaluiereHand(botHand, gemeinschaftsKarten, anzahlGemeinschaftsKarten);
float equity = berechneHandEquity(botEval, currentPhase);
Serial.print("Bot Hand Rank: "); Serial.println(botEval.rank);
Serial.print("Bot Equity: "); Serial.println(equity);
int differenz = spielerEinsatz - botEinsatz;
differenz = max(0, differenz);
// ***** 1. BOT ERÖFFNET DIE RUNDE *****
if(spielerEinsatz == 0 && botEinsatz == 0) {
// Sehr starke Hand: Fast immer raise
if(botEval.rank >= STRAIGHT || equity > 0.70) {
int raiseAmount = berechneOptimalenEinsatz(botEval, equity);
raiseAmount = max(raiseAmount, MIN_RAISE);
raiseAmount = min(raiseAmount, botChips);
if(raiseAmount > 0) {
botRaise(raiseAmount);
return 2;
}
}
// Gute Hand: Häufig raise
if(botEval.rank >= TWO_PAIR || equity > 0.50) {
if(random(100) < 70) { // 70% raise
int raiseAmount = berechneOptimalenEinsatz(botEval, equity);
raiseAmount = max(raiseAmount, MIN_RAISE);
raiseAmount = min(raiseAmount, botChips);
if(raiseAmount > 0) {
botRaise(raiseAmount);
return 2;
}
}
}
// Mittelmäßige Hand: Manchmal raise
if(botEval.rank == ONE_PAIR || equity > 0.35) {
if(random(100) < 40) { // 40% raise
int raiseAmount = min(MIN_RAISE * 2, botChips);
if(raiseAmount > 0) {
botRaise(raiseAmount);
return 2;
}
}
}
// Bluff-Möglichkeit
if(sollBotBluffen(botEval) && botChips >= MIN_RAISE * 2) {
botRaise(MIN_RAISE * 2);
return 2;
}
// Ansonsten: Check
botCall();
return 1;
}
// ***** 2. SPIELER HAT GESETZT (DIFFERENZ > 0) *****
if(differenz > 0) {
float potOdds = berechnePotOdds(differenz);
Serial.print("Pot Odds: "); Serial.println(potOdds);
// Sehr schwache Hand und teurer Call -> FOLD
if(equity < 0.25 && differenz > pot * 0.5) {
aktionsStatus = "B FOLD";
aktualisiereAlleDisplays();
delay(1500);
return 0;
}
// Pot Odds Check: Lohnt sich der Call?
float benoetigteEquity = 1.0 / (potOdds + 1.0);
if(equity < benoetigteEquity && differenz > MIN_RAISE * 2) {
// Call lohnt sich nicht -> FOLD
aktionsStatus = "B FOLD";
aktualisiereAlleDisplays();
delay(1500);
return 0;
}
// Sehr starke Hand: Re-Raise
if(botEval.rank >= FLUSH || equity > 0.80) {
if(random(100) < 80 && botChips >= differenz + MIN_RAISE) {
int raiseAmount = botEinsatz + differenz + berechneOptimalenEinsatz(botEval, equity);
raiseAmount = min(raiseAmount, botChips + botEinsatz);
if(raiseAmount > botEinsatz + differenz) {
botRaise(raiseAmount);
return 2;
}
}
}
// Starke Hand: Manchmal Re-Raise
if(botEval.rank >= THREE_KIND || equity > 0.65) {
if(random(100) < 50 && botChips >= differenz + MIN_RAISE) {
int raiseAmount = botEinsatz + differenz + (pot * 0.5);
raiseAmount = min(raiseAmount, botChips + botEinsatz);
if(raiseAmount > botEinsatz + differenz) {
botRaise(raiseAmount);
return 2;
}
}
}
// Standard: CALL
botCall();
return 1;
}
// ***** 3. SPIELER HAT GECHECKT (DIFFERENZ == 0) *****
else {
// Sehr starke Hand: Value Bet
if(botEval.rank >= STRAIGHT || equity > 0.75) {
int betSize = berechneOptimalenEinsatz(botEval, equity);
betSize = max(betSize, MIN_RAISE);
betSize = min(betSize, botChips + botEinsatz);
if(betSize > botEinsatz) {
botRaise(betSize);
return 2;
}
}
// Gute Hand: Oft Value Bet
if(botEval.rank >= TWO_PAIR || equity > 0.55) {
if(random(100) < 60) {
int betSize = pot * 0.5;
betSize = max(betSize, MIN_RAISE);
betSize = min(betSize, botChips + botEinsatz);
if(betSize > botEinsatz) {
botRaise(betSize);
return 2;
}
}
}
// Bluff-Versuch
if(sollBotBluffen(botEval) && random(100) < 20) {
int bluffSize = pot * 0.4;
bluffSize = max(bluffSize, MIN_RAISE);
bluffSize = min(bluffSize, botChips + botEinsatz);
if(bluffSize > botEinsatz) {
botRaise(bluffSize);
return 2;
}
}
// Ansonsten: CHECK
botCall();
return 1;
}
}
// ====== FLOP / TURN / RIVER ZEIGEN ======
void zeigeFlop() {
gemeinschaftsKarten[0] = zieheKarte();
gemeinschaftsKarten[1] = zieheKarte();
gemeinschaftsKarten[2] = zieheKarte();
anzahlGemeinschaftsKarten = 3;
aktionsStatus = "FLOP";
aktualisiereAlleDisplays();
delay(1500);
}
void zeigeTurn() {
gemeinschaftsKarten[3] = zieheKarte();
anzahlGemeinschaftsKarten = 4;
aktionsStatus = "TURN";
aktualisiereAlleDisplays();
delay(1500);
}
void zeigeRiver() {
gemeinschaftsKarten[4] = zieheKarte();
anzahlGemeinschaftsKarten = 5;
aktionsStatus = "RIVER";
aktualisiereAlleDisplays();
delay(1500);
}
// ====== SHOWDOWN MIT VERBESSERTER EVALUIERUNG ======
void showdown() {
currentPhase = PHASE_SHOWDOWN;
HandEvaluation spielerEval = evaluiereHand(spielerHand, gemeinschaftsKarten, anzahlGemeinschaftsKarten);
HandEvaluation botEval = evaluiereHand(botHand, gemeinschaftsKarten, anzahlGemeinschaftsKarten);
Serial.print("Spieler Score: "); Serial.println(spielerEval.score);
Serial.print("Bot Score: "); Serial.println(botEval.score);
if(spielerEval.score > botEval.score) {
spielerGewinntShowdown();
} else if(botEval.score > spielerEval.score) {
botGewinntShowdown();
} else {
splitPot();
}
}
// ====== GEWINN-FUNKTIONEN ======
void spielerGewinntHand() {
spielerChips += pot;
pot = 0;
aktionsStatus = "P WINS (FOLD)";
aktualisiereAlleDisplays();
delay(2000);
}
void botGewinntHand() {
botChips += pot;
pot = 0;
aktionsStatus = "B WINS (FOLD)";
aktualisiereAlleDisplays();
delay(2000);
}
void spielerGewinntShowdown() {
spielerChips += pot;
pot = 0;
aktionsStatus = "P WINS SHOWDOWN!";
aktualisiereAlleDisplays();
delay(2000);
}
void botGewinntShowdown() {
botChips += pot;
pot = 0;
aktionsStatus = "B WINS SHOWDOWN!";
aktualisiereAlleDisplays();
delay(2000);
}
void splitPot() {
int halberPot = pot / 2;
spielerChips += halberPot;
botChips += halberPot;
pot = 0;
aktionsStatus = "SPLIT POT";
aktualisiereAlleDisplays();
delay(2000);
}
void handPause() {
aktualisiereAlleDisplays();
delay(2000);
}