Skip to content

Instantly share code, notes, and snippets.

@cjgunnar
Last active July 2, 2019 23:06
Show Gist options
  • Save cjgunnar/18fdac23df41e45c3fc46d78bf63ea2f to your computer and use it in GitHub Desktop.
Save cjgunnar/18fdac23df41e45c3fc46d78bf63ea2f to your computer and use it in GitHub Desktop.
MatrixBot - Less sketchy than HalBot
package PokerBots;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
/**
* You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind.
*/
public class MatrixBot extends PokerBot
{
//Simulation Settings
private static final int GAMES_PER_BOT = 100;
private static final int HANDS_PER_GAME = 10000;
/**
* The different bots that will be tested against the opponent
*/
PokerBot[] strategies = new PokerBot[]
{
new BPB(5,3),
new BPB(5,6),
new BPB(5,10),
new BPB(7,3),
new BPB(7,6),
new BPB(7,10),
new BPB(11,3),
new BPB(11,6),
new BPB(11,10),
};
PokerBot opponent;
PokerBot bestStrategy;
double bestStrategyPercent = 0.00;
public MatrixBot()
{
//System.out.println("Creating MatrixBot");
//attempt to reflect the other bot, if failed run basic strategy
if(!setOpponent())
{
//run basic strategy
bestStrategy = new BPB(5,3);
}
else
{
//try each strategy, pick one with highest win percentage
for(PokerBot strategy : strategies)
{
//run simulations
GameSim game = new GameSim(strategy);
game.simulateGames(GAMES_PER_BOT);
//System.out.println("Strategy " + strategy.getBotName() + " won " + game.getWinPercentage() * 100 + "%");
//see if this strategy is the best
if(game.getWinPercentage() > bestStrategyPercent)
{
//make new best strategy
bestStrategy = strategy;
bestStrategyPercent = game.getWinPercentage();
}
}
//System.out.println("MatrixBot: best strategy found to be " + bestStrategy.getBotName());
//create a new copy incase running the simulation messed them up (i.e. for advanced learning/memory bots)
if(bestStrategy instanceof Cloneable && bestStrategy instanceof BPB)
{
try
{
bestStrategy = (PokerBot)(((BPB)bestStrategy).clone());
} catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
}
else
{
try
{
this.bestStrategy = bestStrategy.getClass().getConstructor(null).newInstance(null);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e)
{
e.printStackTrace();
}
}
}
}
/**
* Copy of Game for use of simulations
*/
class GameSim
{
private static final int NUM_HANDS = HANDS_PER_GAME;
public static final int FOLD = 1;
public static final int MATCH = 2;
public static final int RAISE = 3;
private static final int NUM_PLAYERS = 2;
private static final int INITIAL_BET = 5;
private static final int STARTING_MONEY = 10000;
private static final int MAX_BET = 10;
private int moneyInPot;
private boolean createdError = false;
//bot facing the opponent
PokerBot strategyBot;
double winPercentage;
public GameSim(PokerBot strategyBot)
{
this.strategyBot = strategyBot;
this.createdError = false;
}
/**
* Simulate a number of games against the opponent and calculate win percentage
* @param num
*/
public void simulateGames(int num)
{
//System.out.println("MatixBot: Simulating " + num + " games with " + strategyBot.getBotName() + "...");
int gamesWon = 0;
for(int i = 0; i < num; i++)
{
//System.out.println("MatrixBot: Simulating Game #" + (i + 1));
if(simulateGame()) gamesWon++;
if(createdError)
{
winPercentage = 0.00;
return;
}
}
winPercentage = (double)gamesWon / (double)num;
}
private boolean simulateGame()
{
PokerBot player1 = strategyBot;
PokerBot player2;
try
{
player2 = opponent.getClass().getConstructor(null).newInstance(null);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e)
{
e.printStackTrace();
}
finally
{
//use BasicPokerBot() if opponent can't be duplicated
player2 = new BasicPokerBot();
}
//START GAME SIMULATION
player1.setCurrentMoney(STARTING_MONEY);
player2.setCurrentMoney(STARTING_MONEY);
playPoker(player1, player2, NUM_HANDS);
//return true for strategy winning, false otherwise
if(player1.getCurrentMoney() == player2.getCurrentMoney())
{
return false; //tied
}
else if(player1.getCurrentMoney() > player2.getCurrentMoney())
{
return true; //won
}
else //Player 2 must have won.
{
return false; //lost
}
}
private void playPoker(PokerBot player1, PokerBot player2,
int numberOfHands)
{
int player1Card, player2Card;
for(int i = 1; i <= numberOfHands; ++i)
{
moneyInPot = 0;
addStartingMoney(player1, player2);
player1Card = (int)(Math.random() * 13) + 1;
player2Card = (int)(Math.random() * 13) + 1;
if(i % 2 == 0)
{
playHand(player1, player1Card, player2, player2Card);
}
else
{
playHand(player2, player2Card, player1, player1Card);
}
if(player1.getCurrentMoney() <= 0 || player2.getCurrentMoney() <= 0)
{
//player ran out of money, break the loop
i = numberOfHands + 1;
}
}
}
private void addStartingMoney(PokerBot player1, PokerBot player2)
{
//Each player adds initial Bet to the pot.
moneyInPot = NUM_PLAYERS * INITIAL_BET;
player1.setCurrentBet(INITIAL_BET);
player2.setCurrentBet(INITIAL_BET);
}
private void playHand(PokerBot player1, int player1Card,
PokerBot player2, int player2Card)
{
moneyInPot -= player1.getCurrentBet();
int previousDecision = player1.makeDecision(INITIAL_BET, 1,
player2Card, moneyInPot);
moneyInPot += player1.getCurrentBet();
validateBet(previousDecision, INITIAL_BET, player1, 1);
moneyInPot -= player2.getCurrentBet();
int currentDecision = player2.makeDecision(player1.getCurrentBet(), 2,
player1Card, moneyInPot);
moneyInPot += player2.getCurrentBet();
validateBet(currentDecision, player1.getCurrentBet(), player2, 2);
int betCount = 3;
while(betCount <= 6 && currentDecision == RAISE)
{
previousDecision = currentDecision;
//Player1 bets on odd bet counts
if(betCount % 2 == 1)
{
moneyInPot -= player1.getCurrentBet();
currentDecision = player1.makeDecision(player2.getCurrentBet(),
betCount, player2Card, moneyInPot);
moneyInPot += player1.getCurrentBet();
validateBet(currentDecision, player2.getCurrentBet(), player1, betCount);
}
else
{
moneyInPot -= player2.getCurrentBet();
currentDecision = player2.makeDecision(player1.getCurrentBet(),
betCount, player1Card, moneyInPot);
moneyInPot += player2.getCurrentBet();
validateBet(currentDecision, player1.getCurrentBet(), player2, betCount);
}
++betCount;
}
if(betCount % 2 == 1)
{
//Player2 made the most current Bet
determineWinner(player1, previousDecision, player1Card,
player2, currentDecision, player2Card);
}
else
{
//Player1 made the most current Bet
determineWinner(player1, currentDecision, player1Card,
player2, previousDecision, player2Card);
}
}
private void validateBet(int playerDecision, int startingBet, PokerBot player, int round)
{
if(playerDecision == FOLD)
{
//the player's current bet must be within MAX_BET of startingBet
if( !( (player.getCurrentBet() >= (startingBet - MAX_BET)) &&
(player.getCurrentBet() <= startingBet)))
{
System.out.println("ERROR #1: " + player.getBotName() + ": if you fold, your current bet"
+ " needs to stay at what you previously bet. For example if you bet $5 dollars, and the"
+ " other players raises to $12 and you fold, your current bet should stay at $5.");
}
}
if(playerDecision == MATCH)
{
if(player.getCurrentBet() != startingBet)
{
System.out.println("ERROR #2: " + player.getBotName() +
" did not correctly match the bet. Set"
+ " current bet to be equal to"
+ " otherPlayersBet.");
}
}
if(playerDecision == RAISE)
{
if(player.getCurrentBet() <= startingBet
|| player.getCurrentBet() > (startingBet + MAX_BET))
{
System.out.println("ERROR #3: " + player.getBotName() +
": If you choose raise, your bet amount "
+ "must be set to a number 1 to 10 dollars greater"
+ " than otherPlayersBet. Example: otherPlayers bet is 22,"
+ " if you raise your bet should be 23 to 32 dollars.");
}
}
if(playerDecision != RAISE && playerDecision != FOLD && playerDecision != MATCH)
{
System.out.println("ERROR #4: " + player.getBotName() +
" did not return RAISE, FOLD or CALL");
}
if(round == 1 && playerDecision == FOLD)
{
System.out.println("ERROR #5: " + player.getBotName() + ": you cannot fold in round 1");
}
if(round == 6 && playerDecision == RAISE)
{
System.out.println("ERROR #6: " + player.getBotName() + ": you cannot raise in round 6");
}
}
private void determineWinner(PokerBot player1, int player1Bet, int player1Card,
PokerBot player2, int player2Bet, int player2Card)
{
//Subtract whatever they bet.
//the winner will have money added in the code below
player1.setCurrentMoney(player1.getCurrentMoney() - player1.getCurrentBet());
player2.setCurrentMoney(player2.getCurrentMoney() - player2.getCurrentBet());
if(player2Bet == FOLD)
{
// System.out.println(player1.getBotName() + " won "
// + moneyInPot + " dollars this hand.");
player1.setCurrentMoney(player1.getCurrentMoney() + moneyInPot);
}
else if(player1Bet == FOLD)
{
// System.out.println(player2.getBotName() + " won "
// + moneyInPot + " dollars this hand.");
player2.setCurrentMoney(player2.getCurrentMoney() + moneyInPot);
}
else
{
if(player1Card == player2Card)
{
//tie, they get their money back
//Must be an even amount of money, so don't have
//to worry about rounding problems...
player1.setCurrentMoney(player1.getCurrentMoney() + (moneyInPot/2));
player2.setCurrentMoney(player2.getCurrentMoney() + (moneyInPot/2));
// System.out.println("Game was a tie. Both players"
// + " get their money back.");
}
else if(player1Card > player2Card)
{
player1.setCurrentMoney(player1.getCurrentMoney() + moneyInPot);
// System.out.println(player1.getBotName() + " won "
// + moneyInPot + " this hand.");
}
else //player2 must have won...
{
player2.setCurrentMoney(player2.getCurrentMoney() + moneyInPot);
// System.out.println(player2.getBotName() + " won "
// + moneyInPot + " this hand.");
}
}
}
public PokerBot getStrategyBot()
{
return strategyBot;
}
public double getWinPercentage()
{
return winPercentage;
}
}
private boolean setOpponent()
{
//System.out.println("Finding Opponent...");
try
{
//read Game.java file for mention of opponent
Path gameFile = FileSystems.getDefault().getPath("src/PokerBots/Game.java").toAbsolutePath();
List<String> lines = Collections.emptyList();
lines = Files.readAllLines(Paths.get(gameFile.toUri()), StandardCharsets.UTF_8);
String opponentName = "";
for(String s : lines)
{
if(s.trim().contains("PokerBot player1") || s.trim().contains("PokerBot player2") && s.contains("()"))
{
//don't simulate against itself
if(!s.contains("MatrixBot"))
{
//based on the line being: "PokerBot playerX = new OpponentBot();" get the name of the opponent class
int newIdx = s.indexOf("new ");
int bracketIdx = s.indexOf("(");
opponentName = s.substring(newIdx + 4, bracketIdx).trim();
//System.out.println("Opponent is " + opponentName);
break;
}
}
}
//safety check
if(!opponentName.equals(""))
{
//get instance of opponent for simulation
@SuppressWarnings("unchecked")
Class<PokerBot> opponentClass = (Class<PokerBot>) Class.forName("PokerBots."+opponentName);
opponent = opponentClass.getDeclaredConstructor(null).newInstance(null);
return true;
}
}
catch (IOException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | ClassNotFoundException e)
{
//error
e.printStackTrace();
}
return false;
}
@Override
public String getBotName()
{
return "MatrixBot [" + bestStrategy.getBotName() + " " + bestStrategyPercent*100 + "%]";
}
@Override
public void setCurrentBet(int betIn)
{
super.setCurrentBet(betIn);
//pass down to strategy bot
bestStrategy.setCurrentBet(betIn);
}
@Override
public void setCurrentMoney(int moneyIn)
{
super.setCurrentMoney(moneyIn);
//pass down to strategy bot
bestStrategy.setCurrentMoney(moneyIn);
}
@Override
public int makeDecision(int otherPlayersBet, int round, int otherPlayersCard, int moneyInPot)
{
//use internal strategy bot to make the decision
int decision = bestStrategy.makeDecision(otherPlayersBet, round, otherPlayersCard, moneyInPot);
int bet = bestStrategy.getCurrentBet();
//use for MatrixBot so Game can read correct numbers
this.currentBet = bet;
return decision;
}
//Strategies
//what card number (1 to 13) to fold on
//RISKY fold if other > 10
//STANDARD 7
//SAFE 5
//what flat-rate to raise by
//RAISE_HIGH raise by 10
//RAISE_MID 6
//RAISE_LOW 3
/**
* Configurable BasicPokerBot
*/
class BPB extends PokerBot implements Cloneable
{
int riskThreshold;
int raiseAmount;
public BPB(int riskThreshold, int raiseAmount)
{
this.riskThreshold = riskThreshold;
this.raiseAmount = raiseAmount;
}
@Override
public Object clone() throws CloneNotSupportedException
{
return new BPB(this.riskThreshold, this.raiseAmount);
}
/**
* Name is in the form "BPB_(riskThreshold)_(raiseAmount)
* ex BPB_5_3
*/
@Override
public String getBotName()
{
return "BPB_" + riskThreshold +"_" + raiseAmount;
}
/**
* Copied from original BasicPokerBot, but with configurable settings added
*/
@Override
public int makeDecision(int otherPlayersBet, int round, int otherPlayersCard, int moneyInPot)
{
if(round == 6)
{
currentBet = otherPlayersBet;
return Game.MATCH;
}
else
{
if(otherPlayersCard > riskThreshold)
{
//Not necessary, just showing that we keep current bet
//currentBet = currentBet;
if(currentBet == otherPlayersBet)
return Game.MATCH;
else
return Game.FOLD;
}
else
{
currentBet = otherPlayersBet + raiseAmount;
return Game.RAISE;
}
}
}
}
//TODO new and crazy strategies that only work against 1% of all bots?
//just have to create the class here and add to array above
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment