class DuelingGenerator attr_reader :value, :start def initialize(value) @value = value @start = value end def self.for(string) type, value = string.gsub("Generator ", "").split(" starts with ") Object.const_get("DuelingGenerator::Generator#{type}").new value.to_i end def reset! @value = start end def generate! @value = (value * factor) % 2147483647 end def strict_generate! @value = (value * factor) % 2147483647 generate! until meets_criterion? end def meets_criterion? value % criterion == 0 end class GeneratorA < DuelingGenerator def factor 16807 end def criterion 4 end end class GeneratorB < DuelingGenerator def factor 48271 end def criterion 8 end end class GeneratorPair attr_reader :g1, :g2 def initialize(g1, g2) @g1 = g1 @g2 = g2 end def self.for(input) new *input.split("\n").map { |line| DuelingGenerator.for line } end def loose_pair_count(comparisons = 40000000) g1.reset! g2.reset! pairs = 0 comparisons.times do g1.generate! g2.generate! pairs += 1 if g1.value & 65535 == g2.value & 65535 end pairs end def strict_pair_count(comparisons = 5000000) g1.reset! g2.reset! pairs = 0 comparisons.times do g1.strict_generate! g2.strict_generate! pairs += 1 if g1.value & 65535 == g2.value & 65535 end pairs end end end