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;
}
}