Getting to 100 (#119)

On Mon, 09 Apr 2007 01:39:19 +0900, Christian N. wrote:

Since there are only 168 solutions (254 if you allow a sign before the
first digit), brute-forcing is the simplest thing one can do. Additional
operations can be added by changing the base and mapping the digits onto
further operations. (Different digit order is not that easy to
implement and maybe be futile to do with brute-forcing.) =end

(00000000…‘22222222’.to_i(3)).map { |x| x.to_s(3).rjust(8, “0”).
tr(‘012’, '-+ ') }.
find_all { |x| x.count("-") == 2 and x.count("+") == 1 }.

A less ram-intensive version of this would swap the map and find_all
calls as follows:

(00000000…‘22222222’.to_i(3)).
find_all { |x| x.to_s(3).count(“0”) == 2 and
x.to_s(3).count(“1”) == 1 }.
map { |x| x.to_s(3).tr(‘012’, '-+ ').rjust(8," ")}.

(It doesn’t keep maintain references to the bad combinations of
operators, allowing the GC to reclaim them earlier.)

2#787lilith:~/mess/current$ ruby quiz119.rb |grep -C4 100$
123-456-7+89: -251
123+45-67-89: 12
123-45+67-89: 56


123-45-67+89: 100


12+345-67-89: 201
1-234+567-89: 245
1-23-456+789: 311

I like this answer a lot. Think you could generalize it to the extra
credit?

On Sun, 08 Apr 2007 23:25:14 +0900, Kyle S. wrote:

First we have this version

little=Array.new(@setlength+@maxops) do

end

t.store(e,eval(e))
t.store(Array.new(17){|i|
t.each_index{|a| while t[a]=Array.new(17){|i|
i=i%2==0?i/2+1:["","+","-"][rand(3)]}.join and not
t.length==t.uniq.length;end}

t.sort.each {|a| f=eval(a)==100?’*’:’ '; puts “#{f} #{a}=#{eval(a)}
#{f}”}

For those reading along, the magic number 6560==‘22222222’.to_i(3)
His goal is to just generate 6560 different combinations of the
operators
using a random generator.

One should note that this technically violates the rules of code golf
which require the solution to terminate within a short period of time (I
believe 4 seconds), so that its correctness can be verified
automatically
without having to worry about DOS attacks.

Here goes my solution for another nice quiz, yes I know I repeat myself.
It should get all the extras plus one extra from the last quiz, the
fuzzy solutions.

Cheers
Robert
Defaults = { :@fuzz => 0, :@target => 100, :@digits => [*1…9], :@ops
=> [ :-, :- , :+ ] }

Override the default values if you want ;).

Defaults.each do
| key, value |
instance_variable_set “#{key}”, value
end # Configurable.each do

If you are really serious about overriding the default values do it

again ;).

@ops.map!{|o| " #{o} "}
class Array
def each_with_rest
each_with_index do
| ele, i |
yield ele, self[0, i] + self[i+1…-1]
end
end # each_with_rest
def runtempatios
return [[]] if empty?
remps = []
each_with_rest do
| ele, rest |
remps += rest.runtempatios.map{ | p | p.unshift(ele) }
end # each_with_rest do
remps.uniq
end # def runtempatios
end

My wife does not like it very much when I am slicing the bread, the

slices are of

very variable thickness!!!

A long earned skill that I can eventually put to work now :slight_smile:

def _slices outer, inner

In order to be able to slice we have to assure that outer.size >

inner.size
return [ outer ] if inner.empty?
r = []
(outer.size-inner.size+1).times do
|i|
_slices( outer[i+1…-1], inner[1…-1] ).each do
| slice |
r << outer[0,i.succ] + inner[0…0] + slice
end # slices( outer[i+2…-1], rest ).each do
end # (outer.size-inner.size).times do
r
end

def slices outer, inner
_slices( outer, inner ).reject{|s| inner.include? s.last }
end

@count = 0
@total = 0
@target = (@target-@fuzz … @target+@fuzz)
@ops.runtempatios.each do
| ops |
slices( @digits, ops ).each do
| expression |
e = expression.join
value = eval e
e << " = #{value}"
if @target === value then
@count += 1
puts e.gsub(/./,"")
puts e
puts e.gsub(/./,"
")
else
puts e
end
@total += 1
end # slices( @digits, ops ).each do
end # @ops.runtempatios.each do
puts “=”*72
puts “There were #{@count} solutions of a total of #{@total} tested”

On 4/8/07, Ryan L. [email protected] wrote:

I started working on a generalized solution using this algorithm, but
it gets tricky. It isn’t too hard to generalize the number sequence,
but generalizing the operators really makes it messy.

OK, I figured out the generalized solution based on Christian’s
submission:

seq = ARGV[0]
ops = ARGV[1]
res = ARGV[2].to_i
uops = ops.split(‘’).uniq
print (0…(uops.length.to_s * (seq.length-1)).to_i(uops.length+1)).
map { |x| x.to_s(uops.length+1).rjust((seq.length-1), ‘0’).
tr(‘012345’, uops.join.ljust(6, ’ ‘)) }.
find_all { |x| uops.inject(true){|b, op| b and (x.count(op) ==
ops.count(op))} }.
map { |x|
t = seq[0,1] + x.split(’‘).zip(seq[1…-1].split(’‘)).join.delete(’ ')
[eval(t), t]
}.each { |s, x|
puts “" if s == res
puts “#{x}: #{s}”
puts "
” if s == res
}.size
puts " possible equations tested"

This supports any arbitrary sequence of numbers, up to 5 different
operators in whatever combination, and whatever result. It gets slower
as you add operators though.

This was fun, but I can just see how slow it is, especially with the
inject I added.

As you can see I also added printing how many equations were tested.

Ryan

On 4/8/07, Christian N. [email protected] wrote:

puts "*****************" if s == 100

}

That’s brilliant. It took me a minute to figure out how it worked, but I
like.

I started working on a generalized solution using this algorithm, but
it gets tricky. It isn’t too hard to generalize the number sequence,
but generalizing the operators really makes it messy.

Ryan

here is my first pass:

class Array
def combinations(n)
case n
when 0: []
when 1: self.map { |e| [e] }
when size: [self]
else
(0…(size - n)).to_a.inject([]) do |mem,i|
mem += self[(i+1)…size].combinations(n-1).map do |rest|
[self[i],*rest]
end
end
end
end
end

equations = 0
separator = “************************”

(1…8).to_a.combinations(3).each do |partitions|
3.times do |n|
equation = “123456789”

partitions.reverse.each_with_index do |partition,index|
  equation = equation.insert(partition, (index == n ? ' + ' : ' -

'))
end

result = eval(equation)
equation << " = #{result}"

if result == 100
  equation = "#{separator}\n#{equation}\n#{separator}"
end

puts equation

equations += 1

end
end

puts “#{equations} possible equations tested”

After going back and reading the current solutions, I like Ken B.'s
each_partition method. It’s much cleaner than my combinations method.

#!/usr/bin/ruby

Q119 Solution by Sergey V.

Accept

- an arbitrary number and ordering of digits,

- an arbitrary set of operators (but allowing

the same operator more than once),

- an arbitrary target number

Output every possible equation that can be formed,

and the actual result of that equation.

The equation that results in target number have

stars around it.

At the end, print out the number of formulae

that were possible.

require ‘rubygems’
require ‘facets/core/enumerable/permutation’

all possible unique permutations

def op_seqs a
res = Hash.new
a.each_permutation{ |pe|
res[pe] = true
}
res.keys
end

generate all expressions without reordering,

recursive implementation;

I could have implemented Array#each_incut( arr )

to get more generic solution, but I’m too lazy…

Will it be better to avoid recursion?

Not required for this quiz, but must for generic method.

Does anybody knows elegant nonrecursive implementation? Please show

me.
def incut_all digs, opcs, scurr=’’, &block
if digs.empty? || opcs.empty?
# result string
block[ %/#{scurr}#{digs}#{opcs.pack(‘C*’)}/ ]
return
end
# extend with digit
incut_all digs[1…-1], opcs, scurr+digs[0].to_s, &block
# extend with operator
incut_all digs, opcs[1…-1], scurr+opcs[0].chr, &block
end

output all possible equations

def show_all digits, opers, target
# validate arguments
a_digs = digits.scan(/./).map{ |d| Integer( d ) }
fail "invalid operator, only [-, +, , /] allowed" unless %r|^[-
+
/]+| =~ opers
a_ops = opers.unpack(‘C*’)
n_targ = Integer( target )

count = 0 # equation counter
# operators char set
op_cs = %/[#{ Regexp.quote a_ops.uniq.pack('C*') }]/
# Regexp for 'incorrect' expression
bad_exp_rx = %r/^#{op_cs}|#{op_cs}{2}|#{op_cs}$/o
for op_seq in op_seqs( a_ops )
    incut_all( a_digs, op_seq ){ |exp|
        next if bad_exp_rx =~ exp
        # beautify expression
        exp.gsub!( %r/#{op_cs}/, %q/ \0 / )
        # evaluate expression
        next unless val = eval( exp ) rescue nil
        s = %/#{exp} = #{val}/
        sep = (val == n_targ) && '*'*s.size
        puts sep if sep
        puts s
        puts sep if sep
        count += 1
    }
end
puts %/#{count} possible equations tested/

end

Arguments accepted:

an arbitrary number and ordering of digits

digits = ARGV[0] || ‘123456789’

an arbitrary set of operators (but allowing the same operator more

than once)
opers = ARGV[1] || ‘±-’

an arbitrary target number

target = ARGV[2] || 100

Output all possible equations

show_all( digits, opers, target )
exit

#=================================================

L:\Ruby\bin\ruby.exe -w L:\rb\Quiz\Q119.rb

123-456-7+89 = -251
123-45-678+9 = -591


123-45-67+89 = 100


123-45-6+789 = 861
123-4-5678+9 = -5550

168 possible equations tested

On 08/04/07, Carl P. [email protected] wrote:

After going back and reading the current solutions, I like Ken B.'s
each_partition method. It’s much cleaner than my combinations method.

I agree, very clean and efficient. The three lines that put it all
together using #zip are what makes this work for me:

Digits.each_partition(Operators.length+1) do |digitspart|
OperatorPerms.each do |operatorsperm|
expression=digitspart.zip(operatorsperm).flatten.join

I think I would be feeling very happy if I’d submitted this solution :slight_smile:

My first quiz attempt ever so go easy on me :slight_smile:

From looking at the submissions so far it seems like my solution is
quite verbose but I am proud to have a solution that works! (Extra
Credit Too)

#file permutate.rb
module Permutate

def Permutate.generate(n)
permutations = Array.new
perm = Array.new

#first permutation
(1..n).each{|i|
  perm << i
}

print “#{perm}\n”

permutations << perm.to_s

(2..(fact(n))).each do |i|
  m = n - 2

  while (perm[m] > perm[m+1])
    m = m - 1
  end
  k = n - 1

  while perm[m] > perm[k]
    k = k - 1
  end
  swap(perm,m,k)
  p = m + 1
  q = n - 1
  while p < q
    swap(perm,p,q)
    p = p + 1
    q = q - 1
  end

print “#{perm}\n”

  permutations << perm.to_s
end
permutations

end

def Permutate.swap(array, a, b)
temp = array[a]
array[a] = array[b]
array[b] = temp
end

def Permutate.fact(n)
return 1 if n == 0
result = 1
(2…n).each do |i|
result *= i
end
result
end

end

#file equation.rb
class Equation

attr_reader :digits, :rhs, :overlay, :valid

#digits contains an array of digits in the problem
#rhs is the right hand side of the equation
#overlay is a string representation of operators

and their position in available positions between

digits

def initialize(digits, rhs, overlay)
@digits = digits
@rhs = rhs
@overlay = overlay
@eqn = buildEquation

@valid = isValid?

end

def buildEquation
equation = @digits.to_s

#overlay permutation string over digits
#put a space before and after all operators
([email protected]).each{|i|
  equation.insert((4*i + 1)," #{@overlay[i,1]} ")
}

#take _ placeholders out
equation.gsub!(" _ ","")

return equation

end

def isValid?
(eval(@eqn) == @rhs)
end

def to_s
#output the equation in standard format
result = “#{@eqn} = #{eval(@eqn)}”.squeeze(" ")

if @valid
  marker = "*" * result.size
  return "#{marker}\n#{result}\n#{marker}"
else
  return result
end

end

end

#file equationlist.rb
require ‘permutate’
require ‘equation’

class EquationList

attr_reader :digits, :rhs, :operators, :list

def initialize(digits, operators, rhs)
@digits = digits
@operators = operators
@rhs = rhs
@list = Array.new
end

def build
#get permutations for location of operators
perms = Permutate.generate(@digits.size - 1)

#now assign each operator to a number in the perms list
operators.each_with_index{|operator,i|
  perms.each{|perm|
    perm.sub!(Regexp.new((i+1).to_s),operator)
  }
}

#now replace each number left with _
#to denote that field is unused
perms.each{|perm|
  perm.gsub!(/\d/,"_")
}

#now we need to get rid of nonunique equations
perms.uniq!

#now build a list of equation objects with this information
perms.each{|perm|
  #puts perm
  @list << Equation.new(@digits,@rhs,perm)
}

end

def display
puts @list
puts “#{@list.size} possible equations tested”
end
end

#file getTo100.rb
require ‘equationlist’

digits = %w[1 2 3 4 5 6 7 8 9]
operators = %w[+ - -]
rhs = 100

equations = EquationList.new(digits, ops, rhs)
equations.build
equations.display

Comments are welcome, I’m here to learn!

Matt Hulse
[email protected]

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 )

Christian N. wrote:

with checking the immediate results.
find_all { |x| x.count("-") == 2 and x.count("+") == 1 }.

I’m sorry to be a noob on this, but can someone please explain to me
what this is doing. If it works, it must be genius, and I can’t figure
it out.

Raj S.

Wow, this is pretty freaky. My solution is eerily similar to Ken’s
(albeit less concise), and I hadn’t seen his code until now. Look:

On Apr 8, 9:21 pm, “Marcel W.” [email protected] wrote:

On 08/04/07, Carl P. [email protected] wrote:

After going back and reading the current solutions, I like Ken B.'s
each_partition method. It’s much cleaner than my combinations method.

I wrote an Array#each_partition too, and my first implementation of it
looked almost just like his:

def each_partition(n = length)
if n < 1
yield []
else
(0…length-n).each do |x|
section=self[x, length]
self[0, x].each_partition(n-1) do |part|
yield part << section
end
end
end
self
end

I rewrote this when I found an iterative algorithm for it, but I
hadn’t realized that that seemingly extraneous argument could be used
to limit the number of partitions, which is clever. Still, this is a
fundamental algorithm in combinatorics, so I’m not too surprised that
he chose to put in Array. This is where it gets eerie:

I agree, very clean and efficient. The three lines that put it all
together using #zip are what makes this work for me:

Digits.each_partition(Operators.length+1) do |digitspart|
OperatorPerms.each do |operatorsperm|
expression=digitspart.zip(operatorsperm).flatten.join

my version of the above:

digits.send(digits_message) do |part|

operators.send(*ops_send_args) do |tuple|
expr = part.zip(tuple).join(’ ')

And then I go on to eval(expr), as Ken did. Take it for granted that
my uses of send() do essentially the same thing. Weird, no?

I think I would be feeling very happy if I’d submitted this solution :slight_smile:


Marcel

I was, too, before I saw Ken’s.

Harrison

On 4/9/07, Raj S. [email protected] wrote:

Writing this code took maybe ten minutes and happened step-by-step
tr(‘012’, '-+ ') }.
END
1-23-456+789: 311

I’m sorry to be a noob on this, but can someone please explain to me
what this is doing. If it works, it must be genius, and I can’t figure
it out.

Raj S.

Actually I have no idea whatsoever, this is normally a good starting
point :wink:
irb is our friend of course, so let us hack away:
irb(main):003:0> (000…‘222’.to_i(3)).map{|x|x.to_s(3).rjust(3,
“0”).tr(‘012’, '-+ ')}
=> [“—”, “–+”, "-- ", “-±”, “-++”, "-+ ", “- -”, “- +”, "- ",
“±-”, “±+”, "± ", “+±”, “+++”, “++ “, “+ -”, “+ +”, “+ “, " --”,
" -+”, " - “, " ±”, " ++”, " + “, " -”, " +”, " "]

Aha the ternary array is used to create all kind of operator
combinations including " “.
I do not know exactly what this is good for right now, but I guess we
will learn.
As a next step I increase 3 to 8 as I think we can understand that now
and I will add the next method
(00000000…‘22222222’.to_i(3)).map { |x| x.to_s(3).rjust(8,
“0”).tr(‘012’, '-+ ') }.find_all { |x| x.count(”-“) == 2 and
x.count(”+“) == 1 }
=> [”–+ ", "-- + ", "-- + ", "-- + ", "-- + ", “–
+”, "-± ", "-+ - ", "-+ - ", "-+ - ", "-+ - ", “-+
-”, "- -+ ", "- - + ", "- - + ", "- - + ", “- - +”, "-
± ", "- + - ", "- + - ", "- + - ", “- + -”, "- -+ ",
"- - + ", "- - + ", “- - +”, "- ± ", "- + - ", "- + -
", “- + -”, "- -+ ", "- - + ", “- - +”, "- ± ", "- +

  • ", “- + -”, "- -+ ", “- - +”, "- ± ", “- + -”, “-
    -+”, “- ±”, "±- ", "± - ", "± - ", "± - ", "±
    • ", “± -”, "+ – ", "+ - - ", "+ - - ", "+ - - ", "+
  • -", "+ – ", "+ - - ", "+ - - ", “+ - -”, "+ – ",
    "+ - - ", “+ - -”, "+ – ", “+ - -”, “+ --”, " --+
    ", " – + ", " – + ", " – + “, " – +”, " -± ", " -+ -
    ", " -+ - ", " -+ - “, " -+ -”, " - -+ ", " - - + ", " - -
  • “, " - - +”, " - ± ", " - + - ", " - + - “, " - + -”, " -
    -+ “, " - - + “, " - - +”, " - ± “, " - + - “, " - + -”, " -
    -+ “, " - - +”, " - ± “, " - + -”, " - -+”, " - ±”, "
    ±- ", " ± - ", " ± - ", " ± - “, " ± -”, " + – ",
    " + - - ", " + - - “, " + - -”, " + – “, " + - - “, " + -
    -”, " + – “, " + - -”, " + --”, " --+ ", " – + ", " –
  • “, " – +”, " -± ", " -+ - ", " -+ - “, " -+ -”, " -
    -+ ", " - - + “, " - - +”, " - ± ", " - + - “, " - + -”, "
  • -+ “, " - - +”, " - ± “, " - + -”, " - -+“, " - ±”, "
    ±- ", " ± - ", " ± - “, " ± -”, " + – “, " + - - “,
    " + - -”, " + – “, " + - -”, " + --”, " --+ “, " – +
    “, " – +”, " -± “, " -+ - “, " -+ -”, " - -+ “, " - -
    +”, " - ± “, " - + -”, " - -+”, " - ±”, " ±- ", " ±
  • “, " ± -”, " + – “, " + - -”, " + --“, " --+ “, "
    – +”, " -± “, " -+ -”, " - -+”, " - ±", " ±- “, "
    ± -”, " + --“, " --+”, " -±", " ±-"]

It is a little longer but we see already that only 2 minuses and 1
plus is allowed…
By storing this into a variable tmp we can continue easily to explore
what is happening
tmp.map{|x| t = “1” + x.split(//).zip((2…9).to_a).join.delete(" ") ;
[eval(t),t]}
=> [[456785, “1-2-3+456789”], [56754, “1-2-34+56789”], [6443,
“1-2-345+6789”], [-2668, “1-2-3456+789”], [-34479, “1-2-34567+89”],
[-345670, “1-2-345678+9”], [-456787, “1-2+3-456789”], [-56756,
“1-2+34-56789”], [-6445, “1-2+345-6789”], [2666, “1-2+3456-789”],
[34477, “1-2+34567-89”], [345668, “1-2+345678-9”], [56763,
“1-23-4+56789”], [6722, “1-23-45+6789”], [311, “1-23-456+789”],
[-4500, “1-23-4567+89”], [-45691, “1-23-45678+9”], [-56807,
“1-23+4-56789”], [-6766, “1-23+45-6789”], [-355, “1-23+456-789”],
[4456, “1-23+4567-89”], [45647, “1-23+45678-9”], [6551,
“1-234-5+6789”], [500, “1-234-56+789”], [-711, “1-234-567+89”],
[-5902, “1-234-5678+9”], [-7017, “1-234+5-6789”], [-966,
“1-234+56-789”], [245, “1-234+567-89”], [5436, “1-234+5678-9”],
[-1561, “1-2345-6+789”], [-2322, “1-2345-67+89”], [-3013,
“1-2345-678+9”], [-3127, “1-2345+6-789”], [-2366, “1-2345+67-89”],
[-1675, “1-2345+678-9”], [-23373, “1-23456-7+89”], [-23524,
“1-23456-78+9”], [-23537, “1-23456+7-89”], [-23386, “1-23456+78-9”],
[-234565, “1-234567-8+9”], [-234567, “1-234567+8-9”], [-456789,
“1+2-3-456789”], [-56820, “1+2-34-56789”], [-7131, “1+2-345-6789”],
[-4242, “1+2-3456-789”], [-34653, “1+2-34567-89”], [-345684,
“1+2-345678-9”], [-56769, “1+23-4-56789”], [-6810, “1+23-45-6789”],
[-1221, “1+23-456-789”], [-4632, “1+23-4567-89”], [-45663,
“1+23-45678-9”], [-6559, “1+234-5-6789”], [-610, “1+234-56-789”],
[-421, “1+234-567-89”], [-5452, “1+234-5678-9”], [1551,
“1+2345-6-789”], [2190, “1+2345-67-89”], [1659, “1+2345-678-9”],
[23361, “1+23456-7-89”], [23370, “1+23456-78-9”], [234551,
“1+234567-8-9”], [56794, “12-3-4+56789”], [6753, “12-3-45+6789”],
[342, “12-3-456+789”], [-4469, “12-3-4567+89”], [-45660,
“12-3-45678+9”], [-56776, “12-3+4-56789”], [-6735, “12-3+45-6789”],
[-324, “12-3+456-789”], [4487, “12-3+4567-89”], [45678,
“12-3+45678-9”], [6762, “12-34-5+6789”], [711, “12-34-56+789”], [-500,
“12-34-567+89”], [-5691, “12-34-5678+9”], [-6806, “12-34+5-6789”],
[-755, “12-34+56-789”], [456, “12-34+567-89”], [5647, “12-34+5678-9”],
[450, “12-345-6+789”], [-311, “12-345-67+89”], [-1002,
“12-345-678+9”], [-1116, “12-345+6-789”], [-355, “12-345+67-89”],
[336, “12-345+678-9”], [-3362, “12-3456-7+89”], [-3513,
“12-3456-78+9”], [-3526, “12-3456+7-89”], [-3375, “12-3456+78-9”],
[-34554, “12-34567-8+9”], [-34556, “12-34567+8-9”], [-56778,
“12+3-4-56789”], [-6819, “12+3-45-6789”], [-1230, “12+3-456-789”],
[-4641, “12+3-4567-89”], [-45672, “12+3-45678-9”], [-6748,
“12+34-5-6789”], [-799, “12+34-56-789”], [-610, “12+34-567-89”],
[-5641, “12+34-5678-9”], [-438, “12+345-6-789”], [201,
“12+345-67-89”], [-330, “12+345-678-9”], [3372, “12+3456-7-89”],
[3381, “12+3456-78-9”], [34562, “12+34567-8-9”], [6903,
“123-4-5+6789”], [852, “123-4-56+789”], [-359, “123-4-567+89”],
[-5550, “123-4-5678+9”], [-6665, “123-4+5-6789”], [-614,
“123-4+56-789”], [597, “123-4+567-89”], [5788, “123-4+5678-9”], [861,
“123-45-6+789”], [100, “123-45-67+89”], [-591, “123-45-678+9”], [-705,
“123-45+6-789”], [56, “123-45+67-89”], [747, “123-45+678-9”], [-251,
“123-456-7+89”], [-402, “123-456-78+9”], [-415, “123-456+7-89”],
[-264, “123-456+78-9”], [-4443, “123-4567-8+9”], [-4445,
“123-4567+8-9”], [-6667, “123+4-5-6789”], [-718, “123+4-56-789”],
[-529, “123+4-567-89”], [-5560, “123+4-5678-9”], [-627,
“123+45-6-789”], [12, “123+45-67-89”], [-519, “123+45-678-9”], [483,
“123+456-7-89”], [492, “123+456-78-9”], [4673, “123+4567-8-9”], [2012,
“1234-5-6+789”], [1251, “1234-5-67+89”], [560, “1234-5-678+9”], [446,
“1234-5+6-789”], [1207, “1234-5+67-89”], [1898, “1234-5+678-9”],
[1260, “1234-56-7+89”], [1109, “1234-56-78+9”], [1096,
“1234-56+7-89”], [1247, “1234-56+78-9”], [668, “1234-567-8+9”], [666,
“1234-567+8-9”], [444, “1234+5-6-789”], [1083, “1234+5-67-89”], [552,
“1234+5-678-9”], [1194, “1234+56-7-89”], [1203, “1234+56-78-9”],
[1784, “1234+567-8-9”], [12421, “12345-6-7+89”], [12270,
“12345-6-78+9”], [12257, “12345-6+7-89”], [12408, “12345-6+78-9”],
[12279, “12345-67-8+9”], [12277, “12345-67+8-9”], [12255,
“12345+6-7-89”], [12264, “12345+6-78-9”], [12395, “12345+67-8-9”],
[123450, “123456-7-8+9”], [123448, “123456-7+8-9”], [123446,
“123456+7-8-9”]]

Well this is very impressive as it solves the quiz but I lost him
there, I guess we have to look into the block applied to tmp.map
{|x| t = “1” + x.split(//).zip((2…9).to_a).join.delete(" ") ;
[eval(t),t]}

okay let us take just one x, e.g.
x= tmp[32]
=> “- - +”

To my great despair tmp[42] is not a very good example :frowning:

Now we split x into single characters and zip the digits 2 to 9 into
them
x.split(//).zip([*2…9])
=> [[“-”, 2], [" “, 3], [” “, 4], [” “, 5], [”-“, 6], [” “, 7], [” “,
8], [”+", 9]]
and I think I understand what happened now, the rest is basic, add a 1
in the front flatten the array and delete all spaces, and you get the
expressions needed for the quiz.

I guess that the final sort.each is quite straight forward.

HTH

BTW I want to have my ball back James, or adjust my handicap please ;).

Cheers
Robert

Ken B. [email protected] writes:

the immediate results.

A less ram-intensive version of this would swap the map and find_all
calls as follows:

(00000000…‘22222222’.to_i(3)).
find_all { |x| x.to_s(3).count(“0”) == 2 and
x.to_s(3).count(“1”) == 1 }.
map { |x| x.to_s(3).tr(‘012’, '-+ ').rjust(8," ")}.

(It doesn’t keep maintain references to the bad combinations of
operators, allowing the GC to reclaim them earlier.)

Yes, but that confuses the application logic. I don’t think it will
save memory compared to yours, you are #to_s’ing a lot more than me!

On 4/8/07, Marcel W. [email protected] wrote:

I think I would be feeling very happy if I’d submitted this solution :slight_smile:

May I have the temerity to point out that I posted basically the same
solution, which I posted two hours before Ken’s.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

“Ryan L.” [email protected] writes:

puts "#{x}: #{s}"
puts "*****************" if s == 100

}

That’s brilliant. It took me a minute to figure out how it worked, but I like.

I started working on a generalized solution using this algorithm, but
it gets tricky. It isn’t too hard to generalize the number sequence,
but generalizing the operators really makes it messy.

The number sequence is easy, and the operators are easy too (just
change the base), as you have shown. The real problem is to allow the
numbers in any order.

Ryan

P.S: The code was not written deliberately in a cryptic style (but
admittedly unfactored). This is how I code one-shot things.

On Apr 9, 6:18 am, “Rick DeNatale” [email protected] wrote:

OperatorPerms.each do |operatorsperm|
expression=digitspart.zip(operatorsperm).flatten.join

I think I would be feeling very happy if I’d submitted this solution :slight_smile:

May I have the temerity to point out that I posted basically the same
solution, which I posted two hours before Ken’s.

Indeed! Well, isn’t too coincidental after all for me to have used
the same mechanism. Great minds must think alike, no?

Harrison R.

On 09/04/07, Rick DeNatale [email protected] wrote:

 expression=digitspart.zip(operatorsperm).flatten.join

I think I would be feeling very happy if I’d submitted this solution :slight_smile:

May I have the temerity to point out that I posted basically the same
solution, which I posted two hours before Ken’s.

Indeed you may – apologies, I thought I had been back through all the
posts but didn’t go back as far as yours.

So I think you should also be feeling very happy :slight_smile:

I do have one small piece of constructive criticism (if I may) since
you brought attention to your code:

found = val == goal
puts “" if found_in_a_row == 0 && found
puts "
” unless found_in_a_row == 0 || found
puts “#{eqn} = #{val}” if verbose || goal == val
found_in_a_row = found ? found_in_a_row + 1 : 0

Could also have been written:

found = val == goal
puts “" if found
puts “#{eqn} = #{val}” if verbose || goal == val
puts "
” if found
found_in_a_row = found ? found_in_a_row + 1 : 0

For the same number of lines, I find the second much easier to follow
without having to remember any state for the second time around.
There does not seem to be any advantage in placing the asterisk lines
together. (?)

As another aside, I’m in two minds as to whether it’s necessary to
provide such a complete set of parameters (and comments) for these
solutions. On the one hand it sets a good example to newcomers (and
it satisfies our quest for perfection) but on the other it does tend
to obscure some of the more interesting details. It’s like you’re
damned if you do and damned if you don’t - the difficulty is finding
the right balance.

I think there’s room for both kinds of posts but certainly the shorter
ones seem more appealing even if longer ones do use the same
underlying methods. I also like to work at making a solution more
generic for future purposes but I’ve come to the conclusion that
(unless the extra credits mention it) there’s no point because I’m
only going to prejudice my solution.

In the real world I would go for the more generic code and proper
comments any day but for the purposes of the quiz I like to see
solutions that do just as much as is asked of them and ideally fit on
one page of my screen.


Marcel

On Apr 9, 2007, at 4:35 AM, Robert D. wrote:

BTW I want to have my ball back James, or adjust my handicap
please ;).

I’m just glad you broke that code down for us. Now maybe I can read
it to look smart when I write up the summary. :wink:

James Edward G. II