PDA

View Full Version : Help Python code


reefyankee
02-21-2012, 02:09 PM
Hello,

I'm trying to write a python code showing an animation of the Tower of Hanoi.
I'd like to know if its possible to assign an object to another one, like to assign a disc to a tower, because i'd like to write something like "discs, move to tower 1"

here is my code for now :

import maya.cmds as cmds # import the python lybrary

numTower = 3
for i in range(3):

tower = cmds.polyCylinder( name = 'tower' + str(i), radius = 5, height = 100 ) # create 3 cylinder
cmds.move(0, 50, i*80, ('tower' + str(i))) # move all cylinders space by 50


rad = 70
for i in range(4) :
disc = cmds.polyCylinder( name = 'disc' + str(i), radius = rad, height = 10) # create 4 discs
cmds.move(0, 12*i, 160, ('disc' + str(i))) # move them to tower 1
rad = rad*0.5



so for now i've just moved all discs where was the tower but not directly to the tower.


Also, I don't really know how to do the animation, should I make the animation of one disc and then make a loop or something ? and when should I include my recursive solution ?

anyway i'm a bit lost,

thanks for your help !

reefyankee
02-27-2012, 04:10 PM
Nobody can help me ?

cwisbg
02-28-2012, 02:51 AM
not a python way but you could use point constraint to achive this.

reefyankee
03-05-2012, 11:26 AM
Is there a python command for point constraint ?

Otherwise, how does the autokeyframe really work ? I'm doing "cmds.autoKeyframe( state=True )" and then "cmds.autoKeyframe()", should I write something between the 2 brackets ?

cwisbg
03-06-2012, 12:32 AM
yeah, its


cmds.pointConstraint

not sure whats going on with the autokey but
and you might want to look into the setKeyframe comand

file:///Applications/Autodesk/maya2011/docs/Maya2011/en_US/CommandsPython/setKeyframe.html

reefyankee
03-12-2012, 05:44 PM
Hi,

ok I've fixed the autokeyframe, here is my code for now :

import maya.cmds as cmds # import the python lybrary

numTower = 3
for i in range(3):

tower = cmds.polyCylinder( name = 'tower' + str(i), radius = 5, height = 100 ) # create 3 cylinder
cmds.move(0, 50, i*100, ('tower' + str(i))) # move all cylinders space by 50


rad = 70
for i in range(4) :
disc = cmds.polyCylinder( name = 'disc' + str(i), radius = rad, height = 10) # create 4 discs
cmds.move(0, 12*i, 200, ('disc' + str(i))) # move them to tower 1
rad = rad*0.5

cmds.setKeyframe( 'disc0', 'disc1', 'disc2', 'disc3', 'tower0', 'tower1', 'tower2', t=1 )

cmds.autoKeyframe( state=True )

cmds.autoKeyframe(characterOption="all")

cmds.autoKeyframe( state=False )

so, basically I've key everything, then i've moved/key the discs

and now I am trying to include my recursive solution in all of that and I've no idea how to do it.... :bowdown:

zoharl
03-14-2012, 07:05 AM
1. Write a procedure that uses the recursion to write the moves into a list.

2. Write a procedure that moves a disc from peg X to peg Y.
2.1 You will have a list of size three towers[], where each cell contains a list of discs (ordered) in the tower.
2.2 To move a disc from X to Y, you need to move graphical disc towers[X].pop_last() to peg Y. To know its new position in Y, you will use towers[Y].length() to find the height of the tower.

3. Write a main which executes step 1 to generate the moves list, then in a loop executes step 2 for each move.

reefyankee
03-15-2012, 12:42 PM
Hi, thank you for your help :)

this would be for the step one :

def hanoi(n, tower2, tower1, tower0):
print "hanoi( ", n, tower2, tower1, tower0, " called"
if (n > 0):
# move tower of size n - 1 to tower1:
hanoi(n - 1, tower2, tower0, tower1)
# move disk from tower2 peg to target peg
if tower2[0]:
disk = tower2[0].pop()
print "moving " + str(disk) + " from " + tower2[1] + " to " + tower0[1]
tower0[0].append(disk)
# move tower of size n-1 from tower1 to tower3
hanoi(n - 1, tower1, tower2, tower0)

tower2 = ([4,3,2,1], "tower2")
tower0 = ([], "tower0")
tower1 = ([], "tower1")
hanoi(len(tower2[0]),tower2,tower1,tower0)

print tower2, tower1, tower0

isnt it ? thats what i've written in python, but now i have to include the "cmds.move" inside ?

zoharl
03-15-2012, 12:54 PM
I think it would be easier for if you encapsulate (separate) the tasks. Meaning finish step 1 by writing the moves to a list, instead of just printing them, and write step 2 independently.

Alternatively you could just call step 2 instead of the printing in your recursion.

reefyankee
03-15-2012, 01:10 PM
so I should write the moves in that way ?


def hanoi(n, tower2, tower1, tower0):
print "hanoi( ", n, tower2, tower1, tower0, " called"
if (n > 0):
# move tower of size n - 1 to tower1:
cmds.move( 0, 72, 0, 'disc1', relative=True )
cmds.move( 0, 0, -99, 'disc1', relative=True )
cmds.move( 0, -102, 0, 'disc1', relative=True )

zoharl
03-15-2012, 07:59 PM
I think you need something more generic. Forget the recursion for a minute, and focus just on step 2. Write a procedure that gets as an input two integers of tower ids, move_top_disc(tower1, tower2), which moves the top disc from tower1 to tower2 in any layout.

First test and make sure that it works: Start in the init position, and then just manually call it, moving some discs from tower to tower.

reefyankee
04-19-2012, 10:33 AM
Ok I tried to do it but I'm seriously struggling with it, could you help me to start please ?

EightBit
04-22-2012, 03:13 PM
It's not clear exactly what you want to accomplish. Can you outline all the tasks ie
1) Create x number of disks.
2) Snap them to objectA.
3) Key frame them at frame X
4) Snap them to objectB.
5) Set keyframe
etc.

reefyankee
04-23-2012, 10:32 AM
After creating the towers and the discs, I need to make the recursive solution working,
like if there is at least one disc on the first peg2, move the top shelf disc, or the smallest one to the peg1, then if there is already a disc on peg1, move smallest disc to peg0, etc...until all discs are on peg0, I don't know how to write that properly...

zoharl
04-23-2012, 11:47 AM
I think you need something more generic. Forget the recursion for a minute, and focus just on step 2. Write a procedure that gets as an input two integers of tower ids, move_top_disc(tower1, tower2), which moves the top disc from tower1 to tower2 in any layout.

First test and make sure that it works: Start in the init position, and then just manually call it, moving some discs from tower to tower.

Okay, let's break these steps further.

First construct a scene with your three pegs, and 5 discs on the first peg. You can do it manually, and you can do it by code, your choice.
After you do it, please post a print screen of outliner/persp layout.

reefyankee
04-24-2012, 10:19 AM
http://imageshack.us/photo/my-images/24/capturedcran20120424111.png/

zoharl
04-24-2012, 10:52 AM
Good. Now, please write a function that moves disc3 from tower0 to tower1.

reefyankee
04-24-2012, 12:25 PM
cmds.move(0, 4.60, 100, 'disc3')

?

zoharl
04-24-2012, 01:02 PM
Yes.

Now instead of moving disc3 from tower0 to tower0, please write a function:

def move_disc(towers, t1, t2):

that moves the top disc of tower t1 over the top disc of tower t2.
'towers' is a list of size 3, where each element of the list is a stack (LIFO) of the discs in the tower. move_disc should update this list. Also the code that you used to construct the towers, should be embedded inside a function, which also takes 'towers' as a parameter and initializes it.

reefyankee
04-24-2012, 01:28 PM
Sorry, what do you mean by "stack (LIFO) of the discs in the tower"

zoharl
04-24-2012, 02:24 PM
Never mind the stack, just keep a sorted list of the discs.

reefyankee
04-24-2012, 11:19 PM
towers = ["tower2", "tower1", "tower0"]
def move_disc(towers, t1, t2):

Should I write another list into this list ? This is the point I didn't know how to do it, to move the top disc, to the other tower..I dont know how to define it

zoharl
04-25-2012, 02:34 AM
The towers should be initialized to:

towers = [[0,1,2,3], [], []]

Meaning the 'towers' is a list, which contains three lists, one for each tower. Each tower list contains the ids (numbers - integers) of the discs.

reefyankee
04-25-2012, 10:34 PM
towers = [[0,1,2,3], [], []]

def move_disc (towers, t1, t2):
towers[1].append(towers[0].pop())

It would be something like that so ?

By the way, I don't just need to move the discs to each peg, but I would need to make them move (up, right/left, down) as an animation. So its better if I don't include my code to create the towers etc..into a function no ?

zoharl
04-25-2012, 10:55 PM
1. You specifically moved the disc from tower 0 to tower 1, while you wanted something more general, from tower t1 to tower t2. Please make the necessary modification.

2. Again, you would have an init_towers() function, which would construct the towers graphically, and initialize the towers list. And you would have a move_disc() function, which would move the disc in towers, and graphically, as you said up/down, left/right.
So post the init_towers() which you should have by now, and add the move_disc() the graphical part. When you do it, first work on a specific case such as moving the top disc from tower 0 to 1, and then work on a general solution of moving from tower t1 to t2.

reefyankee
04-27-2012, 03:58 PM
def init_towers():
for i in range(3):
cmds.polyCylinder( name = 'tower' + str(i), radius = 5, height = 100 )
cmds.move(0, 50, i*100, ('tower' + str(i))) # move all cylinders space by 50

towers = [[0,1,2,3], [], []]

zoharl
04-27-2012, 05:26 PM
1. init_towers: That's fine, although if tomorrow you'll want 5 towers, it would be cleaner to insert the last line inside the for loop.

2. What about the case where both towers are not empty?
Add the code that graphically moves the disc from t1 to t2.

reefyankee
04-27-2012, 06:29 PM
to move the discs graphically I would have to use cmds.move ? In that case, how can I write it since graphical values would changes depending on where is each disc ? Its that general thing that I find hard to write.

zoharl
04-28-2012, 08:32 AM
Right. So let's take for example two cases:

1. The initial state: towers = [[0,1,2,3], [], []], and you want to move disc3 from tower0 to tower1.

2. The state: towers = [[0,1], [3], [2]], and you want to move disc3 from tower1 to tower0.

Please write the specific command for these two cases.

Answer me this:

A. Can you find parameters that can characterize each case?
B. Can write a general expression that would cover everything using the given parameters?
HINT: The expression should use the number of discs in each tower, and the position of the target tower.

reefyankee
04-29-2012, 05:19 PM
A . parameters : the number of discs on each tower change
the last disc of the list is moving to the other tower

zoharl
04-29-2012, 08:42 PM
A. The parameters that would determine the world (don't use relative move) position of a disc is the tower number (determines its z-coordinate), and the current number of discs in the tower (determines its y-coordinate).

B. I think you are on the right track, but a bit messy, and again I would prefer that you move the disc to an absolute position and not relative. So I expect you to have something like:

discName = ...
y = ...
z = ...
cmds.move(discName, 0, y, z)


C. Also please keyframe your disc movement inside move_disc().

D. Also let's connect everything, I would like to see your whole script. It should be something like (just fill the blanks):

import ...

# Initializes the towers structure, and creates the discs both in towers and graphically.
def init_towers (towers):
...

# Moves the top disc from t1 to t2 in 'towers' and graphically.
def move_disc (towers, t1, t2):
...

def main():
towers = []
init_towers(towers)
move_list = [[0,1], [0,2], [1,2]] # just an example list
for mv in move_list:
move_disc(towers, mv[0], mv[1])
main()


Since python is sensitive to indentation, and it's messy to post the whole code after every change, please send me a link to your python script, and each post just mention when you have updated the file on the link. You can store the file for example on google docs. Don't forget that your file should be shared to everyone, and everyone can access it easily without registering or creating accounts.

zoharl
04-29-2012, 10:30 PM
Another important thing: Never use constant numbers (or strings) in your code. Reasons:

1. When you write something like:

cmds.move(80, 'disc3', y=True,r=True)
cmds.move(-100, 'disc3', z=True,r=True)
cmds.move(-110, 'disc3', y=True,r=True)

I have no idea what these numbers mean, and what goes through your mind.

2. The code should be generic as possible. If tomorrow I'd like larger discs or more towers, I would want to set it in one place for one variable, and not throughout the code.

3. It would help you to think of what you are doing in more general terms.


You could relax this demand in the future, when you'll be experienced enough, and move the constant inside the functions.

So please declare in the beginning of the script variables for all the constants that you are going to use, including my example move_list, and replace all the constant numbers (and const strings such as 'disc') in your script with them. Please give these constants a meaningful name. You should have variables such as: move_list, disc_radius, disc_height, space_between_towers, first_disc_radius, disc_radius_diff, num_towers, num_discs, disc_name_prefix (this should stand for 'disc') ...

For example using the constants first_disc_radius, disc_radius_step you could determine discX radius:

r = first_disc_radius + disc_radius_step*X

reefyankee
04-30-2012, 11:39 AM
Hello,

so I have 2 questions,

1 : Why can't I use relative coordinates ?

2 : Why should I add keyframes into my code ?

zoharl
04-30-2012, 12:50 PM
1. The way you used the relative move implied that your way of thinking is wrong. Currently your main weakness is that you don't think in general terms. When I want to move disc3 from somewhere to towerX, I want it at a specific place, no matter where it was before. Thus the relative flag doesn't fit here. There is a way based on relative movement, but I think it's more cumbersome, and it would be easier for you to do it this way.
If you can come up with a general solution using relative, it's fine as well, I just gave you a hint to a better direction.

2. If you won't put keyframes, the animation would go too fast, or hardware dependent. Using keyframes you could view the animation at your own leisure, and it would be easier for debugging. To add a keyframe you could add a move_no parameter to the move_disc function, which would hold the current move number / frame. Alternatively you could set in the init step the current frame to 1, and for each other step query the current frame, and just increase it by a constant frame_step.

reefyankee
04-30-2012, 01:55 PM
Thank you very much for your answers,
well for now I just want to achieve a working program
that's why I inserted a specific value for the discs and the towers, when the program is going to work, I'll think about generalize it
since it would involve just an adjustment of the parameters, but for now I just want to make it work :)

zoharl
04-30-2012, 04:21 PM
If you just want Hanoi towers in maya, then I think I've seen someone who already did it, and I can look for the link.

If your objective is to learn programming, and this is just a small exercise, I encourage you to follow my restrictions. Their objective is definitely not all about generalizing the program to different number of towers or discs. These restrictions would actually force you to think like a programmer, and a solution would come to you more easily and naturally. For example you should have thought about not using the relative flag in the move by yourself. Also other people, like myself, would be able to read your code, and understand what you had in mind.

reefyankee
05-01-2012, 06:41 PM
Hi, I have some questions :

numDisks = int(raw_input("Enter number of disks (must be greater than 0): "))
# Creates the discs graphically.
def draw_disc():
rad = 70
for i in range(numDisks) :
cmds.polyCylinder( name = 'disc' + str(i), radius = rad, height = 10)
cmds.move(0, 10*i, 0, ('disc' + str(i)))
rad = rad*0.5+i
cmds.setKeyframe(t=1)
draw_disc()



in this part of my code that creates the discs, if im chosing to create 5 discs its ok, but if I'm chosing 6 discs or above the smaller ones have all the same size..

reefyankee
05-03-2012, 03:50 PM
in fact i fixed the keyframes

CGTalk Moderation
05-03-2012, 03:50 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.