Let's make draw poker with ruby-Implementation 2 (role)-

Overview

Let's make draw poker with ruby-Preparation-Let's make draw poker with ruby-test-unit preparation-Let's make draw poker with ruby-Implementation 1 (card)-

Followed by.

Source: https://github.com/rytkmt/ruby_poker

This time we will implement the role.

Implementation of roles

Let's reorganize the requirements. --The role is judged based on 5 cards --Players compare wins and losses based on their roles --If you create a "role" class to compare roles and use Comparable, you can compare them. ――Among the roles, hold the cards to be compared for the same role (1 card) ――The role is "** hand **" in English. This is important.

So it's time to implement.

File creation

First of all, create a file normally

ruby_poker/hand.rb


module RubyPoker
  class Hand
    def intialize(cards:)
    end
  end
end

ruby_poker.rb


require "ruby_poker/hand"

Role judgment

If you are generating a "role" class, you should make a judgment at that timing. ..

Therefore, use the judgment method at the time of generation and set the comparison card for the type and the same role.

Generate

ruby_poker/hand.rb


    attr_reader :hand_type, :comparison_card

    def intialize(cards:)
      raise(ArgumentError) if cards.size != 5
      @hand_type, @comparison_card = judge(cards: cards)
    end

  private

    def judge(cards:)
    end

Don't make it an instance variable because you don't need to keep it just by using cards to judge the role.

How to implement role judgment ...

Since there are many roles, I feel that I haven't been able to separate them by preparing methods one by one. .. So, let's cut it out as a judgment module.

Then, the judgment should be made in order of strength, and the one that matches at the beginning should be set. First, define it as you did for the card.

Type definition

Refer to here for the English name ... lol https://en.wikipedia.org/wiki/List_of_poker_hands

ruby_poker.rb


  HAND_TYPES = %i[
    royal_straight_flush
    straight_flush
    four_of_a_kind
    full_house
    flush
    straight
    three_of_a_kind
    two_pair
    one_pair
    high_card
  ].reverse.freeze

Since I want to get the module class dynamically, I want to convert from snake case to camel case and get it with const_get. .. So let's use the ʻactive_support` gem for word conversion there (When I usually touch rails, it's convenient to reach the itchy area around here and I want to use it.)

Gemfile


gem "activesupport"
$ bundle install

This completes the installation

ruby_poker.rb


require "active_support/all"

Don't forget to read

Transfer judgment to module

ruby_poker/hand.rb


Dir[__dir__ + "/hand/hand_type_judgers/*.rb"].each { |p| require p }

module RubyPoker
  class Hand

ruby_poker/hand.rb


  private

    def judge(cards:)
      matched_cards = nil
      matched_type = RubyPoker::HAND_TYPES.find do |type|
        judger = RubyPoker::Hand::HandTypeJudgers.const_get(type.to_s.classify) # <=Active for here_support
        matched_cards = judger.judge(cards: cards)
      end

      [matched_type, matched_cards.max]
    end

I thought that it was within the responsibility of hand in the form of separating the internal processing of hand, so I will implement it as an inner module of hand. Judger's .judge always returns the card that is the target of the same role judgment if it matches, and returns nil if it does not match

Role judgment module implementation

Royal straight flush

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/royal_straight_flush.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module RoyalStraightFlush
        def self.judge(cards:)
          return nil unless cards.map(&:suit).uniq.size == 1
          return nil unless cards.sort.map(&:number) == [10, 11, 12, 13, 1]
          cards
        end
      end
    end
  end
end
Straight flush

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/straight_flush.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module StraightFlush
        def self.judge(cards:)
          return nil unless cards.map(&:suit).uniq.size == 1
          min_number_level = cards.min.number_level
          expected = [*min_number_level..min_number_level + 4]
          return nil unless cards.sort.map(&:number_level) == expected
          cards
        end
      end
    end
  end
end
Four Cards

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/four_of_a_kind.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module FourOfAKind
        def self.judge(cards:)
          cards.group_by(&:number).detect { |k, v| v.size == 4 }&.second
        end
      end
    end
  end
end
Full house

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/full_house.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module FullHouse
        def self.judge(cards:)
          grouped_number_cards = cards.group_by(&:number)
          three_card_number, three_cards = grouped_number_cards.detect { |k, v| v.size == 3 }
          return nil unless three_card_number
          grouped_number_cards.delete(three_card_number)
          return nil unless grouped_number_cards.detect { |k, v| v.size == 2 }
          three_cards
        end
      end
    end
  end
end
flash

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/flush.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module Flush
        def self.judge(cards:)
          return nil unless cards.map(&:suit).uniq.size == 1
          cards
        end
      end
    end
  end
end
straight

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/straight.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module Straight
        def self.judge(cards:)
          min_number_level = cards.min.number_level
          expected = [*min_number_level..min_number_level + 4]
          return nil unless cards.sort.map(&:number_level) == expected
          cards
        end
      end
    end
  end
end
Three cards

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/three_of_a_kind.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module ThreeOfAKind
        def self.judge(cards:)
          cards.group_by(&:number).detect { |k, v| v.size == 3 }&.second
        end
      end
    end
  end
end
Two pair

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/two_pair.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module TwoPair
        def self.judge(cards:)
          pairs = cards.group_by(&:number_level).select { |k, v| v.size == 2 }
          return nil unless pairs.size == 2
          pairs.max.second
        end
      end
    end
  end
end
One pair

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/one_pair.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module OnePair
        def self.judge(cards:)
          cards.group_by(&:number_level).detect { |k, v| v.size == 2 }&.second
        end
      end
    end
  end
end
High card (pig)

ruby_poker/lib/ruby_poker/hand/hand_type_judgers/high_card.rb


module RubyPoker
  class Hand
    module HandTypeJudgers
      module HighCard
        def self.judge(cards:)
          [cards.max]
        end
      end
    end
  end
end

It was a little difficult including the implementation of the test, but the implementation was completed. Now you can perform the role judgment and return the judgment card at the same time.

Addition of judgment for Comparable

ruby_poker/hand.rb


+    include Comparable

ruby_poker/hand.rb


    def hand_level
      RubyPoker::HAND_TYPES.reverse.index(@hand_type)
    end

    def <=>(other)
      hand_comparison = hand_level <=> other.hand_level
      hand_comparison.zero? ? @comparison_card <=> other.comparison_card : hand_comparison
    end

Now you can compare the wins and losses of roles by > etc.

At the end

With this content, I think that all the important processing for the game, such as cards and roles, has been completed. Next time, I would like to create players who use these and the game progress.

Continued

Try to make draw poker with ruby-Implementation 3 (player)-

Recommended Posts

Let's make draw poker with ruby-Implementation 2 (role)-
Let's make draw poker with ruby-Implementation 1 (card)-
Let's make draw poker with ruby-Implementation 4 (Deck)-
Let's make draw poker with ruby-Implementation 3 (player)-
Let's make draw poker with ruby ~ Preparation ~
Let's make draw poker with ruby ~ test-unit preparation ~
Let's make a Christmas card with Processing!
Let's make a smart home with Ruby!
Let's make an error screen with Rails
Let's make a search function with Rails (ransack)
[Java basics] Let's make a triangle with a for statement
Make Nginx of CentOS8 SSL compatible with Let's Encrypt
Let's make a LINE Bot with Ruby + Sinatra --Part 1
Let's make Rails-like (View)
Let's scrape with Java! !!
Let's write how to make API with SpringBoot + Docker from 0
Let's make a simple API with EC2 + RDS + Spring boot ①