/**
* 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 org.cspoker.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 java.util.EnumSet;
import java.util.HashMap;
import org.cspoker.ai.opponentmodels.weka.PlayerData;
import org.cspoker.ai.opponentmodels.weka.Propositionalizer;
import org.cspoker.ai.opponentmodels.weka.instances.EmptyInstance;
import org.cspoker.ai.opponentmodels.weka.instances.InstancesBuilder;
import org.cspoker.ai.opponentmodels.weka.instances.PostCheckBetInstances;
import org.cspoker.ai.opponentmodels.weka.instances.PostFoldCallRaiseInstances;
import org.cspoker.ai.opponentmodels.weka.instances.PreCheckBetInstances;
import org.cspoker.ai.opponentmodels.weka.instances.PreFoldCallRaiseInstances;
import org.cspoker.ai.opponentmodels.weka.instances.ShowdownInstances;
import org.cspoker.common.elements.cards.Card;
import weka.core.Instance;
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 final HashMap<String, Card> cards = new HashMap<String, Card>();
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());
for(Card c:Card.values()){
cards.put(c.getShortDescription(), c);
}
}
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(EnumSet.noneOf(Card.class));
}
if (line.startsWith(flop)) {
signalFlop();
String[] cardsString = line.substring(line.indexOf("[")).replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
EnumSet<Card> cardsSet = EnumSet.of(cards.get(cardsString[0]),cards.get(cardsString[1]),cards.get(cardsString[2]));
signalCommunityCards(cardsSet);
} else if (line.startsWith(turn)) {
signalTurn();
String[] cardsString = line.substring(line.indexOf("[")).replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
EnumSet<Card> cardsSet = EnumSet.of(cards.get(cardsString[0]),cards.get(cardsString[1]),cards.get(cardsString[2]),cards.get(cardsString[3]));
signalCommunityCards(cardsSet);
} else if (line.startsWith(river)) {
signalRiver();
String[] cardsString = line.substring(line.indexOf("[")).replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
EnumSet<Card> cardsSet = EnumSet.of(cards.get(cardsString[0]),cards.get(cardsString[1]),cards.get(cardsString[2]),cards.get(cardsString[3]),cards.get(cardsString[4]));
signalCommunityCards(cardsSet);
}
}
} 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,cards.get(cardStrings[0]),cards.get(cardStrings[1]));
}
}
}
}
private int parseAmount(String stringAmount) {
return (int)Math.round(100*Double.parseDouble(stringAmount.replaceAll(",", "")));
}
}