package bots.prologbot; import game.NamedPlayer; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import org.apache.commons.io.FileUtils; import util.Utils; 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; public class PrologBot implements Player, NamedPlayer { private static String file_dir = "./data/prologbot/"; static { File file = new File("/dev/shm/"); if (file.exists()) { file_dir = "/dev/shm/"; try { FileUtils.copyFileToDirectory(new File("./data/prologbot/bk.pl"), file); } catch (IOException e) { e.printStackTrace(); file_dir = "./data/prologbot/"; } } } private final static File directory = new File(file_dir); 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 boolean initialized = false; private String name = "Unknown"; public PrologBot() { } 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 { writeState(); return executeProlog(); } 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; } /** * @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) { } private final String n = System.getProperty("line.separator"); public synchronized void writeBot(String prolog) throws IOException { File file = new File(file_dir, name + ".pl"); FileWriter out2 = new FileWriter(file); BufferedWriter out = new BufferedWriter(out2); out.write("% Generated by server" + n); out.write(":- include(bk)." + n); out.write(":- include(state)." + n); out.write("" + n); out.write("% Generated by client" + n); out.write(prolog); out.close(); out2.close(); initialized = true; } public synchronized void writeState() throws IOException { if (initialized) { FileWriter out2 = new FileWriter(new File(file_dir, "state.pl")); BufferedWriter out = new BufferedWriter(out2); 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("handcards([" + cardToString(c1) + "," + cardToString(c2) + "])." + n); out.write("communitycards(["); 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("deficit(" + gi.getAmountToCall(ourSeat) + ")." + n); out.close(); out2.close(); } } public 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() + "," + suit + ")"; } public synchronized Action executeProlog() throws IOException, InterruptedException { double toCall = gi.getAmountToCall(ourSeat); if (initialized) { if (toCall == 0.0D) { return Action.checkAction(); } ProcessBuilder pb = new ProcessBuilder("yap", "-l", name + ".pl", "-g", "evaluate", "-q"); pb.directory(directory); Process p = pb.start(); int exitValue = p.waitFor(); if (exitValue != 0) { throw new IllegalStateException(); } InputStreamReader in = new InputStreamReader(p.getInputStream()); BufferedReader result = new BufferedReader(in); String output = result.readLine(); result.close(); in.close(); if (output.equals("fold")) { if (toCall == 0.0D) { return Action.checkAction(); } else { return Action.foldAction(toCall); } } else if (output.equals("call")) { if (toCall == 0.0D) { return Action.checkAction(); } else { return Action.callAction(toCall); } } else if (output.startsWith("raise(")) { double wantedRaiseAmount = Double.parseDouble(output.substring(output.indexOf("(") + 1, output.indexOf(")"))); 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(10); return Action.foldAction(toCall); } } @Override public void setIngameName(String name) { this.name = name; } }