Skip to content

Instantly share code, notes, and snippets.

@etiennebarrie
Created October 26, 2010 16:40
Show Gist options
  • Select an option

  • Save etiennebarrie/647255 to your computer and use it in GitHub Desktop.

Select an option

Save etiennebarrie/647255 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'rspec'
class Sequence
def initialize(*elements)
@elements = elements.sort
end
def elements
@elements.dup
end
def sum
@elements.inject(:+)
end
def has_digit_trio?
counts.any? { |value| value > 2 }
end
def has_digit_pair?
counts.any? { |count| count == 2 }
end
def valid?
return false if has_digit_trio?
return false unless has_digit_pair?
sum == 15
end
def next
elements = self.elements
return Sequence.new(1) if elements.empty?
new_element = elements.last
new_elements = elements
sequence = nil
loop do
sequence = Sequence.new(*new_elements + [new_element])
if sequence.has_digit_trio?
elsif sequence.sum > 15
new_element = new_elements.pop # throw last away
else
break
end
new_element = new_elements.pop while new_element == 9
return nil unless new_element # empty set, search over
new_element += 1
end
sequence
end
def next_valid
sequence = self
begin
sequence = sequence.next
end while sequence && !sequence.valid?
sequence
end
private
def counts
histogram = Hash.new(0)
@elements.each do |element|
histogram[element] += 1
end
histogram.values
end
def backtrack(elements)
new_elements = elements
new_element = new_elements.pop while new_elements.last == 9
if new_element
new_elements << new_element + 1
end
end
end
describe Sequence do
it "should sum its elements" do
sequence = Sequence.new(1, 2, 3, 4)
sequence.sum.should == 10
end
it "should return its elements" do
sequence = Sequence.new(1, 2)
elements = sequence.elements
elements.should include(1)
elements.should include(2)
elements.should_not include(3)
end
describe "#valid?" do
it "should return false when there is one element more than two times" do
sequence = Sequence.new(1, 1, 1)
sequence.should have_digit_trio
sequence.should_not be_valid
end
it "should return true when there is more than one element two times" do
sequence = Sequence.new(1, 1, 2, 2)
sequence.should have_digit_pair
sequence.should_not be_valid
end
it "should return false when there is no element two times" do
sequence = Sequence.new(1, 2, 3)
sequence.should_not have_digit_pair
sequence.should_not be_valid
end
it "should return false when the sum is not 15" do
sequence = Sequence.new(1, 2, 3, 3, 5)
sequence.should_not be_valid
end
it "should return true for known valid sequences" do
Sequence.new(1, 1, 6, 7).should be_valid
Sequence.new(1, 1, 2, 3, 8).should be_valid
Sequence.new(1, 1, 2, 3, 4, 4).should be_valid
end
end
describe "#next" do
it "should start with a simple sequence" do
sequence = Sequence.new.next
sequence.sum.should == 1
sequence.elements.should include(1)
end
it "should make a new sequence" do
[[1], [1,9,9]].each do |elements|
Sequence.new(*elements).next.elements.should_not == elements
end
end
it "should not make a sequence with a digit trio" do
sequence = Sequence.new(1, 1).next
sequence.should_not have_digit_trio
end
it "should not make a sequence with a number larger than 9" do
sequence = Sequence.new(1, 9, 9).next
sequence.elements.should_not include(10)
end
it "should not make a sequence with a sum larger than 15" do
sequence = Sequence.new(1, 9).next
sequence.sum.should_not > 15
end
it "should stop when there's no other choice" do
sequence = Sequence.new(9, 9)
sequence.next.should be_nil
end
end
describe "#next_valid" do
it "should return nil or a valid sequence" do
sequence = Sequence.new
while sequence = sequence.next_valid
sequence.should be_valid
end
sequence.should be_nil
end
end
end
if __FILE__ == $0
puts <<-EOS.each_line.map(&:strip)
All unique sequences of digits such as:
* Each element of the sequence is a digit between 1 and 9
* The digits add to 15
* There is at least 1 digit that appears exactly twice
* No digit appears more than twice
* Order is irrelevant [1, 1, 2, 3, 8] and [1, 3, 2, 1, 8] are the same sequence and only count once.
EOS
sequence = Sequence.new
sequences = []
while sequence = sequence.next_valid
puts sequence.elements.join(', ')
sequences << sequence
end
puts "#{sequences.size} sequences found"
puts
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment