Решение на Четвърта задача от Стоян Желязков

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

Към профила на Стоян Желязков

Резултати

  • 6 точки от тестове
  • 1 отнета точка
  • 5 точки общо
  • 56 успешни тест(а)
  • 1 неуспешни тест(а)

Код

class Suits
SUITS = {
:spades => 'Spades',
:hearts => 'Hearts',
:diamonds => 'Diamonds',
:clubs => 'Clubs'
}
def self.suit_to_string(suit)
SUITS[suit]
end
def self.all_suits
SUITS.keys
end
end
class Ranks
RANKS = {
:ace => 'Ace',
:king => 'King',
:queen => 'Queen',
:jack => 'Jack',
10 => '10',
9 => '9',
8 => '8',
7 => '7',
6 => '6',
5 => '5',
4 => '4',
3 => '3',
2 => '2',
}
def self.rank_to_string(rank)
RANKS[rank]
end
def self.all_ranks
RANKS.keys
end
end
class Card
def initialize(rank, suit)
@rank = rank
@suit = suit
end
def to_s
Ranks.rank_to_string(@rank) + ' of ' + Suits.suit_to_string(@suit)
end
def rank
@rank
end
def suit
@suit
end
def ==(other)
@rank == other.rank and @suit == other.suit
end
end
class Hand
def initialize(cards)
@cards = cards
end
def size
@cards.length
end
end
class Deck
include Enumerable
SUITS_ORDER = Suits.all_suits
#ascending
RANKS_ORDER = Ranks.all_ranks.reverse
HAND_SIZE = 52
def initialize(cards = generate_default_deck)
@cards = cards
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
@cards.sort_by! do
|card|
#ranks descending
[
self.class::SUITS_ORDER.index(card.suit),
self.class::RANKS_ORDER.reverse.index(card.rank)
]
end
end
def to_s
result = ""
@cards.each { |card| result += (card.to_s + "\n") }
result
end
def deal
class_object = HandClassFactory.make(self.class::HAND_SIZE)
class_object.new(@cards.shift(self.class::HAND_SIZE))
end
def each(&block)
@cards.each do |card|
block.call(card)
end
end
def self.ranks_order
self::RANKS_ORDER
end
def self.suits_order
self::SUITS_ORDER
end
private def generate_default_deck
cards = []
self.class::RANKS_ORDER.product(self.class::SUITS_ORDER).each do
|combination|
cards.push Card.new(combination.first, combination.last)
end
cards
end
end
class HandClassFactory
def self.make(deck_class)
{
26 => WarHand,
6 => SixtySixHand,
8 => BeloteHand
}[deck_class]
end
end
class WarHand < Hand
def play_card
@cards.shift
end
def allow_face_up?
if @cards.length <= 3
true
else
false
end
end
end
class WarDeck < Deck
RANKS_ORDER = Ranks.all_ranks.reverse
HAND_SIZE = 26
def deal
WarHand.new(@cards.shift(HAND_SIZE))
end
end
class SixtySixHand < Hand
def twenty?(trump_suit)
kings = @cards.select { |card| card.rank == :king }
queens = @cards.select { |card| card.rank == :queen }
kings.product(queens).each do
|pair|
if pair.first.suit == pair.last.suit and
pair.first.suit != trump_suit
return true
end
end
false
end
def forty?(trump_suit)
kings = @cards.select { |card| card.rank == :king }
queens = @cards.select { |card| card.rank == :queen }
kings.product(queens).each do
|pair|
if pair.first.suit == pair.last.suit and
pair.first.suit == trump_suit
return true
end
end
false
end
end
class SixtySixDeck < Deck
RANKS_ORDER = [9, :jack, :queen, :king, 10, :ace]
HAND_SIZE = 6
def deal
SixtySixHand.new(@cards.shift(HAND_SIZE))
end
end
class BeloteHand < Hand
def highest_of_suit(suit)
@cards.select do
|card|
card.suit == suit
end
.max_by do
|card|
BeloteDeck::RANKS_ORDER.reverse.index(card.rank)
end
end
def belote?
kings = @cards.select { |card| card.rank == :king }
queens = @cards.select { |card| card.rank == :queen }
kings.product(queens).bsearch do
|pair|
pair.first.suit == pair.last.suit
end != nil
end
def tierce?
belote_helper(3)
end
def quarte?
belote_helper(4)
end
def quint?
belote_helper(5)
end
def carre_of_jacks?
carre_helper(:jack)
end
def carre_of_nines?
carre_helper(9)
end
def carre_of_aces?
carre_helper(:ace)
end
private
def belote_helper(n)
BeloteDeck.suits_order.each do
|suit|
cards_of_suit = @cards.select { |card| card.suit == suit }
if suit_has_sequence(cards_of_suit, n)
return true
end
end
false
end
def suit_has_sequence(cards_of_suit, n)
indices = cards_of_suit.map do
|card|
BeloteDeck.ranks_order.index(card.rank)
end
indices.each do
|index|
if (indices & indices_helper(index, n - 1)).length >= n
return true
end
end
false
end
def indices_helper(index, n)
result = []
(0..n).to_a.each do
|x|
result.push index - x
end
result
end
def carre_helper(rank)
count = 0
@cards.each do
|card|
if card.rank == rank
count += 1
end
end
count == 4
end
end
class BeloteDeck < Deck
RANKS_ORDER = [7, 8, 9, :jack, :queen, :king, 10, :ace]
HAND_SIZE = 8
def deal
BeloteHand.new(@cards.shift(HAND_SIZE))
end
end

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

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

Failures:

  1) BeloteDeck hand #highest_of_suit returns the strongest card of the specified suit
     Failure/Error: expect(hand.highest_of_suit(:clubs)).to eq Card.new(:ace, :clubs)
       
       expected: #<Card:0x007f11e357fe30 @rank=:ace, @suit=:clubs>
            got: #<Card:0x007f11e3585100 @rank=7, @suit=:clubs>
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,2 @@
       -#<Card:0x007f11e357fe30 @rank=:ace, @suit=:clubs>
       +#<Card:0x007f11e3585100 @rank=7, @suit=:clubs>
     # /tmp/d20151112-27349-1w7aezi/spec.rb:232: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.03618 seconds
57 examples, 1 failure

Failed examples:

rspec /tmp/d20151112-27349-1w7aezi/spec.rb:220 # BeloteDeck hand #highest_of_suit returns the strongest card of the specified suit

История (1 версия и 6 коментара)

Стоян обнови решението на 08.11.2015 11:05 (преди над 8 години)

+class Suits
+ SUITS = {
+ :spades => 'Spades',
+ :hearts => 'Hearts',
+ :diamonds => 'Diamonds',
+ :clubs => 'Clubs'
+ }
+
+ def self.suit_to_string(suit)
+ SUITS[suit]
+ end
+
+ def self.all_suits
+ SUITS.keys
+ end
+end
+
+class Ranks
+ RANKS = {
+ :ace => 'Ace',
+ :king => 'King',
+ :queen => 'Queen',
+ :jack => 'Jack',
+ 10 => '10',
+ 9 => '9',
+ 8 => '8',
+ 7 => '7',
+ 6 => '6',
+ 5 => '5',
+ 4 => '4',
+ 3 => '3',
+ 2 => '2',
+ }
+
+ def self.rank_to_string(rank)
+ RANKS[rank]
+ end
+
+ def self.all_ranks
+ RANKS.keys
+ end
+end
+
+class Card
+ def initialize(rank, suit)
+ @rank = rank
+ @suit = suit
+ end
+
+ def to_s
+ Ranks.rank_to_string(@rank) + ' of ' + Suits.suit_to_string(@suit)
+ end
+
+ def rank
+ @rank
+ end
+
+ def suit
+ @suit
+ end
+
+ def ==(other)
+ @rank == other.rank and @suit == other.suit
+ end
+end
+
+class Hand
+ def initialize(cards)
+ @cards = cards
+ end
+
+ def size
+ @cards.length
+ end
+end
+
+class Deck
+ include Enumerable
+
+ SUITS_ORDER = Suits.all_suits
+ #ascending
+ RANKS_ORDER = Ranks.all_ranks.reverse
+ HAND_SIZE = 52
+
+ def initialize(cards = generate_default_deck)
+ @cards = cards
+ 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
+ @cards.sort_by! do
+ |card|
+ #ranks descending
+ [
+ self.class::SUITS_ORDER.index(card.suit),
+ self.class::RANKS_ORDER.reverse.index(card.rank)
+ ]
+ end
+ end
+
+ def to_s
+ result = ""
+ @cards.each { |card| result += (card.to_s + "\n") }
+ result
+ end
+
+ def deal
+ class_object = HandClassFactory.make(self.class::HAND_SIZE)
+ class_object.new(@cards.shift(self.class::HAND_SIZE))
+ end
+
+ def each(&block)
+ @cards.each do |card|
+ block.call(card)
+ end
+ end
+
+ def self.ranks_order
+ self::RANKS_ORDER
+ end
+
+ def self.suits_order
+ self::SUITS_ORDER
+ end
+
+ private def generate_default_deck
+ cards = []
+ self.class::RANKS_ORDER.product(self.class::SUITS_ORDER).each do
+ |combination|
+ cards.push Card.new(combination.first, combination.last)
+ end
+ cards
+ end
+end
+
+class HandClassFactory
+ def self.make(deck_class)
+ {
+ 26 => WarHand,
+ 6 => SixtySixHand,
+ 8 => BeloteHand
+ }[deck_class]
+ end
+end
+
+class WarHand < Hand
+ def play_card
+ @cards.shift
+ end
+
+ def allow_face_up?
+ if @cards.length <= 3
+ true
+ else
+ false
+ end
+ end
+end
+
+class WarDeck < Deck
+ RANKS_ORDER = Ranks.all_ranks.reverse
+ HAND_SIZE = 26
+
+ def deal
+ WarHand.new(@cards.shift(HAND_SIZE))
+ end
+end
+
+class SixtySixHand < Hand
+ def twenty?(trump_suit)
+ kings = @cards.select { |card| card.rank == :king }
+ queens = @cards.select { |card| card.rank == :queen }
+
+ kings.product(queens).each do
+ |pair|
+ if pair.first.suit == pair.last.suit and
+ pair.first.suit != trump_suit
+ return true
+ end
+ end
+ false
+ end
+
+ def forty?(trump_suit)
+ kings = @cards.select { |card| card.rank == :king }
+ queens = @cards.select { |card| card.rank == :queen }
+
+ kings.product(queens).each do
+ |pair|
+ if pair.first.suit == pair.last.suit and
+ pair.first.suit == trump_suit
+ return true
+ end
+ end
+ false
+ end
+end
+
+class SixtySixDeck < Deck
+ RANKS_ORDER = [9, :jack, :queen, :king, 10, :ace]
+ HAND_SIZE = 6
+
+ def deal
+ SixtySixHand.new(@cards.shift(HAND_SIZE))
+ end
+end
+
+class BeloteHand < Hand
+ def highest_of_suit(suit)
+ @cards.select do
+ |card|
+ card.suit == suit
+ end
+ .max_by do
+ |card|
+ BeloteDeck::RANKS_ORDER.reverse.index(card.rank)
+ end
+ end
+
+ def belote?
+ kings = @cards.select { |card| card.rank == :king }
+ queens = @cards.select { |card| card.rank == :queen }
+ kings.product(queens).bsearch do
+ |pair|
+ pair.first.suit == pair.last.suit
+ end != nil
+ end
+
+ def tierce?
+ belote_helper(3)
+ end
+
+ def quarte?
+ belote_helper(4)
+ end
+
+ def quint?
+ belote_helper(5)
+ end
+
+ def carre_of_jacks?
+ carre_helper(:jack)
+ end
+
+ def carre_of_nines?
+ carre_helper(9)
+ end
+
+ def carre_of_aces?
+ carre_helper(:ace)
+ end
+
+ private
+ def belote_helper(n)
+ BeloteDeck.suits_order.each do
+ |suit|
+ cards_of_suit = @cards.select { |card| card.suit == suit }
+ if suit_has_sequence(cards_of_suit, n)
+ return true
+ end
+ end
+ false
+ end
+
+ def suit_has_sequence(cards_of_suit, n)
+ indices = cards_of_suit.map do
+ |card|
+ BeloteDeck.ranks_order.index(card.rank)
+ end
+ indices.each do
+ |index|
+ if (indices & indices_helper(index, n - 1)).length >= n
+ return true
+ end
+ end
+ false
+ end
+
+ def indices_helper(index, n)
+ result = []
+ (0..n).to_a.each do
+ |x|
+ result.push index - x
+ end
+ result
+ end
+
+ def carre_helper(rank)
+ count = 0
+ @cards.each do
+ |card|
+ if card.rank == rank
+ count += 1
+ end
+ end
+ count == 4
+ end
+end
+
+class BeloteDeck < Deck
+ RANKS_ORDER = [7, 8, 9, :jack, :queen, :king, 10, :ace]
+ HAND_SIZE = 8
+
+ def deal
+ BeloteHand.new(@cards.shift(HAND_SIZE))
+ end
+end

Имаш проблеми със спазването на конвенциите на места, направи справка с ръководството за стил.

На места подредбата на кода ти е странна, на други места направо нарушава конвенциите (редове 114-115 и на други места).

highest_of_suit е също с грешна подредба.

if-ът в allow_face_up? е безсмислен, сравнението си връща истина/лъжа.

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

Стояне, не разбрах какво искаш да кажеш. Проблем ли има?

Решението ти минава всички тестове, но не спазва конвенциите, при това "нарушенията" изобщо не са пренебрежими. А на други места, кодът ти може да стане много по-елегантен, ако ползваш правилните методи от Enumerable. И т.н.

Ако не отнемем точка, има опасност да станат две неща:

  1. Други твои колеги да гледат решението ти като примерно, защото има 6 точки и минава всички тестове и да си вземат грешен пример от тези части на кода и да си помислят, че "така трябва да се прави".
  2. Ти може да не положиш необходимите усилия за следващата задача, да видиш къде може да стане по-добре. Сега, след тази -1 точка, се съмнявам да не провериш къде може да стане по-добре.

Не мисля, че 1 точка по-малко е висока цена за тези потенциални ползи. Ако все пак смяташ, че има проблем, сподели, или ни пиши.

Не няма проблем, правилата са си правила :)

И все пак мен такива случки по-скоро ме демотивират.

"А на други места, кодът ти може да стане много по-елегантен, ако ползваш правилните методи от Enumerable"

Това малко ми напомня на проф. Бъчваров в първи курс, при когото ако не е както той го е казал не минава. Според мен е готино да показвате тези "правилните" неща с Enumerable например, но трябва да сме свободни да решаваме задачите както на нас ни е удобно, дори да не е your way/the Ruby way.

Поздрави, Стойо

P.S. Искрено се извинявам за първоначалната си реакция :) просто се бях ядосал.

И все пак мен такива случки по-скоро ме демотивират.

Може би донякъде разбирам фрустрацията ти. Предполагам как би се чувствал, ако си положил много време и усилия и накрая, след като минеш всички тестове, някой ти отнеме точки за привидно дребни неща.

Но аз не мисля, че това е твоят абсолютен лимит. Не мисля, че това е таванът на възможностите ти. Готов съм да се обзаложа, че си могъл да напишеш и по-добро решение. Знам, че изисква време и усилие, а понякога (особено ако работим), приоритетите ни се менят, но сме в този курс, за да учим неща и да си посочваме къде може да стане по-добре.

Пак казвам, че не смятам, че една точка е висока цена, за да научиш ценни уроци – било то технически или принципни.

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

Това малко ми напомня на проф. Бъчваров в първи курс, при когото ако не е както той го е казал не минава.

Ти прегледа ли примерното ни решение и някои от решенията на колеги? Сравни ли това, което предлагаме като алтернатива на твоя код, преди да произнесеш присъдата "Бъчваров"?

Ще ти дам един пример, за да не е само на думи, със следния метод от твоя код:

def carre_helper(rank)
  count = 0
  @cards.each do
    |card|
    if card.rank == rank
      count += 1
    end
  end
  count == 4
end

Може да стане така:

def carre_of?(rank)
  @cards.count { |card| card.rank == rank } == 4
end

Или:

def carre_of?(rank)
  @cards.map(&:rank).count(rank) == 4
end

Не бих казал, че изискваме "нашия вариант" от късогледство или чист инат, защото не разбираме или поради друга причина не признаваме другите имплементации на даден метод.

Да, наистина предпочитаме някой от вторите два варианта, пред твоя код.

Но не казвам, че кодът ти е "грешен". Казвам само, че стилово куца и че може да стане по-добре и аз знам, че ти можеш да го направиш по-добре, ако положиш необходимото усилие.

Изборът как да възприемеш това и какво да правиш за следващите задачи е твой. Твоята съдба е в твоите ръце :)