The code shown below works. I think using recursion is not effective in Python. How can I convert it to for loop version?
def fun(x1, y1, x2, y2, n, r=[]):
if n<1 :
return
r.append( [[x1,y1],[x2,y2]])
x3=(x1+x2)/2.0
y3=(y1+y2)/2.0
fun(x1,y1,x3,y3, n-1)
fun(x3,y3,x2,y2,n-1)
x4=(x2+y2-y3-x3)*0.7+x3;
y4 = (y2 - x2 + x3 - y3)*0.7 + y3;
fun(x3, y3, x4, y4, n - 1);
x3 = (3* x1 + x2)/4;
y3 = (3* y1 + y2)/4;
x2 = (3*x2 + x1)/4;
y2 = (3*y2 + y1)/4;
x4 = (x2*1.7 - y2 + 2*x3 - x3*1.7 + y3)/2;
y4 = (x2 + y2*1.7 - x3 + 2*y3 - 1.7*y3)/2;
fun(x3, y3, x4, y4, n - 1);
return r
print fun(200, 400, 200, 0, 9).__len__()
You may want to consider something like memoize to speed up recursive functions by using more memory. Essentially it stores the results of any call in a cache.
Add the following code
import collections
import functools
class memoized(object):
'''Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, collections.Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return functools.partial(self.__call__, obj)
Then decorate your function like this
#memoized
def fun(x1, y1, x2, y2, n, r=[]):
...
Also be careful with your optional parameter. The list created by r = [] will actually be shared across all calls of f with an r. It is better to do something like this so a new list is created every time.
def fun(x1, y1, x2, y2, n, r=None):
r = [] if r is None else r
A more Pythonic way of getting the length is like this
print len(fun(200, 400, 200, 0, 9))
Related
I'm trying to coding a Point class to determine if a 3 given point can make a trainagle.
this is the Class I did:
import math
class Point(object):
def __init__(self, x1, y1):
self.x = x1
self.y = y1
def getX(self):
return int(self.x)
def getY(self):
return int(self.y)
def Distance(self):
return math.sqrt((self.x ** 2) + (self.y ** 2))
def PointToStr(self):
return '({}, {})'.format(self.x, self.y)
def DistanceFromPoint(self, pX):
dx = int(self.getX - pX.getX)
dy = int(self.getY - pX.getY)
return math.sqrt((dx * dx) + (dy * dy))
#classmethod
def FromString(cls, Point_str):
x, y = Point_str
return cls(x, y)
and this is my Pyhton file:
from Point import Point
def isTriangle(x1, y1, x2, y2, x3, y3):
return (y2 - y1) * (x3 - x2) != (y3 - y2) * (x2 - x1)
def isTriangle2(p1, p2, p3):
d1 = p1.DistanceFromPoint(p2)
d2 = p1.DistanceFromPoint(p3)
d3 = p2.DistanceFromPoint(p3)
if d1 + d2 > d3 and d1 + d3 > d2 and d2 + d3 > d1:
return True
else:
return False
def main():
p1 = Point(5, 10)
p2 = Point(7, 10)
p3 = Point(15, 10)
print(p1.PointToStr())
print(p2.PointToStr())
print(isTriangle(p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY()))
print(isTriangle2(p1, p2, p3))
if __name__ == "__main__":
main()
when I'm trying to run isTriangle2 I get the following error:
TypeError: unsupported operand type(s) for -: 'method' and 'method'
this is the traceback:
Traceback (most recent call last):
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\lec_7+8.py", line 28, in <module>
main()
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\lec_7+8.py", line 25, in main
print(isTriangle2(p1, p2, p3))
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\lec_7+8.py", line 9, in isTriangle2
d1 = p1.DistanceFromPoint(p2)
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\Point.py", line 23, in DistanceFromPoint
dx = int(self.getX - pX.getX)
At first I tought isTriangle2 didnt transfer the given point to int when I used the getX() and getY() function so I did try to cast them but that didnt help as well.
than I tried to change the class a bit, I think the error is coming from DistanceFromPoint function in the Point class but I dont know how to fix that
in
dx = int(self.getX - pX.getX)
dy = int(self.getY - pX.getY)
The getters are functions and need to be called like functions (i.e add () when the getters are called)
One solution would be to use the #property decorator in the methods getX and getY:
#property
def getX(self):
return int(self.x)
#property
def getY(self):
return int(self.y)
This way the functions getX and getY will become properties of the class, so you will need to remove the "()" when using them:
print(isTriangle(p1.getX, p1.getY, p2.getX, p2.getY, p3.getX, p3.getY))
I have a problem with a task. I need to write an python code which calculates a quadratic distance between two points.
The formula is:
D^2 = (x1 - x2)^2 + (y1 - y2)^2
and my code:
def quadratic_distance(p1: Point, p2: Point) -> float:
# YOUR CODE HERE
class p1:
def __init__(self, x1, y1):
self.x = x1
self.y = y1
class p2:
def __init__(self, x2, y2):
self.x = x2
self.y = y2
result1 = p1.x - p2.x
result2 = result1**2
result3 = p1.y - p2.y
result4 = result3**2
result5 = result2 + result4
return result5
but my problem is that i get an attribute error
AttributeError: type object 'p1' has no attribute 'x'
I am fairly new in the object oriented programming and have been stuck at this task. I hope someone can help me
assert quadratic_distance(Point(0, 0),Point(1, 1)) == 1.75
should be the solution
According to your formula, quadratic distance between Point(0,0) and Point(1,1) is 2. Not 1.75
This is my code. Try this
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
P1 = Point(0,0)
P2 = Point(1,1)
def quadratic_distance(p1: Point, p2: Point) -> float:
result1 = p1.x - p2.x
result2 = result1**2
result3 = p1.y - p2.y
result4 = result3**2
result5 = result2 + result4
return result5
print(quadratic_distance(P1, P2))
You are getting an error because you have not created an object of the class. In python, x is not an attribute of a class but x is the attribute of its object.
So you can do it as:
class p1:
def __init__(self, x1, y1):
self.x = x1
self.y = y1
class p2:
def __init__(self, x2, y2):
self.x = x2
self.y = y2
p1_obj = p1(5,5)
p2_obj = p2(10,10)
result1 = p1_obj.x - p2_obj.x
result2 = result1**2
result3 = p1_obj.y - p2_obj.y
result4 = result3**2
result5 = result2 + result4
return results
You can further improve it as p1 and p2 have the same properties (data member and member function) so we can just use one class named p (or any other name) and create two object p1 and p2 of the class
Although you have declared the class p1 and p2 but you haven't created any object. So, you are getting this error.
x and y are the instances of class p1 and p2 you can't access by their class name.
Either define x and y as class variables inside the class or define a object each of class p1 and p2 like given below.
p1ob=p1(4,5)
p2ob=p2(5,6)
I have a Python class which lets you initialize lines, with two x-y coordinate points. I also have a function to add two lines together as follows:
class Line:
def __init__(self, x1, y1, x2, y2):
...
def __add__(self, other):
new_x1 = self.x1 + other.x1
new_y1 = self.y1 + other.y1
new_x2 = self.x2 + other.x2
new_y2 = self.y2 + other.y2
return Line(new_x1, new_y1, new_x2, new_y2)
I have very similar functions for subtraction and multiplication, they're the same as the add function with a different operator symbol inside.
My question is, is there a better or more efficient way to write this?
Slightly more concise:
class Line:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2
def operation(self, other, op):
new_x1 = op(self.x1, other.x1)
new_y1 = op(self.y1, other.y1)
new_x2 = op(self.x2, other.x2)
new_y2 = op(self.y2, other.y2)
return Point(new_x1, new_y1, new_x2, new_y2)
def __add__(self, other):
return self.operation(other, float.__add__)
def __sub__(self, other):
return self.operation(other, float.__sub__)
You can leverage similarities. If you also define __neg__ you get slightly easier add/sub implementations as sub == -add
class Line:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2
def __add__(self, other):
new_x1 = self.x1 + other.x1
new_y1 = self.y1 + other.y1
new_x2 = self.x2 + other.x2
new_y2 = self.y2 + other.y2
return Line(new_x1, new_y1, new_x2, new_y2)
def __sub__(self, other):
return self + (-other) # leverage __neg__
def __neg__(self):
return Line(-self.x1,-self.y1,-self.x2,-self.y2)
def __str__(self):
return f"({self.x1}/{self.y1})->({self.x2}/{self.y2})"
l = Line(0,0,10,10)
l2 = Line(5,5,.20,20)
print(l)
print(l2)
print(l-l2)
Output:
(0/0)->(10/10)
(5/5)->(0.2/20)
(-5/-5)->(9.8/-10)
but most of the time this wont make much sense because operations might vary wildly depending on the domain your class lives in.
The operation thing of #Blotosmeteks answer is great. But to add to that you can also do.
class Line:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1, self.x2, self.y2 = float(x1), float(y1), float(x2), float(y2)
def operation(self, other, op): # Removing the declarations on multiple lines here.
return Point(op(self.x1, other.x1), op(self.y1, other.y1),
op(self.x2, other.x2), op(self.y2, other.y2))
def __add__(self, other):
return self.operation(other, float.__add__)
def __sub__(self, other):
return self.operation(other, float.__sub__)
I'm new to programming and I'm confused as to how you call a method/parameter that is defined within a class in Python 2. For example (with obstacle being a previous class made),
class Block(Obstacle):
def __init__(self, origin, end, detection=9.):
self.type = 'block'
self.origin = origin
self.end = end
x1 = self.origin[0]
y1 = self.origin[1]
x2 = self.end[0]
y2 = self.end[1]
def __str__(self):
return "block obstacle"
When I generate an environment, I define different x1, y1, x2 and y2 values (essentially signifying the coordinate points of the corners of the block). I have another later method where I needs the values of x1, y1, x2 and y2 in calculating something, but I'm confused as to how I actually call them into this new function? What parameters would I put in this new function?
import math
I would make x1 --> self.x1 so you can have it as an object variable.
Inside the class object you can define these functions for calculation as an example.
def calculate_centre(self):
self.centre_x = self.x2 - self.x1
self.centre_y = self.y2 - self.y1
self.centre = (centre_x, centre_y)
def distance_between_block_centres(self, other):
block_x, block_y = other.centre
distance = math.sqrt((self.centre_x - block_x)**2 + (self.centre_y - block_y)**2)
return distance
block = Block(stuff)
block_2 = Block(other_stuff)
if you want to call these function using the objects youve created:
block.calculate_centre()
block_2.calculate_centre()
distance_between = block.distance_between_block_centres(block_2)
And even external to your object call the variables:
print block.centre
#>>> (3, 5)
Lastly you can run the calculations of the centre without having to call it every time you create your object if your put it in def __init__():
self.calculate_centre()
I am currently expanding by python skills by programming a procedurally generated dungeon level in text format. I am confused as to why my "intersects" define is not working. Here is the class containing the def:
class Room:
global x1
global x2
global y1
global y2
global w
global h
global centre
def __init__(self,x,y,w,h):
x1 = x
x2 = x + w
y1 = y
y2 = y + h
self.x = x
self.y = y
self.w = w
self.h = h
centre = math.floor((x1 + x2) / 2),math.floor((y1 + y2) / 2)
#function that checks if the rooms intersect by comparing corner pins relative to the x,y tile map
def intersects(self,room):
if x1 <= room.x2 and x2 >= room.x1 and y1 <= room.y2 and room.y2 >= room.y1:
return True
return False
Here is where it's called:
def placeRooms(r):
rooms = []
#Where the room data is stored
for r in range(0,r):
w = minRoomSize + randint(minRoomSize,maxRoomSize)
h = minRoomSize + randint(minRoomSize,maxRoomSize)
x = randint(1,map_width - w - 1) + 1
y = randint(1,map_height - h - 1) + 1
newRoom = Room(x,y,w,h)
failed = False
#for every room generated, this function checks if new room intersects with the last one
for otherRoom in rooms:
if newRoom.intersects(otherRoom):
failed = True
break
if failed == False:
createRoom(newRoom)
rooms.append(newRoom)
Full traceback:
Traceback (most recent call last):
File "C:\Users\Max\Desktop\LiClipse Workspace\testing\RandomDungeon.py", line 78, in <module>
placeRooms(2)
File "C:\Users\Max\Desktop\LiClipse Workspace\testing\RandomDungeon.py", line 65, in placeRooms
if newRoom.intersects(otherRoom):
File "C:\Users\Max\Desktop\LiClipse Workspace\testing\RandomDungeon.py", line 41, in intersects
if x1 <= room.x2 and x2 >= room.x1 and y1 <= room.y2 and room.y2 >= room.y1:
NameError: name 'x1' is not defined
I hope someone can help me understand why this code won't work, thank you.
I have managed to fix the problem. I'm sorry if my question was not defined very well. I have only been learning Python for around 4 weeks and i am used to Java which has a very different syntax. Here is my solution:
def __init__(self,x,y,w,h):
self.x1 = x
self.x2 = x + w
self.y1 = y
self.y2 = y + h
self.x = x
self.y = y
self.w = w
self.h = h
As most previous comments have said, you use global variables that shouldn't be global at all.
The way I understand your code, you meant for x1, x2, y1 and y2 to be attributes of your Room instance, meaning that each room has its own values for x1, x2, y1 and y2. In Python you don't have to declare attributes at the beginning of the class (where you declare all the global variables), you simply need to initialize the attributes in the __init__ method.
This means that you can safely delete all the global lines, and change your __init__ to
def __init__(self,x,y,w,h):
self.x1 = x
self.x2 = x + w
self.y1 = y
self.y2 = y + h
self.w = w
self.h = h
centre = (self.x1 + self.x2) // 2,(self.y1 + self.y2) // 2
(note that you don't need math.floor since you're already dealing with integers, simply use the integer division operator //)
That way you define x1, y1, x2, y2, w, h and center as attributes of your class meaning that each instance has its own values for these variables. In Python, you need to add self. before all calls to attributes of the object itself, so you should also modify intersects to add self. before each access to an attribute of your current object (all the x1, x2, etc. that are not already prefixed by room. in your code).
Also, while we're at it I don't think your intersect function works as intended, but that's another problem :)