<? /* *******************************************************************************************
* Artificial Black Jack Player by Thomas Ilsche for codewalkers.com contest
*
* Author: Thomas Ilsche
* Date: 29 FEB 2004 {1078086447}
*
* Notes:
* I removed the comments to hide my poor language skills, they were in german anyway.
* Alot of the coding is sloppy due to me having so few time.
* At some parts the readability is sacrificed to performance.
*
* License Information:
* - This may be placed on codewalkers.com and zend.com.
* - Commercial use or any use with the intention to make any kind of profit is scritly prohibited.
* - This software is provided 'as-is', without any express or implied warranty.
* - The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
* - This notice may not be removed or altered from any source distribution.
* *******************************************************************************************/
include('blackjacklib.php');
$default_comp_stats = array ( 1 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.0570454061951, 18 => 0.199487346033, 19 => 0.342146429652, 20 => 0.48551435914, 21 => 0.860615842858, 22 => 0.139384157142, ), 2 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.13000919079, 18 => 0.265417781938, 19 => 0.397338658137, 20 => 0.522995153296, 21 => 0.643406574144, 22 => 0.356593425856, ), 3 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.125457133475, 18 => 0.257369693095, 19 => 0.383644800203, 20 => 0.5062182003, 21 => 0.622782192694, 22 => 0.377217807306, ), 4 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.122514282649, 18 => 0.245983649641, 19 => 0.368465729832, 20 => 0.486277590484, 21 => 0.600112717333, 22 => 0.399887282667, ), 5 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.117813998733, 18 => 0.24099629412, 19 => 0.359066128325, 20 => 0.470108203242, 21 => 0.578365780329, 22 => 0.421634219671, ), 6 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.115284769236, 18 => 0.229631108316, 19 => 0.344878360904, 20 => 0.454945711424, 21 => 0.560977950518, 22 => 0.439022049482, ), 7 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.369845383448, 18 => 0.507909062524, 19 => 0.58613290643, 20 => 0.664866570461, 21 => 0.738454044497, 22 => 0.261545955503, ), 8 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.12931666408, 18 => 0.489886888171, 19 => 0.618762805821, 20 => 0.687802331292, 21 => 0.757344271656, 22 => 0.242655728344, ), 9 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.120624704665, 18 => 0.235313337657, 19 => 0.588262968352, 20 => 0.709005522859, 21 => 0.769933817328, 22 => 0.230066182672, ), 10 => array ( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0, 16 => 0, 17 => 0.112407366253, 18 => 0.224319932896, 19 => 0.33679228001, 20 => 0.674611000253, 21 => 0.787168274661, 22 => 0.212831725339, ), );
function get_microtime()
{
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
function best_val($hand)
{
$sum = 0;
$aces = 0;
foreach($hand as $card)
{
if ($card > 9)
{
$sum += 10;
}
else
{
if ($card == 1)
{
$sum++;
$aces++;
}
else
{
$sum += $card;
}
}
}
while ($aces && ($sum + 10) <= 21)
{
$sum += 10;
$aces--;
}
return $sum;
}
$sub_start = get_microtime(); $rules = StartGame(); $x = $rules['decks'] * 4; $deck = array(1=>$x,2=>$x,3=>$x,4=>$x,5=>$x,6=>$x,7=>$x,8=>$x,9=>$x,10=>4*$x);
while (1)
{
if (isset($result)) $bet = min($rules['maximumbet'],$result['money']);
else $bet = $rules['maximumbet'];
$result = MakeBet($bet);
$deck[min(10,$result['dealercards'][0])]--;
$deck[min(10,$result['yourcards'][0][0])]--;
$deck[min(10,$result['yourcards'][0][1])]--;
$first = true;
$comp_stats_calced = false;
while ($result['status'] == 'YOURTURN')
{
$e_win = array();
$last_was_hit = false;
$hand_points = 0;
$aces = 0;
foreach($result['yourcards'][$result['activehand']] as $card)
{
if ($card > 9)
{
$hand_points += 10;
}
else
{
if ($card == 1)
{
$hand_points++;
$aces++;
}
else
{
$hand_points += $card;
}
}
}
$best_hand_points = $hand_points;
$best_aces = $aces;
while ($best_aces && ($best_hand_points+10) <= 21)
{
$best_hand_points += 10;
$best_aces--;
}
if ($best_hand_points == 21)
{
$result = PlayStand();
}
else
{
$activehand_count = count($result['yourcards'][$result['activehand']]);
if ($rules['double'] && $first && ( $result['money'] >= $result['currentbet']) ) {
check_comp_stats();
$e_win['double'] = expected_win_double($hand_points, $deck, $aces);
}
else {
$e_win['double'] = -1;
}
if ( $rules['split'] && ( $activehand_count == 2 ) && ($result['yourcards'][$result['activehand']][0] == $result['yourcards'][$result['activehand']][1]) && ( $result['money'] >= $result['currentbet']) ) {
check_comp_stats();
$recursion = 0;
$deck_cards_left = array_sum($deck) - 1;
if ($deck_cards_left >= 7) {
$e_win['split'] = expected_win_draw_low($hand_points/2, $deck, $aces/2)*2 - 1;
}
elseif ($deck_cards_left == 2) {
$e_win['split'] = expected_win_double($hand_points/2, $deck, $aces/2)*2 - 1;
}
elseif ($deck_cards_left < 2) {
$e_win['split'] = -1;
}
elseif ($deck_cards_left % 2 == 0) {
$cardsleft = $deck_cards_left / 2;
$e_win['split'] = expected_win_draw_cardsleft($hand_points/2, $deck, $aces/2)*2 - 1;
}
else {
$cardsleft = floor($deck_cards_left / 2);
$e_win['split'] = expected_win_draw_cardsleft($hand_points/2, $deck, $aces/2);
$cardsleft++;
$e_win['split'] += expected_win_draw_cardsleft($hand_points/2, $deck, $aces/2) - 1;
}
}
else {
$e_win['split'] = -1;
}
if ( ($hand_points < 12) && ($aces == 0) && ( array_sum($deck) > 15 ) )
{
if ( ( $e_win['split'] > 0 ) || ( $e_win['double'] > 0 ) ) {
$recursion = 0;
$e_win['hit'] = expected_win_draw_low($hand_points, $deck, $aces);
}
$e_win['hit'] = 1;
$e_win['stand'] = -1;
}
else
{
$checked = check_comp_stats();
if ( ( array_sum($deck) < 11 ) && ( get_microtime() - $sub_start < 45 ) )
{
if (!$checked) {
check_comp_stats(true);
}
$e_win['hit'] = expected_win_draw_total_enum($hand_points, $deck, $aces);
$e_win['stand'] = expected_win_stop($hand_points,$deck,$aces);
}
elseif ( ( array_sum($deck) < 50) && ( get_microtime() - $sub_start < 45 ) )
{
if (!$checked) {
check_comp_stats(true);
}
$recursion = 0;
$e_win['stand'] = expected_win_stop($hand_points,$deck,$aces);
$e_win['hit'] = expected_win_draw_slow($hand_points,$deck,$aces);
}
elseif ( ( get_microtime() - $sub_start ) > 45 * ( 1 - array_sum($deck) / ( $rules['decks'] * 52 ) ) )
{
$recursion = 0;
$e_win['stand'] = expected_win_stop($hand_points,$deck,$aces);
$e_win['hit'] = expected_win_draw_hurry($hand_points,$deck,$aces);
}
else
{
$recursion = 0;
$e_win['stand'] = expected_win_stop($hand_points,$deck,$aces);
$e_win['hit'] = expected_win_draw($hand_points,$deck,$aces);
if (abs($e_win['stand'] - $e_win['hit']) < 0.1) {
if (!$checked) {
check_comp_stats(true);
}
$e_win['hit'] = expected_win_draw_slow($hand_points,$deck,$aces);
$e_win['stand'] = expected_win_stop($hand_points,$deck,$aces);
}
}
}
if ($first && $rules['surrender'] && ( max($e_win) < 0.5 ) ) {
$last_decition = 'surrender';
$result = PlaySurrender();
}
elseif ($e_win['stand'] == max($e_win))
{
$result = PlayStand();
}
elseif ($e_win['double'] == max($e_win))
{
$last_active_hand = $result['activehand'];
$result = PlayDouble();
$deck[min(10,end($result['yourcards'][$last_active_hand]))]--;
}
elseif ($e_win['hit'] == max($e_win))
{
$last_active_hand = $result['activehand'];
$result = PlayHit();
$deck[min(10,end($result['yourcards'][$last_active_hand]))]--;
}
elseif ($e_win['split'] == max($e_win))
{
$last_active_hand = $result['activehand'];
$result = PlaySplit();
$deck[min(10,end($result['yourcards'][$last_active_hand]))]--;
$deck[min(10,end($result['yourcards'][$last_active_hand+1]))]--;
}
}
$first = false;
}
for ($i = 1;$i < count($result['dealercards']); $i++)
{
$deck[min(10,$result['dealercards'][$i])]--;
}
}
function expected_win_draw_slow($hand_points,$deck,$aces)
{
if ( ( $hand_points > 20 ) || ( $aces > 2 ) || ( $hand_points == 11 && $aces > 0 ) )
{
return expected_win_stop($hand_points, $aces);
}
$cards_in_deck = array_sum($deck);
if ( $cards_in_deck <= 1 ) {
return expected_win_stop($hand_points, $aces);
}
$e_w = 0;
$aces++;
foreach ($deck as $points => $count)
{
if ($count > 0) {
if ($hand_points + $points > 20) {
$e_w += expected_win_stop($hand_points + $points,$aces) * $count / $cards_in_deck;
}
else {
$deck[$points]--;
$e_w += max(expected_win_stop($hand_points + $points,$aces), expected_win_draw_slow($hand_points + $points,$deck,$aces) ) * $count / $cards_in_deck;
$deck[$points]++;
}
}
if ($points == 1) $aces--;
}
return $e_w;
}
function expected_win_draw($hand_points,$deck,$aces)
{
if ( ( $hand_points > 20) || ( $hand_points == 11 && $aces > 0 ) )
{
return expected_win_stop($hand_points, $deck, $aces);
}
if ( ( ($GLOBALS['recursion'] + $aces * 2 ) > 4) && ($hand_points > 18 || $aces > 1) ) {
return expected_win_stop($hand_points, $aces);
}
$cards_in_deck = array_sum($deck);
$e_w = 0;
$GLOBALS['recursion']++;
$aces++;
foreach ($deck as $points => $count)
{
if ($count > 0) {
if ($hand_points + $points > 20) {
$e_w += expected_win_stop($hand_points + $points,$aces) * $count / $cards_in_deck;
}
else {
$deck[$points]--;
$e_w += max(expected_win_stop($hand_points + $points,$aces), expected_win_draw($hand_points + $points,$deck,$aces) ) * $count / $cards_in_deck;
$deck[$points]++;
}
}
if ($points == 1) $aces--;
}
$GLOBALS['recursion']--;
return $e_w;
}
function expected_win_stop($hand_points,$aces)
{
if ($hand_points > 21) {
return $GLOBALS['comp_stats'][22];
}
while ($aces && ($hand_points+10) <= 21)
{
$hand_points += 10;
$aces--;
}
return $GLOBALS['comp_stats'][$hand_points-1] + $GLOBALS['comp_stats'][$hand_points] + $GLOBALS['comp_stats'][22] * 2;
}
function calc_comp_stats($hand_points, $deck, $aces, $p)
{
$best_hand_points = $hand_points;
$best_aces = $aces;
while ($best_aces && ($best_hand_points+10) <= 21)
{
$best_hand_points += 10;
$best_aces--;
}
if (($best_hand_points > 17) || ( $best_hand_points == 17 && ( $GLOBALS['rules']['standsoft17'] || ( $hand_points == $best_hand_points ) ) ) ) {
$GLOBALS['comp_stats'][min($best_hand_points,22)] += $p;
}
else
{
$cards_in_deck = array_sum($deck);
if ($cards_in_deck > 0)
{
foreach ($deck as $points => $count)
{
if ($count > 0) {
$deck[$points]--;
calc_comp_stats($hand_points+$points, $deck, ($points == 1) ? $aces+1 : $aces, $p * $count / $cards_in_deck);
$deck[$points]++;
}
}
}
else
{
$GLOBALS['comp_stats'][min($best_hand_points,22)] += $p;
}
}
}
function expected_win_draw_hurry($hand_points,$deck,$aces)
{
if ($hand_points > 20)
{
return expected_win_stop($hand_points, $aces);
}
if ( ( ($GLOBALS['recursion'] + $aces * 2 ) > 3) && ($hand_points > 17 || $aces > 0) ) {
return expected_win_stop($hand_points, $aces);
}
$cards_in_deck = array_sum($deck);
$e_w = 0;
$GLOBALS['recursion']++;
$aces++;
foreach ($deck as $points => $count)
{
if ($count > 0) {
if ($hand_points + $points > 20) {
$e_w += expected_win_stop($hand_points + $points,$aces) * $count / $cards_in_deck;
}
else {
$deck[$points]--;
$e_w += max(expected_win_stop($hand_points + $points,$aces), expected_win_draw_hurry($hand_points + $points,$deck,$aces) ) * $count / $cards_in_deck;
$deck[$points]++;
}
}
if ($points == 1) $aces--;
}
$GLOBALS['recursion']--;
return $e_w;
}
function expected_win_draw_cardsleft($hand_points,$deck,$aces)
{
if ($hand_points > 20)
{
return expected_win_stop($hand_points, $aces);
}
if ( $GLOBALS['recursion'] >= $GLOBALS['cardsleft'] ) {
return expected_win_stop($hand_points, $aces);
}
$cards_in_deck = array_sum($deck);
$e_w = 0;
$GLOBALS['recursion']++;
$aces++;
foreach ($deck as $points => $count)
{
if ($count > 0) {
if ($hand_points + $points > 20) {
$e_w += expected_win_stop($hand_points + $points,$aces) * $count / $cards_in_deck;
}
else {
$deck[$points]--;
$e_w += max(expected_win_stop($hand_points + $points,$aces), expected_win_draw_cardsleft($hand_points + $points,$deck,$aces) ) * $count / $cards_in_deck;
$deck[$points]++;
}
}
if ($points == 1) $aces--;
}
$GLOBALS['recursion']--;
return $e_w;
}
function expected_win_double($hand_points,$deck,$aces)
{
$cards_in_deck = array_sum($deck);
$e_w = 0;
$aces++;
foreach ($deck as $points => $count)
{
if ($count > 0) {
$e_w += expected_win_stop($hand_points + $points,$aces) * $count / $cards_in_deck;
}
if ($points == 1) $aces--;
}
return $e_w*2-1;
}
function check_comp_stats($enforce = false)
{
global $comp_stats_calced;
if (!$comp_stats_calced || $enforce) {
global $deck,$default_comp_stats,$comp_stats,$result,$deck;
if (array_sum($deck) > 70) {
$comp_stats = $default_comp_stats[min(10,$result['dealercards'][0])];
}
else
{
$comp_stats = array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
calc_comp_stats(min(10,$result['dealercards'][0]),$deck,($result['dealercards'][0]==1)?1:0,1);
$s = 0;
for ($i = 0;$i < 22;$i++)
{
$s += $comp_stats[$i];
$comp_stats[$i] = $s;
}
}
$comp_stats_calced = true;
return true;
}
else return false;
}
function expected_win_draw_total_enum($hand_points,$deck,$aces)
{
if ($hand_points > 20)
{
return expected_win_stop_total_enum($hand_points, $deck, $aces);
}
$cards_in_deck = array_sum($deck);
if ($cards_in_deck <= 1)
{
return expected_win_stop_total_enum($hand_points, $deck, $aces);
}
$e_w = 0;
$aces++;
foreach ($deck as $points => $count)
{
if ($count > 0) {
if ($hand_points + $points > 20) {
$e_w += expected_win_stop_total_enum($hand_points + $points,$deck,$aces) * $count / $cards_in_deck;
}
else {
$deck[$points]--;
$e_w += max(expected_win_stop_total_enum($hand_points + $points,$deck,$aces), expected_win_draw_total_enum($hand_points + $points,$deck,$aces) ) * $count / $cards_in_deck;
$deck[$points]++;
}
}
if ($points == 1) $aces--;
}
return $e_w;
}
function expected_win_stop_total_enum($hand_points,$deck,$aces)
{
global $result;
if ($hand_points > 21) {
return calc_comp_stats_total_enum_burst(min(10,$result['dealercards'][0]), $deck, (min(10,$result['dealercards'][0]) == 1) ? 1 : 0, 1);
}
while ($aces && ($hand_points+10) <= 21)
{
$hand_points += 10;
$aces--;
}
$GLOBALS['total_enmum_hand_points'] = $hand_points;
return calc_comp_stats_total_enum(min(10,$result['dealercards'][0]), $deck,(min(10,$result['dealercards'][0]) == 1) ? 1 : 0, 1);
}
function calc_comp_stats_total_enum($hand_points, $deck, $aces, $p)
{
$best_hand_points = $hand_points;
$best_aces = $aces;
while ($best_aces && ($best_hand_points+10) <= 21)
{
$best_hand_points += 10;
$best_aces--;
}
if (($best_hand_points > 17) || ( $best_hand_points == 17 && ( $GLOBALS['rules']['standsoft17'] || ( $hand_points == $best_hand_points ) ) ) ) {
if ($best_hand_points > 21) {
return 2 * $p;
}
elseif ($best_hand_points > $GLOBALS['total_enmum_hand_points']) {
return 0;
}
elseif ($best_hand_points < $GLOBALS['total_enmum_hand_points']) {
return 2 * $p;
}
elseif ($best_hand_points == $GLOBALS['total_enmum_hand_points']) {
return $p;
}
}
else
{
$cards_in_deck = array_sum($deck);
if ($cards_in_deck > 0)
{
$player_win = 0;
foreach ($deck as $points => $count)
{
if ($count > 0) {
$deck[$points]--;
$player_win += calc_comp_stats_total_enum($hand_points+$points, $deck, ($points == 1) ? $aces+1 : $aces, $p * $count / $cards_in_deck);
$deck[$points]++;
}
}
return $player_win;
}
else
{
if ($best_hand_points > 21) {
return 2 * $p;
}
elseif ($best_hand_points > $GLOBALS['total_enmum_hand_points']) {
return 0;
}
elseif ($best_hand_points < $GLOBALS['total_enmum_hand_points']) {
return 2 * $p;
}
elseif ($best_hand_points == $GLOBALS['total_enmum_hand_points']) {
return $p;
}
}
}
}
function calc_comp_stats_total_enum_burst($hand_points, $deck, $aces, $p)
{
$best_hand_points = $hand_points;
$best_aces = $aces;
while ($best_aces && ($best_hand_points+10) <= 21)
{
$best_hand_points += 10;
$best_aces--;
}
if (($best_hand_points > 17) || ( $best_hand_points == 17 && ( $GLOBALS['rules']['standsoft17'] || ( $hand_points == $best_hand_points ) ) ) ) {
if ($best_hand_points > 21) {
return $p;
}
else {
return 0;
}
}
else
{
$cards_in_deck = array_sum($deck);
if ($cards_in_deck > 0)
{
$player_win = 0;
foreach ($deck as $points => $count)
{
if ($count > 0) {
$deck[$points]--;
$player_win += calc_comp_stats_total_enum_burst($hand_points+$points, $deck, ($points == 1) ? $aces+1 : $aces, $p * $count / $cards_in_deck);
$deck[$points]++;
}
}
return $player_win;
}
else
{
if ($best_hand_points > 21) {
return $p;
}
else {
return 0;
}
}
}
}
function expected_win_draw_low($hand_points,$deck,$aces)
{
if ($hand_points > 20)
{
return expected_win_stop($hand_points, $deck, $aces);
}
if ( ( ($GLOBALS['recursion'] + $aces * 2 ) > 4) && ($hand_points > 18 || $aces > 1) ) {
return expected_win_stop($hand_points, $deck, $aces);
}
if ( $GLOBALS['recursion'] == 3) {
for ($i = 3;$i < 8;$i+=2)
{
$deck[$i] += $deck[$i-1];
$deck[$i-1] = 0;
}
}
if ( $GLOBALS['recursion'] == 4) {
$deck[4] += $deck[3] + $deck[5];
$deck[3] = 0;
$deck[5] = 0;
}
$cards_in_deck = array_sum($deck);
$e_w = 0;
$GLOBALS['recursion']++;
$aces++;
foreach ($deck as $points => $count)
{
if ($count > 0) {
if ($hand_points + $points > 20) {
$e_w += expected_win_stop($hand_points + $points,$aces) * $count / $cards_in_deck;
}
else {
$deck[$points]--;
$e_w += max(expected_win_stop($hand_points + $points,$aces), expected_win_draw_low($hand_points + $points,$deck,$aces) ) * $count / $cards_in_deck;
$deck[$points]++;
}
}
if ($points == 1) $aces--;
}
$GLOBALS['recursion']--;
return $e_w;
} ?>
|
|