Решение на Четвърта задача от Добромир Иванов

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

Към профила на Добромир Иванов

Резултати

  • 6 точки от тестове
  • 0 бонус точки
  • 6 точки общо
  • 53 успешни тест(а)
  • 4 неуспешни тест(а)

Код

class Card
attr_reader :rank, :suit
def initialize(rank, suit)
@rank = rank
@suit = suit
end
def to_s
"#{capitalize_first_letter @rank.to_s} of #{capitalize_first_letter @suit}"
end
def ==(other)
other.class == self.class && state == other.state
end
protected
def state
[@suit, @rank]
end
private
def capitalize_first_letter(string)
string[0].capitalize + string[1..string.size]
end
end
class Deck
include Enumerable
def initialize(deck = nil)
if deck == nil
@deck = ranks.product(suits).map { |rank, suit| Card.new(rank, suit) }
else
@deck = deck.dup
end
end
def each
return enum_for(:each) unless block_given?
@deck.each { |card| yield card }
end
def size
@deck.size
end
def draw_top_card
@deck.shift
end
def draw_bottom_card
@deck.pop
end
def top_card
@deck.first
end
def bottom_card
@deck.last
end
def shuffle
loop do
original_deck = @deck.dup
shuffled_deck = @deck.shuffle!
return shuffled_deck if shuffled_deck != original_deck
end
end
def to_s
@deck.map { |card| card.to_s }.join("\n")
end
def deal
PlayerDeck.new(Deck.new(@deck.sample(rand(srand) % size)))
end
def sort
@deck.sort! do |a, b|
if suits.index(a.suit) == suits.index(b.suit)
ranks.index(a.rank) <=> ranks.index(b.rank)
else
suits.index(a.suit) <=> suits.index(b.suit)
end
end
@deck.reverse!
end
private
def ranks
[2, 3, 4, 5, 6, 7, 8, 9, 10, :jack, :queen, :king, :ace]
end
def suits
[:clubs, :diamonds, :hearts, :spades]
end
end
class PlayerDeck
def initialize(deck)
@deck = deck
end
def size
return @deck.size
end
end
class PlayerWarDeck < PlayerDeck
def play_card
@deck.draw_top_card
end
def allow_face_up?
@deck.size <= 3
end
end
class WarDeck < Deck
HAND_SIZE = 26
def deal
PlayerWarDeck.new(WarDeck.new(@deck.slice!(0...HAND_SIZE)))
end
end
class PlayerBeloteDeck < PlayerDeck
def highest_of_suit(suit)
@deck.sort.select { |card| card.suit == suit }.first
end
def belote?
@deck.group_by { |card| card.suit }.each do |suit, group|
if group.include?(Card.new(:king, suit)) &&
group.include?(Card.new(:queen, suit))
return true
end
end
return false
end
def tierce?
@deck.group_by { |card| card.suit }.values.each do |value|
return true if consecutive_cards(value.map(&:rank), 3)
end
false
end
def quarte?
@deck.group_by { |card| card.suit }.values.each do |value|
return true if consecutive_cards(value.map(&:rank), 4)
end
false
end
def quint?
@deck.group_by { |card| card.suit }.values.each do |value|
return true if consecutive_cards(value.map(&:rank), 5)
end
false
end
def carre_of_jacks?
@deck.map(&:rank).count(:jack) == 4
end
def carre_of_nines?
@deck.map(&:rank).count(9) == 4
end
def carre_of_aces?
@deck.map(&:rank).count(:ace) == 4
end
private
def ranks
[7, 8, 9, :jack, :queen, :king, 10, :ace]
end
def consecutive_cards(cards, count)
ranks_found = 0
ranks.each do |rank|
if cards.include? rank
ranks_found += 1
else
ranks_found = 0
end
end
ranks_found >= count
end
end
class BeloteDeck < Deck
HAND_SIZE = 8
def deal
PlayerBeloteDeck.new(BeloteDeck.new(@deck.slice!(0...HAND_SIZE)))
end
private
def ranks
[7, 8, 9, :jack, :queen, :king, 10, :ace]
end
end
class PlayerSixtySixDeck < PlayerDeck
def twenty?(trump_suit)
@deck.group_by { |card| card.suit }.each do |suit, group|
if group.include?(Card.new(:king, suit)) &&
group.include?(Card.new(:queen, suit)) && suit != trump_suit
return true
end
end
return false
end
def forty?(trump_suit)
@deck.group_by { |card| card.suit }.each do |suit, group|
if group.include?(Card.new(:king, suit)) &&
group.include?(Card.new(:queen, suit)) && suit == trump_suit
return true
end
end
return false
end
end
class SixtySixDeck < Deck
HAND_SIZE = 6
def deal
PlayerSixtySixDeck.new(SixtySixDeck.new(@deck.slice!(0...HAND_SIZE)))
end
private
def ranks
[9, :jack, :queen, :king, 10, :ace]
end
end

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

..............................FF.F.F.....................

Failures:

  1) BeloteDeck hand #tierce? with tierce returns true for cards with names
     Failure/Error: expect(hand.tierce?).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-1bwdbpx/spec.rb:284:in `block (5 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 hand #tierce? with tierce returns true for cards with numbers
     Failure/Error: expect(hand.tierce?).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-1bwdbpx/spec.rb:299:in `block (5 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 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-1bwdbpx/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)>'

  4) 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-1bwdbpx/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)>'

Finished in 0.04098 seconds
57 examples, 4 failures

Failed examples:

rspec /tmp/d20151112-27349-1bwdbpx/spec.rb:272 # BeloteDeck hand #tierce? with tierce returns true for cards with names
rspec /tmp/d20151112-27349-1bwdbpx/spec.rb:287 # BeloteDeck hand #tierce? with tierce returns true for cards with numbers
rspec /tmp/d20151112-27349-1bwdbpx/spec.rb:322 # BeloteDeck hand #quarte? detects four cards with increasing ranks
rspec /tmp/d20151112-27349-1bwdbpx/spec.rb:354 # BeloteDeck hand #quint? detects five cards with increasing ranks

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

Добромир обнови решението на 09.11.2015 01:55 (преди около 9 години)

+class Card
+ attr_reader :rank, :suit
+
+ def initialize(rank, suit)
+ @rank = rank
+ @suit = suit
+ end
+
+ def to_s
+ "#{capitalize_first_letter @rank.to_s} of #{capitalize_first_letter @suit}"
+ end
+
+ def ==(other)
+ other.class == self.class && state == other.state
+ end
+
+ protected
+
+ def state
+ [@suit, @rank]
+ end
+
+ private
+
+ def capitalize_first_letter(string)
+ string[0].capitalize + string[1..string.size]
+ end
+end
+
+class Deck
+ include Enumerable
+
+ def initialize(deck = nil)
+ if deck == nil
+ @deck = ranks.product(suits).map {|rank, suit| Card.new(rank, suit)}
+ else
+ @deck = deck.dup
+ end
+ end
+
+ def each
+ return enum_for(:each) unless block_given?
+ @deck.each {|card| yield card}
+ end
+
+ def size
+ @deck.size
+ end
+
+ def draw_top_card
+ @deck.shift
+ end
+
+ def draw_bottom_card
+ @deck.pop
+ end
+
+ def top_card
+ @deck.first
+ end
+
+ def bottom_card
+ @deck.last
+ end
+
+ def shuffle
+ loop do
+ original_deck = @deck.dup
+ shuffled_deck = @deck.shuffle!
+ return shuffled_deck if shuffled_deck != original_deck
+ end
+ end
+
+ def to_s
+ @deck.map {|card| card.to_s}.join("\n")
+ end
+
+ def deal
+ PlayerDeck.new(Deck.new(@deck.sample(rand(srand) % size)))
+ end
+
+ def sort
+ @deck.sort! do |a, b|
+ if suits.index(a.suit) == suits.index(b.suit)
+ ranks.index(a.rank) <=> ranks.index(b.rank)
+ else
+ suits.index(a.suit) <=> suits.index(b.suit)
+ end
+ end
+ @deck.reverse!
+ end
+
+ private
+
+ def ranks
+ [2, 3, 4, 5, 6, 7, 8, 9, 10, :jack, :queen, :king, :ace]
+ end
+
+ def suits
+ [:clubs, :diamonds, :hearts, :spades]
+ end
+end
+
+class PlayerDeck
+ def initialize(deck)
+ @deck = deck
+ end
+
+ def size
+ return @deck.size
+ end
+end
+
+class PlayerWarDeck < PlayerDeck
+ def play_card
+ @deck.draw_top_card
+ end
+
+ def allow_face_up?
+ @deck.size <= 3
+ end
+end
+
+class WarDeck < Deck
+ HAND_SIZE = 26
+
+ def deal
+ PlayerWarDeck.new(WarDeck.new(@deck.slice!(0...HAND_SIZE)))
+ end
+end
+
+class PlayerBeloteDeck < PlayerDeck
+
+ def highest_of_suit(suit)
+ @deck.sort.select { |card| card.suit == suit }.first
+ end
+
+ def belote?
+ @deck.group_by {|card| card.suit}.each do |suit, group|
+ if group.include?(Card.new(:king, suit)) &&
+ group.include?(Card.new(:queen, suit))
+ return true
+ end
+ end
+ return false
+ end
+
+ def tierce?
+ @deck.group_by {|card| card.suit}.values.each do |value|
+ return true if consecutive_cards(value.map(&:rank), 3)
+ end
+ false
+ end
+
+ def quarte?
+ @deck.group_by {|card| card.suit}.values.each do |value|
+ return true if consecutive_cards(value.map(&:rank), 4)
+ end
+ false
+ end
+
+ def quint?
+ @deck.group_by {|card| card.suit}.values.each do |value|
+ return true if consecutive_cards(value.map(&:rank), 5)
+ end
+ false
+ end
+
+ def carre_of_jacks?
+ @deck.map(&:rank).count(:jack) == 4
+ end
+
+ def carre_of_nines?
+ @deck.map(&:rank).count(9) == 4
+ end
+
+ def carre_of_aces?
+ @deck.map(&:rank).count(:ace) == 4
+ end
+
+ private
+
+ def ranks
+ [7, 8, 9, :jack, :queen, :king, 10, :ace]
+ end
+
+ def consecutive_cards(cards, count)
+ ranks_found = 0
+ ranks.each do |rank|
+ if cards.include? rank
+ ranks_found += 1
+ else
+ ranks_found = 0
+ end
+ end
+ ranks_found >= count
+ end
+end
+
+class BeloteDeck < Deck
+ HAND_SIZE = 8
+
+ def deal
+ PlayerBeloteDeck.new(BeloteDeck.new(@deck.slice!(0...HAND_SIZE)))
+ end
+
+ private
+
+ def ranks
+ [7, 8, 9, :jack, :queen, :king, 10, :ace]
+ end
+end
+
+class PlayerSixtySixDeck < PlayerDeck
+
+ def twenty?(trump_suit)
+ @deck.group_by {|card| card.suit}.each do |suit, group|
+ if group.include?(Card.new(:king, suit)) &&
+ group.include?(Card.new(:queen, suit)) && suit != trump_suit
+ return true
+ end
+ end
+ return false
+ end
+
+ def forty?(trump_suit)
+ @deck.group_by {|card| card.suit}.each do |suit, group|
+ if group.include?(Card.new(:king, suit)) &&
+ group.include?(Card.new(:queen, suit)) && suit == trump_suit
+ return true
+ end
+ end
+ return false
+ end
+
+end
+
+class SixtySixDeck < Deck
+ HAND_SIZE = 6
+
+ def deal
+ PlayerSixtySixDeck.new(SixtySixDeck.new(@deck.slice!(0...HAND_SIZE)))
+ end
+
+ private
+
+ def ranks
+ [9, :jack, :queen, :king, 10, :ace]
+ end
+end

Добромир обнови решението на 10.11.2015 20:17 (преди около 9 години)

class Card
attr_reader :rank, :suit
def initialize(rank, suit)
@rank = rank
@suit = suit
end
def to_s
"#{capitalize_first_letter @rank.to_s} of #{capitalize_first_letter @suit}"
end
def ==(other)
other.class == self.class && state == other.state
end
protected
def state
[@suit, @rank]
end
private
def capitalize_first_letter(string)
string[0].capitalize + string[1..string.size]
end
end
class Deck
include Enumerable
def initialize(deck = nil)
if deck == nil
- @deck = ranks.product(suits).map {|rank, suit| Card.new(rank, suit)}
+ @deck = ranks.product(suits).map { |rank, suit| Card.new(rank, suit) }
else
@deck = deck.dup
end
end
def each
return enum_for(:each) unless block_given?
- @deck.each {|card| yield card}
+ @deck.each { |card| yield card }
end
def size
@deck.size
end
def draw_top_card
@deck.shift
end
def draw_bottom_card
@deck.pop
end
def top_card
@deck.first
end
def bottom_card
@deck.last
end
def shuffle
loop do
original_deck = @deck.dup
shuffled_deck = @deck.shuffle!
return shuffled_deck if shuffled_deck != original_deck
end
end
def to_s
- @deck.map {|card| card.to_s}.join("\n")
+ @deck.map { |card| card.to_s }.join("\n")
end
def deal
PlayerDeck.new(Deck.new(@deck.sample(rand(srand) % size)))
end
def sort
@deck.sort! do |a, b|
if suits.index(a.suit) == suits.index(b.suit)
ranks.index(a.rank) <=> ranks.index(b.rank)
else
suits.index(a.suit) <=> suits.index(b.suit)
end
end
@deck.reverse!
end
private
def ranks
[2, 3, 4, 5, 6, 7, 8, 9, 10, :jack, :queen, :king, :ace]
end
def suits
[:clubs, :diamonds, :hearts, :spades]
end
end
class PlayerDeck
def initialize(deck)
@deck = deck
end
def size
return @deck.size
end
end
class PlayerWarDeck < PlayerDeck
def play_card
@deck.draw_top_card
end
def allow_face_up?
@deck.size <= 3
end
end
class WarDeck < Deck
HAND_SIZE = 26
def deal
PlayerWarDeck.new(WarDeck.new(@deck.slice!(0...HAND_SIZE)))
end
end
class PlayerBeloteDeck < PlayerDeck
-
def highest_of_suit(suit)
@deck.sort.select { |card| card.suit == suit }.first
end
def belote?
- @deck.group_by {|card| card.suit}.each do |suit, group|
+ @deck.group_by { |card| card.suit }.each do |suit, group|
if group.include?(Card.new(:king, suit)) &&
group.include?(Card.new(:queen, suit))
return true
end
end
return false
end
def tierce?
- @deck.group_by {|card| card.suit}.values.each do |value|
+ @deck.group_by { |card| card.suit }.values.each do |value|
return true if consecutive_cards(value.map(&:rank), 3)
end
false
end
def quarte?
- @deck.group_by {|card| card.suit}.values.each do |value|
+ @deck.group_by { |card| card.suit }.values.each do |value|
return true if consecutive_cards(value.map(&:rank), 4)
end
false
end
def quint?
- @deck.group_by {|card| card.suit}.values.each do |value|
+ @deck.group_by { |card| card.suit }.values.each do |value|
return true if consecutive_cards(value.map(&:rank), 5)
end
false
end
def carre_of_jacks?
@deck.map(&:rank).count(:jack) == 4
end
def carre_of_nines?
@deck.map(&:rank).count(9) == 4
end
def carre_of_aces?
@deck.map(&:rank).count(:ace) == 4
end
private
def ranks
[7, 8, 9, :jack, :queen, :king, 10, :ace]
end
def consecutive_cards(cards, count)
ranks_found = 0
ranks.each do |rank|
if cards.include? rank
ranks_found += 1
else
ranks_found = 0
end
end
ranks_found >= count
end
end
class BeloteDeck < Deck
HAND_SIZE = 8
def deal
PlayerBeloteDeck.new(BeloteDeck.new(@deck.slice!(0...HAND_SIZE)))
end
private
def ranks
[7, 8, 9, :jack, :queen, :king, 10, :ace]
end
end
class PlayerSixtySixDeck < PlayerDeck
-
def twenty?(trump_suit)
- @deck.group_by {|card| card.suit}.each do |suit, group|
+ @deck.group_by { |card| card.suit }.each do |suit, group|
if group.include?(Card.new(:king, suit)) &&
group.include?(Card.new(:queen, suit)) && suit != trump_suit
return true
end
end
return false
end
def forty?(trump_suit)
- @deck.group_by {|card| card.suit}.each do |suit, group|
+ @deck.group_by { |card| card.suit }.each do |suit, group|
if group.include?(Card.new(:king, suit)) &&
group.include?(Card.new(:queen, suit)) && suit == trump_suit
return true
end
end
return false
end
-
end
class SixtySixDeck < Deck
HAND_SIZE = 6
def deal
PlayerSixtySixDeck.new(SixtySixDeck.new(@deck.slice!(0...HAND_SIZE)))
end
private
def ranks
[9, :jack, :queen, :king, 10, :ace]
end
-end
+end

Бележки:

  • capitalize_first_letter не ти трябва
  • не мисля, че е нужен този loop в shuffle
  • в методите tierce? (и другите подобни), може да минеш с по-елегантен метод от Enumerable и да няма нужда от тези return-и; потърси кой
  • и на други места може да използваш методи от Enumerable, прегледай му пак документацията и помисли.

Прегледай решенията на колеги и нашето примерно решение за алтернативни идеи.

Единствено не съм съгласен за shuffle. Нямам гараниця, че колекцията ми ще бъде с променен ред след изпълнение на shuffle. Колкото по-голяма е колекцията, толкова по-малък е шанса елементите да останат в същя ред. Но все пак шанс има.

Аз намирам, че е напълно валиден изход от едно разбъркване подредбата да остане същата. Вероятността за това е достатъчно малка, но си е валиден изход.

Никъде не изискваме задължително различна подредба и това, което си направил, е over the top.