Ивайло обнови решението на 11.11.2015 10:58 (преди около 9 години)
+class Card
+ attr_reader :rank, :suit
+ def initialize(rank, suit)
+ @rank = rank
+ @suit = suit
+ end
+ def to_s
+ rank = (@rank.is_a? Symbol) ? @rank.capitalize : @rank
+ "#{rank} of #{@suit.capitalize}"
+ end
+ def ==(other)
+ @rank == other.rank && @suit == other.suit
+ end
+end
+
+class Deck
+ include Enumerable
+
+ attr_reader :cards # TODO: REMOVE
+ def initialize(cards = nil)
+ @ranks = [2, 3, 4, 5, 6, 7, 8, 9, 10, :jack, :queen, :king, :ace]
+ @suits = [:spades, :hearts, :diamonds, :clubs]
+
+ if cards == nil
+ @cards = generate_deck
+ else
+ @cards = cards
+ end
+ end
+
+ def each
+ @cards.each { |card| yield card }
+ end
+
+ def size
+ self.to_a.size
+ end
+
+ def draw_top_card
+ @cards.shift
+ end
+
+ def draw_bottom_card
+ @cards.delete_at 1
+ end
+
+ def top_card
+ @cards[0]
+ end
+
+ def bottom_card
+ @cards[-1]
+ end
+
+ def shuffle
+ @cards.shuffle!
+ end
+
+ def sort
+ @cards.sort! { |a, b| compare a, b }
+ end
+
+ def to_s
+ @cards.map(&:to_s).join("\n")
+ end
+
+ private
+ def generate_deck
+ product = @ranks.product @suits
+ product.map { |card| Card.new *card }
+ end
+
+ def compare(a, b)
+ a_rank, a_suit = @ranks.find_index(a.rank), @suits.find_index(a.suit)
+ b_rank, b_suit = @ranks.find_index(b.rank), @suits.find_index(b.suit)
+ if a_suit == b_suit
+ b_rank <=> a_rank
+ else
+ a_suit <=> b_suit
+ end
+ end
+end
+
+class Hand
+ attr_accessor :cards
+ def initialize(cards)
+ @cards = cards
+ end
+
+ def size
+ @cards.size
+ end
+end
+
+class WarHand < Hand
+ def initialize(cards)
+ super
+ end
+
+ def play_card
+ @cards.delete_at 0
+ end
+
+ def allow_face_up?
+ @cards.size <= 3 ? true : false
+ end
+end
+
+class WarDeck < Deck
+ def initialize(cards = nil)
+ @hand_size = 26
+ super cards
+ end
+
+ def deal
+ WarHand.new @cards[0 .. @hand_size - 1]
+ end
+end
+
+class BeloteHand < Hand
+ def initialize(cards)
+ super
+ end
+
+ def highest_of_suit(suit)
+ deck = BeloteDeck.new @cards.select { |card| card.suit == suit }
+ deck.sort
+ deck.top_card
+ end
+
+ def belote?
+ groups = @cards.group_by { |card| card.suit }
+ filter = -> (card) { card.rank == :king || card.rank == :queen }
+ counts = groups.map { |g| g[1].select { |c| filter.call c }.size }
+ counts.any? { |g| g == 2 }
+ end
+
+ def tierce?
+ groups = @cards.group_by { |card| card.suit }
+ check = groups.map { |g| consecutive? g[1], 3 }
+ check.any? { |predicate| predicate == true }
+ end
+
+ def quarte?
+ groups = @cards.group_by { |card| card.suit }
+ check = groups.map { |g| consecutive? g[1], 4 }
+ check.any? { |predicate| predicate == true }
+ end
+
+ def quint?
+ groups = @cards.group_by { |card| card.suit }
+ check = groups.map { |g| consecutive? g[1], 5 }
+ check.any? { |predicate| predicate == true }
+ end
+
+ def carre_of_jacks?
+ amount_of_jacks = @cards.count { |card| card.rank == :jack }
+ amount_of_jacks == 4
+ end
+
+ def carre_of_nines?
+ amount_of_nines = @cards.count { |card| card.rank == 9 }
+ amount_of_nines == 4
+ end
+
+ def carre_of_aces?
+ amount_of_aces = @cards.count { |card| card.rank == :ace }
+ amount_of_aces == 4
+ end
+
+ private
+
+ def consecutive?(cards, count)
+ ranks = BeloteDeck.new.ranks
+ cards = cards.map { |c| ranks.find_index c.rank }.sort
+ last = cards[0]
+ groups = cards.slice_before do |e|
+ last, prev2 = e, last
+ prev2 + 1 != e
+ end
+ groups.to_a.any? { |group| group.size > 2 }
+ end
+end
+
+class BeloteDeck < Deck
+ attr_reader :ranks
+ def initialize(cards = nil)
+ @hand_size = 8
+ @ranks = [7, 8, 9, :jack, :queen, :king, 10, :ace]
+ @suits = [:spades, :hearts, :diamonds, :clubs]
+
+ if cards == nil
+ @cards = generate_deck
+ else
+ @cards = cards
+ end
+ end
+
+ def deal
+ BeloteHand.new @cards[0 .. @hand_size - 1]
+ end
+end
+
+class SixtySixHand < Hand
+ def initialize(cards)
+ super
+ end
+
+ def twenty?(trump_suit)
+ groups = @cards.group_by { |card| card.suit }
+ filter = -> (card) do
+ (card.suit != trump_suit) and (card.rank == :king or card.rank == :queen)
+ end
+ counts = groups.map { |g| g[1].select { |c| filter.call c }.size }
+ counts.any? { |g| g == 2 }
+ end
+
+ def forty?(trump_suit)
+ groups = @cards.group_by { |card| card.suit }
+ filter = -> (card) do
+ (card.suit == trump_suit) and (card.rank == :king or card.rank == :queen)
+ end
+ counts = groups.map { |g| g[1].select { |c| filter.call c }.size }
+ counts.any? { |g| g == 2 }
+ end
+end
+
+class SixtySixDeck < Deck
+ def initialize(cards = nil)
+ @hand_size = 6
+ @ranks = [ 9, :jack, :queen, :king, 10, :ace]
+ @suits = [:spades, :hearts, :diamonds, :clubs]
+
+ if cards == nil
+ @cards = generate_deck
+ else
+ @cards = cards
+ end
+ end
+
+ def deal
+ SixtySixHand.new @cards[0..@hand_size - 1]
+ end
+end