gtheler пре 5 година
родитељ
комит
03312f7fbb
21 измењених фајлова са 690 додато и 0 уклоњено
  1. +22
    -0
      players/00-internal/README.m4
  2. +67
    -0
      players/00-internal/README.md
  3. +1
    -0
      players/00-internal/run.sh
  4. +32
    -0
      players/02-always-stand/README.m4
  5. +77
    -0
      players/02-always-stand/README.md
  6. +1
    -0
      players/02-always-stand/run.sh
  7. +1
    -0
      players/05-no-bust/.gitignore
  8. +46
    -0
      players/05-no-bust/README.m4
  9. +117
    -0
      players/05-no-bust/README.md
  10. +3
    -0
      players/05-no-bust/diff.sh
  11. +26
    -0
      players/05-no-bust/no-bust.awk
  12. +27
    -0
      players/05-no-bust/no-bust.pl
  13. +23
    -0
      players/05-no-bust/no-bust.sh
  14. +4
    -0
      players/05-no-bust/run.sh
  15. +2
    -0
      players/08-mimic-the-dealer/.gitignore
  16. +57
    -0
      players/08-mimic-the-dealer/README.m4
  17. +139
    -0
      players/08-mimic-the-dealer/README.md
  18. +1
    -0
      players/08-mimic-the-dealer/blackjack.conf
  19. +26
    -0
      players/08-mimic-the-dealer/mimic-the-dealer.awk
  20. +4
    -0
      players/08-mimic-the-dealer/run.sh
  21. +14
    -0
      players/README.md

+ 22
- 0
players/00-internal/README.m4 Прегледај датотеку

@@ -0,0 +1,22 @@
define(case_title, Internal player)
---
title: case_title
...

# case_title

> Difficulty: case_difficulty/100

If `blackjack` is called with the `-i` option, it uses an _internal_ player to play against itself. By default it plays basic strategy. Run

```terminal
include(run.sh)dnl
```

and you will get the following report with the results of playing one million hands with basic strategy.

```yaml
include(report.yaml)
```

case_nav

+ 67
- 0
players/00-internal/README.md Прегледај датотеку

@@ -0,0 +1,67 @@

---
title: Internal player
...

# Internal player

> Difficulty: 00/100

If `blackjack` is called with the `-i` option, it uses an _internal_ player to play against itself. By default it plays basic strategy. Run

```terminal
blackjack -i
```

and you will get the following report with the results of playing one million hands with basic strategy.

```yaml
---
rules:
decks: 6
hands: 1e+06
hit_soft_17: 1
double_after_split: 1
blackjack_pays: 1.5
rng_seed: -421186149
number_of_burnt_cards: 0
no_negative_bankroll: 0
max_bet: 0
penetration: 0.75
penetration_sigma: 0.05
cpu:
user: 1.88959
system: 0.32027
wall: 2.20904
second_per_hand: 2.2e-06
hands_per_second: 4.5e+05
player:
wins: 0.445075
pushes: 0.087039
losses: 0.492821
dealer_blackjacks: 0.047582
player_blackjacks: 0.047375
dealer_busts: 0.23537
player_busts: 0.160637
doubled_hands: 0.107207
doubled_wins: 0.0613
insured_hands: 0
insured_wins: 0
number_of_hands: 1e+06
number_of_shuffles: 23215
total_money_waged: 1.23935e+06
worst_bankroll: -7212.5
final_bankroll: -7111
return: -0.007111
variance: 1.32892
deviation: 1.15279
error: 0.00115279
result: "(-0.7 ± 0.2) %"
...

```

-------
:::{.text-center}
[Previous](../) | [Index](../) | [Next](../02-always-stand)
:::

+ 1
- 0
players/00-internal/run.sh Прегледај датотеку

@@ -0,0 +1 @@
blackjack -i

+ 32
- 0
players/02-always-stand/README.m4 Прегледај датотеку

@@ -0,0 +1,32 @@
define(case_title, Always stand)
---
title: case_title
...

# case_title

> Difficulty: case_difficulty/100

To play Blackjack as an “always-stander” run the following command:

```terminal
include(run.sh)dnl
```

The UNIX command `yes stand` writes the string “stand” repeteadly to the standard output, which is piped to the executable `blackjack` (assumed to be installed system-wide). The arguments tell Libre Blackjack to play one hundred thousand hands (`-n1e5`) using a flat bet (`flat_bet`, it defaults to a unit bet in each hand) and without asking for insurance if the dealer shows an ace (`no_insurance`). As there is no `blackjack.conf` file, the rules are---as expected---the default ones (see the documentation for details).

The `/dev/null` part is important, otherwise Libre Blackjack will think that there is a human at the other side of the table and will

1. run slower (it will add explicit time delays to mimic an actual human dealer), and
2. give all the details of the dealt hands in the terminal as ASCII (actually UTF-8) art

This example is only one-way (i.e. the player ignores what the dealer says) so it is better to redirect the standard output to `/dev/null` to save execution time. The results are written as a [YAML](http://yaml.org/)-formatted data to `stderr` by default once the hands are over, so they will show up in the terminal nevertheless. This format is human-friendly (far more than JSON) so it can be easily parsed, but it also allows complex objects to be represented (arrays, lists, etc.).


```yaml
include(report.yaml)
```

> **Exercise:** verify that the analytical probability of getting a natural playing with a single deck (for both the dealer and the player) is 32/663 = 0.04826546...

case_nav

+ 77
- 0
players/02-always-stand/README.md Прегледај датотеку

@@ -0,0 +1,77 @@

---
title: Always stand
...

# Always stand

> Difficulty: 02/100

To play Blackjack as an “always-stander” run the following command:

```terminal
yes stand | blackjack -n1e5 --flat_bet --no_insurance > /dev/null
```

The UNIX command `yes stand` writes the string “stand” repeteadly to the standard output, which is piped to the executable `blackjack` (assumed to be installed system-wide). The arguments tell Libre Blackjack to play one hundred thousand hands (`-n1e5`) using a flat bet (`flat_bet`, it defaults to a unit bet in each hand) and without asking for insurance if the dealer shows an ace (`no_insurance`). As there is no `blackjack.conf` file, the rules are---as expected---the default ones (see the documentation for details).

The `/dev/null` part is important, otherwise Libre Blackjack will think that there is a human at the other side of the table and will

1. run slower (it will add explicit time delays to mimic an actual human dealer), and
2. give all the details of the dealt hands in the terminal as ASCII (actually UTF-8) art

This example is only one-way (i.e. the player ignores what the dealer says) so it is better to redirect the standard output to `/dev/null` to save execution time. The results are written as a [YAML](http://yaml.org/)-formatted data to `stderr` by default once the hands are over, so they will show up in the terminal nevertheless. This format is human-friendly (far more than JSON) so it can be easily parsed, but it also allows complex objects to be represented (arrays, lists, etc.).


```yaml
---
rules:
decks: 6
hands: 100000
hit_soft_17: 1
double_after_split: 1
blackjack_pays: 1.5
rng_seed: -2067081387
number_of_burnt_cards: 0
no_negative_bankroll: 0
max_bet: 0
penetration: 0.75
penetration_sigma: 0.05
cpu:
user: 0.238384
system: 0.226465
wall: 0.462519
second_per_hand: 4.6e-06
hands_per_second: 2.2e+05
player:
wins: 0.38547
pushes: 0.04744
losses: 0.56709
dealer_blackjacks: 0.04749
player_blackjacks: 0.04803
dealer_busts: 0.27168
player_busts: 0
doubled_hands: 0
doubled_wins: 0
insured_hands: 0
insured_wins: 0
number_of_hands: 100000
number_of_shuffles: 2070
total_money_waged: 100000
worst_bankroll: -15870.5
final_bankroll: -15868
return: -0.15868
variance: 0.984727
deviation: 0.992334
error: 0.00313804
result: "(-15.9 ± 0.6) %"
...

```

> **Exercise:** verify that the analytical probability of getting a natural playing with a single deck (for both the dealer and the player) is 32/663 = 0.04826546...

-------
:::{.text-center}
[Previous](../00-internal) | [Index](../) | [Next](../05-no-bust)
:::

+ 1
- 0
players/02-always-stand/run.sh Прегледај датотеку

@@ -0,0 +1 @@
yes stand | blackjack -n1e5 --flat_bet --no_insurance > /dev/null

+ 1
- 0
players/05-no-bust/.gitignore Прегледај датотеку

@@ -0,0 +1 @@
fifo

+ 46
- 0
players/05-no-bust/README.m4 Прегледај датотеку

@@ -0,0 +1,46 @@
define(case_title, No-bust strategy)
---
title: case_title
...

# case_title

> Difficulty: case_difficulty/100

This directory shows how to play a “no-bust” strategy, i.e. not hitting any hand higher or equal to hard twelve with Libre Blackjack. The communication between the player and the back end is through standard input and output. The player reads from its standard input Libre Blackjack's commands and writes to its standard output the playing commands. In order to do this a FIFO (a.k.a. named pipe) is needed. So first, we create it (if it is not already created):

```terminal
mkfifo fifo
```

Then we execute `blackjack`, piping its output to the player (say `no-bust.pl`) and reading the standard input from `fifo`, whilst at the same time we redirect the player's standard output to `fifo`:

```terminal
include(run.sh)dnl
```

As this time the player is coded in an interpreted langauge, it is far smarter than the previous `yes`-based player. So the player can handle bets and insurances, and there is not need to pass the options `--flat_bet` nor `--no_insurance` (though they can be passed anyway). Let us take a look at the Perl implementation:

```perl
include(no-bust.pl)dnl
```

The very same player may be implemented as a shell script:

```bash
include(no-bust.sh)dnl
```

To check these two players give the same results, make them play against Libre Blackjack with the same seed (say one) and send the YAML report to two different files:

```terminal
include(diff.sh)
esyscmd(diff perl.yml shell.yml)dnl
```

As expected, the reports are the same. They just differ in the speed because the shell script is orders of magnitude slower than its Perl-based counterpart.

> **Exercise:** modify the players so they always insure aces and see if it improves or degrades the result.


case_nav

+ 117
- 0
players/05-no-bust/README.md Прегледај датотеку

@@ -0,0 +1,117 @@

---
title: No-bust strategy
...

# No-bust strategy

> Difficulty: 05/100

This directory shows how to play a “no-bust” strategy, i.e. not hitting any hand higher or equal to hard twelve with Libre Blackjack. The communication between the player and the back end is through standard input and output. The player reads from its standard input Libre Blackjack's commands and writes to its standard output the playing commands. In order to do this a FIFO (a.k.a. named pipe) is needed. So first, we create it (if it is not already created):

```terminal
mkfifo fifo
```

Then we execute `blackjack`, piping its output to the player (say `no-bust.pl`) and reading the standard input from `fifo`, whilst at the same time we redirect the player's standard output to `fifo`:

```terminal
if test ! -e fifo; then
mkfifo fifo
fi
blackjack -n1e5 < fifo | ./no-bust.pl > fifo
```

As this time the player is coded in an interpreted langauge, it is far smarter than the previous `yes`-based player. So the player can handle bets and insurances, and there is not need to pass the options `--flat_bet` nor `--no_insurance` (though they can be passed anyway). Let us take a look at the Perl implementation:

```perl
#!/usr/bin/perl
# this is needed to avoid deadlock with the fifo
STDOUT->autoflush(1);

while ($command ne "bye") {
# do not play more than a number of commands
# if the argument -n was not passed to blackjack
if ($i++ == 123456789) {
print "quit\n";
exit;
}
# read and process the commands
chomp($command = <STDIN>);
if ($command eq "bet?") {
print "1\n";
} elsif ($command eq "insurance?") {
print "no\n";
} elsif ($comm eq "play?") {
print "count\n";
chomp($count = <STDIN>); # the count
chomp($play = <STDIN>); # again the "play?" query
if ($count < 12) {
print "hit\n";
} else {
print "stand\n";
}
}
}
```

The very same player may be implemented as a shell script:

```bash
#!/bin/sh

while read command
do
if test "${command}" = 'bye'; then
exit
elif test "${command}" = 'bet?'; then
echo 1
elif test "${command}" = 'insurance?'; then
echo "no"
elif test "`echo ${command} | cut -c-5`" = 'play?'; then
echo "count"
read count
read play # blackjack will ask again for 'play?'
if test ${count} -lt 12; then
echo "hit"
else
echo "stand"
fi
fi
done
```

To check these two players give the same results, make them play against Libre Blackjack with the same seed (say one) and send the YAML report to two different files:

```terminal
blackjack -n1e3 --rng_seed=1 --yaml_report=perl.yml \
< fifo | ./no-bust.pl > fifo
blackjack -n1e3 --rng_seed=1 --yaml_report=shell.yml \
< fifo | ./no-bust.sh > fifo
diff perl.yml shell.yml

15,19c15,19
< user: 0
< system: 0.022603
< wall: 0.034317
< second_per_hand: 3.4e-05
< hands_per_second: 2.9e+04
---
> user: 0.06838
> system: 0.13676
> wall: 11.1446
> second_per_hand: 1.1e-02
> hands_per_second: 9.0e+01
```

As expected, the reports are the same. They just differ in the speed because the shell script is orders of magnitude slower than its Perl-based counterpart.

> **Exercise:** modify the players so they always insure aces and see if it improves or degrades the result.


-------
:::{.text-center}
[Previous](../02-always-stand) | [Index](../) | [Next](../08-mimic-the-dealer)
:::

+ 3
- 0
players/05-no-bust/diff.sh Прегледај датотеку

@@ -0,0 +1,3 @@
../../blackjack -n100000 --rng_seed=1 --yaml_report=perl.yml < fifo | ./no-bust.pl > fifo
../../blackjack -n100000 --rng_seed=1 --yaml_report=shell.yml < fifo | ./no-bust.awk > fifo
# diff perl.yml shell.yml

+ 26
- 0
players/05-no-bust/no-bust.awk Прегледај датотеку

@@ -0,0 +1,26 @@
#!/usr/bin/gawk -f
# mawk does not work, it hangs due to the one-sided FIFO
{
if (n++ > 1234567) {
print "quit";
}
}
/bet\?/ {
print "1"
fflush()
}
/insurance\?/ {
print "no"
fflush()
}
/play\?/ {
if ($2 < 12) {
print "hit";
} else {
print "stand";
}
fflush()
}
/bye/ {
exit;
}

+ 27
- 0
players/05-no-bust/no-bust.pl Прегледај датотеку

@@ -0,0 +1,27 @@
#!/usr/bin/perl
# this is needed to avoid deadlock with the fifo
STDOUT->autoflush(1);

while ($command ne "bye") {
# do not play more than a number of commands
# if the argument -n was not passed to blackjack
if ($i++ == 1234567) {
print "quit\n";
}
# read and process the commands
chomp($command = <STDIN>);
if ($command eq "bet?") {
print "1\n";
} elsif ($command eq "insurance?") {
print "no\n";
} elsif (substr($command, 0, 5) eq "play?") {
@tokens = split(/ /, $command);
if ($tokens[1] < 12) {
print "hit\n";
} else {
print "stand\n";
}
}
}

+ 23
- 0
players/05-no-bust/no-bust.sh Прегледај датотеку

@@ -0,0 +1,23 @@
#!/bin/sh

i=0
while read command
do
i=$((i+1))
if test ${i} -ge 12345; then
echo "quit"
elif test "${command}" = 'bye'; then
exit
elif test "${command}" = 'bet?'; then
echo 1
elif test "${command}" = 'insurance?'; then
echo "no"
elif test "$(echo ${command} | cut -c-5)" = 'play?'; then
count=$(echo ${command} | cut -f2 -d" ")
if test ${count} -lt 12; then
echo "hit"
else
echo "stand"
fi
fi
done

+ 4
- 0
players/05-no-bust/run.sh Прегледај датотеку

@@ -0,0 +1,4 @@
if test ! -e fifo; then
mkfifo fifo
fi
blackjack -n1e5 < fifo | ./no-bust.pl > fifo

+ 2
- 0
players/08-mimic-the-dealer/.gitignore Прегледај датотеку

@@ -0,0 +1,2 @@
d2p
p2d

+ 57
- 0
players/08-mimic-the-dealer/README.m4 Прегледај датотеку

@@ -0,0 +1,57 @@
define(case_title, Mimic the dealer)
---
title: case_title
...

# case_title

> Difficulty: case_difficulty/100

This example implements a “mimic-the-dealer strategy,” i.e. hits if the hand totals less than seventeen and stands on eighteen or more. The player stands on hard seventeen but hits on soft seventeen.

This time, the configuration file `blackjack.conf` is used. If a file with this name exists in the directory where `blackjack` is executed, it is read and parsed. The options should be fairly self descriptive. See the [configuration file] section of the manual for a detailed explanation of the variables and values that can be entered. In particular, we ask to play one hundred thousand hands at a six-deck game where the dealer hits soft seventeens. If the random seed is set to a fixed value so each execution will lead to the very same sequence of cards.

Now, there are two options that tell Libre Blackjack how the player is going to talk to the backend: `player2dealer` and `dealer2player`. The first one sets the communication mechanism from the player to the dealer (by default is `blackjack`’s standard input), and the second one sets the mechanism from the dealer to the player (by default `blackjack`’s standard output). In this case, the configuration file reads:

```ini
include(blackjack.conf)dnl
```

This means that two FIFOs (a.k.a. named pipes) are to be used for communication, `player2dealer` from the player to the dealer and `dealer2player` for the dealer to the player. If these FIFOs do not exist, they are created by `blackjack` upon execution.

The player this time is implemented as an awk script, whose input should be read from `dealer2player` and whose output should be written to `player2dealer`. To run the game, execute `blackjack` in one terminal making sure the current directory is where the `blackjack.conf` file exists. It should print a message telling that it is waiting for someone to be at the other side of the named pipes:

```terminal
$ blackjack
[...]
waiting for dealer2player buffered fifo 'dealer2player'...
```

In another terminal run the player

```terminal
$ ./mimic-the-dealer.awk < dealer2player > player2dealer
```

Both dealer and player may be run in the same terminal putting the first one on the background:

```terminal
include(run.sh)dnl
```

To understand the decisions taken by the player, we have to remember that when Libre Blackjack receives the command `count` asking for the current player's count, it returns a positive number for hard hands and a negative number for soft hands. The instructions `fflush()` are needed in order to avoid deadlocks on the named pipes:

```awk
include(mimic-the-dealer.awk)dnl
```

```yaml
include(report.yaml)
```

> **Exercise:** modify the player and the configuration file so both the dealer and the player may stand on soft seventeen. Analyze the four combinations (player h17 - dealer h17, player h17 - dealer s17, player s17 - dealer h17, player s17 - dealer s17)



case_nav


+ 139
- 0
players/08-mimic-the-dealer/README.md Прегледај датотеку

@@ -0,0 +1,139 @@

---
title: Mimic the dealer
...

# Mimic the dealer

> Difficulty: 08/100

This example implements a “mimic-the-dealer strategy,” i.e. hits if the hand totals less than seventeen and stands on eighteen or more. The player stands on hard seventeen but hits on soft seventeen.

This time, the configuration file `blackjack.conf` is used. If a file with this name exists in the directory where `blackjack` is executed, it is read and parsed. The options should be fairly self descriptive. See the [configuration file] section of the manual for a detailed explanation of the variables and values that can be entered. In particular, we ask to play one hundred thousand hands at a six-deck game where the dealer hits soft seventeens. If the random seed is set to a fixed value so each execution will lead to the very same sequence of cards.

Now, there are two options that tell Libre Blackjack how the player is going to talk to the backend: `player2dealer` and `dealer2player`. The first one sets the communication mechanism from the player to the dealer (by default is `blackjack`’s standard input), and the second one sets the mechanism from the dealer to the player (by default `blackjack`’s standard output). In this case, the configuration file reads:

```ini
hands = 1e5
decks = 6
hit_soft_17 = 1
# uncomment to obtain the same cards each time
# rng_seed = 1

player2dealer = fifo mimic_p2d
dealer2player = fifo mimic_d2p
buffered_fifo = 1
```

This means that two FIFOs (a.k.a. named pipes) are to be used for communication, `player2dealer` from the player to the dealer and `dealer2player` for the dealer to the player. If these FIFOs do not exist, they are created by `blackjack` upon execution.

The player this time is implemented as an awk script, whose input should be read from `dealer2player` and whose output should be written to `player2dealer`. To run the game, execute `blackjack` in one terminal making sure the current directory is where the `blackjack.conf` file exists. It should print a message telling that it is waiting for someone to be at the other side of the named pipes:

```terminal
$ blackjack
[...]
waiting for dealer2player buffered fifo 'dealer2player'...
```

In another terminal run the player

```terminal
$ ./mimic-the-dealer.awk < dealer2player > player2dealer
```

Both dealer and player may be run in the same terminal putting the first one on the background:

```terminal
rm -f mimic_d2p mimic_p2d
mkfifo mimic_d2p mimic_p2d
blackjack &
gawk -f mimic-the-dealer.awk < mimic_d2p > mimic_p2d
```

To understand the decisions taken by the player, we have to remember that when Libre Blackjack receives the command `count` asking for the current player's count, it returns a positive number for hard hands and a negative number for soft hands. The instructions `fflush()` are needed in order to avoid deadlocks on the named pipes:

```awk
#!/usr/bin/gawk -f
function abs(x){return ( x >= 0 ) ? x : -x }

/bet\?/ {
print "1";
fflush();
}

/insurance\?/ {
print "no";
fflush();
}

/play\?/ {
count = $2
# mimic the dealer: hit until 17 (hit soft 17)
if (abs(count) < 17 || count == -17) { # soft hands are negative
print "hit";
} else {
print "stand";
}
fflush();
}

/bye/ {
exit;
}
```

```yaml
---
rules:
decks: 6
hands: 100000
hit_soft_17: 1
double_after_split: 1
blackjack_pays: 1.5
rng_seed: -1448949563
number_of_burnt_cards: 0
no_negative_bankroll: 0
max_bet: 0
penetration: 0.75
penetration_sigma: 0.05
cpu:
user: 0.631905
system: 1.19576
wall: 2.15273
second_per_hand: 2.2e-05
hands_per_second: 4.6e+04
player:
wins: 0.41044
pushes: 0.09695
losses: 0.49261
dealer_blackjacks: 0.04658
player_blackjacks: 0.04663
dealer_busts: 0.18984
player_busts: 0.27268
doubled_hands: 0
doubled_wins: 0
insured_hands: 0
insured_wins: 0
number_of_hands: 100000
number_of_shuffles: 2326
total_money_waged: 100000
worst_bankroll: -5996.5
final_bankroll: -5994.5
return: -0.059945
variance: 0.955017
deviation: 0.97725
error: 0.00309034
result: "(-6.0 ± 0.6) %"
...

```

> **Exercise:** modify the player and the configuration file so both the dealer and the player may stand on soft seventeen. Analyze the four combinations (player h17 - dealer h17, player h17 - dealer s17, player s17 - dealer h17, player s17 - dealer s17)



-------
:::{.text-center}
[Previous](../05-no-bust) | [Index](../) | [Next](../20-basic-strategy)
:::


+ 1
- 0
players/08-mimic-the-dealer/blackjack.conf Прегледај датотеку

@@ -0,0 +1 @@
h17 = true

+ 26
- 0
players/08-mimic-the-dealer/mimic-the-dealer.awk Прегледај датотеку

@@ -0,0 +1,26 @@
#!/usr/bin/gawk -f
function abs(x){return ( x >= 0 ) ? x : -x }

/bet\?/ {
print "1";
fflush();
}

/insurance\?/ {
print "no";
fflush();
}

/play\?/ {
# mimic the dealer: hit until 17 (hit soft 17)
if (abs($2) < 17 || $2 == -17) { # soft hands are negative
print "hit";
} else {
print "stand";
}
fflush();
}

/bye/ {
exit;
}

+ 4
- 0
players/08-mimic-the-dealer/run.sh Прегледај датотеку

@@ -0,0 +1,4 @@
rm -f d2p p2d
mkfifo d2p p2d
gawk -f mimic-the-dealer.awk < d2p > p2d &
../../blackjack -n100000 > d2p < p2d

+ 14
- 0
players/README.md Прегледај датотеку

@@ -0,0 +1,14 @@
---
title: Example players for LibreBlackjack
...

# Example players for LibreBlackjack

The subdirectory `players` contains some automatic players that play against LibreBlackjack. These players are coded in different languages and communicate with LibreBlackjack in a variety of ways in order to illustrate the design basis:

* [`00-internal`](00-internal) uses the internal player that defaults to playing one million hands of basic strategy
* [`02-always-stand`](02-always-stand), using the UNIX tool `yes` this player always says “stand” into the standard output (which is piped to libreblackjack’s standard input) no matter what the cards are
* [`05-no-bust`](05-no-bust) is a PERL-based player does not bust (i.e. hits if the hard total is less than twelve) that receives tha cards through the standard input but draws or stands using a FIFO to talk back to the dealer
* [`08-mimic-the-dealer`](08-mimic-the-dealer) does tha same the dealer do (hits soft seventeens). It is implemented in AWK using two FIFOs.
* [`20-basic-strategy`](20-basic-strategy) derives the basic strategy from scratch in less than one minute.


Loading…
Откажи
Сачувај