Решение на Четвърта задача от Бойко Караджов

Обратно към всички решения

Към профила на Бойко Караджов

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 50 успешни тест(а)
  • 7 неуспешни тест(а)

Код

class Card
attr_reader :rank, :suit
def initialize(rank, suit)
@rank, @suit = rank, suit
end
def to_s
"#{rank.to_s.capitalize} of #{suit.to_s.capitalize}"
end
def ==(other_card)
other_card != nil and
@rank == other_card.rank and @suit == other_card.suit
end
end
class Deck
include Enumerable
SUITS = [:spades, :hearts, :diamonds, :clubs]
def initialize(cards = nil)
@cards = cards || all
end
def each
@cards.each { |c| yield c }
end
def size
@cards.length
end
def draw_top_card
@cards.shift
end
def draw_bottom_card
@cards.pop
end
def top_card
@cards.first
end
def bottom_card
@cards.last
end
def shuffle
@cards.shuffle!
end
def sort
sorted_cards = all
@cards.sort_by! { |rank| sorted_cards.index(rank) }
end
def to_s
@cards.map(&:to_s).join("\n")
end
private
def has_couple?(suit)
king = Card.new(:king, suit)
queen = Card.new(:queen, suit)
@cards.include? king and @cards.include? queen
end
def all
ranks.product(Deck::SUITS).map { |rank, suit| Card.new(rank, suit) }
end
end
class WarHand < Deck
alias_method :play_card, :draw_top_card
def allow_face_up?
size <= 3
end
end
class WarDeck < Deck
RANKS = [:ace, :king, :queen, :jack, 10, 9, 8, 7, 6, 5, 4, 3, 2]
def deal
WarHand.new(@cards.shift(26))
end
private
def ranks
RANKS
end
end
class BeloteHand < Deck
def highest_of_suit(suit)
BeloteDeck.new(@cards.select { |c| c.suit == suit }).sort.first
end
def belote?
Deck::SUITS.any? { |suit| has_couple? suit }
end
def tierce?
Deck::SUITS.any? { |suit| has_consecutive?(3, suit) }
end
def quarte?
Deck::SUITS.any? { |suit| has_consecutive?(4, suit) }
end
def quint?
Deck::SUITS.any? { |suit| has_consecutive?(5, suit) }
end
def carre_of_jacks?
carre? :jack
end
def carre_of_nines?
carre? 9
end
def carre_of_aces?
carre? :ace
end
def carre?(rank)
Deck::SUITS.all? { |suit| @cards.include? Card.new(rank, suit) }
end
private
def has_consecutive?(n, suit)
suited_deck = BeloteDeck.new(@cards.select { |c| c.suit == suit })
suited_deck.sort
suited_deck.each_cons(n).any? { |cards| are_consecutive? cards }
end
def are_consecutive?(cards)
card_ranks = cards.map { |c| BeloteDeck::RANKS.index c.rank }
card_ranks.each_cons(2).all? { |x, y| y == x + 1}
end
end
class BeloteDeck < Deck
RANKS = [:ace, 10, :king, :queen, :jack, 10, 9, 8, 7]
def deal
BeloteHand.new(@cards.shift(8))
end
private
def ranks
RANKS
end
end
class SixtySixHand < Deck
def twenty?(trump_suit)
Deck::SUITS.any? { |suit| suit != trump_suit and has_couple? suit }
end
def forty?(trump_suit)
has_couple?(trump_suit)
end
end
class SixtySixDeck < Deck
RANKS = [:ace, 10, :king, :queen, :jack, 10, 9]
def deal
SixtySixHand.new(@cards.shift(6))
end
private
def ranks
RANKS
end
end

Лог от изпълнението

............F....F.......F.......F.F........F.......F....

Failures:

  1) WarDeck #sort sorts the cards in the defined order
     Failure/Error: expect(deck.sort.to_a).to eq [jack_of_spades, ten_of_hearts, ace_of_clubs, two_of_clubs]
       
       expected: [#<Card:0x007f60515f61e0 @rank=:jack, @suit=:spades>, #<Card:0x007f60515f6028 @rank=10, @suit=:hearts>, #<Card:0x007f60515f6230 @rank=:ace, @suit=:clubs>, #<Card:0x007f60515f6078 @rank=2, @suit=:clubs>]
            got: [#<Card:0x007f60515f6230 @rank=:ace, @suit=:clubs>, #<Card:0x007f60515f61e0 @rank=:jack, @suit=:spades>, #<Card:0x007f60515f6028 @rank=10, @suit=:hearts>, #<Card:0x007f60515f6078 @rank=2, @suit=:clubs>]
       
       (compared using ==)
       
       Diff:
       
       @@ -1,5 +1,5 @@
       -[#<Card:0x007f60515f61e0 @rank=:jack, @suit=:spades>,
       +[#<Card:0x007f60515f6230 @rank=:ace, @suit=:clubs>,
       + #<Card:0x007f60515f61e0 @rank=:jack, @suit=:spades>,
         #<Card:0x007f60515f6028 @rank=10, @suit=:hearts>,
       - #<Card:0x007f60515f6230 @rank=:ace, @suit=:clubs>,
         #<Card:0x007f60515f6078 @rank=2, @suit=:clubs>]
     # /tmp/d20151112-27349-nt22hw/spec.rb:155:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) BeloteDeck behaves like a deck fills the deck if no initialize parameters are given
     Failure/Error: expect(deck.to_a).to match_array all_available_cards
       expected collection contained:  [#<Card:0x007f6051635070 @rank=7, @suit=:clubs>, #<Card:0x007f6051634ff8 @rank=8, @suit=:clubs>, #<Card:0x007f6051634fa8 @rank=9, @suit=:clubs>, #<Card:0x007f6051634f30 @rank=:jack, @suit=:clubs>, #<Card:0x007f6051634e90 @rank=:queen, @suit=:clubs>, #<Card:0x007f6051634e40 @rank=:king, @suit=:clubs>, #<Card:0x007f6051634df0 @rank=10, @suit=:clubs>, #<Card:0x007f6051634d50 @rank=:ace, @suit=:clubs>, #<Card:0x007f6051634d00 @rank=7, @suit=:diamonds>, #<Card:0x007f6051634c38 @rank=8, @suit=:diamonds>, #<Card:0x007f6051634b98 @rank=9, @suit=:diamonds>, #<Card:0x007f6051634af8 @rank=:jack, @suit=:diamonds>, #<Card:0x007f6051634a80 @rank=:queen, @suit=:diamonds>, #<Card:0x007f6051634a30 @rank=:king, @suit=:diamonds>, #<Card:0x007f60516349b8 @rank=10, @suit=:diamonds>, #<Card:0x007f6051634918 @rank=:ace, @suit=:diamonds>, #<Card:0x007f6051634850 @rank=7, @suit=:hearts>, #<Card:0x007f6051634800 @rank=8, @suit=:hearts>, #<Card:0x007f6051634738 @rank=9, @suit=:hearts>, #<Card:0x007f60516346c0 @rank=:jack, @suit=:hearts>, #<Card:0x007f6051634670 @rank=:queen, @suit=:hearts>, #<Card:0x007f60516345d0 @rank=:king, @suit=:hearts>, #<Card:0x007f6051634558 @rank=10, @suit=:hearts>, #<Card:0x007f60516343f0 @rank=:ace, @suit=:hearts>, #<Card:0x007f6051634378 @rank=7, @suit=:spades>, #<Card:0x007f6051634328 @rank=8, @suit=:spades>, #<Card:0x007f60516342d8 @rank=9, @suit=:spades>, #<Card:0x007f6051634288 @rank=:jack, @suit=:spades>, #<Card:0x007f60516341e8 @rank=:queen, @suit=:spades>, #<Card:0x007f6051634148 @rank=:king, @suit=:spades>, #<Card:0x007f60516340a8 @rank=10, @suit=:spades>, #<Card:0x007f60516370f0 @rank=:ace, @suit=:spades>]
       actual collection contained:    [#<Card:0x007f6051637258 @rank=:ace, @suit=:spades>, #<Card:0x007f60516371e0 @rank=:ace, @suit=:hearts>, #<Card:0x007f6051637140 @rank=:ace, @suit=:diamonds>, #<Card:0x007f6051637078 @rank=:ace, @suit=:clubs>, #<Card:0x007f6051636fd8 @rank=10, @suit=:spades>, #<Card:0x007f6051636f38 @rank=10, @suit=:hearts>, #<Card:0x007f6051636ec0 @rank=10, @suit=:diamonds>, #<Card:0x007f6051636e48 @rank=10, @suit=:clubs>, #<Card:0x007f6051636dd0 @rank=:king, @suit=:spades>, #<Card:0x007f6051636d58 @rank=:king, @suit=:hearts>, #<Card:0x007f6051636ce0 @rank=:king, @suit=:diamonds>, #<Card:0x007f6051636c68 @rank=:king, @suit=:clubs>, #<Card:0x007f6051636bc8 @rank=:queen, @suit=:spades>, #<Card:0x007f6051636b28 @rank=:queen, @suit=:hearts>, #<Card:0x007f6051636ab0 @rank=:queen, @suit=:diamonds>, #<Card:0x007f6051636a60 @rank=:queen, @suit=:clubs>, #<Card:0x007f6051636038 @rank=:jack, @suit=:spades>, #<Card:0x007f6051635fe8 @rank=:jack, @suit=:hearts>, #<Card:0x007f6051635f20 @rank=:jack, @suit=:diamonds>, #<Card:0x007f6051635ed0 @rank=:jack, @suit=:clubs>, #<Card:0x007f6051635e58 @rank=10, @suit=:spades>, #<Card:0x007f6051635de0 @rank=10, @suit=:hearts>, #<Card:0x007f6051635cc8 @rank=10, @suit=:diamonds>, #<Card:0x007f6051635c50 @rank=10, @suit=:clubs>, #<Card:0x007f6051635c00 @rank=9, @suit=:spades>, #<Card:0x007f6051635bb0 @rank=9, @suit=:hearts>, #<Card:0x007f6051635b60 @rank=9, @suit=:diamonds>, #<Card:0x007f6051635ae8 @rank=9, @suit=:clubs>, #<Card:0x007f6051635a20 @rank=8, @suit=:spades>, #<Card:0x007f60516359d0 @rank=8, @suit=:hearts>, #<Card:0x007f6051635908 @rank=8, @suit=:diamonds>, #<Card:0x007f60516358b8 @rank=8, @suit=:clubs>, #<Card:0x007f6051635868 @rank=7, @suit=:spades>, #<Card:0x007f6051635818 @rank=7, @suit=:hearts>, #<Card:0x007f60516357c8 @rank=7, @suit=:diamonds>, #<Card:0x007f6051635778 @rank=7, @suit=:clubs>]
       the extra elements were:        [#<Card:0x007f6051635e58 @rank=10, @suit=:spades>, #<Card:0x007f6051635de0 @rank=10, @suit=:hearts>, #<Card:0x007f6051635cc8 @rank=10, @suit=:diamonds>, #<Card:0x007f6051635c50 @rank=10, @suit=:clubs>]
     Shared Example Group: "a deck" called from /tmp/d20151112-27349-nt22hw/spec.rb:191
     # /tmp/d20151112-27349-nt22hw/spec.rb:18:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) BeloteDeck #sort sorts the cards in the defined order
     Failure/Error: expect(deck.sort.to_a).to eq [jack_of_spades, ten_of_hearts, ace_of_clubs, seven_of_clubs]
       
       expected: [#<Card:0x007f6051575c70 @rank=:jack, @suit=:spades>, #<Card:0x007f6051575b08 @rank=10, @suit=:hearts>, #<Card:0x007f6051575ce8 @rank=:ace, @suit=:clubs>, #<Card:0x007f6051575b58 @rank=7, @suit=:clubs>]
            got: [#<Card:0x007f6051575ce8 @rank=:ace, @suit=:clubs>, #<Card:0x007f6051575b08 @rank=10, @suit=:hearts>, #<Card:0x007f6051575c70 @rank=:jack, @suit=:spades>, #<Card:0x007f6051575b58 @rank=7, @suit=:clubs>]
       
       (compared using ==)
       
       Diff:
       
       @@ -1,5 +1,5 @@
       -[#<Card:0x007f6051575c70 @rank=:jack, @suit=:spades>,
       +[#<Card:0x007f6051575ce8 @rank=:ace, @suit=:clubs>,
         #<Card:0x007f6051575b08 @rank=10, @suit=:hearts>,
       - #<Card:0x007f6051575ce8 @rank=:ace, @suit=:clubs>,
       + #<Card:0x007f6051575c70 @rank=:jack, @suit=:spades>,
         #<Card:0x007f6051575b58 @rank=7, @suit=:clubs>]
     # /tmp/d20151112-27349-nt22hw/spec.rb:206:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) BeloteDeck hand #quarte? detects four cards with increasing ranks
     Failure/Error: expect(hand.quarte?).to be true
       
       expected #<TrueClass:20> => true
            got #<FalseClass:0> => false
       
       Compared using equal?, which compares object identity,
       but expected and actual are not the same object. Use
       `expect(actual).to eq(expected)` if you don't care about
       object identity in this example.
     # /tmp/d20151112-27349-nt22hw/spec.rb:334:in `block (4 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) BeloteDeck hand #quint? detects five cards with increasing ranks
     Failure/Error: expect(hand.quint?).to be true
       
       expected #<TrueClass:20> => true
            got #<FalseClass:0> => false
       
       Compared using equal?, which compares object identity,
       but expected and actual are not the same object. Use
       `expect(actual).to eq(expected)` if you don't care about
       object identity in this example.
     # /tmp/d20151112-27349-nt22hw/spec.rb:366:in `block (4 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) SixtySixDeck behaves like a deck fills the deck if no initialize parameters are given
     Failure/Error: expect(deck.to_a).to match_array all_available_cards
       expected collection contained:  [#<Card:0x007f6050bd1e80 @rank=9, @suit=:clubs>, #<Card:0x007f6050bd1db8 @rank=:jack, @suit=:clubs>, #<Card:0x007f6050bd1c78 @rank=:queen, @suit=:clubs>, #<Card:0x007f6050bd1bb0 @rank=:king, @suit=:clubs>, #<Card:0x007f6050bd1a48 @rank=10, @suit=:clubs>, #<Card:0x007f6050bd1110 @rank=:ace, @suit=:clubs>, #<Card:0x007f6050bd0d28 @rank=9, @suit=:diamonds>, #<Card:0x007f6050bd0c38 @rank=:jack, @suit=:diamonds>, #<Card:0x007f6050bd0b20 @rank=:queen, @suit=:diamonds>, #<Card:0x007f6050bd0a80 @rank=:king, @suit=:diamonds>, #<Card:0x007f6050bd08f0 @rank=10, @suit=:diamonds>, #<Card:0x007f6050bd0698 @rank=:ace, @suit=:diamonds>, #<Card:0x007f6050bd0468 @rank=9, @suit=:hearts>, #<Card:0x007f6050bd03f0 @rank=:jack, @suit=:hearts>, #<Card:0x007f6050bd0328 @rank=:queen, @suit=:hearts>, #<Card:0x007f6050bbf8c0 @rank=:king, @suit=:hearts>, #<Card:0x007f6050bbf758 @rank=10, @suit=:hearts>, #<Card:0x007f6050bbf5f0 @rank=:ace, @suit=:hearts>, #<Card:0x007f6050bbf0c8 @rank=9, @suit=:spades>, #<Card:0x007f6050bbc558 @rank=:jack, @suit=:spades>, #<Card:0x007f6050bbc418 @rank=:queen, @suit=:spades>, #<Card:0x007f6050bbc080 @rank=:king, @suit=:spades>, #<Card:0x007f6050bafc18 @rank=10, @suit=:spades>, #<Card:0x007f6050bafad8 @rank=:ace, @suit=:spades>]
       actual collection contained:    [#<Card:0x007f6050f35180 @rank=:ace, @suit=:spades>, #<Card:0x007f6050f350e0 @rank=:ace, @suit=:hearts>, #<Card:0x007f6050f35068 @rank=:ace, @suit=:diamonds>, #<Card:0x007f6050f34f00 @rank=:ace, @suit=:clubs>, #<Card:0x007f6050f343e8 @rank=10, @suit=:spades>, #<Card:0x007f6050f342d0 @rank=10, @suit=:hearts>, #<Card:0x007f6050f34208 @rank=10, @suit=:diamonds>, #<Card:0x007f6050f34168 @rank=10, @suit=:clubs>, #<Card:0x007f6050f340a0 @rank=:king, @suit=:spades>, #<Card:0x007f6050c034a8 @rank=:king, @suit=:hearts>, #<Card:0x007f6050c03408 @rank=:king, @suit=:diamonds>, #<Card:0x007f6050c03340 @rank=:king, @suit=:clubs>, #<Card:0x007f6050c032c8 @rank=:queen, @suit=:spades>, #<Card:0x007f6050c031d8 @rank=:queen, @suit=:hearts>, #<Card:0x007f6050c03070 @rank=:queen, @suit=:diamonds>, #<Card:0x007f6050c02ee0 @rank=:queen, @suit=:clubs>, #<Card:0x007f6050c02e68 @rank=:jack, @suit=:spades>, #<Card:0x007f6050c02cd8 @rank=:jack, @suit=:hearts>, #<Card:0x007f6050c02b48 @rank=:jack, @suit=:diamonds>, #<Card:0x007f6050c02760 @rank=:jack, @suit=:clubs>, #<Card:0x007f6050c025a8 @rank=10, @suit=:spades>, #<Card:0x007f6050c003c0 @rank=10, @suit=:hearts>, #<Card:0x007f6050c00208 @rank=10, @suit=:diamonds>, #<Card:0x007f6050c000f0 @rank=10, @suit=:clubs>, #<Card:0x007f6050bfbd20 @rank=9, @suit=:spades>, #<Card:0x007f6050bfb758 @rank=9, @suit=:hearts>, #<Card:0x007f6050bfaf60 @rank=9, @suit=:diamonds>, #<Card:0x007f6050bea958 @rank=9, @suit=:clubs>]
       the extra elements were:        [#<Card:0x007f6050c025a8 @rank=10, @suit=:spades>, #<Card:0x007f6050c003c0 @rank=10, @suit=:hearts>, #<Card:0x007f6050c00208 @rank=10, @suit=:diamonds>, #<Card:0x007f6050c000f0 @rank=10, @suit=:clubs>]
     Shared Example Group: "a deck" called from /tmp/d20151112-27349-nt22hw/spec.rb:400
     # /tmp/d20151112-27349-nt22hw/spec.rb:18:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  7) SixtySixDeck #sort sorts the cards in the defined order
     Failure/Error: expect(deck.sort.to_a).to eq [jack_of_spades, ten_of_hearts, ace_of_clubs, two_of_clubs]
       
       expected: [#<Card:0x007f6050809be0 @rank=:jack, @suit=:spades>, #<Card:0x007f60508099d8 @rank=10, @suit=:hearts>, #<Card:0x007f6050809c58 @rank=:ace, @suit=:clubs>, #<Card:0x007f6050809b40 @rank=9, @suit=:clubs>]
            got: [#<Card:0x007f6050809c58 @rank=:ace, @suit=:clubs>, #<Card:0x007f60508099d8 @rank=10, @suit=:hearts>, #<Card:0x007f6050809be0 @rank=:jack, @suit=:spades>, #<Card:0x007f6050809b40 @rank=9, @suit=:clubs>]
       
       (compared using ==)
       
       Diff:
       
       @@ -1,5 +1,5 @@
       -[#<Card:0x007f6050809be0 @rank=:jack, @suit=:spades>,
       +[#<Card:0x007f6050809c58 @rank=:ace, @suit=:clubs>,
         #<Card:0x007f60508099d8 @rank=10, @suit=:hearts>,
       - #<Card:0x007f6050809c58 @rank=:ace, @suit=:clubs>,
       + #<Card:0x007f6050809be0 @rank=:jack, @suit=:spades>,
         #<Card:0x007f6050809b40 @rank=9, @suit=:clubs>]
     # /tmp/d20151112-27349-nt22hw/spec.rb:415:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.06752 seconds
57 examples, 7 failures

Failed examples:

rspec /tmp/d20151112-27349-nt22hw/spec.rb:145 # WarDeck #sort sorts the cards in the defined order
rspec /tmp/d20151112-27349-nt22hw/spec.rb:14 # BeloteDeck behaves like a deck fills the deck if no initialize parameters are given
rspec /tmp/d20151112-27349-nt22hw/spec.rb:196 # BeloteDeck #sort sorts the cards in the defined order
rspec /tmp/d20151112-27349-nt22hw/spec.rb:322 # BeloteDeck hand #quarte? detects four cards with increasing ranks
rspec /tmp/d20151112-27349-nt22hw/spec.rb:354 # BeloteDeck hand #quint? detects five cards with increasing ranks
rspec /tmp/d20151112-27349-nt22hw/spec.rb:14 # SixtySixDeck behaves like a deck fills the deck if no initialize parameters are given
rspec /tmp/d20151112-27349-nt22hw/spec.rb:405 # SixtySixDeck #sort sorts the cards in the defined order

История (3 версии и 2 коментара)

Бойко обнови решението на 05.11.2015 22:57 (преди над 9 години)

+class Card
+ attr_reader :rank, :suit
+
+ def initialize(rank, suit)
+ @rank, @suit = rank, suit
+ end
+
+ def to_s
+ "#{rank.to_s.capitalize} of #{suit.to_s.capitalize}"
+ end
+
+ def ==(other_card)
+ other_card != nil and
+ @rank == other_card.rank and @suit == other_card.suit
+ end
+end
+
+class Deck
+ include Enumerable
+
+ SUITS = [:spades, :hearts, :diamonds, :clubs]
+
+ def initialize(cards = nil)
+ @cards = cards || self.class.all
+ end
+
+ def each
+ @cards.each { |c| yield c }
+ end
+
+ def size
+ @cards.length
+ end
+
+ def draw_top_card
+ @cards.shift
+ end
+
+ def draw_bottom_card
+ @cards.pop
+ end
+
+ def top_card
+ @cards.first
+ end
+
+ def bottom_card
+ @cards.last
+ end
+
+ def shuffle
+ @cards.shuffle!
+ end
+
+ def sort
+ all = self.class.all
+ @cards.sort! { |x, y| all.index(x) - all.index(y) }
+ end
+
+ def to_s
+ @cards.map(&:to_s).join("\n")
+ end
+
+ def has_couple?(suit)
+ king = Card.new(:king, suit)
+ queen = Card.new(:queen, suit)
+ @cards.include? king and @cards.include? queen
+ end
+
+ def self::all
+ result = []
+ self::SUITS.each do |suit|
+ self::RANKS.each do |rank|
+ result << Card.new(rank, suit)
+ end
+ end
+ result
+ end
+end
+
+class WarHand < Deck
+ alias :play_card :draw_top_card
+
+ def allow_face_up?
+ self.size <= 3
+ end
+end
+
+class WarDeck < Deck
+ RANKS = [:ace, :king, :queen, :jack, 10, 9, 8, 7, 6, 5, 4, 3, 2]
+
+ def deal
+ WarHand.new(@cards.shift(26))
+ end
+end
+
+class BeloteHand < Deck
+ def highest_of_suit(suit)
+ BeloteDeck.new(@cards.select { |c| c.suit == suit }).sort.first
+ end
+
+ def belote?
+ Deck::SUITS.any? { |suit| self.has_couple? suit }
+ end
+
+ def tierce?
+ Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 3 }
+ end
+
+ def quarte?
+ Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 4 }
+ end
+
+ def quint?
+ Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 5 }
+ end
+
+ def carre_of_jacks?
+ self.carre? :jack
+ end
+
+ def carre_of_nines?
+ self.carre? 9
+ end
+
+ def carre_of_aces?
+ self.carre? :ace
+ end
+
+ def carre?(rank)
+ Deck::SUITS.all? { |suit| @cards.include? Card.new(rank, suit) }
+ end
+
+ def max_consecutive(suit)
+ suited_deck = WarDeck.new(@cards.select { |c| c.suit == suit })
+ suited_deck.sort
+ while suited_deck.size > 0
+ current, previous = suited_deck.draw_top_card, current
+ if previous != nil and self.are_consecutive?(current.rank, previous.rank)
+ consecutive += 1
+ else
+ consecutive = 1
+ end
+ end
+ consecutive || 0
+ end
+
+ def are_consecutive?(first_rank, second_rank)
+ first_index = WarDeck::RANKS.index first_rank
+ second_index = WarDeck::RANKS.index second_rank
+ (first_index - second_index).abs == 1
+ end
+end
+
+class BeloteDeck < Deck
+ RANKS = [:ace, 10, :king, :queen, :jack, 10, 9, 8, 7]
+
+ def deal
+ BeloteHand.new(@cards.shift(8))
+ end
+end
+
+class SixtySixHand < Deck
+ def twenty?(trump_suit)
+ Deck::SUITS.any? { |suit| suit != trump_suit and self.has_couple? suit }
+ end
+
+ def forty?(trump_suit)
+ self.has_couple?(trump_suit)
+ end
+end
+
+class SixtySixDeck < Deck
+ RANKS = [:ace, 10, :king, :queen, :jack, 10, 9]
+
+ def deal
+ SixtySixHand.new(@cards.shift(6))
+ end
+end

Бойко обнови решението на 06.11.2015 08:43 (преди над 9 години)

class Card
attr_reader :rank, :suit
def initialize(rank, suit)
@rank, @suit = rank, suit
end
def to_s
"#{rank.to_s.capitalize} of #{suit.to_s.capitalize}"
end
def ==(other_card)
other_card != nil and
@rank == other_card.rank and @suit == other_card.suit
end
end
class Deck
include Enumerable
SUITS = [:spades, :hearts, :diamonds, :clubs]
def initialize(cards = nil)
@cards = cards || self.class.all
end
def each
@cards.each { |c| yield c }
end
def size
@cards.length
end
def draw_top_card
@cards.shift
end
def draw_bottom_card
@cards.pop
end
def top_card
@cards.first
end
def bottom_card
@cards.last
end
def shuffle
@cards.shuffle!
end
def sort
all = self.class.all
@cards.sort! { |x, y| all.index(x) - all.index(y) }
end
def to_s
@cards.map(&:to_s).join("\n")
end
def has_couple?(suit)
king = Card.new(:king, suit)
queen = Card.new(:queen, suit)
@cards.include? king and @cards.include? queen
end
def self::all
result = []
self::SUITS.each do |suit|
self::RANKS.each do |rank|
result << Card.new(rank, suit)
end
end
result
end
end
class WarHand < Deck
alias :play_card :draw_top_card
def allow_face_up?
self.size <= 3
end
end
class WarDeck < Deck
RANKS = [:ace, :king, :queen, :jack, 10, 9, 8, 7, 6, 5, 4, 3, 2]
def deal
WarHand.new(@cards.shift(26))
end
end
class BeloteHand < Deck
def highest_of_suit(suit)
BeloteDeck.new(@cards.select { |c| c.suit == suit }).sort.first
end
def belote?
Deck::SUITS.any? { |suit| self.has_couple? suit }
end
def tierce?
Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 3 }
end
def quarte?
Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 4 }
end
def quint?
Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 5 }
end
def carre_of_jacks?
self.carre? :jack
end
def carre_of_nines?
self.carre? 9
end
def carre_of_aces?
self.carre? :ace
end
def carre?(rank)
Deck::SUITS.all? { |suit| @cards.include? Card.new(rank, suit) }
end
def max_consecutive(suit)
- suited_deck = WarDeck.new(@cards.select { |c| c.suit == suit })
+ suited_deck = BeloteDeck.new(@cards.select { |c| c.suit == suit })
suited_deck.sort
while suited_deck.size > 0
current, previous = suited_deck.draw_top_card, current
if previous != nil and self.are_consecutive?(current.rank, previous.rank)
consecutive += 1
else
consecutive = 1
end
end
consecutive || 0
end
def are_consecutive?(first_rank, second_rank)
- first_index = WarDeck::RANKS.index first_rank
- second_index = WarDeck::RANKS.index second_rank
+ first_index = BeloteDeck::RANKS.index first_rank
+ second_index = BeloteDeck::RANKS.index second_rank
(first_index - second_index).abs == 1
end
end
class BeloteDeck < Deck
RANKS = [:ace, 10, :king, :queen, :jack, 10, 9, 8, 7]
def deal
BeloteHand.new(@cards.shift(8))
end
end
class SixtySixHand < Deck
def twenty?(trump_suit)
Deck::SUITS.any? { |suit| suit != trump_suit and self.has_couple? suit }
end
def forty?(trump_suit)
self.has_couple?(trump_suit)
end
end
class SixtySixDeck < Deck
RANKS = [:ace, 10, :king, :queen, :jack, 10, 9]
def deal
SixtySixHand.new(@cards.shift(6))
end
end

Здравей :) Няколко коментара:

  • Защо ти е проверката other_card != nil при сравнението на карти? Кога може да сравняваме с nil? Ако си я сложил "за всеки случай", не трябва ли да изброиш и всички останали видове обекти, които може да не е other_card? Разбира се, не трябва да го правиш. Остави кода да гръмне ако някой го използва неправилно.
  • self.class.all обикновено се пише просто като Deck.all, а дефиницията на метода е с точка, не с ::. И по двата начина работи, но стилово с точка е по-добре. Това е така, защото :: се използва за достъп до константи, а . - за методи.
  • С това self::RANKS става голяма магия. Не е ясно защо това работи и кое RANKS ще вземе. Нито на първи, нито на втори, нито на 10-ти поглед :) Сигурен съм, че преди да го използваш и ти не си бил сигурен какво ще направи. Предай RANKS на базовия клас по някакъв друг, по-очевиден, начин.
  • За двата вложени each-a има по-добър вариант. В момента симулираш map.
  • Пробвай alias-ът в WarDeck. Прочети за разликите между alias и alias_method.
  • WarHand наследява Deck. Това е лошо, защото можеш да викаш методи от Deck върху WarHand (и другите). В Ruby има много други начини да преизползваш логика. Наследяването не е най-добрата идея за това.
  • Защо пишеш self като извикваш методи на същата инстанция? self.has_couple? suit => has_couple? suit. Това ще ти позволи и да направиш has_couple? private, което е добра идея за всички методи, които не са в условието на задачата.
  • max_consecutive е почти неразличим от C код. Прегледай го отново, сигурен съм, че ще можеш да го измислиш по по-елегантен начин. :)

Бойко обнови решението на 08.11.2015 05:22 (преди около 9 години)

class Card
attr_reader :rank, :suit
def initialize(rank, suit)
@rank, @suit = rank, suit
end
def to_s
"#{rank.to_s.capitalize} of #{suit.to_s.capitalize}"
end
def ==(other_card)
other_card != nil and
@rank == other_card.rank and @suit == other_card.suit
end
end
class Deck
include Enumerable
SUITS = [:spades, :hearts, :diamonds, :clubs]
def initialize(cards = nil)
- @cards = cards || self.class.all
+ @cards = cards || all
end
def each
@cards.each { |c| yield c }
end
def size
@cards.length
end
def draw_top_card
@cards.shift
end
def draw_bottom_card
@cards.pop
end
def top_card
@cards.first
end
def bottom_card
@cards.last
end
def shuffle
@cards.shuffle!
end
def sort
- all = self.class.all
- @cards.sort! { |x, y| all.index(x) - all.index(y) }
+ sorted_cards = all
+ @cards.sort_by! { |rank| sorted_cards.index(rank) }
end
def to_s
@cards.map(&:to_s).join("\n")
end
+ private
+
def has_couple?(suit)
king = Card.new(:king, suit)
queen = Card.new(:queen, suit)
@cards.include? king and @cards.include? queen
end
- def self::all
- result = []
- self::SUITS.each do |suit|
- self::RANKS.each do |rank|
- result << Card.new(rank, suit)
- end
- end
- result
+ def all
+ ranks.product(Deck::SUITS).map { |rank, suit| Card.new(rank, suit) }
end
end
class WarHand < Deck
- alias :play_card :draw_top_card
+ alias_method :play_card, :draw_top_card
def allow_face_up?
- self.size <= 3
+ size <= 3
end
end
class WarDeck < Deck
RANKS = [:ace, :king, :queen, :jack, 10, 9, 8, 7, 6, 5, 4, 3, 2]
def deal
WarHand.new(@cards.shift(26))
end
+
+ private
+
+ def ranks
+ RANKS
+ end
end
class BeloteHand < Deck
def highest_of_suit(suit)
BeloteDeck.new(@cards.select { |c| c.suit == suit }).sort.first
end
def belote?
- Deck::SUITS.any? { |suit| self.has_couple? suit }
+ Deck::SUITS.any? { |suit| has_couple? suit }
end
def tierce?
- Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 3 }
+ Deck::SUITS.any? { |suit| has_consecutive?(3, suit) }
end
def quarte?
- Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 4 }
+ Deck::SUITS.any? { |suit| has_consecutive?(4, suit) }
end
def quint?
- Deck::SUITS.any? { |suit| self.max_consecutive(suit) >= 5 }
+ Deck::SUITS.any? { |suit| has_consecutive?(5, suit) }
end
def carre_of_jacks?
- self.carre? :jack
+ carre? :jack
end
def carre_of_nines?
- self.carre? 9
+ carre? 9
end
def carre_of_aces?
- self.carre? :ace
+ carre? :ace
end
def carre?(rank)
Deck::SUITS.all? { |suit| @cards.include? Card.new(rank, suit) }
end
- def max_consecutive(suit)
+ private
+
+ def has_consecutive?(n, suit)
suited_deck = BeloteDeck.new(@cards.select { |c| c.suit == suit })
suited_deck.sort
- while suited_deck.size > 0
- current, previous = suited_deck.draw_top_card, current
- if previous != nil and self.are_consecutive?(current.rank, previous.rank)
- consecutive += 1
- else
- consecutive = 1
- end
- end
- consecutive || 0
+ suited_deck.each_cons(n).any? { |cards| are_consecutive? cards }
end
- def are_consecutive?(first_rank, second_rank)
- first_index = BeloteDeck::RANKS.index first_rank
- second_index = BeloteDeck::RANKS.index second_rank
- (first_index - second_index).abs == 1
+ def are_consecutive?(cards)
+ card_ranks = cards.map { |c| BeloteDeck::RANKS.index c.rank }
+ card_ranks.each_cons(2).all? { |x, y| y == x + 1}
end
end
class BeloteDeck < Deck
RANKS = [:ace, 10, :king, :queen, :jack, 10, 9, 8, 7]
def deal
BeloteHand.new(@cards.shift(8))
end
+
+ private
+
+ def ranks
+ RANKS
+ end
end
class SixtySixHand < Deck
def twenty?(trump_suit)
- Deck::SUITS.any? { |suit| suit != trump_suit and self.has_couple? suit }
+ Deck::SUITS.any? { |suit| suit != trump_suit and has_couple? suit }
end
def forty?(trump_suit)
- self.has_couple?(trump_suit)
+ has_couple?(trump_suit)
end
end
class SixtySixDeck < Deck
RANKS = [:ace, 10, :king, :queen, :jack, 10, 9]
def deal
SixtySixHand.new(@cards.shift(6))
+ end
+
+ private
+
+ def ranks
+ RANKS
end
end

Благодаря за коментарите!

Цялата магия със self::RANKS и self.class.all беше за да се 'наследи' константа. Кошмар, наистина. Мисля, че го поправих.

Проверката за nil в == е, защото ми светеше exception при max_consecutive в previous != nil. Предпочитам да запазя проверката дори и като не правя вече това. Не искам exception при проверка за nil, случва се понякога.

Да гледам на ръцете като на тестета ми е доста удобно. И те се правят от множество карти, можеш да теглиш карта от тях, да ги бъркаш, подреждаш и т.н. Особено във война, то си е тесте. Ако трябваше да сложа общата логика в модул то щях да го кръстя "DeckOperations" примерно. Просто за момента семантично ми излгежда като ръката да е вид тесте.

За другите неща се постарах да намеря правилните методи из Enumerable. Май се получиха по-прибрано вече. Особено all ми харесва доста повече така. Мерси :)