Joshua Cody Joshua Cody - 3 months ago 9
Ruby Question

Ruby Greed Koan - How can I improve my if/then soup?

I'm working my way through the Ruby Koans in order to try and learn Ruby, and so far, so good. I've gotten to the greed koan, which at the time of this writing is 183. I've got a working solution, but I feel like I've cobbled together just a bunch of if/then logic and that I'm not embracing Ruby patterns.

In the following code, are there ways you would point me to more fully embracing Ruby patterns? (My code is wrapped in "MY CODE [BEGINS|ENDS] HERE" comments.

# 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


Thanks so much to any help you can give as I try to get my head around Ruby.

Answer

Looks OK. I might have written some things slightly differently, say:

def do_triples number, total
  total + (number == 1 ? 1000 : number * 100)
end

If you want to do something that few languages other than Ruby can do, I suppose the following might be justifiable under DIE and DRY, on alternate Tuesdays, but I don't think those Ruby maxims were really intended to apply to common subexpression elimination. Anyway:

def do_triples number, total
  total +
  if number == 1
    1000
  else
    number * 100
  end
end

def do_triples number, total
  if number == 1
    1000
  else
    number * 100
  end + total
end