package bots.prologbot; import game.NamedPlayer; import java.io.IOException; import java.io.StringWriter; import util.Utils; import bots.prologbot.prologsystem.PrologSystem; import bots.prologbot.prologsystem.TuPrologSystem; import bots.prologbot.prologsystem.YapPrologSystem; import com.biotools.meerkat.Action; import com.biotools.meerkat.Card; import com.biotools.meerkat.GameInfo; import com.biotools.meerkat.Hand; import com.biotools.meerkat.Player; import com.biotools.meerkat.util.Preferences; /** * A bot that makes decisions based on Prolog code. */ public class PrologBot implements Player, NamedPlayer { private final static String n = System.getProperty("line.separator"); private int ourSeat; // our seat for the current hand private Card c1, c2; // our hole cards private GameInfo gi; // general game information private Preferences prefs; // the configuration options for this bot private String name = "Unknown"; private PrologSystem system; private volatile boolean initialized = false; private String lastUsedRule = "Geen"; private long lastRuntime = 0; public PrologBot() { } public String getLastUsedRule() { return lastUsedRule; } public long getLastRuntime() { return lastRuntime; } public String getName() { return name; } /** * An event called to tell us our hole cards and seat number * @param c1 your first hole card * @param c2 your second hole card * @param seat your seat number at the table */ public void holeCards(Card c1, Card c2, int seat) { this.c1 = c1; this.c2 = c2; this.ourSeat = seat; } /** * Requests an Action from the player * Called when it is the Player's turn to act. */ public Action getAction() { try { updateState(); return query(); } catch (IOException e) { throw new IllegalStateException(e); } catch (InterruptedException e) { throw new IllegalStateException(e); } } /** * Get the current settings for this bot. */ public Preferences getPreferences() { return prefs; } /** * Load the current settings for this bot. */ public void init(Preferences playerPrefs) { this.prefs = playerPrefs; if (prefs.getPreference("SYSTEM").equalsIgnoreCase("Yap")) { this.system = new YapPrologSystem(this); } else if (prefs.getPreference("SYSTEM").equalsIgnoreCase("2p")) { this.system = new TuPrologSystem(); } else { throw new IllegalArgumentException(); } } /** * @return true if debug mode is on. */ public boolean getDebug() { return prefs.getBooleanPreference("DEBUG", false); } /** * print a debug statement. */ public void debug(String str) { if (getDebug()) { System.out.println(str); } } /** * print a debug statement with no end of line character */ public void debugb(String str) { if (getDebug()) { System.out.print(str); } } /** * A new betting round has started. */ public void stageEvent(int stage) { } /** * A showdown has occurred. * @param pos the position of the player showing * @param c1 the first hole card shown * @param c2 the second hole card shown */ public void showdownEvent(int seat, Card c1, Card c2) { } /** * A new game has been started. * @param gi the game stat information */ public void gameStartEvent(GameInfo gInfo) { this.gi = gInfo; } /** * An event sent when all players are being dealt their hole cards */ public void dealHoleCardsEvent() { } /** * An action has been observed. */ public void actionEvent(int pos, Action act) { } /** * The game info state has been updated * Called after an action event has been fully processed */ public void gameStateChanged() { } /** * The hand is now over. */ public void gameOverEvent() { } /** * A player at pos has won amount with the hand handName */ public void winEvent(int pos, double amount, String handName) { } @Override public void setIngameName(String name) { this.name = name; } public GameInfo getGameInfo() { return gi; } public void setGameInfo(GameInfo gi){ this.gi = gi; } public Card getC1() { return c1; } public Card getC2() { return c2; } public int getOurSeat() { return ourSeat; } public Preferences getPrefs() { return prefs; } public void setProlog(String prolog) { System.out.println(getName() + " submits:"); System.out.println(prolog); system.updateBotProlog(prolog); initialized = true; } public void updateState() { if (initialized) { StringWriter out = new StringWriter(); if (gi.isPreFlop()) { out.write("round(preflop)." + n); } else if (gi.isFlop()) { out.write("round(flop)." + n); } else if (gi.isTurn()) { out.write("round(turn)." + n); } else if (gi.isRiver()) { out.write("round(river)." + n); } else { throw new IllegalStateException(); } out.write("handkaarten([" + cardToString(c1) + "," + cardToString(c2) + "])." + n); out.write("tafelkaarten(["); Hand h = gi.getBoard(); for (int i = 0; i < h.size(); i++) { if (i > 0) { out.write(","); } out.write(cardToString(h.getCard(i))); } out.write("])." + n); out.write("tekort(" + gi.getAmountToCall(ourSeat) + ")." + n); out.write("saldo(" + gi.getBankRoll(ourSeat) + ")." + n); out.write("potgrootte(" + gi.getTotalPotSize() + ")." + n); if (gi.getBigBlindSeat() == ourSeat) { out.write("isbigblind." + n); } else if (gi.getSmallBlindSeat() == ourSeat) { out.write("issmallblind." + n); } if (gi.getButtonSeat() == ourSeat) { out.write("isbutton." + n); } out.write("actievespelers(" + gi.getNumActivePlayers() + ")." + n); out.write("actievespelersmetgeld(" + gi.getNumActivePlayersNotAllIn() + ")." + n); out.write("maximalewinst(" + gi.getEligiblePot(ourSeat) + ")." + n); out.write("maximaalverlies(" + gi.getBankRollAtRisk(ourSeat) + ")." + n); out.write("minimumraise(" + gi.getMinRaise() + ")." + n); out.write("maximumraise(" + (gi.getBankRoll(ourSeat) - gi.getAmountToCall(ourSeat)) + ")." + n); out.write("aantalraises(" + gi.getNumRaises() + ")." + n); //out.write("plaatsinrij(" + gi.getNumToAct() + ")." + n); system.updateState(out.toString()); } } private String cardToString(Card c) { String suit; if (c.getSuit() == Card.CLUBS) { suit = "c"; } else if (c.getSuit() == Card.SPADES) { suit = "s"; } else if (c.getSuit() == Card.HEARTS) { suit = "h"; } else if (c.getSuit() == Card.DIAMONDS) { suit = "d"; } else { throw new IllegalStateException(); } return "card(" + (c.getRank() + 2) + "," + suit + ")"; } public Action query() throws IOException, InterruptedException { double toCall = gi.getAmountToCall(ourSeat); if (initialized) { lastRuntime = -System.currentTimeMillis(); String result = system.executeQuery(); lastRuntime += System.currentTimeMillis(); // System.out.println(ourSeat + " returns " + result); String action = result.substring(0, result.indexOf(",")); lastUsedRule = result.substring(result.lastIndexOf(",") + 1, result.length()); if (action.equals("fold") || action.equals("")) { if (toCall == 0.0D) { return Action.checkAction(); } else { return Action.foldAction(toCall); } } else if (action.equals("call")) { if (toCall == 0.0D) { return Action.checkAction(); } else { return Action.callAction(toCall); } } else if (action.startsWith("raise(")) { double wantedRaiseAmount = Utils.roundToCents(Double.parseDouble(action.substring(action.indexOf("(") + 1, action.indexOf(")")))); wantedRaiseAmount = Math.abs(wantedRaiseAmount); // no negative amount if (gi.getAmountToCall(ourSeat) > 0) { if (gi.getBankRoll(ourSeat) > gi.getAmountToCall(ourSeat)) { double maxPossibleRaise = Utils.roundToCents(gi.getBankRoll(ourSeat) - gi.getAmountToCall(ourSeat)); if (maxPossibleRaise < wantedRaiseAmount) { wantedRaiseAmount = maxPossibleRaise; } return Action.raiseAction(gi, wantedRaiseAmount); } else { return Action.callAction(gi); } } else { if (gi.getBankRoll(ourSeat) < wantedRaiseAmount) { wantedRaiseAmount = gi.getBankRoll(ourSeat); } return Action.betAction(wantedRaiseAmount); } } else { return Action.foldAction(toCall); } } else { // avoid crazy fast games Thread.sleep(2); if (toCall == 0.0D) { return Action.checkAction(); } else { return Action.foldAction(toCall); } } } }