stackflow12345678
stackflow12345678

Reputation: 23

changing the frequency of iteration

I am trying to solve a challenge where I have 100 empty boxes and every time you touch an empty box you are supposed to fill it and every time you touch a filled box you must empty it. The boxes all start out empty.

You are supposed to first touch every box, then every other box, then every 3rd box, then every 4th box until you are touching every 100th box.

I am trying to create a program that symbolizes this. I am doing so by creating a boxes hash and then doing a double while loop once I have the hash that I want to iterate as directed. However my output is:

{1=>"1", 2=>"1", 3=>"1", 4=>"1", 5=>"1", 6=>"1", 7=>"1", 8=>"1", 9=>"1", 10=>"1", 11=>"1", 12=>"1", 13=>"1", 14=>"1", 15
=>"1", 16=>"1", 17=>"1", 18=>"1", 19=>"1", 20=>"1", 21=>"1", 22=>"1", 23=>"1", 24=>"1", 25=>"1", 26=>"1", 27=>"1", 28=>"
1", 29=>"1", 30=>"1", 31=>"1", 32=>"1", 33=>"1", 34=>"1", 35=>"1", 36=>"1", 37=>"1", 38=>"1", 39=>"1", 40=>"1", 41=>"1",
 42=>"1", 43=>"1", 44=>"1", 45=>"1", 46=>"1", 47=>"1", 48=>"1", 49=>"1", 50=>"1", 51=>"1", 52=>"1", 53=>"1", 54=>"1", 55
=>"1", 56=>"1", 57=>"1", 58=>"1", 59=>"1", 60=>"1", 61=>"1", 62=>"1", 63=>"1", 64=>"1", 65=>"1", 66=>"1", 67=>"1", 68=>"
1", 69=>"1", 70=>"1", 71=>"1", 72=>"1", 73=>"1", 74=>"1", 75=>"1", 76=>"1", 77=>"1", 78=>"1", 79=>"1", 80=>"1", 81=>"1",
 82=>"1", 83=>"1", 84=>"1", 85=>"1", 86=>"1", 87=>"1", 88=>"1", 89=>"1", 90=>"1", 91=>"1", 92=>"1", 93=>"1", 94=>"1", 95
=>"1", 96=>"1", 97=>"1", 98=>"1", 99=>"1", 100=>"1"}

This doesn't seem right as some boxes should be full(e.i = 1) and some should be empty(e.i = 0) but my result shows them all full... What am I doing wrong?

Here is my code, thanks in advance:

number_setter = 1

boxes = {}

while number_setter <= 100 do
  boxes[number_setter] = '0'
  number_setter += 1
end

iteration_setter = 1
increaser = 1

while increaser <= 100 do   
  while iteration_setter <= 100 do
    if boxes[iteration_setter] == '0'
      boxes[iteration_setter] = '1'
    elsif boxes[iteration_setter] == '1'
      boxes[iteration_setter] = '0'
    else
      puts "something is not right on #{iteration_setter} hash key"
    end 
    iteration_setter += increaser
  end
  increaser += 1
end

puts boxes

Upvotes: 0

Views: 47

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110675

I assume you are not looking for a mathematical solution (whether box i is empty or filled at the end can be expressed as a function of i).

Ruby has a number of methods that can be helpful here. One is Array#cycle, which returns an enumerator:

state = [:empty, :filled]
touch = state.cycle
  #=> #<Enumerator: [:empty, :filled]:cycle>

which allows us to write:

touch.next #=> :empty
touch.next #=> :filled
touch.next #=> :empty

rather than something clunky like

touch = (touch==:empty) ? :filled : :empty

We first want to create an array of boxes, the value of each being this enumerator:

nboxes = 20
boxes = Array.new(nboxes) { [:empty, :filled].cycle }

Another useful method is Range#step, allowing us to write:

npasses = 100
(1..npasses).each { |n| (0...nboxes).step(n).each { |i| boxes[i].next } }

We can then examine the state of each box:

boxes.map(&:next)

You may have noticed that the first time a box is touched, it's state is set to :empty, which is incorrect. However, the last line above, which retrieves the final state applies .next, which gets the "next" state, correcting the error at the beginning (since there are two states).

Putting this together:

def touch_boxes(nboxes, npasses=100)
  boxes = Array.new(nboxes) { [:empty, :filled].cycle }
  (1..npasses).each { |n| (0...nboxes).step(n).each { |i| boxes[i].next } }
  boxes.map(&:next)
end

touch_boxes(20, npasses=1)
  #=> [:filled, :filled, :filled, :filled, :filled,
  #    :filled, :filled, :filled, :filled, :filled,
  #    :filled, :filled, :filled, :filled, :filled,
  #    :filled, :filled, :filled, :filled, :filled] 
touch_boxes(20, npasses=2)
  #=> [:empty,  :filled, :empty,  :filled, :empty,
  #    :filled, :empty,  :filled, :empty,  :filled, 
  #    :empty,  :filled, :empty,  :filled, :empty,
  #    :filled, :empty,  :filled, :empty,  :filled] 
touch_boxes(20, npasses=3)
  #=> [:filled, :filled, :empty,  :empty,  :empty,
  #    :filled, :filled, :filled, :empty,  :empty,
  #    :empty,  :filled, :filled, :filled, :empty,
  #    :empty,  :empty,  :filled, :filled, :filled] 
touch_boxes(20, npasses=20)
  #=> [:empty,  :filled, :empty,  :empty,  :filled,
  #    :empty,  :empty,  :empty,  :empty,  :filled,
  #    :empty,  :empty,  :empty,  :empty,  :empty,
  #    :empty,  :filled, :empty,  :empty,  :empty] 

Upvotes: 0

DigitalRoss
DigitalRoss

Reputation: 146073

Well, for one thing, you never start iteration_setter over again, so it just remains 101 forever...

Moving iteration_setter = 1 to the line right before while iteration_setter <= 100 do should do the trick.

Upvotes: 1

Related Questions