二十一点!

作者:David Whipp

在“二十一点!”游戏中,参赛者必须编写一个脚本,用于发牌并玩一局二十一点(也称为黑杰克)。

比赛场景

作为高级组的决赛项目,您必须编写一个脚本,该脚本可以发牌并玩一局二十一点(也称为黑杰克)。在本项目中,我们将玩一个简化版的二十一点,其规则如下:

  • 不涉及下注。(抱歉,也许明年会加入。)

  • 所有 A 都计为 11 点。是的,我们知道:在标准的二十一点中,A 可以计为 1 点或 11 点。但是,在项目 10 中,A 只能计为 11 点。(我们不想让这个项目太复杂。)

好吧,如果您愿意,可以让 A 计为 1 点或 11 点。但除非您想这样做,否则不必这样做。

  • 所有花牌(国王、皇后、杰克)都计为 10 点。

  • 所有其他牌都等于其面值:黑桃 3 计为 3 点,方块 7 计为 7 点,等等。

  • 平局(推)算庄家赢。假设,在一局结束时,玩家有 18 点,庄家也有 18 点。在这种情况下,庄家被宣布为获胜者。

您的脚本应该首先“洗牌”一副标准的扑克牌,然后给玩家发两张牌,再给庄家发两张牌。(不知道“一副标准的扑克牌”有哪些牌?请点击此处了解更多信息。)与正规的二十一点一样,发给玩家的两张牌应该是“面朝上”的;也就是说,两张牌都应该亮出来。

Your cards:
Seven of Spades
Eight of Spades

相反,庄家的两张牌只有一张应该亮出来。

Dealer's cards:
Ace of Hearts

注意:请注意,我们是用名称来指定纸牌的。不要只列出纸牌的值,像这样:

7
8

这将导致您的脚本失败。在列出纸牌时要具体。

同样,按照标准的二十一点规则,玩家应该可以选择要牌(玩发给他的两张牌)或停牌(不再要牌)。换句话说:

Stay (s) or hit (h) ?

如果玩家选择“要牌”,那么应该再给他发一张牌。如果三张牌的总和超过 21,那么玩家自动输掉。

Stay (s) or hit (h) ?h
Seven of Spades
Eight of Spades
Seven of Diamonds
Over 21. Sorry, you lose.

如果总和是 20 或更少,那么玩家将有另一次机会选择要牌或停牌。(如果总和是 21,则玩家获胜。)一旦玩家选择停牌,庄家(计算机)就会检查自己的点数是否超过玩家。例如,假设玩家有黑桃 7 和黑桃 8;这意味着玩家有 15 点。现在假设庄家有红心 A 和方块 6。这意味着庄家有 17 点(11 + 6),这也意味着庄家自动获胜。

现在,假设玩家有 16 点,庄家有 13 点。在这种情况下,必须再给庄家发一张牌。让我们来看看下一张牌的一些可能性:

  • 庄家得到一张 2,使庄家有 15 点。这比玩家的 16 点少,所以庄家必须继续要牌。

  • 庄家得到一张 9,使他有 22 点。22 大于 21,所以庄家输了。

  • 庄家得到一张 3,使庄家和玩家都有 16 点。因为平局算庄家赢,所以庄家自动获胜。

一局完整的牌局可能像这样进行:

Your cards:
King of Hearts
Seven of Hearts

Dealer's cards:
Nine of Hearts

Stay (s) or hit (h)?s

You have 17.

Dealer's cards:
Nine of Hearts
Seven of Diamonds

Dealers' cards:

Nine of Hearts
Seven of Diamonds
Five of Diamonds
The dealer has 21. Sorry, you lose.

看到了吗?这应该不会太难,尤其是对于那些已经完成了前九个项目的人来说。

http://web.archive.org/web/20080406020248/http://www.microsoft.com/technet/scriptcenter/funzone/games/games08/aevent10.mspx

源代码:event010-dwhipp.p6

use v6;

sub MAIN(Bool :$computer-player = False) {
    my $player_is_human = not $computer-player;

    my @values = (
        ace => 1|11,
        two => 2,
        three => 3,
        four => 4,
        five => 5,
        six => 6,
        seven => 7,
        eight => 8,
        nine => 9,
        ten => 10,
        jack => 10,
        queen => 10,
        king => 10,
    );

    my @suites = < spades clubs diamonds hearts >;

    my @deck = ( @values X @suites ).flat.map: {
        my ($name, $value) = $^a.kv;
        $name ~= " of $^b";
        $name => $value
    };

    my @cards = $computer-player ?? default-cards() !! @deck.pick( @deck.elems );

    my @dealer;
    my @player;

    @dealer.push( @cards.shift );
    @player.push( @cards.shift );
    @dealer.push( @cards.shift );

    say "DEALER:";
    say @dealer[0].key;
    say "";

    say "PLAYER:";
    .key.say for @player;

    my $player_value = [+] @player.map: { .value };

    loop {
        my $card = @cards.shift;

        @player.push( $card );
        say $card.key;

        $player_value += $card.value;

        say "current value is { $player_value.perl }";

        if $player_value == 21 {
            say "congratulations, you win!";
            exit 0;
        }
        elsif $player_value < 21 {
            say "hit (h) or stay (s)";
            my $choice;
            if ($player_is_human) {
                loop {
                    $choice = lc $*IN.get;
                    last if $choice eq "h" | "s";
                    say "invalid entry: 'h' or 's'";
                }
            }
            else {
                $choice = $player_value < 16 ?? "hit" !! "stay";
            }
            say $choice;
            last if $choice ~~ /s/;
        }
        else {
            say "sorry, you bust!";
            exit 0;
        }
    }

    say "";

    $player_value = max (4 .. 21).grep: { $_ == $player_value };

    say "DEALER:";
    .key.say for @dealer;

    my $dealer_value = [+] @dealer.map: { .value };

    loop {
        say "dealer value: {$dealer_value.perl}";

        if $dealer_value == any( $player_value ^.. 21) {
            say "you lose!";
            exit 0;
        }
        elsif $dealer_value < 21 {
            my $card = @cards.shift;
            @dealer.push( $card );
            say $card.key;
            $dealer_value += $card.value;
        }
        else {
            say "dealer bust: you win!";
            exit 0;
        }
    }
}

sub default-cards {
    return [
    "three of diamonds" => 3,
    "five of diamonds" => 5,
    "seven of diamonds" => 7,
    "ten of diamonds" => 10,
    "two of diamonds" => 2,
    "jack of spades" => 10,
    "five of clubs" => 5,
    "five of hearts" => 5,
    "eight of diamonds" => 8,
    "six of spades" => 6,
    "five of spades" => 5,
    "king of hearts" => 10,
    "nine of diamonds" => 9,
    "two of hearts" => 2,
    "king of clubs" => 10,
    "eight of clubs" => 8,
    "two of spades" => 2,
    "ace of hearts" => any(1, 11),
    "nine of hearts" => 9,
    "eight of spades" => 8,
    "jack of diamonds" => 10,
    "jack of hearts" => 10,
    "nine of clubs" => 9,
    "ten of hearts" => 10,
    "eight of hearts" => 8,
    "king of spades" => 10,
    "ace of spades" => any(1, 11),
    "queen of hearts" => 10,
    "nine of spades" => 9,
    "two of clubs" => 2,
    "queen of diamonds" => 10,
    "three of spades" => 3,
    "queen of clubs" => 10,
    "three of clubs" => 3,
    "ten of spades" => 10,
    "ace of clubs" => any(1, 11),
    "ace of diamonds" => any(1, 11),
    "four of hearts" => 4,
    "six of clubs" => 6,
    "ten of clubs" => 10,
    "seven of hearts" => 7,
    "king of diamonds" => 10,
    "four of diamonds" => 4,
    "seven of spades" => 7,
    "queen of spades" => 10,
    "four of spades" => 4,
    "six of hearts" => 6,
    "four of clubs" => 4,
    "seven of clubs" => 7,
    "six of diamonds" => 6,
    "three of hearts" => 3,
    "jack of clubs" => 10]<>;
}