The Java code below calculates the probability a specific pre-flop hand will win given a number of players in Texas Hold’em.
To make the code below into an executable jar in a linux environment do the following steps:
1. Create a directory for this project in a place you choose with a name you choose.
2. In that directory create a directory org.
3. Create a directory org/dealhands.
4. In org/dealhands create the 2 source files below.
5. Create a manifest - echo Main-Class: org.dealhands.Hand>manifest.txt
6. Compile the source - javac org/dealhands/*.java
7. Make the jar file - jar cvfm Deal.jar manifest.txt org/dealhands/*.class
8. To execute it - java -jar Deal.jar
Deck.java
package org.dealhands;
import java.util.Random;
public class Deck {
int[] cards;
public Deck(){
boolean noMatch;
int cardIndex;
int dealtCardIndex;
int randHold;
cards = new int[52];
Random randGen = new Random();
cards[0] = randGen.nextInt(52);
for(cardIndex=1;cardIndex<52;++cardIndex){
while(true){
noMatch=true;
randHold=randGen.nextInt(52);
for(dealtCardIndex=0;dealtCardIndex<cardIndex;++dealtCardIndex){
if(cards[dealtCardIndex]==randHold){
noMatch=false;
break;
}
}
if(noMatch){
cards[cardIndex]=randHold;
break;
}
}
}
}
public int[] getDeck() {
return cards;
}
}
Hand.java
package org.dealhands;
public class Hand {
public static final int ACE = 12;
public static final int DEUCE = 0;
public static final int THREE = 1;
public static final int FOUR = 2;
public static final int FIVE = 3;
public static final int SIX = 4;
public static final int SEVEN = 5;
public static final int EIGHT = 6;
public static final int NINE = 7;
public static final int TEN = 8;
public static final int JACK = 9;
public static final int QUEEN = 10;
public static final int KING = 11;
public static final long HANDTYPE = 10000000000L;
public static final int FIRSTKICKER = 100000000;
public static final int SECONDKICKER = 1000000;
public static final int THIRDKICKER = 10000;
public static final int FOURTHKICKER = 100;
public static final int FIFTHKICKER = 1;
public static final int SFLUSH = 9;
public static final int QUADS = 8;
public static final int BOAT = 7;
public static final int FLUSH = 6;
public static final int STRAIGHT = 5;
public static final int TRIPS = 4;
public static final int TWOPAIR = 3;
public static final int ONEPAIR = 2;
public static final int HIGHCARD = 1;
public static final int UNKNOWN = 0;
public static final String[] cards = {"2c", "2d", "2h", "2s",
"3c", "3d", "3h", "3s",
"4c", "4d", "4h", "4s",
"5c", "5d", "5h", "5s",
"6c", "6d", "6h", "6s",
"7c", "7d", "7h", "7s",
"8c", "8d", "8h", "8s",
"9c", "9d", "9h", "9s",
"Tc", "Td", "Th", "Ts",
"Jc", "Jd", "Jh", "Js",
"Qc", "Qd", "Qh", "Qs",
"Kc", "Kd", "Kh", "Ks",
"Ac", "Ad", "Ah", "As"};
public static final String[] cardRank={"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"};
private int sortedCards[]=new int[7];
private int cardIndex;
private long handValue[];
private int suits[];
private int i;
private int handCards[][];
private int highCard;
private int cardCount[];
private int kicker1;
private int kicker2;
private int kicker3;
private int handsPerGame;
private int flop[]=new int [5];
private boolean handIsSuited[];
private int handKey[];
private int orderedHand[][];
private long winningHand;
public Hand(int handsPerGame){
if(handsPerGame < 2 || handsPerGame > 10){
throw new IllegalArgumentException("Error: Valid number of players is between 2 and 10.\n");
}
this.handsPerGame=handsPerGame;
handCards=new int[handsPerGame][7];
handValue=new long[handsPerGame];
handIsSuited=new boolean[handsPerGame];
orderedHand=new int[handsPerGame][2];
handKey=new int[handsPerGame];
int cardNo = 0;
int playerIndex;
int shuffDeck[];
int card1;
int card2;
int hold;
Deck d = new Deck();
shuffDeck=d.getDeck();
for(cardIndex=0;cardIndex<2;++cardIndex){
for(playerIndex=0;playerIndex<handsPerGame;++playerIndex){
handCards[playerIndex][cardIndex]=shuffDeck[cardNo++];
}
}
cardNo++; //burn - the burns probably don't affect the outcome but it follows the way the game is played
flop[0]=shuffDeck[cardNo++];
flop[1]=shuffDeck[cardNo++];
flop[2]=shuffDeck[cardNo++];
cardNo++; //burn
flop[3]=shuffDeck[cardNo++];
cardNo++; //burn
flop[4]=shuffDeck[cardNo++];
for(playerIndex=0;playerIndex<handsPerGame;++playerIndex){
for(cardIndex=2;cardIndex<7;++cardIndex){
// Add the board cards to each players hand to be used in valuing the hand
handCards[playerIndex][cardIndex]=flop[cardIndex-2];
}
}
setWinningHand(0);
for(playerIndex=0;playerIndex<handsPerGame;++playerIndex){
card1=handCards[playerIndex][0];
card2=handCards[playerIndex][1];
orderedHand[playerIndex][0]=card1;
orderedHand[playerIndex][1]=card2;
handIsSuited[playerIndex]=false;
if((card1 % 4) == (card2 % 4)){
handIsSuited[playerIndex]=true;
}
card1=card1/4;
card2=card2/4;
// Once we've removed suit from the card value we want the relativly
// higher ranked card to always be the first card (does not matter
// for pairs
if(card1<card2){
hold=card1;
card1=card2;
card2=hold;
}
handKey[playerIndex]=(card1*100)+card2;
computeHandvalue(playerIndex);
if(handValue[playerIndex]>getWinningHand()){
setWinningHand(handValue[playerIndex]);
}
}
}
private void computeHandvalue(int playerIndex) {
handValue[playerIndex]=UNKNOWN;
// Makes sense to check for a flush first, if a flush exists within the seven cards
// the only higher possible hand is a straight flush which is easy to check for
// using the same code that will check for a straight
isThereAFlush(playerIndex);
if(handValue[playerIndex]==UNKNOWN){
if(!isThereQuads(playerIndex)){
if(!isThereABoat(playerIndex)){
if(!isThereAStraight(playerIndex)){
if(!isThereTrips(playerIndex)){
if(!isThereTwoPairs(playerIndex)){
if(!isThereOnePair(playerIndex)){
for(cardIndex=0;cardIndex<7;cardIndex++){
sortedCards[cardIndex]=handCards[playerIndex][cardIndex]/4;
}
sortCards();
handValue[playerIndex]=(HANDTYPE*HIGHCARD)+(FIRSTKICKER*sortedCards[0])
+(SECONDKICKER*sortedCards[1])
+(THIRDKICKER*sortedCards[2])
+(FOURTHKICKER*sortedCards[3])
+(FIFTHKICKER*sortedCards[4]);
//print "Player playerIndex has high card handValue[playerIndex]<br>\n";
}
}
}
}
}
}
}
}
private void sortCards() {
// simple bubble sort
int i2;
int i3;
int holdCard;
for(i = 0;i<6;i++){
for(i2 = 0;i2<6;i2++){
i3 = i2+1;
if(sortedCards[i2]<sortedCards[i3]){
holdCard = sortedCards[i2];
sortedCards[i2]=sortedCards[i3];
sortedCards[i3]=holdCard;
}
}
}
}
private boolean isThereOnePair(int playerIndex) {
loadCardCount(playerIndex);
int pair=-1;
kicker1=-1;
kicker2=-1;
kicker3=-1;
for(i=12;i>-1;i--){
if(cardCount[i]==2){
pair=i;
break;
}
}
if(pair>-1){
for(i=12;i>-1;i--){
if(i!=pair){
if(cardCount[i]>0){
if(kicker1==-1){
kicker1=i;
}
else{
if(kicker2==-1){
kicker2=i;
}
else{
kicker3=i;
handValue[playerIndex]=(HANDTYPE*ONEPAIR)+(FIRSTKICKER*pair)+(SECONDKICKER*kicker1)+
(THIRDKICKER*kicker2)+(FOURTHKICKER*kicker3);
//print "Player playerIndex has 1 pair handValue[playerIndex]<br>\n";
return true;
}
}
}
}
}
}
return false;
}
private boolean isThereTwoPairs(int playerIndex) {
loadCardCount(playerIndex);
int highPair=-1;
int lowPair=-1;
kicker1=-1;
for(i=12;i>-1;i--){
if(cardCount[i]==2){
highPair=i;
break;
}
}
if(highPair>-1){
for(i=12;i>-1;i--){
if(i != highPair){
if(cardCount[i]==2){
lowPair=i;
break;
}
}
}
}
if(highPair>-1 && lowPair>-1){
for(i=12;i>-1;i--){
if(i != highPair && i != lowPair){
if(cardCount[i]>0){
kicker1=i;
handValue[playerIndex]=(HANDTYPE*TWOPAIR)+(FIRSTKICKER*highPair)+(SECONDKICKER*lowPair)+(THIRDKICKER*kicker1);
// print "Player playerIndex has 2 pair handValue[playerIndex]<br>\n";
return true;
}
}
}
}
return false;
}
private boolean isThereTrips(int playerIndex) {
loadCardCount(playerIndex);
int highTrips=-1;
kicker1=-1;
kicker2=-1;
for(i=12;i>-1;i--){
if(cardCount[i]==3){
highTrips=i;
break;
}
}
if(highTrips>-1){
for(i=12;i>-1;i--){
if(i!=highTrips){
if(cardCount[i]>0){
if(kicker1==-1){
kicker1=i;
}
else{
kicker2=i;
handValue[playerIndex]=(HANDTYPE*TRIPS)+(FIRSTKICKER*highTrips)+
(SECONDKICKER*kicker1)+(THIRDKICKER*kicker2);
//print "Player playerIndex has trips handValue[playerIndex]<br>\n";
return true;
}
}
}
}
}
return false;
}
private boolean isThereAStraight(int playerIndex) {
loadCardCount(playerIndex);
highCard=0;
if(cardCount[FIVE] > 0 && cardCount[FOUR] > 0 && cardCount[THREE] > 0 && cardCount[DEUCE] > 0 && cardCount[ACE] > 0){
highCard=FIVE;
}
if(cardCount[SIX] > 0 && cardCount[FIVE] > 0 && cardCount[FOUR] > 0 && cardCount[THREE] > 0 && cardCount[DEUCE] > 0){
highCard=SIX;
}
if(cardCount[SEVEN] > 0 && cardCount[SIX] > 0 && cardCount[FIVE] > 0 && cardCount[FOUR] > 0 && cardCount[THREE] > 0){
highCard=SEVEN;
}
if(cardCount[EIGHT] > 0 && cardCount[SEVEN] > 0 && cardCount[SIX] > 0 && cardCount[FIVE] > 0 && cardCount[FOUR] > 0){
highCard=EIGHT;
}
if(cardCount[NINE] > 0 && cardCount[EIGHT] > 0 && cardCount[SEVEN] > 0 && cardCount[SIX] > 0 && cardCount[FIVE] > 0){
highCard=NINE;
}
if(cardCount[TEN] > 0 && cardCount[NINE] > 0 && cardCount[EIGHT] > 0 && cardCount[SEVEN] > 0 && cardCount[SIX] > 0){
highCard=TEN;
}
if(cardCount[JACK] > 0 && cardCount[TEN] > 0 && cardCount[NINE] > 0 && cardCount[EIGHT] > 0 && cardCount[SEVEN] > 0){
highCard=JACK;
}
if(cardCount[QUEEN] > 0 && cardCount[JACK] > 0 && cardCount[TEN] > 0 && cardCount[NINE] > 0 && cardCount[EIGHT] > 0){
highCard=QUEEN;
}
if(cardCount[KING] > 0 && cardCount[QUEEN] > 0 && cardCount[JACK] > 0 && cardCount[TEN] > 0 && cardCount[NINE] > 0){
highCard=KING;
}
if(cardCount[ACE] > 0 && cardCount[KING] > 0 && cardCount[QUEEN] > 0 && cardCount[JACK] > 0 && cardCount[TEN] > 0){
highCard=ACE;
}
if(highCard>0){
handValue[playerIndex]=(HANDTYPE*STRAIGHT)+(FIRSTKICKER*highCard);
//print "Player playerIndex has a straight handValue[playerIndex]<br>\n";
return true;
}
return false;
}
private boolean isThereABoat(int playerIndex) {
loadCardCount(playerIndex);
int highTrips=-1;
int highPair=-1;
for(i=12;i>-1;i--){
if(cardCount[i]==3){
highTrips=i;
break;
}
}
if(highTrips>-1){
for(i=12;i>-1;i--){
if(i != highTrips){
if(cardCount[i]>1){ // Could have 2 trips in which case second trips count as a pair
highPair=i;
handValue[playerIndex]=(HANDTYPE*BOAT)+(FIRSTKICKER*highTrips)+(SECONDKICKER*highPair);
//print "Player playerIndex has a boat handValue[playerIndex]<br>\n";
return true;
}
}
}
}
return false;
}
private boolean isThereQuads(int playerIndex) {
loadCardCount(playerIndex);
for(i=0;i<13;i++){
if(cardCount[i]==4){
//areQuads=true;
// FIRSTKICKER is what you have 4 of
// no need for a second kicker because 2 players can't
// have the same quads
handValue[playerIndex]=(HANDTYPE*QUADS)+(FIRSTKICKER*i);
//print "Player $playerIndex has quads $handValue[$playerIndex]<br>\n";
return true;
}
}
return false;
}
private void loadCardCount(int playerIndex) {
cardCount=new int [13];
for(cardIndex=0;cardIndex<7;cardIndex++){
if(handCards[playerIndex][cardIndex]!=-1){
cardCount[handCards[playerIndex][cardIndex]/4]++;
}
}
}
private boolean isThereAFlush(int playerIndex) {
suits=new int [4];
int flushSuit=-1;
for(cardIndex=0;cardIndex<7;cardIndex++){
suits[handCards[playerIndex][cardIndex]%4]++;
}
for(i=0;i<4;i++){
if(suits[i]>4){
flushSuit=i;
break;
}
}
if(flushSuit!=-1){
// OK we have a flush is it a straight Flush?
// first lets remove the unsuited cards so we check for a straight
for(cardIndex=0;cardIndex<7;cardIndex++){
if((handCards[playerIndex][cardIndex]%4)==flushSuit){
sortedCards[cardIndex]=handCards[playerIndex][cardIndex]/4;
}
else{
handCards[playerIndex][cardIndex]=-1;
sortedCards[cardIndex]=-1;
}
}
if(isThereAStraight(playerIndex)){
// Wow a Straight Flush!
handValue[playerIndex]=(HANDTYPE*SFLUSH)+(FIRSTKICKER*highCard); // $highCard comes from isThereAStraight
//print "Player $playerIndex has a straight flush $handValue[$playerIndex]<br>\n";
return true;
}
else{
sortCards();
handValue[playerIndex]=(HANDTYPE*FLUSH)+(FIRSTKICKER*sortedCards[0])+(SECONDKICKER*sortedCards[1])+
(THIRDKICKER*sortedCards[2])+(FOURTHKICKER*sortedCards[3])+(FIFTHKICKER*sortedCards[4]);
//print "Player $playerIndex has a flush $handValue[$playerIndex]<br>\n";
return true;
}
}
return false;
}
public void printHands() {
System.out.print("Flop ");
for(cardIndex=0;cardIndex<5;cardIndex++){
System.out.print(cards[flop[cardIndex]]);
System.out.print(" ");
}
System.out.print("\n");
for(int playerIndex = 0;playerIndex<handsPerGame;++playerIndex){
System.out.print("Player ");
System.out.print(playerIndex);
System.out.print(" ");
System.out.print(cards[orderedHand[playerIndex][0]]);
System.out.print(" ");
System.out.print(cards[orderedHand[playerIndex][1]]);
System.out.print(" ");
System.out.print(handValue[playerIndex]);
if(getWinningHand()==handValue[playerIndex]){
System.out.print(" <--");
}
System.out.print("\n");
}
}
public long getWinningHand() {
return winningHand;
}
public void setWinningHand(long winningHand) {
this.winningHand = winningHand;
}
public int getHandKey(int hand) {
return handKey[hand];
}
public boolean getHandIsSuited(int hand) {
return handIsSuited[hand];
}
private long getHandValue(int playerIndex) {
return handValue[playerIndex];
}
public static void main(String[] args) {
int suitedHandsDealt[]=new int[1213];
int suitedHandsWon[]=new int[1213];
int unsuitedHandsDealt[]=new int[1213];
int unsuitedHandsWon[]=new int[1213];
int handsToPlay = 0;
int handsPerGame = 0;
int i;
int card1;
int card2;
float winPct;
String hand;
if(args.length!=2){
usage();
}
try{
handsToPlay=Integer.parseInt(args[0]);
}
catch(NumberFormatException e){
usage();
}
try{
handsPerGame=Integer.parseInt(args[1]);
}
catch(NumberFormatException e){
usage();
}
if(handsPerGame < 2 || handsPerGame > 10){
usage();
}
if(handsToPlay < 1){
usage();
}
for(i=0;i<handsToPlay;i++){
Hand h = new Hand(handsPerGame);
//h.printHands();
for(int playerIndex=0;playerIndex<handsPerGame;playerIndex++){
if(h.getHandIsSuited(playerIndex)){
suitedHandsDealt[h.getHandKey(playerIndex)]++;
if(h.getWinningHand()==h.getHandValue(playerIndex)){
suitedHandsWon[h.getHandKey(playerIndex)]++;
}
}
else{
unsuitedHandsDealt[h.getHandKey(playerIndex)]++;
if(h.getWinningHand()==h.getHandValue(playerIndex)){
unsuitedHandsWon[h.getHandKey(playerIndex)]++;
}
}
}
}
System.out.print("Suited Hands\n");
for(i=0;i<1213;i++){
if(suitedHandsDealt[i]>0){
card1=i/100;
card2=i-(card1*100);
hand=cardRank[card1]+cardRank[card2];
System.out.print(hand);
System.out.print(" ");
System.out.print(suitedHandsDealt[i]);
System.out.print(" ");
System.out.print(suitedHandsWon[i]);
winPct=(float)suitedHandsWon[i]/(float)suitedHandsDealt[i]*100;
System.out.print(" ");
System.out.format("%.2f", winPct);
System.out.print("\n");
}
}
System.out.print("Unsuited Hands\n");
for(i=0;i<1213;i++){
if(unsuitedHandsDealt[i]>0){
card1=i/100;
card2=i-(card1*100);
hand=cardRank[card1]+cardRank[card2];
System.out.print(hand);
System.out.print(" ");
System.out.print(unsuitedHandsDealt[i]);
System.out.print(" ");
System.out.print(unsuitedHandsWon[i]);
winPct=(float)unsuitedHandsWon[i]/(float)unsuitedHandsDealt[i]*100;
System.out.print(" ");
System.out.format("%.2f", winPct);
System.out.print("\n");
}
}
}
public static void usage(){
System.out.print("deal requires 2 arguments - number of hands to play (>0) and number of players per hand (2 -10)\n");
System.exit(1);
}
}