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 :)
Related
I wrote classes for Ray, Line, Point, and some other shapes, but I was stopped by the need for a function that takes a Line class object and a Ray class object as a parameter, and returns the point at which the line and the ray intersect.
Point class:
class Point:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def __getitem__(self, index):
if index == 0:
return self.x
elif index == 1:
return self.y
def __iter__(self):
yield self.x
yield self.y
def __str__(self):
return f"x = {self.x}; y = {self.y}"
Ray class:
class Ray:
def __init__(self, start: Point, end: Point):
self.start = start
self.end = end
def get_direction(self):
x_diff = self.end[0] - self.start[0]
y_diff = self.end[1] - self.start[1]
return (x_diff, y_diff)
Line class:
class Line:
def __init__(self, point1: Point, point2: Point):
self.point1 = point1
self.point2 = point2
def get_direction(self) -> tuple:
x_diff = abs(self.point2[0] - self.point1[0])
y_diff = abs(self.point2[1] - self.point1[1])
return (x_diff, y_diff)
def get_params(self) -> tuple:
x1, y1 = self.point1
x2, y2 = self.point2
a = y2 - y1
b = x1 - x2
c = x2 * y1 - x1 * y2
return a, b, c
def get_normal(self):
a, b, c = self.get_params()
return -b, a, c
And perhaps the following functions can help:
Is the point on the line?
def point_on_line(point: Point, line: Line):
x1, y1 = line.point1
x2, y2 = line.point2
x, y = point
return (y - y1) * (x2 - x1) == (y2 - y1) * (x - x1)
Is the point on the ray?
def point_on_ray(point: Point, ray: Ray) -> bool:
start = ray.start
end = ray.end
direction = ray.get_direction()
x_diff = point[0] - start[0]
y_diff = point[1] - start[1]
if x_diff * direction[1] == y_diff * direction[0]:
if x_diff >= 0 and y_diff >= 0:
return True
return False
I am bad in Math so i asked ChatGPT to help me, but he wrote some functions which will return wrong result
I tried giving ChatGPT several completely different prompts, and I got several completely different functions in response, but anyway, they all didn't work. Some of them returned the wrong points, some of them thought the ray and the line were parallel, although they have not worked correctly
You have to solve equation system
ray.start.x + t * ray.diff.x = line.point1.x + u * line.diff.x
ray.start.y + t * ray.diff.y = line.point1.y + u * line.diff.y
for unknowns t and u, then check that t >= 0
Then substitute t value into the left parts to get intersection point coordinates.
Standalone Python function
def ray_line_intersection(rx0, ry0, rdiffx, rdiffy, lx0, ly0, ldiffx, ldiffy):
denom = ldiffy * rdiffx - ldiffx * rdiffy
if denom == 0: #ray and line are parallel or coincident
return (1) if (lx0 - rx0) * rdiffy == (ly0 - ry0) * rdiffx else None
t = (ldiffx * (ry0 - ly0) + ldiffy * (lx0 - rx0)) / denom
return (rx0 + rdiffx * t, ry0 + rdiffy * t) if t >=0 else None
print(ray_line_intersection(0, 0, 1, 1, 3, 0, -1, 1))
print(ray_line_intersection(0, 0, 1, 1, 3, 0, 1, 1))
print(ray_line_intersection(0, 0, 1, 1, -1, -1, 4, 4))
print(ray_line_intersection(0, 0, 1, 1, -1, 0, 1, -1))
>>> (1.5, 1.5) normal intersection
>>> None parallel
>>> 1 ray lies in the line
>>> None intersection beyond ray range
i need to find out whether two circles which are c1 and c2 touch each other externally and at only one point by using Circle class.
I created method which is touches. The method should return a boolean value and it needs to be called like this c1.touches(c2)
this formula to check circles touch or intersect with each other formula
this is my code
import math
class Circle:
def __init__(self, x, y, r):
self.x = x
self.y = y
self.r = r
def touches(self):
dist_between_centers = math.sqrt((self.c1.x - self.c2.x)^(2 + (self.c1.y - self.c2.y)^2))
if dist_between_centers == (self.c1.r + self.c2.r):
print("True")
elif dist_between_centers > (self.c1.r + self.c2.r):
print("False")
else:
print("False")
c1 = Circle(2,3,12)
c2 = Circle(15, 28, 10)
c1.touches(c2)
However i am getting error like this, TypeError: touches() takes 1 positional argument but 2 were given
Seems like you mix up with usage self, c1 and c2 in def touches
You should pass c2 as parameter to def touches(circle). Inside method you should refer the first circle as self rather self.c1 and the second as circle rather than self.c2
Final code like this
import math
class Circle:
def __init__(self, x, y, r):
self.x = x
self.y = y
self.r = r
def touches(self, circle):
dist_between_centers = math.sqrt((self.x - circle.x)^2 + (self.y - circle.y)^2)
if dist_between_centers == (self.r + circle.r):
print("True")
elif dist_between_centers > (self.r + circle.r):
print("False")
else:
print("False")
c1 = Circle(2, 3, 12)
c2 = Circle(15, 28, 10)
c1.touches(c2)
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'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'm trying to learn Object Oriented Programming in Python. To do this I need to create a method that calculates the slope of a line, which joins the origin to a point. (I think) we're assuming that the origin is (0,0). For example:
Point(4, 10).slopeFromOrigin()
2.5
Point(12, -3).slopeFromOrigin()
-0.25
Point(-6, 0).slopeFromOrigin()
0
And we're using the equation slope = (Y2 - Y1) / (X2 - X1) to calculate the slope. Also, since dividing by 0 isn't allowed, we need to return None when the method fails. Here's what I tried:
class Point:
#Point class for representing and manipulating x,y coordinates
def __init__(self, initX, initY):
#Create a new point at the given coordinates
self.x = initX
self.y = initY
def getX(self):
return self.x
def getY(self):
return self.y
def distanceFromOrigin(self):
return ((self.x ** 2) + (self.y ** 2)) ** 0.5
#define a method called slopeFromOrigin here
def slopeFromOrigin(self):
#set origin values for x and y (0,0)
self.x = 0
self.y = 0
#slope = (Y2 - Y1) / (X2 - X1)
if (Point(x) - self.x) == 0:
return None
else:
return (Point(y) - self.y) / (Point(x) - self.x)
#some tests to check our code
from test import testEqual
testEqual( Point(4, 10).slopeFromOrigin(), 2.5 )
testEqual( Point(5, 10).slopeFromOrigin(), 2 )
testEqual( Point(0, 10).slopeFromOrigin(), None )
testEqual( Point(20, 10).slopeFromOrigin(), 0.5 )
testEqual( Point(20, 20).slopeFromOrigin(), 1 )
testEqual( Point(4, -10).slopeFromOrigin(), -2.5 )
testEqual( Point(-4, -10).slopeFromOrigin(), 2.5 )
testEqual( Point(-6, 0).slopeFromOrigin(), 0 )
As you can see, I'm trying to say that we need the first parameter of Point to be x2, and the second parameter of Point to be y2. I tried it this way and got
NameError: name 'y' is not defined on line 32.
I also tried to get the index values of Point like this:
return (Point[0] - self.y / (Point[1] - self.x)
But that also gave me an error message:
TypeError: 'Point' does not support indexing on line 32
I'm not sure how to get the value of the x and y parameters from Point so that the method works when it's tested. Please share your suggestions if you have any. Thank you.
First problem
self.x = 0
self.y = 0
You just set the current point to the origin. Don't do that. The distance from the origin would then be 0...
Second problem Point(x) and Point(y) are not how you get the values for self.x and self.y.
Then, slope is simply "rise over run". Plus you want to return None when self.x == 0.
So, simply
def slopeFromOrigin(self):
if self.x == 0:
return None
return self.y / self.x
Or even
def slopeFromOrigin(self):
return None if self.x == 0 else self.y / self.x
Or let Python return None on its own
def slopeFromOrigin(self):
if self.x != 0:
return self.y / self.x
I think your confusion lies in that you think you need to somehow define "the origin". If you needed to do that, you would instead have this
origin = Point(0,0)
Point(-6, 0).slopeFromPoint(origin)
if (Point(x) - self.x) == 0:
return None
else:
return (Point(y) - self.y) / (Point(x) - self.x)
As you can see, I'm trying to say that we need the first parameter of Point to be x2, and the second parameter of Point to be y2. I tried it this way and got
NameError: name 'y' is not defined on line 32.
You're trying to access the value of y, which is a global variable that you haven't assigned yet.
I also tried to get the index values of Point like this:
return (Point[0] - self.y / (Point[1] - self.x)
Two problems:
"Point" is a class, not an object (which is an instance of an object).
Even if you've put an object instead, Point is not an list-like object. In order to access an item using index like variableName[index], the class of the variableName must have an implementation for __getitem__(self, key). For example:
>>> class GoodListClass:
... def __init__(self, list):
... self.myList = list
... def __getitem__(self, key):
... return self.myList[key]
...
>>> class BadListClass:
... def __init__(self, list):
... self.myList = list
...
>>> someList = range(10)
>>> goodListObject = GoodListClass(someList)
>>> badListObject = BadListClass(someList)
>>> print(goodListObject[2])
2
>>> print(badListObject[2])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: BadListClass instance has no attribute '__getitem__'