Ok, maybe not really 'learning', more of a statistical
model, perhaps even a flawed one. Many hands of Blackjack
are played and results of play are reported: the score
of your hand, the house's up-card, whether you should
stay or hit, percent won by staying, percent won by hitting.
An 'infinite' deck is used, a better model would use a 4-deck
or 8-deck shoe. It would also be useful to analyse when to
split pairs and when to double down.
There are some surprising results. I thought conventional
wisdom was to hit a 16 if dealer has a 7 or better, but
this model suggests to only hit 16 if dealer has an 7 or
Ace. Maybe I need to play more hands...
JackFoo
#!/usr/bin/perl
use strict;
my @DECK = qw(02 03 04 05 06 07 08 09 10 10 10 10 11);
my (%grid);
for (1..64000) { learn(\%grid); }
for my $score (12..20) {
print " You House S/H S% H%\n";
for my $house (2..11) {
$house = sprintf("%2.2d", $house);
my ($std, $hit, $do);
my $key = "$house-$score";
if ($grid{$key}{'stot'} > 0) {
$std = $grid{$key}{'swin'} / $grid{$key}{'stot'};
}
if ($grid{$key}{'htot'} > 0) {
$hit = $grid{$key}{'hwin'} / $grid{$key}{'htot'};
}
if ($std > $hit) { $do = 'S'; }
else { $do = 'H'; }
$std = sprintf("%3d", ($std*100));
$hit = sprintf("%3d", ($hit*100));
print " $score $house $do $std $hit\n";
}
print "\n";
}
#-----------------------------------------------------------
sub learn {
my ($grid) = @_;
my (@house, $hscore);
my (@mine, $mscore);
push (@house, draw());
push (@house, draw());
$hscore = score(\@house);
while ($hscore > 0 && $hscore < 17) {
push (@house, draw());
$hscore = score(\@house);
}
push (@mine, draw());
push (@mine, draw());
$mscore = score(\@mine);
while ($mscore > 0 && $mscore < 21) {
my $key = "$house[0]-$mscore";
if (!defined($grid->{$key})) { $grid->{$key} = {}; }
if ($mscore > $hscore) { $grid->{$key}{'swin'}++; }
$grid->{$key}{'stot'}++;
push (@mine, draw());
$mscore = score(\@mine);
if ($mscore > $hscore) { $grid->{$key}{'hwin'}++; }
$grid->{$key}{'htot'}++;
}
}
#-----------------------------------------------------------
sub score {
my ($cards) = @_;
my ($aces, $score);
for my $card (@$cards) {
$score += $card;
if ($card == 11) { $aces++; };
}
while($score > 21 && $aces) {
$score -= 10;
$aces--;
}
if ($score > 21) { $score = 0; }
return sprintf("%2.2d", $score);
}
#-----------------------------------------------------------
sub draw {
return $DECK[rand(@DECK)];
}