ブラックジャックの Perl プログラム

ブラックジャックの Perl プログラム

以下は、Perl によるブラックジャックのプログラムの一例です。


#!/usr/bin/perl

#カードを混ぜる
&shuffle;

while ($#stack > 10) {
  undef @PlayerHands;#プレーヤーの手札
  undef @DealerHands;#ディーラーの手札

  printf "--- Round %d ---\n". ++$nround;

  #カードを配る
  for (0 .. 1) {
    push(@PlayerHands, shift(@stack));
    push(@DealerHands, shift(@stack));
  }

  #合計点数を計算する
  $PlayerPoint = &calc(@PlayerHands);
  $DealerPoint = &calc(@DealerHands);

  #プレーヤーの処理を行う
  &player;

  #ディーラーの処理を行う
  &dealer;

  #カードを画面に表示する
  &display(1);
}

printf "--- Dealer doesn't have enough cards to continue. ---\n";

#カードを混ぜる
sub shuffle {
  local($s);

  #擬似乱数を初期化する
  srand:

  foreach $s ("S", "H", "D", "C") {#1 組 52 枚のカード
    for (1 .. 13) {
      push(@deck, "$s$_");
    }
  }

  #@deck から 1 枚ずつ @stack に移動する
  while ($#deck >= 0) {
    push(@stack, splice(@deck, int(rand($#deck + 1)), 1));
  }
}

#合計点数を計算する
sub calc {
  local(@hands) = @_;
  local(@numbers, $point, $na);

  #数字を取出す
  foreach (@hands) {
    $_ =~ /[A-Z](\d+)/;#「アルファベットと 1 文字以上の数字」の数字部分を取出す
    push(@numbers, $1);
  }

  foreach (@numbers) {
    if ($_ <= 10) {
      $point += $_;

      $na++ if ($_ == 1);#A の枚数を数える
    } else {#絵札は 10 点
      $point += 10;
    }
  }

  if      ($point <= 11) {#A は 1 点としても 11 点としてもよい
    $point += 10 if ($na);
  } elsif ($point >= 22) {#合計点数が 21 点を超えていたら 0 点にする
    $point = 0;
  }

  $point;
}

#カードを画面に表示する
sub display {
  local($flag) = @_;

  print "PlayerHands : ", join(", ", @PlayerHands), " [$PlayerPoint]\n";

  if      ($flag == 0) {
    print "DealerHands : ", @DealerHands[0], ", ?\n";
  } elsif ($flag == 1) {
    print "DealerHands : ", join(", ", @DealerHands), " [$DealerPoint]\n";

    if      ($PlayerPoint == 0) {
      printf "Player Busted.\n";
    } elsif ($DealerPoint == 0) {
      printf "Dealyer Busted.\n";
    } elsif ($PlayerPoint >  $DealerPoint) {
      printf "Player Won.\n";
    } elsif ($PlayerPoint <  $DealerPoint) {
      printf "Dealer Won.\n";
    } elsif ($PlayerPoint == $DealerPoint) {
      printf "Push.\n";
    }
  }
}

#プレーヤーの処理を行う
sub player {
  local($input);

  while (1) {
    #カードを画面に表示する
    &display(0);

    #プレーヤーの処理を行う
    printf "  Draw(D, d) or Stand(S, s) or Quit(Q, q)? : ";
    chop($input = <STDIN>);
    if      (($input eq "D") || ($input eq "d")) {#カードを引く
      printf "  Draw\n";
      push(@PlayerHands, shift(@stack));
      $PlayerPoint = &calc(@PlayerHands);
      last if ($PlayerPoint == 0);
    } elsif (($input eq "S") || ($input eq "s")) {#カードを引かない
      printf "  Stand\n";
      last;
    } elsif (($input eq "Q") || ($input eq "q")) {#終了する
      exit;
    } else {
      printf "Input Error!\n";
    }
  }
}

#ディーラーの処理を行う
sub dealer {
  while ($PlayerPoint) {
    last if ($DealerPoint >= 17);#16 でドロー(ヒット)/17 でスタンド(ステイ)

    push(@DealerHands, shift(@stack));
    $DealerPoint = &calc(@DealerHands);
    last if ($DealerPoint == 0);
  }
}

各ルーチンについて、以下に説明します。