/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package bots.mctsbot.ai.bots.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import weka.core.Instance;
import bots.mctsbot.ai.opponentmodels.weka.PlayerData;
import bots.mctsbot.ai.opponentmodels.weka.Propositionalizer;
import bots.mctsbot.ai.opponentmodels.weka.instances.EmptyInstance;
import bots.mctsbot.ai.opponentmodels.weka.instances.InstancesBuilder;
import bots.mctsbot.ai.opponentmodels.weka.instances.PostCheckBetInstances;
import bots.mctsbot.ai.opponentmodels.weka.instances.PostFoldCallRaiseInstances;
import bots.mctsbot.ai.opponentmodels.weka.instances.PreCheckBetInstances;
import bots.mctsbot.ai.opponentmodels.weka.instances.PreFoldCallRaiseInstances;
import bots.mctsbot.ai.opponentmodels.weka.instances.ShowdownInstances;
import com.biotools.meerkat.Card;
import com.biotools.meerkat.Hand;
public class PropositionalDataSetGenerator extends Propositionalizer {
private static final String nl = InstancesBuilder.nl;
protected static final String hole = "*** HOLE";
protected static final String flop = "*** FLOP";
protected static final String turn = "*** TURN";
protected static final String river = "*** RIVER";
// if you want all files in 'unzipped' then make folder empty string
protected static final String folder = "FTP_NLH50";
protected final Writer preCheckBetFile;
protected final Writer postCheckBetFile;
protected final Writer preFoldCallRaiseFile;
protected final Writer postFoldCallRaiseFile;
protected final Writer showdownFile;
protected final Writer preBetSizeFile;
protected final Writer postBetSizeFile;
protected final Writer betSizeFile;
private boolean forgetCurrentGame = false;
private int bb;
private final PreCheckBetInstances preCheckBetInstance;
private final PostCheckBetInstances postCheckBetInstance;
private final PreFoldCallRaiseInstances preFoldCallRaiseInstance;
private final PostFoldCallRaiseInstances postFoldCallRaiseInstance;
private final ShowdownInstances showdownInstance;
private final EmptyInstance preBetSizeInstance;
private final EmptyInstance postBetSizeInstance;
private final EmptyInstance betSizeInstance;
public PropositionalDataSetGenerator() throws IOException {
String tmpFolder = folder + (folder.equals("") ? "" : "/");
preCheckBetFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "PreCheckBet.arff"));
postCheckBetFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "PostCheckBet.arff"));
preFoldCallRaiseFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "PreFoldCallRaise.arff"));
postFoldCallRaiseFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "PostFoldCallRaise.arff"));
showdownFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "Showdown.arff"));
preBetSizeFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "PreBetSize.arff"));
postBetSizeFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "PostBetSize.arff"));
betSizeFile = new OutputStreamWriter(new FileOutputStream("output/" + tmpFolder + "BetSize.arff"));
this.preCheckBetInstance = new PreCheckBetInstances("PreCheckBet", "@attribute betProb real" + nl + "@attribute action {check, bet}" + nl);
preCheckBetFile.write(preCheckBetInstance.toString());
this.postCheckBetInstance = new PostCheckBetInstances("PostCheckBet", "@attribute betProb real" + nl + "@attribute action {check, bet}" + nl);
postCheckBetFile.write(postCheckBetInstance.toString());
this.preFoldCallRaiseInstance = new PreFoldCallRaiseInstances("PreFoldCallRaise", "@attribute foldProb real" + nl + "@attribute callProb real" + nl
+ "@attribute raiseProb real" + nl + "@attribute action {fold,call,raise}" + nl);
preFoldCallRaiseFile.write(preFoldCallRaiseInstance.toString());
this.postFoldCallRaiseInstance = new PostFoldCallRaiseInstances("PostFoldCallRaise", "@attribute foldProb real" + nl + "@attribute callProb real" + nl
+ "@attribute raiseProb real" + nl + "@attribute action {fold,call,raise}" + nl);
postFoldCallRaiseFile.write(postFoldCallRaiseInstance.toString());
this.showdownInstance = new ShowdownInstances("Showdown", "@attribute part0Prob real" + nl + "@attribute part1Prob real" + nl
+ "@attribute part2Prob real" + nl + "@attribute part3Prob real" + nl + "@attribute part4Prob real" + nl + "@attribute part5Prob real" + nl
+ "@attribute avgPartition {0,1,2,3,4,5}" + nl);
showdownFile.write(showdownInstance.toString());
this.preBetSizeInstance = new EmptyInstance("PreBetSize", "@attribute minRaise real" + nl + "@attribute maxRaise real" + nl
+ "@attribute relBetSize real" + nl + "@attribute blindRelBetSize real" + nl);
preBetSizeFile.write(preBetSizeInstance.toString());
this.postBetSizeInstance = new EmptyInstance("PostBetSize", "@attribute minRaise real" + nl + "@attribute maxRaise real" + nl
+ "@attribute relBetSize real" + nl + "@attribute blindRelBetSize real" + nl);
postBetSizeFile.write(postBetSizeInstance.toString());
this.betSizeInstance = new EmptyInstance("BetSize",
// "@attribute minRaise real"+nl+
// "@attribute maxRaise real"+nl+
"@attribute relBetSize real" + nl
// "@attribute blindRelBetSize real"+nl
);
betSizeFile.write(betSizeInstance.toString());
}
private void close() throws IOException {
preCheckBetFile.close();
postCheckBetFile.close();
preFoldCallRaiseFile.close();
postFoldCallRaiseFile.close();
showdownFile.close();
preBetSizeFile.close();
postBetSizeFile.close();
betSizeFile.close();
}
private void write(Writer writer, Instance instance) {
try {
writer.write(instance.toString() + nl);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException(e);
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
throw new IllegalStateException(e);
}
}
protected void logFold(Object actorId) {
// if(getRound().equals("preflop")){
// write(preFoldCallRaiseFile,
// preFoldCallRaiseInstance.getClassifiedInstance(this, actorId, new Object[]{1,0,0,"fold"}));
// }else{
// write(postFoldCallRaiseFile,
// postFoldCallRaiseInstance.getClassifiedInstance(this, actorId, new Object[]{1,0,0,"fold"}));
// }
}
protected void logCall(Object actorId) {
// if(getRound().equals("preflop")){
// write(preFoldCallRaiseFile,
// preFoldCallRaiseInstance.getClassifiedInstance(this, actorId, new Object[]{0,1,0,"call"}));
// }else{
// write(postFoldCallRaiseFile,
// postFoldCallRaiseInstance.getClassifiedInstance(this, actorId, new Object[]{0,1,0,"call"}));
// }
}
protected void logRaise(Object actorId, double raiseAmount) {
// if(getRound().equals("preflop")){
// write(preFoldCallRaiseFile,
// preFoldCallRaiseInstance.getClassifiedInstance(this, actorId, new Object[]{0,0,1,"raise"}));
// }else{
// write(postFoldCallRaiseFile,
// postFoldCallRaiseInstance.getClassifiedInstance(this, actorId, new Object[]{0,0,1,"raise"}));
// }
logRaiseAmount(actorId, raiseAmount);
}
protected void logCheck(Object actorId) {
// if(getRound().equals("preflop")){
// write(preCheckBetFile,
// preCheckBetInstance.getClassifiedInstance(this, actorId, new Object[]{0,"check"}));
// }else{
// write(postCheckBetFile,
// postCheckBetInstance.getClassifiedInstance(this, actorId, new Object[]{0,"check"}));
// }
}
protected void logBet(Object actorId, double raiseAmount) {
// if(getRound().equals("preflop")){
// write(preCheckBetFile,
// preCheckBetInstance.getClassifiedInstance(this, actorId, new Object[]{1,"bet"}));
// }else{
// write(postCheckBetFile,
// postCheckBetInstance.getClassifiedInstance(this, actorId, new Object[]{1,"bet"}));
// }
logRaiseAmount(actorId, raiseAmount);
}
@Override
protected void logShowdown(Object actorId, double[] partitionDistr) {
// Object[] targets = new Object[partitionDistr.length+1];
// double avgBucket = 0;
// for(int i=0;i<partitionDistr.length;i++){
// targets[i]=partitionDistr[i];
// avgBucket += i*partitionDistr[i];
// }
// targets[partitionDistr.length] = (int)Math.round(avgBucket);
// write(showdownFile,
// showdownInstance.getClassifiedInstance(this, actorId, targets));
}
private void writeRaise(Object actorId, double minRaise, double maxRaise, double blindRelRaiseAmount, double relRaiseAmount) {
if (getRound().equals("preflop")) {
write(preBetSizeFile,
preBetSizeInstance.getClassifiedInstance(this, actorId, new Object[] { minRaise, maxRaise, relRaiseAmount, blindRelRaiseAmount }));
} else {
write(postBetSizeFile,
postBetSizeInstance.getClassifiedInstance(this, actorId, new Object[] { minRaise, maxRaise, relRaiseAmount, blindRelRaiseAmount }));
}
write(betSizeFile, betSizeInstance.getClassifiedInstance(this, actorId,
// new Object[]{minRaise, maxRaise, relRaiseAmount, blindRelRaiseAmount}));
new Object[] { relRaiseAmount }));
}
private void logRaiseAmount(Object actorId, double raiseAmount) {
PlayerData p = this.getPlayers().get(actorId);
double bb = p.getBB();
double relAmount = raiseAmount;
raiseAmount = raiseAmount * bb;
double minRaise = (double) getMinRaise(p);
double maxRaise = (double) getMaxRaise(p);
raiseAmount = Math.min(raiseAmount, maxRaise);
// float logBetSize = (float)Math.log(raiseAmount);
if (Math.abs(minRaise - maxRaise) > 0.6) //only when we have a choice
{
if (Math.abs(minRaise - raiseAmount) < 0.6) {
// betSizeInstance(p, minRaise, maxRaise, raiseAmount+","+logBetSize+",0,1,0,0,minBet", betSizeClass);
writeRaise(actorId, minRaise, maxRaise, 0, 0);
} else if (Math.abs(maxRaise - raiseAmount) < 0.6) {
// betSizeInstance(p, minRaise, maxRaise, raiseAmount+","+logBetSize+",1,0,0,1,allin", betSizeClass);
writeRaise(actorId, minRaise, maxRaise, Double.NaN, 1);
} else {
if (raiseAmount < minRaise || minRaise > maxRaise) {
System.out.println("Skipping illegal bet");
return;
}
double relBetSize = (raiseAmount - minRaise) / (maxRaise - minRaise);
// betSizeInstance(p, minRaise, maxRaise, raiseAmount+","+logBetSize+","+relBetSize+",0,1,0,avg", betSizeClass);
writeRaise(actorId, minRaise, maxRaise, relAmount, relBetSize);
// betSizeInstance(p, minRaise, maxRaise, raiseAmount+","+logBetSize+","+relBetSize+","+(float)Math.log(relBetSize), betSize);
}
}
}
public void run() throws Exception {
try {
int nbFiles = 0;
final int maxNbFiles = 100;
String line;
File dir1 = new File("../../../data/unzipped");
String[] children1 = dir1.list();
if (children1 == null) {
// Either dir does not exist or is not a directory
} else {
for1: for (String element : children1) {
File child1 = new File(dir1, element);
String[] children2 = child1.list();
if (children2 == null) {
// Either dir does not exist or is not a directory
} else {
for (String element2 : children2) {
if (element.equals(folder) || folder.equals("")) {
// Get filename of file or directory
System.out.println("Starting file #" + (nbFiles + 1) + "/" + maxNbFiles + ": " + element + "/" + element2);
BufferedReader r = new BufferedReader(new FileReader(new File(child1, element2)));
while ((line = r.readLine()) != null) {
try {
doLine(line);
} catch (Exception e) {
System.out.println(line);
throw e;
}
}
r.close();
nbFiles++;
if (nbFiles >= maxNbFiles)
break for1;
}
}
}
}
}
} finally {
close();
}
}
private void doLine(String line) throws IOException {
// inputRaise.write(line+"\n");
// foldFile.write(line+"\n");
// System.out.println(line);
if (line.startsWith("Full Tilt Poker Game ")) {
// if(line.startsWith("Full Tilt Poker Game #7148395139")){
// System.out.println("Found needle");
// }
int temp = line.indexOf("/");
this.bb = parseAmount(line.substring(temp + 2, line.indexOf(" ", temp + 2)));
forgetCurrentGame = false;
signalNewGame();
signalBBAmount(bb);
} else if (!forgetCurrentGame) {
if (line.startsWith("Seat ")) {
if (line.endsWith("(0)")) {
forgetCurrentGame = true;
} else {
int startName = line.indexOf(":") + 2;
int startDollar = line.indexOf("(", startName);
int stack = parseAmount(line.substring(startDollar + 2, line.indexOf(")", startDollar)));
String name = line.substring(startName, startDollar - 1);
signalSeatedPlayer(stack, name);
}
} else if (line.startsWith("*** ")) {
if (line.startsWith("*** SUMMARY ***")) {
forgetCurrentGame = true;
signalShowdown();
} else {
if (line.startsWith(hole)) {
signalCommunityCards(new Hand());
}
if (line.startsWith(flop)) {
signalFlop();
String[] cardsString = line.substring(line.indexOf("[")).replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
Hand cardSet = new Hand();
cardSet.addCard(new Card(cardsString[0]));
cardSet.addCard(new Card(cardsString[1]));
cardSet.addCard(new Card(cardsString[2]));
signalCommunityCards(cardSet);
} else if (line.startsWith(turn)) {
signalTurn();
String[] cardsString = line.substring(line.indexOf("[")).replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
Hand cardSet = new Hand();
cardSet.addCard(new Card(cardsString[0]));
cardSet.addCard(new Card(cardsString[1]));
cardSet.addCard(new Card(cardsString[2]));
cardSet.addCard(new Card(cardsString[3]));
signalCommunityCards(cardSet);
} else if (line.startsWith(river)) {
signalRiver();
String[] cardsString = line.substring(line.indexOf("[")).replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
Hand cardSet = new Hand();
cardSet.addCard(new Card(cardsString[0]));
cardSet.addCard(new Card(cardsString[1]));
cardSet.addCard(new Card(cardsString[2]));
cardSet.addCard(new Card(cardsString[3]));
cardSet.addCard(new Card(cardsString[4]));
signalCommunityCards(cardSet);
}
}
} else if (line.contains(":")) {
// ignore chat message
} else {
boolean isAllIn = line.contains("all in");
if (line.contains(" posts the small blind")) {
String id = line.substring(0, line.indexOf(" posts the small blind"));
signalBlind(isAllIn, id, bb / 2);
} else if (line.contains(" posts the big blind")) {
String id = line.substring(0, line.indexOf(" posts the big blind"));
signalBlind(isAllIn, id, bb);
} else if (line.endsWith(" folds")) {
String id = line.substring(0, line.indexOf(" folds"));
signalFold(id);
} else if (line.contains(" calls")) {
int allinIndex = line.lastIndexOf(", and is all in");
if (allinIndex <= 0) {
allinIndex = line.length();
}
String id = line.substring(0, line.indexOf(" calls"));
int movedAmount = parseAmount(line.substring(line.indexOf("$") + 1, allinIndex));
signalCall(isAllIn, id, movedAmount);
} else if (line.contains(" raises to")) {
int allinIndex = line.lastIndexOf(", and is all in");
if (allinIndex <= 0) {
allinIndex = line.length();
}
int maxBetParsed = parseAmount(line.substring(line.indexOf("$") + 1, allinIndex));
String id = line.substring(0, line.indexOf(" raises to"));
signalRaise(isAllIn, id, maxBetParsed);
} else if (line.endsWith(" checks")) {
String id = line.substring(0, line.indexOf(" checks"));
signalCheck(id);
} else if (line.contains(" bets ") && !line.contains("bo bets all")) {
String id = line.substring(0, line.indexOf(" bets"));
int allinIndex = line.lastIndexOf(", and is all in");
if (allinIndex <= 0) {
allinIndex = line.length();
}
int maxBetParsed = parseAmount(line.substring(line.indexOf("$") + 1, allinIndex));
//cannot be bet by big blind, is raise in dataset
signalBet(isAllIn, id, maxBetParsed);
} else if (line.contains(" shows [")) {
int showsIndex = line.indexOf(" shows [");
String id = line.substring(0, showsIndex);
int start = showsIndex + 8;
String[] cardStrings = line.substring(start, line.indexOf("]", start)).split(" ");
signalCardShowdown(id, new Card(cardStrings[0]), new Card(cardStrings[1]));
}
}
}
}
private int parseAmount(String stringAmount) {
return (int) Math.round(100 * Double.parseDouble(stringAmount.replaceAll(",", "")));
}
}