How do I represent this object unambiguously? - python

I have written a class MyPoint:
import math
class MyPoint:
def __init__(self,x=0,y=0):
self.x,self.y = x,y
def __str__(self,x=0,y=0):
return "{}".format((self.x,self.y))
def move(self, dx, dy):
self.x += dx
self.y += dy
def move_to(self, new_x, new_y):
self.x = new_x
self.y = new_y
def get_distance(self, other_point):
distance = math.sqrt(((other_point.x - self.x)**2)+((other_point.y - self.y)**2))
return distance
def is_near_by(self, other_point):
distance = MyPoint.get_distance(self, other_point)
if distance < 5.0:
return True
else:
return False
Now I need to write the MyLine class.
Define a class named MyLine by using the MyPoint class. A line is composed of two points. The MyLine class contains the following:
A data field named start_point of type MyPoint that defines the start point.
A data field named end_point of type MyPoint that defines the end point.
A constructor/initializer which takes 4 integers as parameters (start_x, start_y, end_x, end_y) and creates a line with two MyPoint objects or creates a line with the default values. The default value for each coordinate is 0.
This is the code I have written to use the __repr__(self) method to represent it as follows:
c1 = MyLine(10, 20, 20, 30)
print(repr(c1))
produces
MyLine(10, 20, 20, 30)
My code:
class MyLine:
def __init__(self,start_x=0, start_y=0, end_x=0, end_y=0):
self.start_x, self.start_y, self.end_x, self.end_y = start_x, start_y, end_x, end_y
start_point = MyPoint(start_x, start_y)
self.start_point = start_point
end_point = MyPoint(end_x, end_y)
self.end_point = end_point
def __str__(self):
return "{} to {}".format(self.start_point, self.end_point)
def __repr__(self):
return "MyLine({}, {}, {}, {})".format(self.start_x, self.start_y, self.end_x, self.end_y)
My issue is in the __repr(self)__.
Test1:
line1 = MyLine(10, 20, 20, 30)
print(repr(line1))
line2 = MyLine()
print(repr(line2))
print(type(line1.start_point))
Expected Output1:
MyLine(10, 20, 20, 30)
MyLine(0, 0, 0, 0)
<class '__main__.MyPoint'>
Received Output1:
MyLine(10, 20, 20, 30)
MyLine(0, 0, 0, 0)
<class '__main__.MyPoint'>
Test2:
line1 = MyLine()
line1.start_point = MyPoint(100, 200)
line1.end_point = MyPoint(-100, 40)
print(repr(line1))
Expected Output2:
MyLine(100, 200, -100, 40)
Received Output2:
MyLine(0, 0, 0, 0)
Where am I going wrong? I know there is an issue with what I'm doing in the .format() part but not sure what's the issue.

There are 2 ways.
First is to change
def __repr__(self):
return "MyLine({}, {}, {}, {})".format(self.start_point.x, self.start_point.y, self.end_point.x, self.end_point.y)
2nd, is to use attribute getters and setters.
class MyLine:
def __init__(self,start_x=0, start_y=0, end_x=0, end_y=0):
self.start_x, self.start_y, self.end_x, self.end_y = start_x, start_y, end_x, end_y
start_point = MyPoint(start_x, start_y)
self._start_point = start_point
end_point = MyPoint(end_x, end_y)
self._end_point = end_point
def __str__(self):
return "{} to {}".format(self._start_point, self._end_point)
#property
def start_point(self):
return self._start_point
#start_point.setter
def start_point(self, point):
self._start_point = point
self.start_x = point.x
self.start_y = point.y
#property
def end_point(self):
return self._end_point
#end_point.setter
def end_point(self, point):
self._end_point = point
self.end_x = point.x
self.end_y = point.y
def __repr__(self):
return "MyLine({}, {}, {}, {})".format(self.start_x, self.start_y, self.end_x, self.end_y)

Related

Snake with pygame method - pixel overlap problem

I started playing a little with pygame and so far I'm not doing badly. I encountered a problem and managed to solve it. The solution is possible. It is not 100% correct. I want to implement an eat method when the head of the subject meets the food.
It is probably a relatively simple method when the rest of the value of X and Y are equal to the head of the snake being eaten.
For some reason I was not able to fully understand the overlap of pixels and I am not really correct in the method.
The problem at the moment is that there is no overlap between the pixels and "eating is not done".
BACKGROUND = pygame.image.load("background.jpg")
WIDTH, HEIGHT = BACKGROUND.get_width(), BACKGROUND.get_height()
pygame.font.init()
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
def checkForEat(self):
head = self.body[-1]
x = self.food.getPos()[0]
y= self.food.getPos()[1]
# if abs(head[0] - x ) < 9 and abs(head[1] - y ) < 9: -- This is my temporary solution
if head[0] == x and head[1] == y:
self.food = Food()
self.eat()
I try not to add too much unnecessary code.
class Food:
def __init__(self):
self.color = (5, 5, 255)
self.pos = (random.randint(10,WIDTH-50),random.randint(10,HEIGHT-50))
def draw(self,win):
pygame.draw.circle(win,self.color, self.pos, 5)
def getPos(self):
return self.pos
class Snake:
START_POS = (85, 85)
def __init__(self):
self.food = Food()
self.block_size = 11
self.x , self.y = self.START_POS
self.body = self.create_body()
def create_body(self):
body = []
for i in range(self.length):
body.append((85,85+i*self.block_size))
return body
def draw(self,win):
WIN.blit(BACKGROUND, (0, 0))
self.food.draw(win)
for i in range(self.length):
pygame.draw.circle(win, (255, 0, 0), self.body[i], 5)
I'm not adding the rest of the program.
Just saying that apart from the problem I wrote above everything works fine.
Use pygame.Rect/pygame.Rect.colliderect to check if the bounding rectangle of the food overlaps with the head of the snake:
class Food:
def __init__(self):
self.color = (5, 5, 255)
self.pos = (random.randint(10,WIDTH-50),random.randint(10,HEIGHT-50))
def draw(self,win):
pygame.draw.circle(win,self.color, self.pos, 5)
def getPos(self):
return self.pos
def getRect(self):
return pygame.Rect(self.pos[0]-5, self.pos[1]-5, 10, 10)
class Snake:
START_POS = (85, 85)
def __init__(self):
self.food = Food()
self.block_size = 11
self.x , self.y = self.START_POS
self.body = self.create_body()
# [...]
def checkForEat(self):
head = self.body[-1]
head_rect = pygame.Rect(head[0]-5, head[1]-5, self.block_size, self.block_size)
food_rect = self.food.getRect()
if food_rect.colliderect(head_rect):
self.food = Food()
self.eat()
Also see How do I detect collision in pygame?.
Alternatively you can compute the Euclidean distance between the circle center of the circles and compare the distance to the sum of the radii:
class Snake:
# [...]
def checkForEat(self):
dx = self.food.getPos()[0] - self.body[-1][0]
dy = self.food.getPos()[1] - self.body[-1][1]
dist_center = math.hypot(dx, dy)
if dist_center <= 20:
self.food = Food()
self.eat()

How to put a button image borderless/tansparent

I'm trying to put my button borderless so we can we see the progressbar on the background
I tried all the forum but coundt put the border of the button round or make something like the second picture
this is the part of the code for the button :
bg3 = Image.open("blanc.png")
resized_bg03 = bg3.resize((20, 20),Image.ANTIALIAS)
new_bg03 = ImageTk.PhotoImage(resized_bg03)
s = Button(Fenetre,image=new_bg03,borderwidth=0,highlightthickness=0)
s.place(x=600, y=10,height = 20 , width = 20)
I would like to have something more like this with a circle and no border :
can someone help me :)
Try this:
import tkinter as tk
# Kindly plagiarised from: https://stackoverflow.com/a/17985217/11106801
def _create_circle(self, x, y, r, **kwargs):
return self.create_oval(x-r, y-r, x+r, y+r, **kwargs)
tk.Canvas.create_circle = _create_circle
# Please suggest a better name for the class
class ProgressBar(tk.Canvas):
def __init__(self, height=20, radius=6, width=400, circle_colour="black",
colour="red", bar_width=6, bd=0, highlightthickness=0,
anti_bar_colour="white", **kwargs):
super().__init__(height=height, width=width, bd=bd,
highlightthickness=highlightthickness, **kwargs)
self.radius = radius
self.height = height
self.width = width
self.rectangle = None
self.circle_colour = circle_colour
self.colour = colour
self.bar_width = bar_width
self.circle = None
self.button_1_down = False
self.create_anti_bar(anti_bar_colour)
self.progress = 0
super().bind("<Enter>", self.show_circle)
super().bind("<Leave>", self.hide_circle)
super().bind("<Button-1>", self.mouse_click)
super().bind("<ButtonRelease-1>", self.mouse_release)
super().bind("<B1-Motion>", self.mouse_motion)
def create_anti_bar(self, colour):
start_y = (self.height - self.bar_width)/2
end_y = self.height - start_y
start_x = self.radius
end_x = self.width - self.radius
# Change it to >= if you don't what the bar to appear when the
# progress is at 0
if start_x > end_x:
return None
super().create_rectangle(start_x, start_y, end_x, end_y,fill=colour,
outline=colour)
def mouse_click(self, event):
self.button_1_down = True
self.progress = (event.x - self.radius)/(self.width - 2*self.radius)
def mouse_release(self, event=None):
self.button_1_down = False
def mouse_motion(self, event):
if self.button_1_down:
self.mouse_click(event)
def hide_circle(self, event=None):
if self.circle is not None:
super().delete(self.circle)
self.circle = None
def show_circle(self, event=None):
# Try removing the circle if we can
self.hide_circle()
x = (self.width - 2*self.radius)*self._progress + self.radius
self.circle = super().create_circle(x, self.height//2, self.radius,
fill=self.circle_colour,
outline=self.circle_colour)
def update_bar(self):
# Try removing the progress bar
if self.rectangle is not None:
super().delete(self.rectangle)
start_y = (self.height - self.bar_width)/2
end_y = self.height - start_y
start_x = self.radius
end_x = (self.width - 2*self.radius)*self._progress + self.radius
# Change it to >= if you don't what the bar to appear when the
# progress is at 0
if start_x > end_x:
return None
self.rectangle = super().create_rectangle(start_x, start_y, end_x,
end_y, fill=self.colour,
outline=self.colour)
#property
def progress(self):
return self._progress
#progress.setter
def progress(self, new_value):
# Check if the new_value is in the correct range
if new_value < 0:
new_value = 0
elif new_value > 1:
new_value = 1
# Update self._progress
self._progress = new_value
# Update the progress bar
self.update_bar()
# If the circle was shown update it
if self.circle is not None:
self.show_circle()
if __name__ == "__main__":
root = tk.Tk()
pbar = ProgressBar()
pbar.pack()
pbar.progress = 0
# keep incrementing the progress until the end then stop
def increment_progress():
pbar.progress += 0.001
if pbar.progress >= 1:
return None
pbar.after(10, increment_progress)
increment_progress()
root.mainloop()
Tell me if you don't get what any of the methods do. It is too much code to properly annotate

tkinter: object with different movement patterns

I'm working on a simulation in which some cubes of the same class are moving randomly. My aim is to give them another moving pattern, when they fulfill some characteristics (for example their object number).
My Problem:
If they fulfill the characteristics, how can I "switch off" the first moving pattern and activate the next?
Here a strongly simplified example of the simulation, and how it doesn't work:
from tkinter import *
from random import *
class Cubes:
def __init__(self, master, canvas, number, x1, y1, color):
self.master = master
self.canvas = canvas
self.number = number
self.x1 = x1
self.y1 = y1
self.x2 = x1 + 15
self.y2 = y1 + 15
self.color = color
self.rectangle = canvas.create_rectangle(x1, y1, self.x2, self.y2, fill=color)
def movement(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
if self.number == 2:
def movementII(self):
canvas.move(self.rectangle, 0, 0)
self.canvas.after(100, self.movementII)
self.canvas.after(100, self.movement)
if __name__ == "__main__":
master = Tk()
canvas = Canvas(master, width=900, height=600)
canvas.pack()
master.title("Simulation")
cube = Cubes(master, canvas, 2, randint(50, 800), randint(25, 500), "black")
cube.movement()
mainloop()
how can I "switch off" the first moving pattern and activate the next?
When you call after, it returns a unique identifier. You can save that identifier and then later pass it to after_cancel to cancel the job if it hasn't already run.
I'm not entirely clear what you want, but if you want to turn off the old movement when you switch to the new, it would look something like this:
class Cubes:
def __init__(self, master, canvas, number, x1, y1, color):
...
self.after_id = None
...
def cancel(self):
if self.after_id is not None:
self.after_cancel(self.after_id)
self.after_id = None
def movement(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
if self.number == 2:
def movementII(self):
canvas.move(self.rectangle, 0, 0)
self.cancel()
self.after_id = self.canvas.after(100, self.movementII)
self.after_id = self.canvas.after(100, self.movement)
A better way might be to have a single method that you call with after, and it simply calls the appropriate method.
For example, something like this:
def move(self):
if self.number == 1:
self.movement_1()
elif self.number == 2:
self.movement_2()
self.canvas.after(100, self.move)
def movement_1(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
def movement_2(self):
canvas.move(self.rectangle, 0, 0)
Then, to switch the movement method, just change self.number and it will automatically be called at the appropriate time.

How to fix typerror dealing with '<='

what the codes is supposed to is take the users input and then movie the rectangle around and when I run the code i get a Typeerror:<=' not supported between instances of 'str' and 'int'
these were some of the comments made on my code
For both Point and Rectangle class constructors, you are providing default values for the parameters. You should not since the assignment states, you should make them required arguments. (-4)
rectangleCount static attribute of the Rectangle class not kept up to date (should be incremented in the constructor to keep track of count of Rectangle objects created so far) (-2)
Rectangle's constructor doesn't check if width and height is negative, and if so print error message. (-2)
Calculations in the bottomRight property is incorrect. (-2) It should be
#property
def bottomRight(self):
return Point(self.topLeft.x + self.width, self.topLeft.y + self.height)
Calculations in the perimeter proper
# Prog 120
# Rectangle & Point Classes
class Point:
def __init__(self, x, y): # makes the value required
self.__x = x
self.__y = y
#property # read only property for x
def x(self):
return self.__x
#property # read only property for y
def y(self):
return self.__y
def translate(self, dx, dy): # moves x coordinate by 'dx' amount of time and move dy
self.__x += dx
self.__y += dy
class Rectangle:
DEFAULT_WIDTH = 1 # static attributes
DEFAULT_HEIGHT = 1
rectangleCount = 0
def __init__(self, topLeft, width, height):
self.__topLeft = topLeft
# check width argument
if (width <= 0):
print("Invalid width")
self.__width = Rectangle.DEFAULT_WIDTH
else:
self.__width = width
# check height argument
if (height <= 0):
print("Invalid Height")
self.__height = Rectangle.DEFAULT_HEIGHT
else:
self.__height = height
Rectangle.rectangleCount +=1 #updates the count of rectangels created
#property
def topLeft(self):
return self.__topLeft
#topLeft.setter
def topLeft(self, newTopLeft):
self.__topLeft = newTopLeft
#property
def width(self):
return self.__width
#width.setter
def width(self, newWidth):
if (newWidth <= 0):
print("Width cannot be less than '0'. ")
else:
self.__width = newWidth
#property
def height(self):
return self.__height
#height.setter
def height(self, newHeight):
if (newHeight <= 0):
print("Height cannot be less than '0'. ")
else:
self.__height = newHeight
#property
def bottomRight(self):
return Point(self.topLeft.x + self.topLeft.y + self.height)
#property
def area(self):
return self.__width * self.__height
#property
def perimeter(self):
return self.__width *2 + self.__height *2
def translate(self, dx, dy): # moves x coordinate by 'dx' amount of time and move y
self.__topLeft.translare(dx,dy)
def main():
bill = Point(x="", y="")
will = Rectangle(topLeft="", width="", height="")
if will.width and will.height < 0:
print("Width and Height cannot be less than 0.")
will.width = will.DEFAULT_WIDTH
will.height = will.DEFAULT_HEIGHT
will.rectangleCount += 1
if __name__ == "__main__":
main()
bill = Point(x="", y="")
will = Rectangle(topLeft="", width="", height="")
Here you are setting the attributes in Rectangle to the empty string.
And here:
def __init__(self, topLeft, width, height):
self.__topLeft = topLeft
# check width argument
if (width <= 0):
print("Invalid width")
self.__width = Rectangle.DEFAULT_WIDTH
You are comparing that string to 0 - an int. Obviously you can't compare "" with 0. That doesn't make any sense. That's what python is telling you with that error message.
Maybe try passing integers to the constructors. Like this:
bill = Point(x=5, y=9)
will = Rectangle(topLeft=2, width=4, height=1)

Learning class in python but having issue that probably is simple

I have simple code that creates a rectangle
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
class Rectangle:
def __init__(self, posn, w, h):
self.corner = posn
self.width = w
self.height = h
def __str__(self):
return "({0},{1},{2})".format(self.corner, self.width, self.height)
box = Rectangle(Point(0, 0), 100, 200)
print("box: ", box)
The output of this code is
('box: ', <__main__.Rectangle instance at 0x0000000002368108>)
I expect the output to be
box: ((0, 0), 100, 200)
Can someone please help?
You don't define a __repr__() on your Rectangle class. Printing a tuple (as you are doing) uses the repr() of the class, not the str(). You also need a __str__() on your Point class.
You need to define __repr__ in both the Classes, like this
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __repr__(self):
return "({}, {})".format(self.x, self.y)
class Rectangle(object):
def __init__(self, posn, w, h):
self.corner = posn
self.width = w
self.height = h
def __repr__(self):
return "({0},{1},{2})".format(self.corner, self.width, self.height)
print "box: ", box
# box: ((0, 0),100,200)
It seems like you're using Python 2.x: In Python 2.x, print is statement, not a function.
By putting (...), you're printing str(("box:", box)). (A tuple containing a string and Rectangle object)
Remove parentheses, and define Point.__str__ to get what you expected.
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return str((self.x, self.y))
# OR return '({0.x}, {0.y})'.format(self)
class Rectangle:
def __init__(self, posn, w, h):
self.corner = posn
self.width = w
self.height = h
def __str__(self):
return "({0},{1},{2})".format(self.corner, self.width, self.height)
box = Rectangle(Point(0, 0), 100, 200)
print("box: ", box) # This prints a tuple: `str(("box: ", box))`
print "box: ", box # This prints `box: ` and `str(box)`.
output:
('box: ', <__main__.Rectangle instance at 0x00000000027BC888>)
box: ((0, 0),100,200)

Categories