Skip to content

Instantly share code, notes, and snippets.

@peterellisjones
Last active August 29, 2015 14:06
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 peterellisjones/426ced0eb025e00d0a94 to your computer and use it in GitHub Desktop.
Save peterellisjones/426ced0eb025e00d0a94 to your computer and use it in GitHub Desktop.
Create random arithmetic operations using numbers between 0 and 20
# returns a random operation that
# result in n. eg:
# randomOperation(20) => [4, '*', 5]
# randomOperation(10) => [20, '/', 2]
class RandomOperationGenerator
def initialize(min = 0, max = 20)
raise "min must be less than max" unless min < max
@min = min
@max = max
end
def random_operation(n)
raise "n must be in range [#{min}, #{max}]" unless n >= min && n <= max
r = rand(0)
# with large numbers, favour multiplication and addition
if n >= min + (max - min) / 2
distribution = [[4, :addition], [2, :multiplication], [1, :subtraction], [1, :division]]
else
distribution = [[1, :addition], [1, :multiplication], [4, :subtraction], [4, :division]]
end
operation = choose_from_distribution(distribution)
operations.fetch(operation).call(n)
end
private
attr_reader :min, :max
def operations
symbols = [:addition, :multiplication, :subtraction, :division]
Hash[symbols.map { |func| [func, proc { |n| self.send(func, n) } ] } ]
end
def addition(n)
a = rand(n - min).floor + min
[a, '+', n - a]
end
def subtraction(n)
b = rand(max + 1 - n)
[n + b, '-', b]
end
def division(n)
return [0, '/', rand(max)] if n.zero?
b = 1 + rand((max/n).ceil - min) + min
[n * b, '/', b]
end
def multiplication(n)
if n == 0
a, b = [rand(max), 0].shuffle
else
a = ((min > 0 ? min : 1)..n).select { |f| (n % f).zero? }.shuffle.first
b = n / a
end
[a, '*', b]
end
def choose_from_distribution(distribution)
width = distribution.map(&:first).inject(&:+)
r = rand(0) * width
distribution.each do |d|
r -= d.first
return d.last if r <= 0
end
end
end
if __FILE__ == $0
100.times do
min = 0
max = 99
n = rand(max - min + 1) + min
op = RandomOperationGenerator.new(min, max).random_operation(n)
puts "#{op[0].to_s.rjust(2, ' ')} #{op[1]} #{op[2].to_s.rjust(2, ' ')} = #{n.to_s.rjust(2, ' ')}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment