役を確認する

役を確認する

check は、役を確認するサブルーチンです。

手札を配列として、印と数字毎の枚数を数えて、以下のどの系統の役か判別します。

  1. フラッシュ系
  2. ストレート系
  3. ペア系

#役を確認する
sub check(@) {
  my (@player) = @_;
  my ($npair);#ペアの数
  my (@s);    #印毎の枚数
  my (@n);    #数字毎の枚数
  my (%flag); #確認フラグ

  #配列を初期化する
  for (0 .. $#suits) {
    $s[$_] = 0;
  }
  for (0 .. 12) {
    $n[$_] = 0;
  }

  foreach (@player) {
    my ($s0, $n0);#カードの印と数字

    #番号をカードに換算する
    ($s0, $n0) = &calc($_);

    #換算したカードの印と数字の枚数を追加する
    $s[$s0]++;
    $n[$n0]++;
  }

  #フラッシュ系
  $flag{'flush'} = 0;#フラッシュの確認フラグ
  foreach (@s) {
    if ($_ == $#player + 1) {
      $flag{'flush'} = 1;
      last;
    }
  }

  #ストレート系
  for (my $i = 0; $i < 10; $i++) {#ストレートの低位の数字は 1 から 10 まで
    $flag{'straight'} = 1;#ストレートの確認フラグ

    for (my $j = 0; $j <= $#player; $j++) {
      if ($n[($i + $j) % 13] != 1) {#13 は 1 と連なる
        $flag{'straight'} = 0;
        last;
      }
    }

    if ($flag{'straight'}) {
      if ($flag{'flush'}) {
        if ($i == 9) {
          return(9);#ロイヤル・ストレート・フラッシュ
        } else {
          return(8);#ストレート・フラッシュ
        }
      } else {
        return(4);#ストレート
      }
      last;
    }
  }
  return(5) if ($flag{'flush'});#フラッシュ

  #ペア系
  $flag{'three'} = 0;#スリーカードの確認フラグ
  $npair         = 0;
  foreach (@n) {
    if      ($_ == 4) {
      return(7);#フォーカード
    } elsif ($_ == 3) {
      $flag{'three'} = 1;
    } elsif ($_ == 2) {
      $npair++;
    }
  }
  if ($flag{'three'}) {
    if ($npair == 1) {
      return(6);#フルハウス
    } else {
      return(3);#スリーカード
    }
  } else {
    if      ($npair == 2) {
      return(2);#ツーペア
    } elsif ($npair == 1) {
      return(1);#ワンペア
    }
  }
  return(0);#ノーペア
}

参考として、正規表現を利用するサブルーチンも作ってみました。


sub check(@) {
  my (@player) = @_;
  my ($flag, $suits, $numbers);

  $suits   = '';
  $numbers = '';
  foreach (@player) {
    my ($s, $n);#カードの印と数字

    #番号をカードに換算する
    ($s, $n) = &calc($_);

    #A23456789TJQK を
    #abcdefghijklm に変えて、sort と正規表現を利用する
    $n++;
    if      (($n eq '1')  || ($n eq 'A')) {
      $n = 'a';
    } elsif (($n eq '10') || ($n eq 'T')) {
      $n = 'j';
    } elsif (($n eq '11') || ($n eq 'J')) {
      $n = 'k';
    } elsif (($n eq '12') || ($n eq 'Q')) {
      $n = 'l';
    } elsif (($n eq '13') || ($n eq 'K')) {
      $n = 'm';
    } else {
      $n =~ tr/2-9/b-i/;
    }

    $suits   .= $s;
    $numbers .= $n . ' ';
  }
  $numbers = join('', sort(split(/ /, $numbers)));

  #フラッシュやストレートを 2 進数で表現する
  $flag = ($suits          =~ /(.)\1{4}/) * 2**2 #フラッシュ
        + ($numbers        eq 'ajklm')    * 2**1 #ロイヤル・ストレート
        + ('abcdefghijklm' =~ /$numbers/) * 2**0;#ストレート

  return(9) if ($flag    == 6);                                #ロイヤル・ストレート・フラッシュ
  return(8) if ($flag    == 5);                                #ストレート・フラッシュ
  return(5) if ($flag    == 4);                                #フラッシュ
  return(4) if ($flag    >= 1);                                #ストレート
  return(7) if ($numbers =~ /(.)\1{3}/);                       #フォーカード
  return(6) if ($numbers =~ /((.)\2{2}(.)\3)|((.)\5(.)\6{2})/);#フルハウス
  return(3) if ($numbers =~ /(.)\1{2}/);                       #スリーカード
  return(2) if ($numbers =~ /(.)\1.?(.)\2/);                   #ツーペア
  return(1) if ($numbers =~ /(.)\1/);                          #ワンペア
  return(0);                                                   #ノーペア
}