Ruby Greed Koan - Как я могу улучшить свой суп if / then? - PullRequest
14 голосов
/ 20 января 2011

Я пробираюсь через Ruby Koans, чтобы попытаться выучить Ruby, и пока все хорошо.Я добрался до жадного коана, который на момент написания этой статьи составлял 183. У меня есть рабочее решение, но я чувствую, что собрал воедино только кучу логики if / then и что я неиспользование шаблонов Ruby.

В следующем коде, есть ли способы, по которым вы бы указали мне на более полное использование шаблонов Ruby?(Мой код обернут в комментарии «МОЙ КОД [НАЧИНАЕТСЯ | КОНЕЦ] ЗДЕСЬ».

# Greed is a dice game where you roll up to five dice to accumulate
# points.  The following "score" function will be used calculate the
# score of a single roll of the dice.
#
# A greed roll is scored as follows:
#
# * A set of three ones is 1000 points
#
# * A set of three numbers (other than ones) is worth 100 times the
#   number. (e.g. three fives is 500 points).
#
# * A one (that is not part of a set of three) is worth 100 points.
#
# * A five (that is not part of a set of three) is worth 50 points.
#
# * Everything else is worth 0 points.
#
#
# Examples:
#
# score([1,1,1,5,1]) => 1150 points
# score([2,3,4,6,2]) => 0 points
# score([3,4,5,3,3]) => 350 points
# score([1,5,1,2,4]) => 250 points
#
# More scoring examples are given in the tests below:
#
# Your goal is to write the score method.

# MY CODE BEGINS HERE

def score(dice)

  # set up basic vars to handle total points and count of each number
  total = 0
  count = [0, 0, 0, 0, 0, 0]

  # for each die, make sure we've counted how many occurrencess there are
  dice.each do |die|
    count[ die - 1 ] += 1
  end

  # iterate over each, and handle points for singles and triples
  count.each_with_index do |count, index|
    if count == 3
      total = doTriples( index + 1, total )
    elsif count < 3
      total = doSingles( index + 1, count, total )
    elsif count > 3
      total = doTriples( index + 1, total )
      total = doSingles( index + 1, count % 3, total )
    end
  end

  # return the new point total
  total

end

def doTriples( number, total )
  if number == 1
    total += 1000
  else
    total += ( number ) * 100
  end
  total
end

def doSingles( number, count, total )
  if number == 1
    total += ( 100 * count )
  elsif number == 5
    total += ( 50 * count )
  end
  total
end

# MY CODE ENDS HERE

class AboutScoringProject < EdgeCase::Koan
  def test_score_of_an_empty_list_is_zero
    assert_equal 0, score([])
  end

  def test_score_of_a_single_roll_of_5_is_50
    assert_equal 50, score([5])
  end

  def test_score_of_a_single_roll_of_1_is_100
    assert_equal 100, score([1])
  end

  def test_score_of_multiple_1s_and_5s_is_the_sum_of_individual_scores
    assert_equal 300, score([1,5,5,1])
  end

  def test_score_of_single_2s_3s_4s_and_6s_are_zero
    assert_equal 0, score([2,3,4,6])
  end

  def test_score_of_a_triple_1_is_1000
    assert_equal 1000, score([1,1,1])
  end

  def test_score_of_other_triples_is_100x
    assert_equal 200, score([2,2,2])
    assert_equal 300, score([3,3,3])
    assert_equal 400, score([4,4,4])
    assert_equal 500, score([5,5,5])
    assert_equal 600, score([6,6,6])
  end

  def test_score_of_mixed_is_sum
    assert_equal 250, score([2,5,2,2,3])
    assert_equal 550, score([5,5,5,5])
  end

end

Большое спасибо за любую помощь, которую вы можете оказать, когда я пытаюсь разобраться с Ruby.

Ответы [ 37 ]

1 голос
/ 11 июля 2012

В моем ответе используется подход "таблица поиска" ...

def score(dice)
  tally = (1..6).inject(Array.new(7,0)){|a,i| a[i] = dice.count(i); a}
  rubric = {1 => [0,100,200,1000,1100,1200], 5 => [0,50,100,500,550,600]}
  score = rubric[1][tally[1]] + rubric[5][tally[5]]
  [2,3,4,6].each do |i| score += 100 * i if dice.count(i) >= 3 end
  score
end
1 голос
/ 06 декабря 2012
def score(dice)
    result = 0
    result += 1000 * (dice.find_all{|e| e == 1}).length.divmod(3)[0]
    result += 100 * (dice.find_all{|e| e == 1}).length.divmod(3)[1]
    result += 50 * (dice.find_all{|e| e == 5}).length.divmod(3)[1]
    (2..6).each {|value| result += value*100 * (dice.find_all{|e| e == value}).length.divmod(3)[0]}
    return result
end
0 голосов
/ 16 марта 2014

Моей целью было найти хороший баланс между читабельностью и длиной кода

def score(dice)
  return 0 if dice.empty?

  dice.each do |roll|
    tracker[roll] += 1
  end

  tracker.each do |key, value|
    if ![1,5].include?(key) && value > 2
      score += key * 100
    else
      if value < 3
        key == 1 ? score += (100 * value) : score += (50 * value)
      else
        value -= 3
        key == 1 ? score += (1000 + (value * 100)) : score += (500 + (value * 50))
      end
    end

  return score
end

Я все еще хотел бы избавиться от некоторых условных выражений, не жертвуя удобочитаемостью.

0 голосов
/ 04 октября 2013
def score(dice)
  # You need to write this method
  grouped_die = dice.sort_by{ |i| -dice.count(i)}.first.to_i
  total       = 100 * ( dice.count(1) % 3 ) + 50 * ( dice.count(5) % 3 )
  total       += (grouped_die == 1 ? 1000 : grouped_die * 100) if dice.count( grouped_die ) >= 3
  total
end
0 голосов
/ 08 августа 2013

Я предпочитаю решение, которое делает документацию в начале файла избыточной, то есть делает код самодокументированным. Обратите внимание, как последние 4 строки метода соответствуют каждому из первых 4 правил, описанных в комментариях.

def score(dice)
  counts = Hash.new { |hash, key| hash[key] = dice.count(key) }
  total = 0
  total += 1000 if counts[1] >= 3
  (2..6).each { |number| total += 100 * number if counts[number] >= 3 }
  total += 100 * (counts[1] % 3)
  total += 50 * (counts[5] % 3)
end
0 голосов
/ 08 августа 2013

Опоздал на вечеринку, но хотел попытаться ответить, только используя знания, представленные в Коанах. В частности, я не использую Enumerable#count, как большинство других.

Это кажется очень простым для меня, но если кто-нибудь случится, я буду рад услышать об оптимизации, которую вы можете иметь.

А что я могу сказать? Мне нравится использовать преимущества индексации массивов.

def score(dice)
  return 0 if dice.empty? # Immediately recognize an empty roll

  # Create an array to hold the scores for each die face
  totals = []
  7.times { totals << 0 }

  # Handle each roll and calculate new score
  dice.each do |roll|
    if roll == 5
      # If we have seen two 5s thus far, make the score 500 for 5s, otherwise add 50
      totals[roll] == 100 ? totals[roll] = 500 : totals[roll] += 50
    elsif roll == 1
      # If we have seen two 1s thus far, make the score 1000 for 5s, otherwise add 100
      totals[roll] == 200 ? totals[roll] = 1000 : totals[roll] += 100
    else
      # If we see any other number three times, score is the number times 100
      totals[roll] == 2 ? totals[roll] = roll * 100 : totals[roll] += 1
    end
  end

  # Count up the scores for each die face; if score is less than 50, then it's just zero
  return totals.inject(0) { |sum, points| points >= 50 ? sum += points : sum }
end
0 голосов
/ 22 марта 2011

А как насчет этого решения? Спасибо за отзыв!

def score(dice)
  count = Hash.new(0)
  dice.each do |die|
    count[die] += 1
  end
  total = 0
  count.each_pair { |die, set| total += set < 3 ? single_value(die,set) : triple_value(die,set)}
  total
end

def single_value(die,set)
  value = 0
  value += (set * 100) if die == 1
  value += (set * 50) if die == 5
  value
end

def triple_value(die,set)
  value = 0
  diff = set - 3
  value += single_value(die,diff)
  value += die == 1 ? 1000 : die * 100
  value
end
0 голосов
/ 22 мая 2015

Можно ли добавить еще одно право?

def score(dice)
  roll_counts = Hash.new {|hash, key| hash[key] = 0}

  dice.each {|roll| roll_counts[roll] += 1}

  score = 0
  roll_counts.each do |roll_value, count|
    case roll_value
    when 1
      score += count >=3 ? 1000 + (100 * (count - 3)) : 100 * count
    when 5
      score += count >= 3 ? 500 + (50 * (count - 3)) : 50 * count
    else score += roll_value * 100 if count >= 3
    end
  end
  score
end
0 голосов
/ 08 сентября 2011

И еще один, просто для удовольствия:

def score(dice)
  result = 0
  dice.uniq.each { |k|
    result += ((dice.count(k) / 3) * 1000 + (dice.count(k) % 3) * 100) if k == 1
    result += ((dice.count(k) / 3) * 100 * k + (dice.count(k) % 3) * ( k == 5 ? 50 : 0 )) if k != 1
  }
  result
end
0 голосов
/ 13 октября 2012

Я сгруппировал кости лицом к лицу, затем зациклил эти группы, сначала выиграв по три, затем отдельные кости.Вот как бы я оценил игру, если бы я играл в IRL

def score(dice)
    points = 0
    dice.group_by {|face| face}.each do |face,group|
        while group.size >= 3
            if face == 1
                # A set of three ones is 1000 points
                points += 1000
            else
                # A set of three numbers (other than ones) is worth 100 times the number.
                points += 100 * face
            end
            group.pop(3)
        end
        group.each do |x|
             # A one (that is not part of a set of three) is worth 100 points.
            points += 100 if x==1
            # A five (that is not part of a set of three) is worth 50 points.
            points += 50 if x==5 
        end
    end
    return points
end

Вот так я кидаю

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...