require 'rubygems'
require 'test/unit'

# http://permutation.rubyforge.org/
require 'permutation'

#
# Partitions collections into all possible in-order subsets
#
#
module Enumerable

   #
   # Generate the partion sizes for a collection of a given
   # length and a specific number of partitions.
   #
   def Enumerable.partition_sizes( collection_length,  
partition_count, &proc )
     Enumerable.generate_partition_sizes( [], collection_length,  
partition_count, proc )
   end

   #
   # Create all in-order partitions of the given collection.  Each
   # partition should have partition_count elements.
   #
   # For example partitions( [1,2,3], 2 ) would yield
   #      [1],[2,3]
   # and  [1,2],[3]
   #
   # and partitions( [1,2,3,4], 2 ) would yield
   #      [1],[2,3,4]
   # and  [1,2],[3,4]
   # and  [1,2,3],[4]
   #
   def partitions( partition_count, &proc )
     Enumerable.partition_sizes( self.size, partition_count ) do | 
partition|
       partitioned_collection = []
       consumed_so_far = 0
       partition.each do |partition_size|
         partitioned_collection << self[ consumed_so_far,  
partition_size ]
         consumed_so_far += partition_size
       end
       yield partitioned_collection
     end
   end

   private
     def Enumerable.generate_partition_sizes( so_far, length,  
partition_count, proc )

       raise "Invalid parameter" if( ( partition_count < 1 ) ||  
( partition_count > length ) )
       partition_size_sum_so_far = so_far.inject(0) { |total,item|  
total+item }

       if so_far.length == partition_count -1
         working = so_far.dup
         working << length - partition_size_sum_so_far
         proc.call( working )
       else
         up_to = length - partition_size_sum_so_far -  
(partition_count - so_far.length ) + 1
         for size in 1..( up_to )
           working = so_far.dup
           working << size
           generate_partition_sizes( working, length,  
partition_count, proc )
         end
       end
     end
end

class PartitionTest < Test::Unit::TestCase
   def test_partition_size_4_count_2
     expected = []
     [1,2,3,4].partitions( 2 ) do |partition|
       expected << partition
     end

     assert_equal expected, [
                              [ [1], [2, 3, 4] ],
                              [ [1, 2], [3, 4] ],
                              [ [1, 2, 3], [4] ]
                            ]
   end

   def test_partition_size_4_count_3
     expected = []
     [1,2,3,4].partitions( 3 ) do |partition|
       expected << partition
     end

     assert_equal expected, [
                             [ [1], [2], [3, 4] ],
                             [ [1], [2, 3], [4] ],
                             [ [1, 2], [3], [4] ]
                            ]
   end

   def test_partition_size_5_count_1
     expected = []
     [1,2,3,4,5].partitions( 1 ) do |partition|
       expected << partition
     end

     assert_equal expected, [
                             [ [ 1, 2, 3,4, 5 ] ],
                            ]
   end

   def test_partition_size_5_count_5
     expected = []
     [1,2,3,4,5].partitions( 5 ) do |partition|
       expected << partition
     end

     assert_equal expected, [
                             [ [1], [2], [3], [4], [5] ],
                            ]
   end

end

def find( digits, operators, magic_number )
   # Generate all possible permutation of operations. Make sure that  
each operator set
   # begins with an "+" since we are actually creating an equation of
   # "+{term1} {op1}{term2} {op2}{term3}" as it is easier to compute
   operator_permutations = Permutation.for( operators ).map { |p|  
( "+" + p.project).split(//) }.uniq

   separator_string = "*" * 20

   total_equations_evaluated = 0

   # Partition the digits into groups of length one more than the  
number of operators
   digits.partitions( operators.length + 1 ) do |digit_partition|

     # For each operator permutation we'll compute the result of  
mixing the operators
     # between the current partition
     operator_permutations.each do |operator_permutation|

       # Match up the digit partition and the operators
       equation = digit_partition.zip( operator_permutation )

       # Create the string representation, joining operators
       # and operands into a resulting equation.
       equation_string = equation.inject("") do |result,term|
         # Only add the operator if we have something in the string
         # this strips out the initial dummy "+" operator from our
         # equation.
         result = result + " " + term[1] + " " unless result.empty?
         result = result + term[0].join
       end

       # Evaluate the equation
       equation_value = eval( equation_string )
       total_equations_evaluated += 1

       # Output as required with stars surrounding any
       # equation that yielded the value we wanted
       puts separator_string if equation_value == magic_number
       puts "#{equation_string} = #{equation_value}"
       puts separator_string if equation_value == magic_number
     end
   end
   puts "#{total_equations_evaluated} possible equations tested"
end


digits = [1,2,3,4,5,6,7,8,9]
operators = "--+"
find( digits, operators, 100 )