Skip to content

Instantly share code, notes, and snippets.

@sunny
Created July 10, 2023 06:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sunny/c1453062edfe63c6e0051428a56f84db to your computer and use it in GitHub Desktop.
Save sunny/c1453062edfe63c6e0051428a56f84db to your computer and use it in GitHub Desktop.
class Die
def initialize(count = 1, faces = 1)
@count = count
@faces = faces
end
attr_reader :count, :faces
def rolls
return [count] if faces == 1
@roll ||= count.times.map { rand(1..faces) }
end
def total
rolls.sum
end
def to_s
return count.to_s if faces == 1
"#{count}d#{faces}"
end
def ==(other)
case other
when Die
to_s == other.to_s
else
super
end
end
def self.parse(string)
case string
when /\A([0-9]*)d([0-9]+)\z/
new(($1 || 1).to_i, $2.to_i)
when /\A[0-9]+\z/
new(string.to_i)
else
raise ArgumentError, "unknown die #{string.inspect}"
end
end
end
require_relative "./die"
class DieExpression
def initialize(line)
@line = line
end
def total
dice.sum(&:total)
end
def dice
@dice ||=
line
.gsub(/\s+/, '')
.split(/\+/)
.map { |v| Die.parse(v) }
end
private
attr_reader :line
end
require_relative "../lib/die_expression"
RSpec.describe DieExpression do
describe "#total" do
it { expect(described_class.new("1").total).to eq(1) }
it { expect(described_class.new("1d1").total).to eq(1) }
it { expect(described_class.new("1d2").total).to match(1..2) }
it { expect(described_class.new("1d6").total).to match(1..6) }
it { expect(described_class.new("1d6 + 1").total).to match(2..7) }
it { expect(described_class.new("1d6 + 10").total).to match(11..16) }
it { expect(described_class.new("1d6 + 2d20").total).to match(3..46) }
it { expect(denuescribed_class.new("1d6 + 2d20 + 1").total).to match(4..47) }
end
describe "#dice" do
it { expect(described_class.new("1").dice).to eq([Die.new(1)]) }
it { expect(described_class.new("1d1").dice).to eq([Die.new(1)]) }
it { expect(described_class.new("1d2").dice).to eq([Die.new(1, 2)]) }
it { expect(described_class.new("1d6").dice).to eq([Die.new(1, 6)]) }
it {
expect(described_class.new("1d6 + 1").dice)
.to eq([Die.new(1, 6), Die.new(1)])
}
it {
expect(described_class.new("1d6 + 10").dice)
.to eq([Die.new(1, 6), Die.new(10)])
}
it {
expect(described_class.new("1d6 + 2d20").dice)
.to eq([Die.new(1, 6), Die.new(2, 20)])
}
it {
expect(described_class.new("1d6 + 2d20 + 1").dice)
.to eq([Die.new(1, 6), Die.new(2, 20), Die.new(1)])
}
end
end
require_relative "../lib/die"
RSpec.describe Die do
let(:die) { described_class.new(2, 20) }
it { expect(die.count).to eq(2) }
it { expect(die.faces).to eq(20) }
it { expect(die.total).to match(2..40) }
it {
expect(die.rolls)
.to containing_exactly(a_value_between(1, 20), a_value_between(1, 20))
}
it { expect(die.to_s).to eq("2d20") }
it { expect(Die.parse("2d20")).to eq(die) }
context "with a static value" do
let(:die) { described_class.new(5, 1) }
it { expect(die.count).to eq(5) }
it { expect(die.faces).to eq(1) }
it { expect(die.total).to eq(5) }
it { expect(die.rolls).to eq([5]) }
it { expect(die.to_s).to eq("5") }
it { expect(Die.parse("5")).to eq(die) }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment