What do I wrong?

I’m doing the Hanoi Project learning about stacks and I just can’t get it to work despite watching the walkthrough video several times. Can someone find my mistake?

note: everything works fine but when I enter my from_stack and to_stack I always get: “\n\nInvalid Move. Try Again1” so it doesn’t check the conditions in the elif statement because then it would function

code:

from stack import Stack

print("\nLet's play Towers of Hanoi!!")

#Create the Stacks
stacks = []
left_stack = Stack('Left')
middle_stack = Stack('Middle')
right_stack = Stack('Right')
stacks += [left_stack, middle_stack, right_stack]

###   Set up the Game

num_disks = int(input("\nHow many disks do you want to play with?\n"))

  #to ensure playability
while num_disks < 3:
  num_disks = int(input("Enter a number greater than or equal to 3\n"))

for i in range(num_disks, 0, -1):
  left_stack.push(i)
  
num_optimal_moves = 2 ** num_disks - 1
print("\nThe fastest you can solve this game is in {} moves".format(num_optimal_moves))


####   Get User Input

def get_input():
   
  choices = [i.get_name()[0] for i in stacks]
  
  while True:
    for i in range(len(stacks)):
      name = stacks[i].get_name()
      letter = choices[i]
      print('Enter {0} for {1}'.format(letter, name))
      
    user_input = input('')
    
    if user_input in choices:
      for i in range(len(stacks)):
        return stacks[i]
        
          
###   Play the Game

num_user_moves = 0

while right_stack.get_size() != num_disks:
  
  print("\n\n\n...Current Stacks...")
  for i in stacks:
    i.print_items()
    
  while True:
    
    print("\nWhich stack do you want to move from?\n")
    from_stack = get_input()
    print("\nWhich stack do you want to move to?\n")
    to_stack = get_input()
      
    if from_stack.get_size() == 0:
      print("\n\nInvalid Move. Try Again")
    elif to_stack.get_size() == 0 or from_stack.peek() < to_stack.peek():
      disk = from_stack.pop()
      to_stack.push(disk)
      num_user_moves += 1
      break
        
    else:
      print("\n\nInvalid Move. Try Again1")
        
        
print("\n\nYou completed the game in {0} moves, and the optimal number of moves is {1}".format(num_user_moves, num_optimal_moves))

and what in turn causes that? keep digging backwards from the problem until you find where it behaves differently from how it should

I cant figure it out. I tried now for half an hour. Can you tell me?

Ah. You seemed to be so well on your way. Taking a look I guess.
Uh. Do you have a copy of stack.py, or just a link to the exercise?
Also, how exactly do I reproduce the problem? Like, I run it, and then what input do I enter?

…found it


Let's play Towers of Hanoi!!

How many disks do you want to play with?
3

The fastest you can solve this game is in 7 moves



...Current Stacks...
Left Stack: [3, 2, 1]
Middle Stack: []
Right Stack: []

Which stack do you want to move from?

Enter L for Left
Enter M for Middle
Enter R for Right
L

Which stack do you want to move to?

Enter L for Left
Enter M for Middle
Enter R for Right
R


Invalid Move. Try Again1

And I can reproduce it.

So, you’d probably want to print out more information, the things that were used in the condition to reach that conclusion of it being an invalid move…maybe something like:

    else:
      print('to_stack.get_size()')
      print(to_stack.get_size())
      print('from_stack.get_size()')
      print(from_stack.get_size())
      print("\n\nInvalid Move. Try Again1")

And that does indeed say something about the problem:

to_stack.get_size()
3
from_stack.get_size()
3

So next you would look at how you created those. Maybe they’re actually the same stack. Or maybe you placed rings on both stacks.

You can get unique id’s for values with the function id, or you can compare two with the operator is. Though in this case, printing them out as strings shows their id’s:

print(to_stack)
print(from_stack)
<stack.Stack object at 0x7f79cf7d4e10>
<stack.Stack object at 0x7f79cf7d4e10>

so, clearly it is being compared to itself.

from here you would… keep digging backwards. It is get_input that gave you two of the same one, so you would start looking at what happened in there. You might for example check whether it has access to all the stacks and not just the same one, and you might check that the logic for reading>parsing>lookup is right.

Thank you very much! I’ll try to fix the problem.

There’s also a debugger module in the standard library that you can drop into instead of adding print statements

so you could for example:

import pdb
pdb.set_trace()

On more recent python versions (3.7? not sure) you can just do:

breakpoint()

and from there you can view variables and step through the program, for example:

(Pdb) stacks
[<stack.Stack object at 0x7fefe51f6080>, <stack.Stack object at 0x7fefe50b0748>, <stack.Stack object at 0x7fefe50b07b8>]

so clearly the stacks are different values here, then you might step forwards until reaching the return, to see what got carried out:

Enter L for Left
Enter M for Middle
Enter R for Right
R          <-----------------------------------I picked R
> /tmp/derp/aeuthao/script.py(44)get_input()
-> if user_input in choices:
(Pdb) step
> /tmp/derp/aeuthao/script.py(45)get_input()
-> for i in range(len(stacks)):
(Pdb) 
> /tmp/derp/aeuthao/script.py(46)get_input()
-> return stacks[i]             <----------- reached the return statement
(Pdb) i
0          <---------------- at which point i is 0
(Pdb) stacks[0].name
'Left' <-------------------- its name is Left, not Right

A command-line debugger probably isn’t the easiest thing ever to figure out at first. I think there are graphical front-ends to this, IDE’s probably use this module and associate buttons with different commands, but text is more than fine for me, buttons get in the way.

Found it! As you said the get_input() function was malfunctioning. Instead of returning the targeted stack I think it returned every stack. Thank you again!!

fix:

def get_input():
   
  choices = [i.get_name()[0] for i in stacks]
  
  while True:
    for i in range(len(stacks)):
      name = stacks[i].get_name()
      letter = choices[i]
      print('Enter {0} for {1}'.format(letter, name))
      
    user_input = input('')
    
    if user_input in choices:
      for i in range(len(stacks)):
        **if user_input == choices[i]:**
          return stacks[i]

return exits. you can’t return after returning, you have stopped existing.