Picking classes based on given parameters [duplicate] - python

This question already has answers here:
pick a subclass based on a parameter
(4 answers)
Closed 7 years ago.
So i have a class:
class Unit(object):
def __init__(self, name, x , y, z):
self.name = name
self.strength = x + y
self.intelligence = x + z
self.speed = y + z - x
and two species of these Units
class Red(Unit):
def __init__(self, name, x, y, z):
Unit.__init__(self,name, x, y, z)
self.strength = self.strength * 2
class Blue(Unit):
def__init__(self, name, x, y, z):
Unit.__init__(self, name, x, y, z)
self.speed = self.speed * 2
I want the race to be decided based on what x, y, z, was used as input (z > x means the unit belongs to class Red and x > z means the unit belongs to class Blue) without having to set one before hand, how do I do this?

You could create function for that:
def builder(name, x, y, z):
if z > x:
return Red(name, x, y, z)
elif x > z:
return Blue(name, x, y, z)

You can set the __class__ attribute in your __init__:
class Unit(object):
def __init__(self, name, x , y, z):
self.name = name
self.strength = x + y
self.intelligence = x + z
self.speed = y + z - x
if z > x:
self.__class__ = Red
else:
self.__class__ = Blue
red = Unit("foo", 1,2,3)
blue = Unit("bar", 3,2,1)
You can also create a factory method that instantiates the appropriate class. You can do this as a stand-alone function, or you could make a class method. Here's the stand-alone version:
def unit_factory(name, x, y, z):
if x > z:
return Red(name, x, y, z)
return Blue(name, x, y, z)
red = unit_factory("foo", 1, 2, 3)
blue = unit_factory("bar", 3, 2, 1)

Related

Think Python exercise 6.1

This is an exercise 6.1 in the book "Think Python". The question is to find the print result.
This is what I can get so far.
x = 1, y = 2
bring to a(x, y), return 4
b(z), return z**2 + z
I couldn't find the valve z from c(x, y, z) function.
def b(z):
prod = a(z, z)
print(z, prod)
return prod
def a(x, y):
x = x + 1
return x * y
def c(x, y, z):
total = x + y + z
square = b(total)**2
return square
x = 1
y = x + 1
print(c(x, y+3, x+y))
The x and y in def a(x, y): are not the same x and y defined elsewhere in the script. It might as well say def a(j, k):. When you see prod = a(z, z), you need to know what the value of z is, and then go to the definition of def a(j, k): and think j = z and k = z.
If we just tell you what the output is, then you wouldn't learn to "Think Python"

Python flood fill not returning

I'm currently developing a flood fill code to fill polygons in a software renderer I made for my Computer Graphics class. Here's the code below of my recursion, I based it on an algorithm from geeksforgeeks.
def flood(self, x, y, colorOld, colorNew):
if (x < 0 or x >= self.width or y < 0 or y >= self.height):
print("height/width not in range")
return
if (self.framebuffer[x][y] != colorOld):
print("color is old")
return
print(str(x) + ", " + str(y))
self.point(x, y, colorNew)
self.flood(x+1, y, colorOld, colorNew)
self.flood(x-1, y, colorOld, colorNew)
self.flood(x, y+1, colorOld, colorNew)
self.flood(x, y-1, colorOld, colorNew)
return
def floodFill(self, x, y, colorN):
colorO = self.framebuffer[x][y]
self.flood(x, y, colorO, colorN)
However, it gets stuck when it reaches the end of the width, it's not returning even though it reaches one of the flags.
If I need to provide my whole renderer, just tell me.

A more elegant way of deleting the last value of multiple lists?

I have multiple lists namely, X, Y, VX, VY, R, T, KE, PE, TE, for which I need to delete their (i+1)th value off once their iterations break. The way I can do it currently is if I do:
del X[i+1:]
del Y[i+1:]
del VX[i+1:]
del VY[i+1:]
del R[i+1:]
del T[i+1:]
del KE[i+1:]
del PE[i+1:]
del TE[i+1:]
Which I think it looks rather ugly. Is there a way to minimize the use of lines in this case. Maybe a loop which does that but in just 1 or 2 lines?
Edit:
I didn't want to include the body of my code because I'm aware that a lot of my colleagues are doing the same problem and I don't want anyone to plagiarize. Anyway, here's what I did.
def F_1(X):
return VX
def F_2(X):
return VY
def F_3(X, Y):
return -G*EM*X/((X**2 + Y**2)**(3/2))
def F_4(X, Y):
return -G*EM*Y/((X**2 + Y**2)**(3/2))
def RKutta(F_1, F_2, F_3, F_4, XSTART, YSTART, VXSTART, VYSTART):
N = 100000
X, Y = np.zeros([N+1]), np.zeros([N+1])
VX, VY = np.zeros([N+1]), np.zeros([N+1])
R, T = np.zeros([N+1]), np.zeros([N+1])
KE, PE, TE = np.zeros([N+1]), np.zeros(N+1), np.zeros([N+1])
X[0], Y[0] = XSTART, YSTART
VX[0], VY[0] = VXSTART, VYSTART
T[0] = 0
# KE[0], PE[0], TE[0] = KE, PE, TE
for i in range (1,N):
K_1X = F_1(VX[i-1])
K_1Y = F_2(VY[i-1])
K_1VX = F_3(X[i-1], Y[i-1])
K_1VY = F_4(X[i-1], Y[i-1])
K_2X = F_1(VX[i-1] + (H*K_1VX/2))
K_2Y = F_2(VY[i-1] + (H*K_1VY/2))
K_2VX = F_3(X[i-1] + (H*K_1X/2), Y[i-1] + (H*K_1Y/2))
K_2VY = F_4(X[i-1] + (H*K_1X/2), Y[i-1] + (H*K_1Y/2))
K_3X = F_1(VX[i-1] + (H*K_2VX/2))
K_3Y = F_2(VY[i-1] + (H*K_2VY/2))
K_3VX = F_3(X[i-1] + (H*K_2X/2), Y[i-1] + (H*K_2Y/2))
K_3VY = F_4(X[i-1] + (H*K_2X/2), Y[i-1] + (H*K_2Y/2))
K_4X = F_1(VX[i-1] + H*K_3VX)
K_4Y = F_2(VY[i-1] + H*K_3VY)
K_4VX = F_3(X[i-1] + H*K_3X, Y[i-1] + H*K_3Y)
K_4VY = F_4(X[i-1] + H*K_3X, Y[i-1] + H*K_3Y)
X[i] = X[i-1] + (H/6)*(K_1X + 2*K_2X + 2*K_3X + K_4X)
Y[i] = Y[i-1] + (H/6)*(K_2Y + 2*K_2Y + 2*K_3Y + K_4Y)
VX[i] = VX[i-1] + (H/6)*(K_1VX + 2*K_2VX + 2*K_3VX + 2*K_4VX)
VY[i] = VY[i-1] + (H/6)*(K_1VY + 2*K_2VY + 2*K_3VY + 2*K_4VY)
R[i] = ((X[i])**2 + (Y[i])**2)**(0.5)
T[i] = T[i-1] + H
KE[i] = ((VX[i]**2 + VY[i]**2)/2)
PE[i] = (-1*G*EM/R[i])
TE[i] = KE[i] + PE[i]
if R[i] < 6.371E6: #if orbit radius is less than Earth radius
break
for sublist in [X, Y, VX, VY, R, T, KE, PE, TE]:
del sublist[i+1:]
return X, Y, VX, VY, R, T, KE, PE, TE
X = 3.84E8
Y = 0
X, Y, VX, VY, R, T, KE, PE = RKutta(F_1, F_2, F_3, F_4, X, Y, VX, VY)
plt.plot(X, Y, label = "")
plt.xlabel("X distance (m)")
plt.ylabel("Y distance (m)")
plt.title("X against Y")
plt.legend()
plt.show()
I'm trying to implement 4th-order Runge-Kutta method to simulate a rocket orbiting the Earth. The goal is to finally print out the orbit of the rocket. I'm still figuring out my code so they're still not working yet. How would using class improve this?
Keep references of your list in another data structure and then loop through that to delete everything at once:
for sublist in [X, Y, VX, VY, R, T, KE, PE, TE]:
del sublist[i+1:]
Edit:
You wanted to use classes instead of lists.
Right now you have nine lists, and the ith element in each list corresponds to an attribute about the ith rocket. So you can create a rocket class:
class Rocket:
def __init__(self, X, Y, VX, VY, R, T, KE, PE, TE):
self.X = X
self.Y = Y
self.VX = VX
...
This will let you access the attributes of each rocket like so:
Saturn_V = Rocket(1, 2, 3, 4, 5, 6, 7, 8, 9)
Saturn_V.X
>>>1
Now instead of nine seperate lists you can use one list of rockets:
rocket_list = [Saturn_V, Sputnik, Atlas-Agena ...]
An to remove all the information about on specifc rocket you only need to remove one element from the list:
del rocket_list[0] #removes Saturn_V and all its attributes
Here's what I was trying to explain in my comment(s). Although I don't know the details of what you're doing, hopefully this will be enough give you the general idea:
# Define a class to hold each group of values.
class Example:
def __init__(x, y, vx, vy, r, t, ke, pe, te):
self.x = x
self.y = y
self.vx = vx
self.vy = vy
self.r = r
self.t = t
self.ke = ke
self.pe = pe
self.te = te
# Somehow create a list of Example instances.
my_data = [Example(x1, y1, vx1, vy1, r1, t1, ke1, pe1, te1),
Example(x2, y2, vx2, vy2, r2, t2, ke2, pe2, te2),
...
Example(xN, yN, vxN, vyN, rN, tN, keN, peN, teN)]
# Then you could do what you asked about like this:
for i, elem in enumerate(my_data):
if elem.ke > elem.pe: # Done?
break
del my_data[i+1:] # Delete remaining elements in my_data.

I have set of points like P1,P2,P3,....,Pn and each point has x and y as numbers. How can I do math to these points in python?

I have these points:
P1 = (1,2) = (1**2+2**2)**1/2 = 5**1/2 //this is how we can compute the point and so on for the rest. the ** means the power of.
P2 = (3,2) //P2.x = 3 , P2.y = 2 and so on for the rest points
P3 = (1,1) // P3.x= 1 , P3.y = 1
..
..
..
Pn = (m,k)
P= <P1(1,2),P2(3,2),P3(1,1),......,Pn(2,2)>
P
|P|= ((P1**2)+(P2**2)+.....+(Pn**2))**1/2 //the square root of the sum of square points
What is the best way to write python function for a distance from P1 to Pn? for those equations Sx and Sy
Sx = (P1.x)/|P| + (P2.x)/|P| + (P3.x)/|P| + ...... +(Pn.x)/|P|
Sy = (P1.y)/|P| + (P2.y)/|P| + (P3.y)/|P| + ...... +(Pn.y)/|P|
form the above equations we will get point of S(Sx,Sy).
I tried my way I put x values in a list and y values in another list to slice it based on n value. so suppose you already have x, y values of P:
x = [1,3,1,.......,m]
y = [2,2,1, ......,k]
In pure Python, you can create a Point class, and overload relevant operators:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def sqnorm(self):
p = self * self
return p.x + p.y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __radd__(self, other):
return self.sqnorm() + other
def __mul__(self, other):
return Point(self.x * other.x, self.y * other.y)
And a norm function:
def norm(points):
return math.sqrt(sum(points))
Usage:
points = [Point(1,2), Point(3,2), Point(1,1)]
print(norm(points))
In NumPy,
import numpy as np
x = np.array(x)
y = np.array(y)
points = np.concatenate((x, y), axis=1)
norm = np.sum(points**2)
Sx = x / norm
Sy = y / norm

"Properly" organise (spread out) x and y data

Not really sure how to word this question, so I will give an example of what I want.
I have two variables xsteps and ysteps.
If xsteps is 4 and ysteps is 2, then I would like a variable result to be "x, x, y, x, x, y"
If xsteps is 10 and ysteps is 5, then I would like result to be
"x, x, y, x, x, y, x, x, y, x, x, y, x, x, y"
If xsteps is 15 and ysteps is 5 then I would like result to be "x, x, x, y, x, x, x, y, x, x, x, y, x, x, x, y, x, x, x, y"
If xsteps is 1 and ysteps is 6, I would like result to be "x, y, y, y, y, y, y"
If xsteps is 4 and ysteps is 4, I would like result to be "x, y, x, y, x, y, x, y"
If xsteps is 10 and ysteps is 4, I would like result to be "x, x, y, x, x, y, x, x, y, x, x, y, x, x"
Xsteps and ysteps are not always easily divisible. If they do not divide, then I would just like them to be kind of separated out. It does not need to be perfect, just so it spreads them out reasonable well.
Really, I need the xsteps and ysteps variables organised into one variable that spreads them out.
You can try something like this:
from __future__ import division
def spreadout(X, Y):
ratio = len(X) / len(Y)
result = []
while X or Y:
if not Y or len(X)/len(Y) >= ratio:
result.append(X.pop())
else:
result.append(Y.pop())
return result
The idea behind the algorithm is to determine the ratio of the X andY lists and to alternately pop elements from either of the lists to keep the ratio in the result list similar.
This implementaiton works with lists of arbitrary elements and will return the result as a list. If you want just your x,y string, the code can be simplified and optimized some, e.g. using len this often would be wasteful is you have very long lists of xs and ys. Or you can just write a wrapper for that:
def xy_wrapper(x, y):
return ",".join(spreadout(['x'] * x, ['y'] * y))
Example Output:
>>> spreadout(range(6), list("ABC"))
[5, 'C', 4, 3, 'B', 2, 1, 'A', 0]
>>> xy_wrapper(5, 17)
'x,y,y,y,y,x,y,y,y,x,y,y,y,y,x,y,y,y,x,y,y,y'
def spread_generator(xsteps, ysteps):
ratio = xsteps / ysteps
while xsteps > 0 or ysteps > 0:
if xsteps > ratio * ysteps:
yield "x"
xsteps -= 1
else:
yield "y"
ysteps -= 1
xsteps = 7
ysteps = 3
result = [x for x in spread_generator(xsteps, ysteps)]
# Next line will make result variable hold desired value
result.reverse()
print result
# ['x', 'x', 'y', 'x', 'x', 'y', 'x', 'x', 'y', 'x']
# And if you want string
result_as_str = ",".join(result)
print result_as_str
# x,x,y,x,x,y,x,x,y,x
The crucial value is the ratio between x and y steps.
The list is reversed in the beginning, so we reverse it.
Remember that list.reverse() modifies the list in place and returns None.
Looks like someone beat me to the punch with a much nicer response, but I've written it now!
This would do close to what you want, but your example for (10, 4) doesn't work the way you have specified it.
def xy_spread(xsteps, ysteps):
out = []
if xsteps == 0:
out = ['y'] * ysteps
else:
y_per_x = float(ysteps) / float(xsteps)
y_budget = 0.0
for _ in xrange(xsteps):
out.append('x')
y_budget += y_per_x
while y_budget >= 1:
y_budget -= 1
out.append('y')
return ','.join(out)
Not necessarily pretty, but functional.
Basically it seems you want to split the xsteps into chunks, and intersperse a "y" between the chunks until either the x's or y's run out.
def get_chunks(mylist, n):
"""
Adapted from:
http://www.how2code.co.uk/2013/04/how-to-split-a-list-into-chunks-in-python/
"""
if n == 0:
return mylist
else:
return [mylist[x:x+n] for x in range(0, len(mylist), n)]
def combine(xs=0, ys=0):
"""
>>> combine(xs=4, ys=2)
x,x,y,x,x,y
>>> combine(xs=10, ys=5)
x,x,y,x,x,y,x,x,y,x,x,y,x,x,y
>>> combine(xs=15, ys=5)
x,x,x,y,x,x,x,y,x,x,x,y,x,x,x,y,x,x,x,y
>>> combine(xs=1, ys=6)
x,y,y,y,y,y,y
>>> combine(xs=4, ys=4)
x,y,x,y,x,y,x,y
>>> combine(xs=10, ys=4)
x,x,y,x,x,y,x,x,y,x,x,y,x,x
"""
output = list()
x = ['x'] * xs
y = ['y'] * ys
step = xs // ys
xchunks = get_chunks(x, step)
while xchunks or y:
if xchunks:
output += xchunks.pop()
if y:
output += y.pop()
print ','.join(output)

Categories