Problem 54

Problem 54

In the card game poker, a hand consists of five cards and are ranked, from lowest to highest, in the following way:

* High Card: Highest value card.
* One Pair: Two cards of the same value.
* Two Pairs: Two different pairs.
* Three of a Kind: Three cards of the same value.
* Straight: All cards are consecutive values.
* Flush: All cards of the same suit.
* Full House: Three of a kind and a pair.
* Four of a Kind: Four cards of the same value.
* Straight Flush: All cards are consecutive values of same suit.
* Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.

The cards are valued in the order:
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.

If two players have the same ranked hands then the rank made up of the highest value wins; for example, a pair of eights beats a pair of fives (see example 1 below). But if two ranks tie, for example, both players have a pair of queens, then highest cards in each hand are compared (see example 4 below); if the highest cards tie then the next highest cards are compared, and so on.

Consider the following five hands dealt to two players:

[table][tr][td]Hand[/td][td]Player 1[/td][td]Player 2[/td][td]Winner[/td][/tr][tr][td]1[/td][td]5H 5C 6S 7S KD - Pair of Fives[/td][td]2C 3S 8S 8D TD - Pair of Eights[/td][td]Player 2[/td][/tr][tr][td]2[/td][td]5D 8C 9S JS AC - Highest card Ace[/td][td]2C 5C 7D 8S QH - Highest card Queen[/td][td]Player 1[/td][/tr][tr][td]3[/td][td]2D 9C AS AH AC - Three Aces[/td][td]3D 6D 7D TD QD - Flush with Diamonds[/td][td]Player 2[/td][/tr][tr][td]4[/td][td]4D 6S 9H QH QC - Pair of Queens Highest card Nine[/td][td]3D 6D 7H QD QS - Pair of Queens Highest card Seven[/td][td]Player 1[/td][/tr][tr][td]5[/td][td]2H 2D 4C 4D 4S - Full House With Three Fours[/td][td]3C 3D 3S 9S 9D - Full House with Three Threes[/td][td]Player 1[/td][/tr][/table]

The file, poker.txt, contains one-thousand random hands dealt to two players. Each line of the file contains ten cards (separated by a single space): the first five are Player 1’s cards and the last five are Player 2’s cards. You can assume that all hands are valid (no invalid characters or repeated cards), each player’s hand is in no specific order, and in each hand there is a clear winner.

How many hands does Player 1 win?

[code=ruby]#!/usr/bin/env ruby

s = File.read(“poker.txt”)

#s = “5H 5C 6S 7S KD 2C 3S 8S 8D TD
#5D 8C 9S JS AC 2C 5C 7D 8S QH
#2D 9C AS AH AC 3D 6D 7D TD QD
#4D 6S 9H QH QC 3D 6D 7H QD QS
#2H 2D 4C 4D 4S 3C 3D 3S 9S 9D”

def pair_high_cards(cards)
high_cards = []
u = [true]*5
%w{ 2 3 4 5 6 7 8 9 T J Q K A }.each do |f|
t = cards.collect { |c| c[0].chr }
if [f, f] == t[0…1] && t[2] != f
high_cards << cards[1]
u[0…1] = [false, false]
elsif [f, f] == t[1…2] && t[0] != f && t[3] != f
high_cards << cards[2]
u[1…2] = [false, false]
elsif [f, f] == t[2…3] && t[1] != f && t[4] != f
high_cards << cards[3]
u[2…3] = [false, false]
elsif [f, f] == t[3…4] && t[2] != f
high_cards << cards[4]
u[3…4] = [false, false]
end
end
if high_cards != []
other_cards = []
(0…4).each { |i| other_cards << cards[i] if u[i] }
[other_cards[-1]]+high_cards
else
[]
end
end

def three_high_cards(cards)
high_cards = []
%w{ 2 3 4 5 6 7 8 9 T J Q K A }.each do |f|
t = cards.collect { |c| c[0].chr }
if [f]*3 == t[0…2]
high_cards = [cards[4], cards[2]]
elsif [f]*3 == t[1…3]
high_cards = [cards[4], cards[3]]
elsif [f]*3 == t[2…4]
high_cards = [cards[1], cards[4]]
end
end
high_cards
end

def four_high_cards(cards)
high_cards = []
%w{ 2 3 4 5 6 7 8 9 T J Q K A }.each do |f|
t = cards.collect { |c| c[0].chr }
if [f]*4 == t[0…3]
high_cards = [cards[4], cards[3]]
elsif [f]*4 == t[1…4]
high_cards = [cards[0], cards[4]]
end
end
high_cards
end

def flush_high_card(cards)
cards[4] if cards.collect { |c| c[1].chr }.uniq.size == 1
end

def straight_high_card(cards)
high_card = nil
[%w{ 2 3 4 5 A },
%w{ 2 3 4 5 6 },
%w{ 3 4 5 6 7 },
%w{ 4 5 6 7 8 },
%w{ 5 6 7 8 9 },
%w{ 6 7 8 9 T },
%w{ 7 8 9 T J },
%w{ 8 9 T J Q },
%w{ 9 T J Q K },
%w{ T J Q K A }].each do |t|
if t == cards.collect { |c| c[0].chr }
high_card = (t[0] == “2” && t[4] == “A” ? cards[3] : cards[4])
end
end
high_card
end

def card_score(card)
%w{ 2 3 4 5 6 7 8 9 T J Q K A }.index(card[0].chr)
end

def cards_score(cards)
if (high_card = straight_high_card(cards))
if flush_high_card(cards)
# poker
8000000+card_score(high_card)
else
# strit
4000000+card_score(high_card)
end
elsif (high_cards = four_high_cards(cards)) != []
# kareta
p high_cards
7000000+100card_score(high_cards[1])+card_score(high_cards[0])
elsif (high_card = flush_high_card(cards))
# kolor
5000000+card_score(high_card)
elsif (high_cards = three_high_cards(cards)) != []
if (high_cards2 = pair_high_cards(cards)) != []
# ful
6000000+100
card_score(high_cards[-1])+card_score(high_cards2[1])
else
# trojka
3000000+100card_score(high_cards[1])+card_score(high_cards[1])
end
elsif (high_cards = pair_high_cards(cards)) != []
if high_cards.size == 3
# dwie pary
2000000+10000
card_score(high_cards[2])+100card_score(high_cards[1])+card_score(high_cards[0])
else
# jedna para
1000000+100
card_score(high_cards[1])+card_score(high_cards[0])
end
else
# wysoka karta
card_score(cards[-1])
end
end

t = s.strip.split("\n").collect { |l| l.split(" ").collect { |c| c } }

n = 0
t.each do |l|
cards1 = l[0…4].sort { |a, b| card_score(a) <=> card_score(b) }
cards2 = l[5…9].sort { |a, b| card_score(a) <=> card_score(b) }
score1 = cards_score(cards1)
score2 = cards_score(cards2)
n += 1 if score1 >= score2
end
puts n[/code]

[code=ruby]def hand_score©
color = “SHDC”
rank = “23456789TJQKA”
[rank =~ /#{c[0]}/, color =~ /#{c[1]}/]
end

def score(hand)
flush = lambda { |x| x.map {|y| y[1]}.uniq.size == 1 }
ordered = lambda { |x| x.map {|y| y[0]}.sort.reverse }
cards = lambda { |x,n| ordered.call(x).group_by(&:to_s).values.select {|y| y.size == n}.map(&:first).sort.reverse}
has_card = lambda {|x,n| !cards.call(x,n).empty? }
straight = lambda {|x| cards.call(x,1).size == 5 && ordered.call(x).first - ordered.call(x).last == 4}
highest = lambda {|x| (1…4).to_a.reverse.map {|y| cards.call(x,y)}}

if flush.call(hand) && straight.call(hand)
r = 9
elsif has_card.call(hand,4)
r = 8
elsif [2,3].all? {|y| has_card.call(hand,y)}
r = 7
elsif flush.call(hand)
r = 6
elsif straight.call(hand)
r = 5
elsif has_card.call(hand,3)
r = 4
elsif cards.call(hand,2).size > 1
r = 3
elsif has_card.call(hand,2)
r = 2
else
r = 1
end
[r, highest.call(hand)]
end

i = 0
File.read(‘poker.txt’).each_line do |line|
game = line.split(’ ').map{|x| hand_score(x)}.each_slice(5).to_a
i += 1 if (score(game[0]) <=> score(game[1])) == 1
end

puts i[/code]

znacznie krócej to zrobiłeś :slight_smile:

Bawię się ostatnio trochę programowaniem funkcyjnym (clojure) - anonimowe funkcje, kompozycja funkcji, lazy sequences etc.

Pomyślałem, że anonimowe funkcje + ich “pseudokompozycja” będzie pasować do tego problemu :slight_smile:

kojarze clojure ale co to takiego jest ta kompozycja funkcji anomimowych?
czy to po prostu wykorzystanie funkcji anonimowych kodzie?