PHP

The HTML calling page and the PHP script below are a web application that calculates the probability a specific pre-flop hand will win given a number of players in Texas Hold’em.

Like with Perl this is not a great application to to build in PHP. Performance is almost as bad as Perl though the page that’s displayed looks good. For building web pages quickly PHP is a great tool. Intense processing is not PHP’s strong suit (get it suit).

index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Holdem Hand Value Calculator</title>
</head>
  <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#4F9D9D" VLINK="#4A0063" ALINK="#4F9D9D">
    <form name="holdemForm" method="post" action="dealHands.php">
    <CENTER>
    <TABLE>
      <TR>
        <TD>Select number of hands per game:
            <select id="handsPerGame" name="handsPerGame">
              <option value=2>2</option>
              <option value=3>3</option>
              <option value=4>4</option>
              <option value=5>5</option>
              <option value=6>6</option>
              <option value=7>7</option>
              <option value=8>8</option>
              <option value=9>9</option>
              <option value=10 selected>10</option>
            </select>
        </td>
      </TR>
      <TR>
        <TD>Select number of hands to play:
            <select id="handsToPlay" name="handsToPlay">
              <option value=1>1</option>
              <option value=10>10</option>
              <option value=100>100</option>
              <option value=1000>1000</option>
              <option value=10000>10000</option>
              <option value=100000>100000</option>
              <option value=1000000>1000000</option>
            </select>
        </td>
      </TR>
      <TR>
        <TD><BR>
        <INPUT TYPE="submit" VALUE="Submit"> <INPUT TYPE="reset" VALUE="Reset"><BR>
        </TD>
      </TR>
    </FORM>
    </TABLE>
    </CENTER>
  </BODY>
</html>

dealHands.php
<?php
$start=time();
echo "<style>
table{
	border-collapse:collapse;
}
table th{
	color:#ffffff;background-color:#555555;border:1px solid #555555;padding:3px;vertical-align:top;text-align:center;
}

table td{
	border:1px solid #d4d4d4;padding:5px;padding-top:7px;padding-bottom:7px;vertical-align:top;
}
.anumber {text-align: right}
</style>
";
define('TRUE', '1');
define('FALSE', '0');
define('ACE', '12');
define('DEUCE', '0');
define('THREE', '1');
define('FOUR', '2');
define('FIVE', '3');
define('SIX', '4');
define('SEVEN', '5');
define('EIGHT', '6');
define('NINE', '7');
define('TEN', '8');
define('JACK', '9');
define('QUEEN', '10');
define('KING', '11');
define('HANDTYPE', '10000000000');
define('FIRSTKICKER', '100000000');
define('SECONDKICKER', '1000000');
define('THIRDKICKER', '10000');
define('FOURTHKICKER', '100');
define('FIFTHKICKER', '1');
define('SFLUSH', '9');
define('QUADS', '8');
define('BOAT', '7');
define('FLUSH', '6');
define('STRAIGHT', '5');
define('TRIPS', '4');
define('TWOPAIR', '3');
define('ONEPAIR', '2');
define('HIGHCARD', '1');
define('UNKNOWN', '0');
#$deck = array("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");

$cardRank=array("2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A");
$handsToPlay=$_POST["handsToPlay"];
$handsPerGame=$_POST["handsPerGame"];
$highCard=0;
function getDeck(&$shuffDeck){
        $shuffDeck[0]=rand(0, 51); # first card is easy to deal just a random number
        # After the first card we need to check that the card has not been dealt already
        for($cardIndex=1;$cardIndex<52;++$cardIndex){
                while(TRUE){
                        $noMatch=TRUE;
                        $randHold=rand(0, 51);
                        for($dealtCardIndex=0;$dealtCardIndex<$cardIndex;++$dealtCardIndex){
                                if($shuffDeck[$dealtCardIndex]==$randHold){
                                        $noMatch=FALSE;
                                        break;
                                }
                        }
                        if($noMatch==TRUE){
                                $shuffDeck[$cardIndex]=$randHold;
                                break;
                        }
                }
        }
}
function deal($handsPerGame, &$handCards, &$suitedHandsDealt, &$suitedHandsWon, &$unsuitedHandsDealt, &$unsuitedHandsWon){
	global $cardRank;
	$handIsSuited=array();
	$handValue=array();
        $flop=array();
        $handKey=array();
        $shuffDeck=array();
        getDeck($shuffDeck);
        $cardNo=0;
        for($cardIndex=0;$cardIndex<2;++$cardIndex){
                for($playerIndex=0;$playerIndex<$handsPerGame;++$playerIndex){
                        $handCards[$playerIndex][$cardIndex]=$shuffDeck[$cardNo++];
                }
        }
        
	#global $deck;
        #for($i=0;$i<$handsPerGame;$i++){
		#$card1=$deck[$handCards[$i][0]];
		#$card2=$deck[$handCards[$i][1]];
              #echo "Player $i $card1 $card2<br>";
        #}
        
        $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++];
        
	$card1=$deck[$flop[0]];
	$card2=$deck[$flop[1]];
	$card3=$deck[$flop[2]];
	$card4=$deck[$flop[3]];
	$card5=$deck[$flop[4]];
        #print "Flop $card1 $card2 $card3 $card4 $card5<br>\n";
        
        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];
                }
        }
        $winningHand=0;
        for($playerIndex=0;$playerIndex<$handsPerGame;++$playerIndex){
                $handIsSuited[$playerIndex]=FALSE;
                $card1=$handCards[$playerIndex][0];
                $card2=$handCards[$playerIndex][1];
                # getHandValue computes value for each hand this will be
                # used to compute the winning hand.
                # getHandValue may change the order of the cards to calculate
                # the proper value so I need to store the players cards
                # before we calculate value
                getHandValue($playerIndex, $handValue, $handCards);
                if(($card1 % 4) == ($card2 % 4)){
                        $handIsSuited[$playerIndex]=TRUE;
                }
                # cards are identified by their position in a sorted deck
                # by doing a modulus operation on the card number you get
                # the suit (we only care if the players cards are suited not
                # what suit they are) by dividing by 4 we get the value of the
                # card. For example at index 4 is the THREE of CLUBS, at index 5
                # is the THREE of DIAMONDS ..... by doing an integer divide by
                # 4 gets us a result of 1 regardless of the suit. And 1 is the
                # index for a THREE.

                $card1=intval($card1/4);
                $card2=intval($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]=$cardRank[$card1].$cardRank[$card2];
                if($handValue[$playerIndex]>$winningHand){
                        $winningHand=$handValue[$playerIndex];
                }
        }
        for($playerIndex=0;$playerIndex<$handsPerGame;++$playerIndex){
                if($handValue[$playerIndex] != 0){
                        if($handIsSuited[$playerIndex]){
                                $suitedHandsDealt[$handKey[$playerIndex]]++;
                        }
                        else{
                                $unsuitedHandsDealt[$handKey[$playerIndex]]++;
                        }
                }
                if($handValue[$playerIndex] == $winningHand){
                        #print "Player $playerIndex wins $handValue[$playerIndex]!<br>\n";
                        if($handIsSuited[$playerIndex]){
                                $suitedHandsWon[$handKey[$playerIndex]]++;
                        }
                        else{
                                $unsuitedHandsWon[$handKey[$playerIndex]]++;
                        }
                }
        }
}
function isThereQuads($playerIndex, &$handValue, &$handCards){
	$cardCount=array();
        loadCardCount($playerIndex, $cardCount, $handCards);
        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;
}
function isThereABoat($playerIndex, &$handValue, &$handCards){
	$cardCount=array();
        loadCardCount($playerIndex, $cardCount, $handCards);
        $highTrips=-1;
        $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;
                                        break;
                                }
                        }
                }
        }
        return FALSE;
}
function isThereAFlush($playerIndex, &$handValue, &$handCards){
        $suits=array(0,0,0,0);
        $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]=intval($handCards[$playerIndex][$cardIndex]/4);
                                }
                                else{
                                        $handCards[$playerIndex][$cardIndex]=-1;
                                        $sortedCards[$cardIndex]=-1;
                                }
                        }
			global $highCard;
                        if(isThereAStraight($playerIndex, $handValue, $handCards)){
                                # 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($sortedCards);
                                $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;
}
function isThereAStraight($playerIndex, &$handValue, &$handCards){
	global $highCard;
	$cardCount=array();
        loadCardCount($playerIndex, $cardCount, $handCards);
        $highCard=FALSE;
        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[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){
                $handValue[$playerIndex]=(HANDTYPE*STRAIGHT)+(FIRSTKICKER*$highCard);
                #print "Player $playerIndex has a straight $handValue[$playerIndex]<br>\n";
                return TRUE;
        }
        return FALSE;
}
function isThereTrips($playerIndex, &$handValue, &$handCards){
	$cardCount=array();
        loadCardCount($playerIndex, $cardCount, $handCards);
        $highTrips=-1;
        $kicker1=-1;
        $kicker2=-1;
        for($i=12;$i>-1;$i--){
                if($cardCount[$i]==3){
                        $highTrips=$i;
                        last;
                }
        }
        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;
                                                break;
                                        }
                                }
                        }
                }
        }
        return FALSE;
}
function isThereTwoPairs($playerIndex, &$handValue, &$handCards){
	$cardCount=array();
        loadCardCount($playerIndex, $cardCount, $handCards);
        $highPair=-1;
        $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;
                                        break;
                                }
                        }
                }
        }
        return FALSE;
}
function isThereOnePair($playerIndex, &$handValue, &$handCards){
	$cardCount=array();
        loadCardCount($playerIndex, $cardCount, $handCards);
        $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;
                                                        break;
                                                }
                                        }
                                }
                        }
                }
        }
        return FALSE;
}
function getHandValue($playerIndex, &$handValue, &$handCards){
	$sortedCards=array();
        $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, $handValue, $handCards);
        if($handValue[$playerIndex]==UNKNOWN){
                if(!isThereQuads($playerIndex, $handValue, $handCards)){
                        if(!isThereABoat($playerIndex, $handValue, $handCards)){
                                if(!isThereAStraight($playerIndex, $handValue, $handCards)){
                                        if(!isThereTrips($playerIndex, $handValue, $handCards)){
                                                if(!isThereTwoPairs($playerIndex, $handValue, $handCards)){
                                                        if(!isThereOnePair($playerIndex, $handValue, $handCards)){
                                                                for($i=0;$i<7;$i++){
                                                                        $sortedCards[$i]=intval($handCards[$playerIndex][$i]/4);
                                                                }
                                                                sortCards($sortedCards);
                                                                $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";
                                                        }
                                                }
                                        }
                                }
                        }
                }
        }
}
function loadCardCount($playerIndex, &$cardCount,&$handCards){
        $cardCount=array(0,0,0,0,0,0,0,0,0,0,0,0,0);
        for($cardIndex=0;$cardIndex<7;$cardIndex++){
                if($handCards[$playerIndex][$cardIndex]!=-1){
                        $cardCount[intval($handCards[$playerIndex][$cardIndex]/4)]++;
                }
        }
}
function sortCards(&$sortedCards){
        # simple bubble sort
        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;
                        }
                }
        }
}
# Main processing
$suitedHandsDealt=array();
$suitedHandsWon=array();
$unsuitedHandsDealt=array();
$unsuitedHandsWon=array();
for($handIndex=0;$handIndex<$handsToPlay;++$handIndex){
        $handCards=array();
	deal($handsPerGame, $handCards, $suitedHandsDealt, $suitedHandsWon, $unsuitedHandsDealt, $unsuitedHandsWon);
}
# print results for suited hands
$handsToPlay=number_format($handsToPlay);
$end=time();
$diff = $end-$start;
$diff=number_format($diff);
echo "<table>
	<tr>
	  <th colspan=5>Players per game are $handsPerGame, Number of hands palyed was $handsToPlay</th>
	</tr>
	<tr>
	  <th colspan=5>Run time was $diff seconds</th>
	</tr>
	<tr>
	  <th>Type</td>
	  <th>Hand</td>
	  <th>Times Dealt</td>
	  <th>Times Won</td>
	  <th>Winning %</td>
	</tr>
";
for($i=0;$i<13;$i++){
        for($i2=0;$i2<13;$i2++){
                $hand=$cardRank[$i].$cardRank[$i2];
                if($suitedHandsDealt[$hand]>0){
                        $winPct=100*($suitedHandsWon[$hand]/$suitedHandsDealt[$hand]);
			$winPct=sprintf("%.2f", $winPct);
			$suitedHandsDealt[$hand]=number_format($suitedHandsDealt[$hand]);
			$suitedHandsWon[$hand]=number_format($suitedHandsWon[$hand]);
			echo "        <tr>
	  <td>suited</td>
	  <td>$hand</td>
	  <td class='anumber'>$suitedHandsDealt[$hand]</td>
	  <td class='anumber'>$suitedHandsWon[$hand]</td>
	  <td class='anumber'>$winPct</td>
        </tr>
";
                }
        }
}
# print results for unsuited hands
for($i=0;$i<13;$i++){
        for($i2=0;$i2<13;$i2++){
                $hand=$cardRank[$i].$cardRank[$i2];
                if($unsuitedHandsDealt[$hand]>0){
                        $winPct=100*($unsuitedHandsWon[$hand]/$unsuitedHandsDealt[$hand]);
                        $winPct=sprintf("%.2f", $winPct);
			$unsuitedHandsDealt[$hand]=number_format($unsuitedHandsDealt[$hand]);
			$unsuitedHandsWon[$hand]=number_format($unsuitedHandsWon[$hand]);
			echo "        <tr>
	  <td>unsuited</td>
	  <td>$hand</td>
	  <td class='anumber'>$unsuitedHandsDealt[$hand]</td>
	  <td class='anumber'>$unsuitedHandsWon[$hand]</td>
	  <td class='anumber'>$winPct</td>
        </tr>
";
                }
        }
}
echo "</table>
";
?>