Cleaning While Loop for Maya Python Study - python

I made a while loop for Maya python study. It works well, but it is redundant and I think there must be a way to shorten them better or make it looks good. Can you guys give me a suggestion about what I should do? Do you think using another def function would be better than this?
def addWalls(self, length, width, floorNum, bboxScale):
# count variables
count = 1
floorCount = 1
# length loop
while count < length:
# Adding floors on wall
while floorCount < floorNum:
cmds.duplicate(instanceLeaf=True)
cmds.xform(relative=True, translation=[0, 0, bboxScale[2]])
floorCount += 1
floorCount = 1
# Adding next wall
cmds.duplicate(instanceLeaf=True)
cmds.xform(relative=True, translation=[0, -bboxScale[1], -bboxScale[2] * (floorNum - 1)])
count += 1
# Final adding floors
if count == length:
while floorCount < floorNum:
cmds.duplicate(instanceLeaf=True)
cmds.xform(relative=True, translation=[0, 0, bboxScale[2]])
floorCount += 1
floorCount = 1

When I run your script it creates a grid of objects like this:
So if all it needs to do is make a grid of objects then your assumption is right, it makes no sense using a while loop. In fact it's really easy to do it with 2 for loops that represent the "wall's" width and height:
import maya.cmds as cmds
spacing = 5
width_count = 15
height_count = 15
for z in range(width_count):
for y in range(height_count):
cmds.duplicate(instanceLeaf=True)
cmds.xform(ws=True, t=[0, y * spacing, z * spacing])
It will yield the same result with a much shorter and readable script. If you want more flexibility in there it would only take simple tweaks.

Related

For Loop Function Iteration

I am attempting to use a for loop to run a function f(x) on a range of values. I am running into an issue when I want to recalculate my input on the next step dependent on the previous step. Below is some pseudo code that might explain my issue better and below that is the actual code I am attempting to write. The goal is to have a loop that calculates the results on one step and recalculates an input on the next step dependent on the results. IE:
for i in range(10):
H = i - 1
result_up = f(H)
H_delta = (nsolve(Eq(result_up,A(H1)),H1,1))
i += H_delta
The idea is that in the next iteration result_up = f(i += H_delta) so on and so forth.
from sympy import *
USHead = np.linspace(1,3,25)
PHeight = 1.5
WH = Symbol('WH')
for i in USHead:
if i <= PHeight:
Oh = i-1
OD = ((Cd * 0.738 * math.sqrt(2 * 32.2 * (Oh)))* 2)
i_delta = (nsolve(Eq(OD,(0.0612*(TwH1/1)+3.173)*(6-0.003)*(TwH1+.003)**(1.5)), TwH1,1))
i += i_delta
My understanding of for loops is that you have the ability to recalculate i as you continue through the iteration but am thinking the issue is because I have defined my range as a list?
The step size of the list is .083 starting at 1 and ending at 3.
You can't use a for loop if you want to update the iteration variable yourself, since it will override that with the next value from the range. Use a while loop.
i = 0
while i < 10:
H = i - 1
result_up = f(H)
H_delta = (nsolve(Eq(result_up,A(H1)),H1,1))
i += H_delta

I used return, however the recursion does not end. help me please

I am doing a question that gives me a start coordinate, a end coordinate and the number of times of moving.Every time you can add 1 or minus 1 to x or y coordinate based on previous coordinate and the number of moving limit the time the coordinate can move. At last, I need to identify whether there is a possibility to get to the end coordinate
I decide to use recursion to solve this problem however, it does not end even if I wrote return inside a if else statement. Do you mind to take a look at it.
This is the code
# https://cemc.uwaterloo.ca/contests/computing/2017/stage%201/juniorEF.pdf
# input
start = input()
end = input()
count = int(input())
coo_end = end.split(' ')
x_end = coo_end[0]
y_end = coo_end[1]
end_set = {int(x_end), int(y_end)}
#processing
coo = start.split(' ')
x = int(coo[0])
y = int(coo[1])
change_x = x
change_y = y
sum = x + y+count
set1 = set()
tim = 0
timer = 0
ways = 4** (count-1)
def elit(x, y, tim,timer, ways = ways):
print(tim,timer)
tim = tim +1
co1 = (x, y+1)
co2 = (x+1, y)
co3 = (x, y-1)
co4 = (x-1, y)
if tim == count:
tim =0
set1.add(co1)
set1.add(co2)
set1.add(co3)
set1.add(co4)
print(timer)
timer = timer +1
if timer == ways:
print('hiii')
return co1, co2, co3, co4 #### this is the place there is a problem
elit(co1[0],co1[1],tim,timer)
elit(co2[0],co2[1],tim,timer)
elit(co3[0],co3[1],tim, timer)
elit(co4[0],co4[1],tim, timer)
#print(elit(change_x,change_y,tim)) - none why
elit(change_x,change_y,tim, timer)
#print(list1)
for a in set1:
if end_set != a:
answer = 'N'
continue
else:
answer = "Y"
break
print(answer)
In addition, if you have any suggestions about writing this question, do you mind to tell me since I am not sure I am using the best solution.
one of example is
Sample Input
3 4 (start value)
3 3 (end value)
3 (count)
Output for Sample Input
Y
Explanation
One possibility is to travel from (3, 4) to (4, 4) to (4, 3) to (3, 3).
the detailed question can be seen in this file https://cemc.uwaterloo.ca/contests/computing/2017/stage%201/juniorEF.pdf
It is question 3. Thank you
thank you guys
the function is returning properly however by the time you reach the recursive depth to return anything you have called so many instances of the function that it seems like its in an infinite loop
when you call elite the first time the function calls itself four more times, in the example you have given timer is only incremented every 3 cycles and the function only return once timer hits 16 thus the function will need to run 48 times before returning anything and each time the function will be called 4 more times, this exponential growth means for this example the function will be called 19807040628566084398385987584 times, which depending on your machine may well take until the heat death of the universe
i thought i should add that i think you have somewhat over complicated the question, on a grid to get from one point to another the only options are the minimum distance or that same minimum with a diversion that must always be a multiple of 2 in length, so if t the movement is at least the minimum distance or any multiple of 2 over the result should be 'Y', the minimum distance will just be the difference between the coordinates on each axis this can be found by add in the difference between the x and y coordinates
abs(int(start[0]) - int(end[0])) + abs(int(start[1]) -int(end[1]))
the whole function therefore can just be:
def elit():
start = input('start: ').split(' ')
end = input('end: ').split(' ')
count = int(input('count: '))
distance = abs(int(start[0]) - int(end[0])) + abs(int(start[1]) -int(end[1]))
if (count - distance) % 2 == 0:
print('Y')
else:
print('N')
input:
3 4
3 3
3
output:
Y
input:
10 4
10 2
5
output:
N

How to append randomized float values into array within loop

I have a set of randomized float values that are to be arranged into an array at the end of each loop that produces 67 of them, however, there are 64 total loops.
As an example, if I had 4 values per loop and 3 total loops of integers, I would like it to be like this:
values = [[0, 4, 5, 1],[6, 6, 5, 3],[0,0,0,7]]
such that I could identify them as separate arrays, however, I am unsure of the best way to append the values after they are created, but am aware of how to return them. Forgive me as I am unskilled with the logic.
import math
import random
funcs = []
coord = []
pi = math.pi
funcAmt = 0
coordAmt = 0
repeatAmt = 0
coordPass = 0
while funcAmt < 64:
while coordAmt < 67:
coordAmt += 1
uniform = round(random.uniform(-pi, pi), 2)
print("Coord [",coordAmt,"] {",uniform,"} Func:", funcAmt + 1)
if uniform in coord:
repeatAmt += 1
print("Repeat Found!")
coordAmt -= 1
print("Repeat [",repeatAmt,"] Resolved")
pass
else:
coordPass += 1
coord.append(uniform)
#<<<Append Here>>>
funcAmt += 1
coord.clear()
coordAmt = 0
In my given code above, it would be similar to:
func = [
[<67 items>],
...63 more times
]
Your "append here" logic should append the coordinate list and then clear that list for the next iteration of the outer loop:
funcs.append(coord[:]) # The slice notation makes a copy of the list
coord.clear() # or simply coord = []
You should learn to use a for loop. This will simplify your looping: you don't have to maintain the counts yourself. For instance:
for funcAmt in range(64):
for coordAmt in range(67):
...
You might also look up how to make a "list comprehension", which can reduce your process to a single line of code -- a long, involved line, but readable with proper white space.
Does that get you moving?
There are a couple of ways around this. Instead of using while lists and counters, you could just use for loops. Or at least do that for the outer loop, since it looks like you still want to check for repeats. Here's an example using your original dimensions of 3 and 4:
from math import pi
import random
coord_sets = 3
coords = 4
biglist = []
for i in range(coord_sets):
coords_set = []
non_repeating_coords = 0
while non_repeating_coords < coords:
new_coord = round(random.uniform(-1.0*pi, pi), 2)
if new_coord not in coords_set:
coords_set.append(new_coord)
non_repeating_coords += 1
biglist.append(coords_set)
print(biglist)
You can use sets because they don't allow duplicate values:
from math import pi
import random
funcs = []
funcAmt = 0
while funcAmt < 64: # This is the number of loops
myset = set()
while len(myset) < 67: # This is the length of each set
uniform = round(random.uniform(-pi, pi), 2)
myset.add(uniform)
funcs.append(list(myset)) # Append randomly generated set as a list
funcAmt += 1
print(funcs)
maybe you can benefit from arrays in numpy:
import numpy as np
funcs = np.random.uniform(-np.pi, np.pi, [63, 67])
This creates an array of shape (63, 67) from uniform random between -pi to pi.

The bowling game kata in pythonic python

I made an attempt to solve Uncle Bobs bowling game kata (http://www.butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata) but didn't really find a solution that felt pythonic enough.
This solution is more or less an adaptation of Martins C++ solution and uses array indexes to calculate scores for strikes and spares. It works but doesn't feel quite as pythonic as I would like it to be.
class Game():
def __init__(self):
self.rolls = []
def roll(self, pins):
self.rolls.append(pins)
def score_c(self):
total_score = 0
frame_index = 0
for frame in range(10):
if self.rolls[frame_index] == 10:
total_score += 10 + self.rolls[frame_index + 1] + self.rolls[frame_index + 2]
frame_index +=1
elif self.rolls[frame_index] + self.rolls[frame_index + 1] == 10:
total_score += 10 + self.rolls[frame_index + 1]
frame_index += 2
else:
total_score += self.rolls[frame_index] + self.rolls[frame_index + 1]
frame_index += 2
return total_score
I could have used convenience functions for strike and spare conditions, but you get the picture.
But I thought there must be a way to do it without accessing the rolls array directly though indexes. That feels like a very c-like way of doing it and incrementing frame_index directly definitely doesn't feel right in python. So I think there must be a neater way to do it. I made an attempt below which didn't really work for perfect games.
This one use a generator to provide frames which felt pretty neat but it also meant that 0 had to be added for strikes to make complete 2 roll frames.
class Game():
def __init__(self):
self.rolls = []
def _frame_iterator(self):
for i in range(0, 20, 2):
yield (self.rolls[i], self.rolls[i+1])
def roll(self, pins):
self.rolls.append(pins)
if pins == 10:
self.rolls.append(0)
def score(self):
total_score = 0
spare = False
strike = False
for frame in self._frame_iterator():
if spare:
total_score += frame[0]
spare = False
if strike:
total_score += frame[1]
strike = False
if frame[0] + frame[1] == 10:
spare = True
if frame[0] == 10:
strike = True
total_score += frame[0] + frame[1]
return total_score
My questions are basically, has anyone solved the bowling kata in Python in a different and more pythonic way than uncle bobs C++ solution? And suggestions how to improve on my attempt?
This is definitely a different approach (implementing most of the rules in roll(), instead of score()), and I think it's pretty pythonic too.
class Game(object):
def __init__(self):
self._score = [[]]
def roll(self, pins):
# start new frame if needed
if len(self._score[-1]) > 1 or 10 in self._score[-1]:
self._score.append([])
# add bonus points to the previous frames
for frame in self._score[-3:-1]:
if sum(frame[:2]) >= 10 and len(frame) < 3:
frame.append(pins)
# add normal points to current frame
for frame in self._score[-1:10]:
frame.append(pins)
def score(self):
return sum(sum(x) for x in self._score)
The main idea here is instead of storing all rolls in a single list, to make a list of frames that contains a list of rolls (and bonus points) for each frame.
What makes it pythonic is for example the generator expression in the score method.
Another pythonic example is the use of list slices. A previous version of middle part of roll() I did looked like:
for i in [2, 3]:
if len(self._score) >= i:
sum(self._score[-i][:2]) >= 10 and len(self._score[-i]) < 3:
self._score[-i].append(pins)
The elegant thing of the current version using a list slice is that you don't have to check whether the list is long enough to look 1 or 2 frames back. Moreover, you get a nice local variable (frame = self._score[-i]) for free, without having to dedicate a separate line for it.

python turtle graphics iterating through color index throwing an error

I've just started with pythons Turtle graphics module, and I'm running into an issue not with Turtle itself I don't think, but my algorithm styling. I'm using the window.colormode(255) which is awesome and working great when I iterate from red to blue in my program, incrementing the blue variable and decrementing the red variable once every loop.
I'm running into a problem with my filter that should reverse the order of the color incrementor/decrementor (i want to go from blue back to red once r = 0 and b = 255):
Here's the code to draw:
counter = 1
firstlength = 1
secondlength = 1
thirdlength = 1
fourthlength = 1
fifthlength = 1
colorList = [255,0,0] # r g b
f = 0 # index for colorlist
for i in listOfTurtles:
i = turtle.Turtle()
i.pencolor(colorList[0], colorList[1], colorList[2])
i.speed(0) # no turn animations
i.left(counter)
i.forward(firstlength)
i.left(15)
i.forward(secondlength)
i.left(15)
i.forward(thirdlength)
i.left(15)
i.forward(fourthlength)
i.left(15)
i.forward(fifthlength)
counter += 1
firstlength += .1
secondlength += .11
thirdlength += .12
fourthlength += .13
fifthlength += .14
Here's the problem with iterating through the pen color (using an answer below):
blueUp = True
if blueUp == True:
colorList[0] -= 1
colorList[2] += 1
if colorList[0] <= 1:
blueUp = False
else:
colorList[0] += 1
colorList[2] -= 1
if colorList[2] <= 0:
blueUp = True
however, this filter I've set up isn't flipping the color incrementor/decrementor when it needs to; thus resulting in a "bad color sequence error: (-1, 0, 256)
So I know its incrementing my blue 1 digit too high, and my red one too low on the first pass and then erroring out, but I'm unsure how to fix it. I've played with the > values and made them higher (to catch around 5 or 250) but I'm not getting results.
I'm totally open to a completely different way to write this, as I'm sure I've thought up the worst possible way to solve this issue.
For starters, you should probably change this:
if blueUp == False:
if colorsList[2] > 0:
to this:
if blueUp == False:
if colorList[2] > 1:
I'm an idiot. My bool variable was local to my outer for statement, the one iterating through my i's. every loop it would reset the value of blueUp and force the index down again by 1. Resolved the issue by moving my bool outside my outer for loop.

Categories