Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@t-kunou

Ruby2.7.0-devのパターンマッチでポーカーの役を判定してみた

More than 1 year has passed since last update.

Ruby2.7ではパターンマッチが入るらしいと聞いたので、Ruby2.7.0-devでポーカーの役のチェックを書いてみました。
このコードは今の所Ruby2.7.0-devでしか動きませんし、もしかすると将来的にもRuby2.7.0-devでしか動かないかもしれません。あしからず。

コード

出来上がったコードはこんな感じで、

class PokerChecker
  def check(cards)
    case cards.sort { @1[1] <=> @2[1] }
      in [[m, a], [^m, b], [^m, c], [^m, d], [^m, e]] if a != 1 && [a, b, c, d].zip([b, c, d, e]).map { @2 - @1 }.all? { @1 == 1 } ; :straight_flush
      in [[m, 1], [^m, 10], [^m, 11], [^m, 12], [^m, 13]]; :straight_flush
      in [[_, a], [_, ^a], [_, ^a], [_, ^a], [_, _]]; :four_of_kind
      in [[_, _], [_, a], [_, ^a], [_, ^a], [_, ^a]]; :four_of_kind
      in [[_, a], [_, b], [_, c], [_, d], [_, e]] if a != 1 && [a, b, c, d].zip([b, c, d, e]).map { @2 - @1 }.all? { @1 == 1 } ; :straight
      in [[_, 1], [_, 10], [_, 11], [_, 12], [_, 13]]; :straight
      in [[m, _], [^m, _], [^m, _], [^m, _], [^m, _]]; :flush
      in [[_, a], [_, ^a], [_, b], [_, ^b], [_, ^b]]; :full_house
      in [[_, a], [_, ^a], [_, ^a], [_, b], [_, ^b]]; :full_house
      in [[_, a], [_, ^a], [_, ^a], [_, _], [_, _]]; :three_of_kind
      in [[_, _], [_, a], [_, ^a], [_, ^a], [_, _]]; :three_of_kind
      in [[_, _], [_, _], [_, a], [_, ^a], [_, ^a]]; :three_of_kind
      in [[_, a], [_, ^a], [_, b], [_, ^b], [_, _]]; :two_pair
      in [[_, _], [_, a], [_, ^a], [_, b], [_, ^b]]; :two_pair
      in [[_, a], [_, ^a], [_, _], [_, b], [_, ^b]]; :two_pair
      in [[_, a], [_, ^a], [_, _], [_, _], [_, _]]; :one_pair
      in [[_, _], [_, a], [_, ^a], [_, _], [_, _]]; :one_pair
      in [[_, _], [_, _], [_, a], [_, ^a], [_, _]]; :one_pair
      in [[_, _], [_, _], [_, _], [_, a], [_, ^a]]; :one_pair
      else; :buta
    end
  end
end

使うときはこんな感じです。

irb(main):003:0> PokerChecker.new.check([[:s, 2], [:d, 2], [:h, 2], [:c, 8], [:h, 8]])
=> :full_house

checkメソッドに配列の配列を渡していて、中身の配列の1つ目がトランプのマーク、2つ目がトランプの数値を表しています。上の例だと、スペードの2、ダイヤの2、ハートの2、クラブの8、ハートの8でフルハウスとなっています。

ストレートフラッシュの判定でいきなり if の力に頼っているのがいささか残念ですが、20行ちょっとで書けていることからパターンマッチの強力さが伺えます。(テストも書いたので多分バグは無いと思いますが、バグってたらすみません)

パターンマッチの記法に慣れないうちは面食らうと思いますが、慣れてくれば気にならなくなるのではないでしょうか(きっと)。

書いていてなかなか楽しかったので、早く仕事でも使えるようになると良いですね。

その他所感

ストレート(とストレートフラッシュ)の判定について

本当は

in [[_, a], [_, ^a + 1], [_, ^a + 2], [_, ^a + 3], [_, ^a + 4]]; :straight

のように書きたかったのですが、これはSyntaxErrorになってしまいました。

SyntaxError ((irb):9: syntax error, unexpected '+', expecting ']')
in [[_, a], [_, ^a + 1], [_, ^a + 2], [_, ^a + 3]...
                   ^

^a + 1 を括弧で囲んでも変わらなかったので、諦めて連続しているかの判定を if で書いています。

Arrayパターンで変数へ代入しつつ複数条件書く時

パターンマッチでは、 | 区切りで複数のパターンが書けます。

irb(main):018:0> case 3; in 1 | 2 | 3; :match; end
=> :match

これはArrayパターンでも同様に使えます。

irb(main):016:0> case [1, 2, 2]; in [1, 2, 2] | [2, 2, 1]; :match; end
=> :match

が、変数への代入も合わせて書くと…

irb(main):017:0> case [1, 2, 2]; in [_, a, ^a] | [a, ^a, _]; :match; end
Traceback (most recent call last):
        1: from (irb)
SyntaxError ((irb):17: illegal variable in alternative pattern (a))
(irb):17: illegal variable in alternative pattern (a)

と、これまたSyntaxErrorになってしまいました。

irb(main):019:0> case [1, 2, 2]; in [_, a, ^a]; :match; end
=> :match

↑は動くので意図的な物なのか何なのかよく分かりません。

ただし、分解して別のin にすれば良いですし、かえって分解したほうが読みやすくなったので結果的には良かったです。

Numbered arguments

ついでにNumbered argumentsも使ってみました。一行に収まる程度のブロック(またはProc)であれば、可読性を保ったまま短くかけそうです。

おまけ

本文中では読みやすさのために消していますが、パターンマッチを書くと warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby! というありがたい警告が出ました。

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
esm
ソフトウェアで未来をつくる、人のチカラで未来をつくる。福井、東京、沖縄で活動するエンジニア集団。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?