Sunday, September 20, 2015

Kata: Yatzi refactoring kata in Ruby

Last night I did the Yatzy refactoring kata in Ruby.

I mainly used it to practice with Enumerable functions.

This is the original code:

class Yatzy
def self.chance(d1, d2, d3, d4, d5)
total = 0
total += d1
total += d2
total += d3
total += d4
total += d5
return total
end
def self.yatzy(dice)
counts = [0]*(dice.length+1)
for die in dice do
counts[die-1] += 1
end
for i in 0..counts.size do
if counts[i] == 5
return 50
end
end
return 0
end
def self.ones( d1, d2, d3, d4, d5)
sum = 0
if (d1 == 1)
sum += 1
end
if (d2 == 1)
sum += 1
end
if (d3 == 1)
sum += 1
end
if (d4 == 1)
sum += 1
end
if (d5 == 1)
sum += 1
end
sum
end
def self.twos( d1, d2, d3, d4, d5)
sum = 0
if (d1 == 2)
sum += 2
end
if (d2 == 2)
sum += 2
end
if (d3 == 2)
sum += 2
end
if (d4 == 2)
sum += 2
end
if (d5 == 2)
sum += 2
end
return sum
end
def self.threes( d1, d2, d3, d4, d5)
s = 0
if (d1 == 3)
s += 3
end
if (d2 == 3)
s += 3
end
if (d3 == 3)
s += 3
end
if (d4 == 3)
s += 3
end
if (d5 == 3)
s += 3
end
return s
end
def initialize(d1, d2, d3, d4, _5)
@dice = [0]*5
@dice[0] = d1
@dice[1] = d2
@dice[2] = d3
@dice[3] = d4
@dice[4] = _5
end
def fours
sum = 0
for at in Array 0..4
if (@dice[at] == 4)
sum += 4
end
end
return sum
end
def fives()
s = 0
i = 0
for i in (Range.new(0, @dice.size))
if (@dice[i] == 5)
s = s + 5
end
end
s
end
def sixes
sum = 0
for at in 0..@dice.length
if (@dice[at] == 6)
sum = sum + 6
end
end
return sum
end
def self.score_pair( d1, d2, d3, d4, d5)
counts = [0]*6
counts[d1-1] += 1
counts[d2-1] += 1
counts[d3-1] += 1
counts[d4-1] += 1
counts[d5-1] += 1
at = 0
(0...6).each do |at|
if (counts[6-at-1] >= 2)
return (6-at)*2
end
end
return 0
end
def self.two_pair( d1, d2, d3, d4, d5)
counts = [0]*6
counts[d1-1] += 1
counts[d2-1] += 1
counts[d3-1] += 1
counts[d4-1] += 1
counts[d5-1] += 1
n = 0
score = 0
for i in Array 0..5
if (counts[6-i-1] >= 2)
n = n+1
score += (6-i)
end
end
if (n == 2)
return score * 2
else
return 0
end
end
def self.four_of_a_kind( _1, _2, d3, d4, d5)
tallies = [0]*6
tallies[_1-1] += 1
tallies[_2-1] += 1
tallies[d3-1] += 1
tallies[d4-1] += 1
tallies[d5-1] += 1
for i in (0..6)
if (tallies[i] >= 4)
return (i+1) * 4
end
end
return 0
end
def self.three_of_a_kind( d1, d2, d3, d4, d5)
t = [0]*6
t[d1-1] += 1
t[d2-1] += 1
t[d3-1] += 1
t[d4-1] += 1
t[d5-1] += 1
for i in [0,1,2,3,4,5]
if (t[i] >= 3)
return (i+1) * 3
end
end
0
end
def self.smallStraight( d1, d2, d3, d4, d5)
tallies = [0]*6
tallies[d1-1] += 1
tallies[d2-1] += 1
tallies[d3-1] += 1
tallies[d4-1] += 1
tallies[d5-1] += 1
(tallies[0] == 1 and
tallies[1] == 1 and
tallies[2] == 1 and
tallies[3] == 1 and
tallies[4] == 1) ? 15 : 0
end
def self.largeStraight( d1, d2, d3, d4, d5)
tallies = [0]*6
tallies[d1-1] += 1
tallies[d2-1] += 1
tallies[d3-1] += 1
tallies[d4-1] += 1
tallies[d5-1] += 1
if (tallies[1] == 1 and tallies[2] == 1 and tallies[3] == 1 and tallies[4] == 1 and tallies[5] == 1)
return 20
end
return 0
end
def self.fullHouse( d1, d2, d3, d4, d5)
tallies = []
_2 = false
i = 0
_2_at = 0
_3 = false
_3_at = 0
tallies = [0]*6
tallies[d1-1] += 1
tallies[d2-1] += 1
tallies[d3-1] += 1
tallies[d4-1] += 1
tallies[d5-1] += 1
for i in Array 0..5
if (tallies[i] == 2)
_2 = true
_2_at = i+1
end
end
for i in Array 0..5
if (tallies[i] == 3)
_3 = true
_3_at = i+1
end
end
if (_2 and _3)
return _2_at * 2 + _3_at * 3
else
return 0
end
end
end
and this is the refactored one:

class Yatzy
def self.chance *dies
dies.reduce(:+)
end
def self.yatzy *dies
return 50 if all_equal?(dies)
return 0
end
def self.ones *dies
compute_score(dies, 1)
end
def self.twos *dies
compute_score(dies, 2)
end
def self.threes *dies
compute_score(dies, 3)
end
def self.fours *dies
compute_score(dies, 4)
end
def self.fives *dies
compute_score(dies, 5)
end
def self.sixes *dies
compute_score(dies, 6)
end
def self.one_pair *dies
compute_group_of_a_kind_score(dies, 2)
end
def self.two_pairs *dies
pairs = extract_groups_with_equal_or_larger_size(dies, 2)
pairs.keys.reduce(:+) * 2
end
def self.four_of_a_kind *dies
compute_group_of_a_kind_score(dies, 4)
end
def self.three_of_a_kind *dies
compute_group_of_a_kind_score(dies, 3)
end
def self.small_straight *dies
return 15 if small_straight?(dies)
return 0
end
def self.large_straight *dies
return 20 if large_straight?(dies)
return 0
end
def self.full_house *dies
return 0 unless full_house?(dies)
compute_full_house_score(dies)
end
private
def self.compute_score dies, die_value
dies_with_value = dies.select {|die| die == die_value}
die_value * dies_with_value.size
end
def self.compute_frequencies dies
dies.inject({}) do |frequencies_so_far, die|
if frequencies_so_far.include?(die)
frequencies_so_far[die] += 1
else
frequencies_so_far.merge!({die => 1})
end
frequencies_so_far
end
end
def self.extract_groups_with_equal_or_larger_size dies, size
extract_groups(
dies,
lambda { |frequency| frequency >= size }
)
end
def self.compute_group_of_a_kind_score dies, group_size
group = extract_groups_with_equal_or_larger_size(dies, group_size)
compute_group_score(group, group_size)
end
def self.compute_group_score group, group_size
(group.keys.max || 0) * group_size
end
def self.small_straight? dies
frequencies = compute_frequencies(dies)
frequencies.all? do |die, frequency|
frequency == 1 && die != 6
end
end
def self.large_straight? dies
frequencies = compute_frequencies(dies)
frequencies.all? do |die, frequency|
frequency == 1 && die != 1
end
end
def self.all_equal? dies
dies.uniq.size == 1
end
def self.compute_full_house_score dies
pairs_score = compute_full_house_group(dies, 2)
triplets_score = compute_full_house_group(dies, 3)
pairs_score + triplets_score
end
def self.full_house? dies
triplets = extract_groups_with_equal_size(dies, 3)
pairs = extract_groups_with_equal_size(dies, 2)
only_one_pair = pairs.size == 1
only_one_triplet = triplets.size == 1
only_one_pair && only_one_triplet
end
def self.extract_groups_with_equal_size dies, size
extract_groups(
dies,
lambda { |frequency| frequency == size }
)
end
def self.compute_full_house_group dies, group_size
group = extract_groups_with_equal_size(dies, group_size)
compute_group_score(group, group_size)
end
def self.extract_groups dies, predicate
compute_frequencies(dies).select do |_, frequency|
predicate.call(frequency)
end
end
end
I committed after every small refactoring (the commits step by step).

You can find the code in this repository in GitHub.

No comments:

Post a Comment