2

NOTE: I understand the recursive solution; but I don't see how the code is achieving it, as I can't follow the step-by-step of the code's executing.

I'm having a difficult time understanding the recursive loop for the Towers of Hanoi. I've commented and tried various tactics to see how the procedure is operating, but I can't seem to grasp how the loops are operating and how the rings are being directed.

  def move(rings, from, destination, other)
    if rings == 1
      ring = from.pop
      p "Move ring #{ring} from #{from} to #{destination}"
      destination.push ring
    else
      move(rings-1, from, other, destination)
      move(1, from, destination, other)
      move(rings-1, other, destination, from)
    end
  end

Here's the output:

"Move ring 1 from a to c"
"Move ring 2 from a to b"
"Move ring 1 from c to b"
"Move ring 3 from a to c"
"Move ring 1 from b to a"
"Move ring 2 from b to c"
"Move ring 1 from a to c"

I've looked at various explanations, however, I don't see one explaining how the loops are being executed. For instance, I can't figure out why in the cases where the rings are even, the first step places ring 1 from a to b, while for all odd number of rings, it's from a to c, as shown above.

I understand the logic behind the solution, that in order to move n number of rings to destination while using an auxiliary peg requires that you first move n-1 number of rings to the auxiliary peg followed by moving the nth ring to the destination and repeating the first procedure, again. But, I'm unsure how the directions for placement are changing, e.g. I don't see how a block is going from c to b when the call to the move method, above, doesn't seem to mention c to b.

Thank you, in advance, for your time and help.

Also, if you have any suggestions for helping track the process of code executions in Ruby, please let me know. I'd love to hear some of your insights to how you'd troubleshoot instances where you're unsure how things are being executed.

Eager to hear your answers :)

Vendetta
  • 63
  • 1
  • 8
  • Did you read this - http://en.wikipedia.org/wiki/Tower_of_Hanoi ? – Arup Rakshit Aug 21 '13 at 18:04
  • Yes, I explained in my question that I understand the logic behind the game, as it's pretty easy to solve. My question is how the code is executing the loops as I can't follow the code's step-by-step timeframe. – Vendetta Aug 21 '13 at 18:12
  • Have you tried using one of Ruby's debugger's to single-step the code and WATCH what's happening? – the Tin Man Aug 21 '13 at 18:16
  • Thanks for the tip. I'm very new to this, but I'd love to hear your input on what I could use to watch this. Is there anything like repl.it (online interpreter) that could make this easier? Thanks, again! – Vendetta Aug 21 '13 at 18:18
  • @theTinMan: There really isn't anything to "watch" beyond what the program outputs anyway. It is simply a way of generating a solution - there is no state kept of where the rings are at any time. – Borodin Aug 21 '13 at 21:02
  • I know that, but a debugger lets us look into the program flow as it's single-stepped, and check the value of any variable at any point. It's about as intimate view of a piece of code as we can get. That's how I figured out what TOH was doing back in the days of Turbo Pascal. – the Tin Man Aug 21 '13 at 22:39
  • You may not understand it as well as you think, since you use the word "loop" several times. There are no loops here, only function calls. – pjs Aug 21 '13 at 22:49

1 Answers1

6

The tower of Hanoi is an excellent example of a Divide and Conquer algorithm. You have an algorithm that takes for granted it can move everything from source to destination by moving all elements except the last to spare, then move the last one from source to destination, so move all from spare to destination.

Every call to move that isn't the base case gets divided in 2 more calls exponentially until it hits the base case. The trace of you 3-disk game, only considering the first part (before moving the middle element) is:

move(3, source, dest, spare)
move(2, source, spare, dest)
move(1, source, dest, spare) 

Where it outputs "move ring 1 from source to spare"

The trick here is that the arguments (the stacks) that are passed have different roles for different level. for the 2. level the destination is the 3. levels spare. When moving from spare to destination suddenly the source gets used as spare, but the function doesn't care about that. It merely does it's shuffling until it hits the base case. There are 2^n-1 moves (base cases hit) for n discs.

The recursion finishes the second level before going back and then the 3. layer starts another 2. layer, after moving it's middle, for the move from spare to destination.

Tip: You should add a trace text, like "entering 3, a, c, b" at the beginning and "exiting 3, a, c, b" at the end. That should give you a good idea how many recursions is done and how it's done.

Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • Thanks for the informative comment. I'm going to be following the code with a debugger to see exactly how the calls are being made and where/how the arguments are being flipped. What I can't seem to understand is why/how the variables change. I assume that every time that method is being called with those variables, they would remain, but I can't seem to get my head around to why they are changing and in what sequence. – Vendetta Aug 22 '13 at 15:04
  • The variables are more like labels. You have 3 stacks, A B & C and in the beginning you pass them as source, destination and spare. The function then says whatever you have as spare (C) is the destination of half the job. In that call rings are 2 and it's got source=A, destination=C and spare=B. Neither A, B or C is changed but the parameters in the function points to different data. Only when rings=1 you have pop and push. – Sylwester Aug 22 '13 at 18:28
  • Thanks, again, for the help. I guess the problem is that I've never encountered this idea that the variables would change like that for every time they are being called. I was always under the impression that those variables would stay consistent throughout, so I'm still confused, as I want to understand the logic and methodology behind this, in case, I need to make use of it in the future. How can one predict or understand how the variables are or will change? e.g. I see that at one point, even the source changes from source to spare (e.g. C to B) while other times, it remains the same. – Vendetta Aug 23 '13 at 01:46