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