Last active
December 21, 2015 10:28
-
-
Save plonk/6291703 to your computer and use it in GitHub Desktop.
ポーカーの役を判定するやつ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # -*- coding: utf-8 -*- | |
| # This is the Card class. | |
| # An instance of it has a suit and value. | |
| class Card | |
| attr_reader :suit, :number | |
| # Card numbers. | |
| NUM_ACE = 14 | |
| NUM_JACK = 11 | |
| NUM_QUEEN = 12 | |
| NUM_KING = 13 | |
| SUITS = [:spade, :heart, :diamond, :club] | |
| def initialize(suit, number) | |
| # suit must be one of the following symbols. | |
| raise ArumentError unless SUITS.include? suit | |
| raise ArumentError unless number.is_a? Integer | |
| @suit = suit | |
| @number = number | |
| end | |
| def <=>(other) | |
| self.number <=> other.number | |
| end | |
| include Comparable | |
| end | |
| class Hand | |
| RANK_HIGH_CARD = 0 | |
| RANK_ONE_PAIR = 1 | |
| RANK_TWO_PAIRS = 2 | |
| RANK_THREE_OF_A_KIND = 3 | |
| RANK_STRAIGHT = 4 | |
| RANK_FLUSH = 5 | |
| RANK_FULL_HOUSE = 6 | |
| RANK_FOUR_OF_A_KIND = 7 | |
| RANK_STRAIGHT_FLUSH = 8 | |
| RANK_ROYAL_FLUSH = 9 | |
| SYMBOL_VALUE = { | |
| '2'=>2, | |
| '3'=>3, | |
| '4'=>4, | |
| '5'=>5, | |
| '6'=>6, | |
| '7'=>7, | |
| '8'=>8, | |
| '9'=>9, | |
| 'T'=>10, | |
| 'J'=>Card::NUM_JACK, | |
| 'Q'=>Card::NUM_QUEEN, | |
| 'K'=>Card::NUM_KING, | |
| 'A'=>Card::NUM_ACE, | |
| 'C'=>:club, | |
| 'D'=>:diamond, | |
| 'S'=>:spade, | |
| 'H'=>:heart | |
| } | |
| def initialize(cards) | |
| @cards = [] | |
| cards.split(/ /).each do |mnemonic| | |
| number = SYMBOL_VALUE[mnemonic[0]] | |
| suit = SYMBOL_VALUE[mnemonic[1]] | |
| @cards << Card.new(suit, number) | |
| end | |
| @cards.sort! | |
| @cards.reverse! | |
| @number = -1 | |
| end | |
| attr_reader :number | |
| def rank | |
| {:royal_flush? => 9, :straight_flush? => 8, :four_of_a_kind? => 7, :full_house? => 6, :flush? => 5, :straight? => 4, :three_of_a_kind? => 3, :two_pairs? => 2, :one_pair? => 1, :high_card? => 0}.each_pair do |pred, n| | |
| # p [pred, self.send(pred)]1 | |
| if self.send(pred) | |
| return n | |
| end | |
| end | |
| raise | |
| end | |
| def royal_flush? | |
| return (flush? and straight? and | |
| @cards.find {|c| c.number == 10} and | |
| @cards.find {|c| c.number == Card::NUM_ACE}) | |
| end | |
| def straight_flush? | |
| return (straight? and flush?) | |
| end | |
| def four_of_a_kind? | |
| return n_of_a_kind?(4) | |
| end | |
| def n_of_a_kind?(n) | |
| @cards.each do |c| | |
| if @cards.count {|d| d.number == c.number } == n | |
| return true | |
| end | |
| end | |
| return false | |
| end | |
| def full_house? | |
| return (one_pair? and n_of_a_kind?(3)) | |
| end | |
| def flush? | |
| suits = @cards.map {|c| c.suit } | |
| suits.all? {|s| s == suits.first} | |
| end | |
| def straight? | |
| # p [:straight_cards, @cards] | |
| a = @cards.map(&:number) | |
| #p [:a, a] | |
| b = a.each_cons(2) | |
| # p [:b, b] | |
| ret = b.map{|a, b| a - b}.all? {|n| n==1} | |
| # p [:ret, ret] | |
| ret | |
| end | |
| def three_of_a_kind? | |
| n_of_a_kind?(3) | |
| end | |
| def two_pairs? | |
| found = false | |
| the_num = nil | |
| @cards.each do |c| | |
| if @cards.count {|d| d.number == c.number } == 2 | |
| the_num = c.number | |
| found = true | |
| break | |
| end | |
| end | |
| return false unless found | |
| cards = @cards.reject {|c| c.number == the_num } | |
| cards.each do |c| | |
| if @cards.count {|d| d.number == c.number } == 2 | |
| return true | |
| end | |
| end | |
| return false | |
| end | |
| def one_pair? | |
| n_of_a_kind?(2) | |
| end | |
| def high_card? | |
| true | |
| end | |
| attr_reader :cards | |
| def <=>(other) | |
| res = self.rank <=> other.rank | |
| return res unless res == 0 | |
| case self.rank | |
| when RANK_FOUR_OF_A_KIND, | |
| RANK_THREE_OF_A_KIND, | |
| RANK_FULL_HOUSE, | |
| RANK_TWO_PAIRS, | |
| RANK_ONE_PAIR | |
| res = same_hand_compare(other) | |
| end | |
| return res unless res == 0 | |
| res = high_card_compare(other) | |
| raise "could not decide winner" if res == 0 | |
| return res | |
| end | |
| def max_value_of_largest_groups | |
| values = self.cards.map{|c| c.number}.uniq | |
| freqcounts = values.map {|n| | |
| [ n, self.cards.count{|c| c.number == n} ] | |
| } | |
| maxfreq = freqcounts.map(&:last).max | |
| return freqcounts.find_all { |val, freq| freq == maxfreq }.map(&:first).max | |
| end | |
| def same_hand_compare(other) | |
| self.max_value_of_largest_groups <=> other.max_value_of_largest_groups | |
| end | |
| def high_card_compare(other) | |
| res = nil | |
| these = self.cards | |
| those = other.cards | |
| these.each_with_index do |this, i| | |
| res = (this <=> those[i]) | |
| if res != 0 | |
| break | |
| end | |
| end | |
| if res == 0 | |
| puts "Warning: high card comparison tied" | |
| end | |
| return res | |
| end | |
| include Comparable | |
| end | |
| def assert(bool) | |
| raise unless bool | |
| end | |
| ranks = [:royal_flush?, :straight_flush?, :four_of_a_kind?, :full_house?, :flush?, :straight?, :three_of_a_kind?, :two_pairs?, :one_pair?, :high_card?].reverse | |
| filename = ARGV[0] || "poker.txt" | |
| =begin | |
| # ------------ テスト ------------ | |
| highcard_ten = Hand.new( "TD 9D 6D 2D 3S" ) | |
| assert(highcard_ten.rank == Hand::RANK_HIGH_CARD) | |
| one_pair_three = Hand.new( "TD 3D 6D 2D 3S" ) | |
| assert(one_pair_three.rank == Hand::RANK_ONE_PAIR) | |
| two_pairs = Hand.new( "TD TS 3D 3S 2D") | |
| assert(two_pairs.rank == Hand::RANK_TWO_PAIRS) | |
| three_card = Hand.new("TD TS TH 3D 2D") | |
| assert(three_card.rank == Hand::RANK_THREE_OF_A_KIND) | |
| straight = Hand.new("TD 9S 8H 7D 6D") | |
| assert(straight.rank == Hand::RANK_STRAIGHT) | |
| flush = Hand.new("TD AD 3D 7D 9D") | |
| assert(flush.rank == Hand::RANK_FLUSH) | |
| full_house = Hand.new("TD TH TS 9D 9H") | |
| assert(full_house.rank == Hand::RANK_FULL_HOUSE) | |
| four_card = Hand.new("TD TH TS TC 9H") | |
| assert(four_card.rank == Hand::RANK_FOUR_OF_A_KIND) | |
| straight_flush = Hand.new("TD 9D 8D 7D 6D") | |
| assert(straight_flush.rank == Hand::RANK_STRAIGHT_FLUSH) | |
| royal_flush = Hand.new("AD KD QD JD TD") | |
| assert(royal_flush.rank == Hand::RANK_ROYAL_FLUSH) | |
| highcard_king = Hand.new( "KC 7H QC 6D 8H") | |
| highcard_ace = Hand.new( "6S 5S AH 7S 8C") | |
| p highcard_king.cards | |
| p highcard_ace.cards | |
| p (highcard_king <=> highcard_ace) | |
| assert(highcard_king < highcard_ace) | |
| puts " all tests succeeded" | |
| =end | |
| count = 0 | |
| File.open(filename) do |f| | |
| f.each_line do |line| | |
| line.chomp! | |
| puts "----------------------" | |
| p line[0,14] | |
| p line[15,14] | |
| player1_hand = Hand.new(line[0,14]) | |
| player2_hand = Hand.new(line[15,14]) | |
| p [:p1rank, ranks[ player1_hand.rank] ] | |
| p [:p2rank, ranks[ player2_hand.rank] ] | |
| if player1_hand == player2_hand | |
| "TIED" | |
| exit 1 | |
| end | |
| p ((player1_hand > player2_hand) ? :player1 : :player2) | |
| if player1_hand > player2_hand | |
| count += 1 | |
| end | |
| end | |
| end | |
| p count |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment