one of my def variables is stuck at the same value - python-3.x

I am new to python and this website
*I am having difficulties understanding why I'm getting the same value from my Car.name function
class Car:
def __init__(self, name, price):
Car.name = name
Car.price = price
I have stored some cars data in the class
Lamborghini_Centenario = Car("Lamborghini Centenario", 2500000)
Rolls_Royce_Sweptail = Car("Roll's-Royce Sweptail", 12800000)
McLarenP1LM = Car("McLaren P1 LM", 3600000)
Koenigsigg = Car("Koenigsigg CCXR Trevita", 4800000)
Lykan_Hypersport = Car("Lykan Hypersport", 3400000)
Lamborghini_Veneno_Roadster = Car("Lamborghini Veneno Roadster", 4500000)
Aston_Martin_Valkyrie = Car("Aston Martin Valkyrie", 3200000)
Bugatti_Chiron = Car("Bugatti Chiron", 2700000)
Pagani_Huayra_BC = Car("Pagani Huayra BC", 2800000)
Ferrari_Sergio = Car("Ferrari Pininfarina\n Sergio", 3000000) <--.
|
#But when I try to get the name of a random car |
#Here is the code I used vvv (Carlist is not shown here) |
#b = random.choice(carlist) | ignore arrow not part of
#b.name | code(sorry couldn't come
#it only gets the name from the bottom of the car data area. --------+ up with a name)
#I have switched it up and have only been getting the bottom value
#it might be due to the turtle module .mainloop() function
here is the whole script
Thanks in advance
import random
import turtle
import os
import time
class Car:
def __init__(self, name, price):
Car.name = name
Car.price = price
higher_true = 0
lower_true = 0
lives1 = 1
score = 0
Lamborghini_Centenario = Car("Lamborghini Centenario", 2500000)
Rolls_Royce_Sweptail = Car("Roll's-Royce Sweptail", 12800000)
McLarenP1LM = Car("McLaren P1 LM", 3600000)
Koenigsigg = Car("Koenigsigg CCXR Trevita", 4800000)
Lykan_Hypersport = Car("Lykan Hypersport", 3400000)
Lamborghini_Veneno_Roadster = Car("Lamborghini Veneno Roadster", 4500000)
Aston_Martin_Valkyrie = Car("Aston Martin Valkyrie", 3200000)
Bugatti_Chiron = Car("Bugatti Chiron", 2700000)
Pagani_Huayra_BC = Car("Pagani Huayra BC", 2800000)
Ferrari_Sergio = Car("Ferrari Pininfarina\n Sergio", 3000000)
carlist = [Lamborghini_Centenario, Rolls_Royce_Sweptail, McLarenP1LM, Koenigsigg, Lykan_Hypersport, Lamborghini_Veneno_Roadster, Aston_Martin_Valkyrie, Bugatti_Chiron, Ferrari_Sergio, Pagani_Huayra_BC]
wn = turtle.Screen()
wn.screensize(1000, 500)
wn.title("Higher or Lower: Car Price Edition")
wn.setup(1050, 650, 0, 0)
Higher = turtle.Turtle()
Higher.penup()
style = ('Courier', 55, 'italic')
Higher.color('black')
Higher.goto(130, -300)
Higher.write('Higher', font=style, align='center')
Higher.hideturtle()
Or = turtle.Turtle()
Or.penup()
Or.color('black')
Or.goto(275, -300)
Or.write('or', font=style, align='center')
Or.hideturtle()
correct = turtle.Turtle()
correct.penup()
correct.color('green')
correct.hideturtle()
Lower = turtle.Turtle()
Lower.penup()
Lower.color('black')
Lower.goto(406, -300)
Lower.write('Lower', font=style, align='center')
Lower.hideturtle()
line = turtle.Turtle()
line.goto(0, 0)
line.shape('square')
line.shapesize(500, 0.5)
line.color('black')
Lives = turtle.Turtle()
Lives.penup()
Lives.color('black')
style = ('Courier', 60, 'italic')
Lives.goto(158, 260)
Lives.write('Lives:', font=style, align='center')
Lives.hideturtle()
Scores = turtle.Turtle()
Scores.penup()
Scores.color('black')
Scores.goto(-258, 260)
Scores.write('Score:', font=style, align='center')
Scores.hideturtle()
wn.addshape(os.path.expanduser("~/Downloads/Lamborghini_Centenario.gif"))
wn.addshape(os.path.expanduser("~/Downloads/RollsRoyceSweptail.gif"))
wn.addshape(os.path.expanduser("~/Downloads/McLaren-P1-LM.gif"))
wn.addshape(os.path.expanduser("~/Downloads/Koenigsegg-CCRX-Trevita.gif"))
wn.addshape(os.path.expanduser("~/Downloads/Lamborghini-Veneno-Roadster.gif"))
wn.addshape(os.path.expanduser("~/Downloads/Aston-martin-Valkyrie.gif"))
wn.addshape(os.path.expanduser("~/Downloads/Bugatti-Chiron.gif"))
wn.addshape(os.path.expanduser("~/Downloads/Pagani-Huayra-BC.gif"))
wn.addshape(os.path.expanduser("~/Downloads/Ferrari-Pininfarina-Sergio.gif"))
wn.addshape(os.path.expanduser("~/Downloads/Lykan-Hypersport.gif"))
BugattiChiron = turtle.Turtle()
BugattiChiron.penup()
BugattiChiron.shape(os.path.expanduser("~/Downloads/Bugatti-Chiron.gif"))
BugattiChiron.goto(-300, 0)
Carname = turtle.Turtle()
Carname.penup()
Carname.color('black')
Carname.goto(-300, -200)
style1 = ('Courier', 40, 'italic')
Carname.write("Bugatti Chiron", font=style1, align='center')
Carname.hideturtle()
def screenclick(x, y):
print(x, y)
if x in range(39, 227) and y in range(-290, -250):
higher_true + 1
wn.listen()
wn.onscreenclick(screenclick)
a = Bugatti_Chiron
b = random.choice(carlist)
bname = turtle.Turtle()
bname.penup()
bname.goto(275, -200)
bname.write(b.name, font=style1, align='center')
# problem ^^^^^^ is here(it's just giving the Car.name of Ferrari_Sergio)
while higher_true == 0:
wn.update
while higher_true == 1:
if b >= a:
score = score + 1
correct.write('Correct!', font=style, align='center')
time.sleep(1.5)
correct.clear()

You need to set attributes on the object and not on the class.
class Car:
def __init__(self, name, price):
self.name = name
self.price = price
Car.name will set a name attribute on the Car class. You would be able to access the name attribute from the Car class directly without using objects like Car.name.
Setting Car.name every time updates the name attribute of the Car class and it gets updated every time you create a Car object. Hence, it retains only the last value.

Related

Electric Vehicle Routing Path Simulation Giving Wrong Output

My electric vehicle charging algorithm aims at returning the shortest path length by a charging drone. The drone will meet the electric vehicle at a rendezvous point and charge the vehicle. The vehicle selection is done based on the charging urgency of the vehicles. The total path length is calculated when all vehicles are charged based on their urgency. The pseudocode is:
EDF(List_Req)
SunchrgEV = List_Req
Pathlen = 0
Nchgreq = 0
while(SunchrgEV = 0):
U obtains the updated location of all ei element of SunchrgEV via message exchange
S'gcs = set of GCS element of Sgcs
Gr = min {Eucleadian distance between Loc(ei) and Loc(Gj)} //The closest GCS
ex = min [{Eucleadian distance between Loc(ei) and Loc(Gr)}/ResidDist(ei)] // most urgent EV
if SoC(U)<RqB2D(ex) // then U(the drone) itself needs charge and it reports its termination to the server
// the server dispatches another U(drone) to charge the remaining EVs (ei)
Gr = min {Eucleadian distance between Loc(U) and Loc(Gj)} //The closest GCS to U where U goes to full charge
end if
t = tcurrent
// Finding rendezvous point where ex and U meets
RdvLoc = FindRdvLoc(ex, Loc(ex), Loc(U),t)
if RdvLoc is out of service area of U then
Report2server(ex,'Outofservicearea')
continue
end if
Pathlen += Dist2(Loc(U),RdvLoc)
U sends RdvLoc to ex and flies to RdvLoc
if U reaches ex in ChgRng(U) then
{Pathlen += Charge(ex, RdvLoc)
Nchgreq ++
}
else
Report2server(ex, 'Outofservicearea')
endif
SunchrgEV -= ex
do
Update (Loc(U))
Gr = min {Eucleadian distance between Loc(U) and Loc(Gj)} //U returns to Gr
Pathlen += Dist2(Loc(U), Loc(Gr))
return Pathlen and Nchgreq
//Compute the expected location where U meets e on Map(e)
def FindRdvLoc(e,Le,Lu,t):
Compute X = (x,y) on Rte(e,t) so that {Dist(e,X)/Speed(e,t)} = {Dist(U, X-ChgRng(U))/Speed(U)}
return X
def Charge(ei, RdvLoc):
U starts to charge ei and follows Rte(ei,t)
eLoc = FindLoc(Map(ei), Loc(ei), ChgTime(ei), Speed(ei,t))
return DistM(Map(ei), RdvLoc, eLoc)
The code that I have written so far gives the same output regardless of the input. The code is:
import math
import sys
from typing import List, Any
class Location:
x = 0
y = 0
def __init__(self, x, y):
self.x = x
self.y = y
class Result:
path_len: int = 0
n_charge_request: int = 0
def __init__(self, path_len, n_charge_request):
self.path_len = path_len
self.n_charge_request = n_charge_request
def to_string(self):
return "path len : " + str(self.path_len) + ", n_charge_request : " + str(self.n_charge_request)
def print(self):
print(self.to_string())
#SGCs
class ChargingStation:
def __init__(self, location: Location, fuel):
self.location = location
self.fuel = fuel
#EVs(ex)
class Vehicle:
location = Location(0, 0)
fuel = 1
isNeedEmergencyFuel = False
per_fuel_distance_travel = 2
def __init__(self, id, location, fuel):
self.id = id
self.location = location
self.fuel = fuel
# Resid (U)
def residual_distance(self):
return self.fuel * self.per_fuel_distance_travel # assuming each watt or kw fuel will yield to 2 killos or milies
# RqB2D
def requested_amount_of_charge(self, nearest_charge_station_location: Location) -> int:
distance = get_distance(self.location, nearest_charge_station_location)
cover = self.fuel * self.per_fuel_distance_travel
diff = math.fabs(distance - cover)
if diff > 0:
needed_fuel = diff / self.per_fuel_distance_travel + 2
return needed_fuel
return 0
# U(i)
class Drone:
location = Location(0, 0)
fuel = 0
isFlying = False
isSendForEvCharge = False
per_fuel_distance_travel = 20
serving_radius = 15
G = [
ChargingStation(Location(20, 10), 50),
ChargingStation(Location(50, 80), 40),
ChargingStation(Location(30, 30), 60)
]
def __init__(self, location, fuel):
self.location = location
self.fuel = fuel
# Resid (U)
def residual_distance(self):
return self.fuel * self.per_fuel_distance_travel # assuming each unit of fuel will yield to 2 kilos or miles
def is_out_of_service_zone(self, vehicle_location: Location): # ----->
distance = get_distance(self.location, vehicle_location)
return distance > self.serving_radius
#staticmethod
def get_distance(from_location, to_location):
x_dis = to_location.x - from_location.x
y_dis = to_location.y - from_location.y
x_dis_sqr = math.pow(x_dis, 2)
y_dis_sqr = math.pow(y_dis, 2)
final_dis_sum = x_dis_sqr + y_dis_sqr
final = math.sqrt(final_dis_sum)
return final
class EDFGenerator:
min_fuel = 50
charging_stations_for_drones = [ChargingStation(Location(2, 10), 80), ChargingStation(Location(2, 10), 50),
ChargingStation(Location(2, 10), 100)]
list_waiting_drones = [Drone(Location(5, 10), 50), Drone(Location(2, 10), 50), Drone(Location(2, 10), 50)]
list_sent_drones = []
list_charging_drones = []
def __init__(self):
pass
def rdv_loc(self, ei: Vehicle, drone_location: Location, t: int) -> Location | None:
needed_fuel = ei.requested_amount_of_charge(drone_location)
nearest_charge_station = self.get_nearest_charge_station(ei.location, self.charging_stations_for_drones)
needed_fuel_at_nearest_station = needed_fuel / ei.per_fuel_distance_travel
if nearest_charge_station.fuel < needed_fuel_at_nearest_station:
return None
else:
return nearest_charge_station.location
#staticmethod
def get_nearest_charge_station(from_location: Location, list_of_stations: List[ChargingStation]) -> ChargingStation:
nearest = list_of_stations[0]
min_distance = get_distance(from_location, nearest.location)
for station in list_of_stations:
dis = get_distance(from_location, station.location)
if min_distance > dis:
min_distance = dis
nearest = station
return nearest
def NChgReq(self) -> int:
charging_requesters = 0
for drone in self.list_waiting_drones:
if drone.isNeedEmergencyFuel:
charging_requesters += 1
return charging_requesters
def send_drone_to_charge(self, drone: Drone): # ----->
if drone.fuel < self.min_fuel:
nearest_station = self.get_nearest_charge_station(
drone.location,
self.charging_stations_for_drones)
self.list_sent_drones.append(drone)
self.list_waiting_drones.remove(drone)
drone.isSendForEvCharge = True
# send the drone to the charging station here
print(f"Drone {drone} sent to charging station at {nearest_station}")
def check_fuel_and_send_to_charge(self): # ----->
for drone in self.list_waiting_drones:
self.send_drone_to_charge(drone)
def get_drone(self, max_try=4) -> Drone:
if max_try <= 0:
print("max try failed for get_drone")
return None
# take one time from list_waiting_drones ------->
# add to list_sent_drones
# send or return the taken item
if len(self.list_waiting_drones) == 0:
return None
else:
# lastOne = self.list_waiting_drones.pop()
self.last_one = self.list_waiting_drones.pop()
if self.last_one.fuel < self.min_fuel:
print("low fuel failed to get_drone, retry")
self.list_waiting_drones.insert(0, self.last_one)
return max_try - 1
self.list_sent_drones.append(self.last_one)
return self.last_one
def get_closest_location_from_sending_server_to_e_vehicle(self, current_vechicle_location):
min_distance = sys.maxsize
for current_server in self.charging_stations_for_drones:
distance = get_distance(current_vechicle_location, current_server.location)
if min_distance > distance:
min_distance = distance
return min_distance
def get_most_urgent_electric_vehicle(self, closest_distance_between_server_ev: int,
all_uncharged_electric_vehicles: List[Vehicle]) -> Vehicle:
final_ev = None
min_distance = sys.maxsize
for ev in all_uncharged_electric_vehicles:
g_r = self.get_closest_location_from_sending_server_to_e_vehicle(ev.location)
residual_distance = ev.residual_distance()
eq = g_r / residual_distance
if min_distance > eq:
min_distance = eq
final_ev = ev
return final_ev
def reports_termination_to_server(self, drone: Drone):
self.list_charging_drones.append(drone)
self.charge_all_waiting_drones()
def charge_all_waiting_drones(self):
# assuming the environment is not async but synchronous
for drone in self.list_charging_drones:
drone.fuel = 100
self.list_waiting_drones.insert(0, drone)
self.list_charging_drones.clear()
#staticmethod
def report_to_server(ev: Vehicle, message):
print(ev.id + " - " + message)
def get_edf(self, list_req: List[Vehicle]) -> Result:
s_uncharged_electric_vehicles = list_req
path_len = 0
n_charge_req = 0
while len(s_uncharged_electric_vehicles) > 0:
print("uncharged_ev : " + str(len(s_uncharged_electric_vehicles)))
current_uncharged_ev = s_uncharged_electric_vehicles[0]
u = self.get_drone()
if u is None:
print("no drones from any station or with min charge")
return Result(path_len, n_charge_req)
# current_uncharged_ev.location aka e----->
e = current_uncharged_ev.location
# confusion SGCS what would be the SET
g_r: int = self.get_closest_location_from_sending_server_to_e_vehicle(
e) # closest vehicle from sending location
# confusion regarding dis (loc(e), g_r) , g_r already contains the distance
e_x = self.get_most_urgent_electric_vehicle(g_r, s_uncharged_electric_vehicles)
drone_residual_distance = u.residual_distance() # Resid (U)
ev_requested_amount_of_charge = e_x.requested_amount_of_charge(u.location) # RqB2D
if drone_residual_distance < ev_requested_amount_of_charge:
self.reports_termination_to_server(u)
u = self.get_drone()
g_r_2 = self.get_closest_location_from_sending_server_to_e_vehicle(
u.location) # closest vehicle from sending location
self.reports_termination_to_server(u) # sends back the drone for charging
# ?? t is something confusing, how to include t into the equation??
rdv_loc = self.rdv_loc(e_x, u.location, 0) # t should be random
if rdv_loc is None:
self.report_to_server(e_x, "rdv location generate failed")
continue
if u.is_out_of_service_zone(rdv_loc):
self.report_to_server(e_x, "Out of Service")
continue
path_len += get_distance(u.location, rdv_loc)
u.location = rdv_loc
e_x.location = rdv_loc
# list_1 = filter(lambda x: x[3] <= 0.3 and x[2] < 5, list_1)
s_uncharged_electric_vehicles.remove(e_x)
n_charge_req = n_charge_req + 1
return Result(path_len, n_charge_req)
if __name__ == '__main__':
edf_runner = EDFGenerator()
un_charged_vehicles = [
Vehicle(1, Location(1, 1), 2),
Vehicle(2, Location(5, 10), 16),
Vehicle(3, Location(6, 10), 13),
Vehicle(4, Location(8, 11), 22),
Vehicle(5, Location(5, 6), 35),
]
edf_result = edf_runner.get_edf(un_charged_vehicles)
print("first_path_len - edf : ")
edf_result.print()
Where am I wrong? What needs fix?

AttributeError: 'list' object has no attribute 'x' in Python

I'm working on a basic game with python, but the system gives an error
impostors.x = new_x_pos
AttributeError: 'list' object has no attribute 'x'
Below is my code, can anyone tell me what I'm doing wrong? I've checked very carefully but still can't find the error, Since I'm a newbie, I don't have much experience so I hope you guys can help me
import pgzrun
import random
FONT_COLOR = (255, 255, 255) #màu RGB
WIDTH = 1300
HEIGHT = 700
CENTER_X = WIDTH / 2
CENTER_Y = HEIGHT / 2
CENTER = (CENTER_X, CENTER_Y)
START_SPEED = 10
COLORS = ["orange", "blue"]
current_level = 1
final_level = 5
game_over = False
game_complete = False
impostors = []
animation = []
def draw():
global impostors,current_level,game_over,game_complete
screen.clear()
screen.blit("dark",(0,0))
if game_over:
display_message("Game Over", "Press Space to play again")
elif game_complete:
display_message("You win", "Press Space to play again")
else:
for im in impostors:
im.draw()
def update():
global impostors,current_level,game_over,game_complete
if len(impostors) == 0:
impostors = make_impostors(current_level)
if (game_over or game_complete) and keyboard.space:
impostors = []
current_level = 1
game_complete = False
game_over = False
def make_impostors(number_of_impostors):
colors_to_create = get_colors_to_create(number_of_impostors)
new_impostors = create_impostors(colors_to_create)
layout_impostors(new_impostors)
animate_impostors(new_impostors)
return new_impostors
def get_colors_to_create(number_of_impostors):
colors_to_create = ["red"]
for i in range(0,number_of_impostors):
random_color = random.choice(COLORS)
colors_to_create.append(random_color)
return colors_to_create
def create_impostors(colors_to_create):
new_impostors = []
for color in colors_to_create:
impostor = Actor(color + "-im")
new_impostors.append(impostors)
return new_impostors
def layout_impostors(impostors_to_layout):
number_of_gaps = len(impostors_to_layout) + 1
gap_size = WIDTH/number_of_gaps
random.shuffle(impostors_to_layout)
for index, impostor in enumerate(impostors_to_layout):
new_x_pos = (index + 1)*gap_size
impostor.x = new_x_pos
def animation_impostors(impostors_to_animate):
for impostors in impostors_to_animate:
duration = START_SPEED - current_level
impostors.anchor = ("center", "bottom")
animation = animation(impostors, duration = duration, on_finished = handle_game_over, y = HEIGHT)
animations.append(animation)
def handle_game_over():
global game_over
game_over = True
def on_mouse_down(pos):
global impostors, current_level
for impostors in impostors:
if impostors.collidepoint(pos):
if "red" in impostors.image:
red_impostor_click()
else:
handle_game_over()
def red_impostor_click():
global current_level, impostors, animation, game_complete
stop_animations(animations)
if current_level == final_level:
game_complete = True
else:
current_level = current_level + 1
impostors = []
animations = []
def stop_animations(animations_to_stop):
for animation in animations_to_stop:
if animation.running:
animation.stop()
def display_message(heading_text, sub_heading_text):
screen.draw.text(heading_text, fontsize = 60, center = CENTER, color = FONT_COLOR)
screen.draw.text(sub_heading_text,
fontsize = 30,
center = (CENTER_X, CENTER_Y + 30),
color = FONT_COLOR)
pgzrun.go()
The problem is the loop for impostors in impostors:. Rename the loop variable to impostor:
def on_mouse_down(pos):
global impostors, current_level
for impostor in impostors:
if impostor.collidepoint(pos):
if "red" in impostors.image:
red_impostor_click()
else:
handle_game_over()

How to check if two objects touch each other in python tkinter?

I'm trying to create a function that tells me if two canvas objects(in my code, rec and block) touch each other in Tkinter. I tried to do so with the information of their coordinates but it doesn't seem to work. Can you please help me?
The function will be used in snake which I'm creating in the code below, so don't ask my why the code is so long.
The function is in the line 119, same_poz
This is my code:
from tkinter import *
import time
import random
import threading
root = Tk()
root.title('Snake')
x, y = 484, 484
recX, recY = x // 2, y // 2
recW, recH = recX + 22, recY + 22
randoms = []
for i in range(484):
if i % 11 == 0:
randoms.append(i)
blockX, blockY = random.choice(randoms), random.choice(randoms)
blockW, blockH = blockX + 22, blockY + 22
c = Canvas(root, bg='black', width=x, height=y)
c.pack()
class Snake(threading.Thread):
def __init__(self, c, x, y, recX, recY, recW, recH, blockX, blockY, blockW, blockH):
super(Snake, self).__init__()
self.c = c
self.x = x
self.y = y
self.recX = recX
self.recY = recY
self.recW = recW
self.recH = recH
self.blockW = blockW
self.blockH = blockH
self.rec = c.create_rectangle(recX, recY, recW, recH, fill='red', outline='white')
self.blockX = blockX
self.blockY = blockY
self.block = c.create_rectangle(blockX, blockY, blockW, blockH, fill='green',
outline='white')
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = False
def movingright(self):
self.moving_right = True
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = True
c.move(self.rec, 11, 0)
self.after4 = root.after(150, self.movingright)
def movingleft(self):
self.moving_left = True
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = True
c.move(self.rec, -11, 0)
self.after3 = root.after(150, self.movingleft)
def movingup(self):
self.moving_up = True
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving = True
c.move(self.rec, 0, -11)
self.after = root.after(150, self.movingup)
def movingdown(self):
self.moving_down = True
self.moving_right = False
self.moving_left = False
self.moving_down = False
self.moving = True
c.move(self.rec, 0, 11)
self.after2 = root.after(150, self.movingdown)
def stop(self):
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = False
try:
root.after_cancel(self.after)
except AttributeError:
pass
try:
root.after_cancel(self.after2)
except AttributeError:
pass
try:
root.after_cancel(self.after3)
except AttributeError:
pass
try:
root.after_cancel(self.after4)
except AttributeError:
pass
def move(self, n):
if n.keysym == 'Up':
self.stop()
self.movingup()
if n.keysym == 'Down':
self.stop()
self.movingdown()
if n.keysym == 'Right':
self.stop()
self.movingright()
if n.keysym == 'Left':
self.stop()
self.movingleft()
def same_poz(self):
if self.blockY == self.recY:
self.helpY = random.randint(10, self.y - self.blockY)
self.c.move(self.block, 0, self.helpY)
if self.blockX == self.recY:
self.helpX = random.randint(10, self.x - self.blockX)
self.c.move(self.block, 0, self.helpX)
if self.blockW == self.recW:
self.helpW = random.randint(10, self.x - self.blockW)
self.c.move(self.block, 0, self.helpW)
if self.blockH == self.recH:
self.helpH = random.randint(10, self.y - self.blockH)
self.c.move(self.block, 0, helpH)
cube = Snake(c, x, y, recX, recY, recW, recH, blockX, blockY, blockW, blockH)
cube.start()
cube.c.bind_all('<Key>', cube.move, cube.stop)
cube.c.bind_all('<Key>', cube.moving_left, cube.moving_right)
cube.c.bind_all('<Key', cube.moving_up, cube.moving_down)
cube.c.bind(cube.same_poz)
root.mainloop()
There are way too many problems with your code, with what you provided. I do not know why you are programming using Tkinter when you are still lacking the basics of Python. (Don't mean to sound harsh)
I do not know why you decided to inherit from threading.Thread when
you do not have any use for anything Thread provides in that
class.
Way too many instance parameters which you have no use for at all, and too many instance parameters that you have to change every single time.
Not using elif and instead using if constantly.
If you are using a thread to handle Tkinter changes outside of mainloop, there is no need to use .after since it basically does that.
Tkinter has dedicated bindings for every single key, including combinations of keys. There is no need to catch every single key event.
Use if __name__ == '__main__': if you are working with a single script, for testing it.
Some reading material on Tkinter - http://effbot.org/tkinterbook/
Here is a minimal rework of the code, that is working.
import time
import random
import threading
from tkinter import *
MOVINGUP = 'u'
MOVINGDOWN = 'd'
MOVINGLEFT = 'l'
MOVINGRIGHT = 'r'
NOTMOVING = '0'
class Snake:
def __init__(self, root, recX, recY, recW, recH, blockX, blockY, blockW, blockH):
self.root = root
self.c = Canvas(root, bg='black', width=x, height=y)
self.c.pack()
self.rec = self.c.create_rectangle(recX, recY, recW, recH, fill='red', outline='white')
self.block = self.c.create_rectangle(blockX, blockY, blockW, blockH, fill='green', outline='white')
self.direction = NOTMOVING
self.root.bind('<Up>', lambda e: self.moveset(MOVINGUP))
self.root.bind('<Down>', lambda e: self.moveset(MOVINGDOWN))
self.root.bind('<Left>', lambda e: self.moveset(MOVINGLEFT))
self.root.bind('<Right>', lambda e: self.moveset(MOVINGRIGHT))
def moveset(self, direction):
self.direction = direction
def movement(self):
if self.direction == MOVINGUP:
self.c.move(self.rec, 0, -11)
elif self.direction == MOVINGDOWN:
self.c.move(self.rec, 0, 11)
elif self.direction == MOVINGLEFT:
self.c.move(self.rec, -11, 0)
elif self.direction == MOVINGRIGHT:
self.c.move(self.rec, 11, 0)
self.same_poz()
def run(self):
while True:
time.sleep(0.15)
self.movement()
def same_poz(self):
# Snake (x0, y0, x1, y1)
snakepos = self.c.bbox(self.rec)
# Food block (x0, y0, x1, y1)
food = self.c.bbox(self.block)
# If direction matters, if not then possible to only use self.hit in a single condition.
if self.direction == MOVINGRIGHT and self.hit(snakepos, food):
print('Caught the food moving right.')
elif self.direction == MOVINGLEFT and self.hit(snakepos, food):
print('Caught the food moving left.')
elif self.direction == MOVINGUP and self.hit(snakepos, food):
print('Caught the food moving up.')
elif self.direction == MOVINGDOWN and self.hit(snakepos, food):
print('Caught the food moving down.')
def hit(self, snakepos, food):
"""
Recieves coordinates of food block and snake block and returns if they collide.
:param snakepos: Tuple containing (x0, y0, x1, y1) of the snake.
:param food: Tuple containing (x0, y0, x1, y1) of the food block.
:return: Boolean whether they collide
"""
snakex = (snakepos[0], snakepos[2])
snakey = (snakepos[1], snakepos[3])
foodx = (food[0], food[2])
foody = (food[1], food[3])
# Returns True if any of the snake x cooridnates are between the food x coordinates, or both x coordinates match.
if any((foodx[0] < xcoord < foodx[1] for xcoord in snakex)) or foodx == snakex:
# Returns True if any of the snake y cooridnates are between the food y coordinates, or both y coordinates match.
return any((foody[0] < ycoord < foody[1] for ycoord in snakey)) or foody == snakey
return False
if __name__ == '__main__':
root = Tk()
root.title('Snake')
x, y = 484, 484
recX, recY = x // 2, y // 2
recW, recH = recX + 22, recY + 22
randoms = []
for i in range(484):
if i % 11 == 0:
randoms.append(i)
blockX, blockY = random.choice(randoms), random.choice(randoms)
blockW, blockH = blockX + 22, blockY + 22
snake = Snake(root, recX, recY, recW, recH, blockX, blockY, blockW, blockH)
threading.Thread(target=snake.run, daemon=True).start()
root.mainloop()

pygame sets position of all instances of class to the same value for some reason?

I'm making a snake game in pygame and i've run into a problem. Whenever the snake eats food, the player gains a point. From that point on a tail is created behind the snake whenever it moves. Only the tails the number of player points away from the snake head will be drawn while the rest are deleted. The problem arises when i'm creating the tails. Whenever i create an instance of the tail, i have to get the position of the snake head and subtract away a value equal to the snake size in the opposite direction. That's where the tail will be drawn. However the position of all the tails are set to the same value for some reason and i cant't figure out why that is. I'm using my own library so i cant post it in here but iv'e determined it's not the cause.
import pygame as pg
from random import randrange
import widget
# disp -> display properties
disp = widget.get_json("config", ["display"])
food = widget.Surface(image="../images/food.png", pos=[0, 0])
def set_food_pos(snake):
while True:
pos = [randrange(0, disp["size"][_], disp["cell"]) for _ in range(2)]
safe = 0
for tail in snake.tails:
if tail.pos != pos: safe += 1
if safe == len(snake.tails):
food.pos = pos
food.rect.topleft = food.pos
break
class Snake(widget.Sprite):
""" Snake: main playable sprite """
SIZE = [disp["cell"]] * 2
KEYS = [[276, 275], [273, 274]]
def __init__(self):
self.image = pg.image.load("../images/snake_head.png")
self.pos = widget.VEC(0, 0)
super().__init__(pg.sprite.GroupSingle)
self.axis, self.orient, self.do_move = 0, 1, False
self.past, self.delay = pg.time.get_ticks(), 150
self.speed, self.vel = disp["cell"], [-1, 1]
self.alive, self.points = True, 0
self.tails = [self]
def control(self, key):
axis = [0 if key in Snake.KEYS[0] else 1][0]
if axis != self.axis:
if self.do_move:
self.axis = axis
self.orient = Snake.KEYS[axis].index(key)
self.do_move = False
def time_base_movement(self):
now = pg.time.get_ticks()
if now - self.past >= self.delay:
self.do_move = True
self.pos[self.axis] += self.vel[self.orient] * self.speed
self.past = pg.time.get_ticks()
def eat_food(self):
if food.rect.contains(self.rect):
set_food_pos(self)
self.points += 1
def create_tail(self):
if self.points:
if self.do_move:
pos = [_ for _ in self.rect.topleft]
pos[self.axis] += self.vel[::-1][self.orient] * 20
tail = widget.Sprite(image="../images/snake_head.png", pos=pos)
self.tails.insert(0, tail)
def render_tails(self, surface):
if self.points > 0:
tails = self.tails[:-1]
for tail in tails[0:self.points]: tail.group.draw(surface)
[self.tails.remove(tail) for tail in tails[self.points:]]
def check_boundary_collision(self):
for _ in range(2):
if self.pos[_] > disp["size"][_] - Snake.SIZE[_]:self.alive = False
elif self.pos[_] < 0: self.alive = False
for tail in self.tails[:-1]:
if tail.rect.contains(self.rect): self.alive = False
def reset_properties(self):
if self.alive == False:
print([tail.pos for tail in self.tails[:-1]])
self.tails = [self]
self.do_move = False
self.pos = widget.VEC([0, 0])
self.rect.topleft = self.pos
self.axis, self.orient = 0, 1
self.points, self.alive = 0, True
set_food_pos(self)
def update(self):
if self.alive:
self.time_base_movement()
self.check_boundary_collision()
self.reset_properties()
self.rect.topleft = self.pos
I figured it out, it seems python doesn't create a new copy of an attribute each time it is assigned to a different attribue. Instead the new attribute points to the assigned attribute. The fix for this is the "deepcopy" method in the built in module "copy".
Exe: new_value = copy.deepcopy(old_value)

Displaying the shortest path along a random walk

I'm a CS teacher, and we wrote some Python code in class to have a turtle draw a random walk. Someone asked if we could draw a new turtle that will trace the route (from starting point to ending point) that will take the minimum path. Current code is below.
I suspect we'll have to start a list of coordinates and then create some kind of tree. I'm sure there's already a library to do this, just not sure.
import turtle
import random
import time
from math import sqrt
leo = turtle.Turtle()
leo.speed(0)
leo.color("green")
leo.dot(6) # mark the starting location
leo.color("black")
directions = ['N', 'S', 'E', 'W']
steps = 100
step_size = 10
start = time.time()
for i in range(steps):
heading = random.choice(directions)
if heading == 'N':
leo.setheading(90)
elif heading == 'S':
leo.setheading(270)
elif heading == 'E':
leo.setheading(0)
else:
leo.setheading(180)
leo.forward(step_size)
(x,y) = leo.position()
distance = sqrt( x**2 + y**2 )
end = time.time()
leo.color("red") # mark the end location
leo.dot(6)
leo.hideturtle()
# drawing the final distance: start to end
raph = turtle.Turtle()
raph.color("blue")
raph.goto(x,y)
raph.hideturtle()
print("Total time:", end - start)
print("Total steps:", steps)
print("Total distance:", distance / step_size)
The approach is to:
1- Generate a random walk and paint it on the canvas
2- use that random walk to generate a lattice (a graph of coordinates and their connections to their neighbors.
2- use the start and end points to search the lattice for the shortest path. Here, using Breadth First Search, but you could use other searches.
3- paint the shortest path on the canvas, over the lattice
Here is an example of a walk, with the shortest path superimposed upon it:
The code used to generate it:
(extended from the code you posted)
import random
import turtle
class Walker:
"""a random walker on a virtual lattice
defines the rules of taking a step in a direction
records the sequence of directions of the steps takem
"""
# four directions
DIRECTIONS = ('N', 'S', 'E', 'W')
ID = 1
def __init__(self):
self.name = f"{self.__class__.__name__} no.: {Walker.ID}"
Walker.ID += 1
self.sequence_of_steps = [] # a sequence of directions
def take_step(self):
direction = random.choice(Walker.DIRECTIONS)
self.sequence_of_steps.append(direction)
def __str__(self):
return f"{self.name}"
class RandomWalk:
"""manages Walkers take_step"""
def __init__(self, walker=Walker, numwalkers=1, numsteps=100):
self.numsteps = numsteps
self.numwalkers = numwalkers
self.walkers = [walker() for _ in range(numwalkers)]
print(f'walking {self.numwalkers} {walker} for {self.numsteps} steps')
self.do_walk()
def do_walk(self):
for step in range(self.numsteps):
for walker in self.walkers:
walker.take_step()
def __str__(self):
return '\n'.join(str(walker.sequence_of_steps)
for walker in self.walkers)
def paint_walker_path(walker):
"""paints the path of one walker on the canvas"""
headings = {'N': 90, 'S': 270, 'E': 0, 'W': 180}
unit_move = 10 # pixels
direction_path = walker.sequence_of_steps
t = turtle.Turtle()
t.speed('fastest')
t.color('green')
t.dot(size=10)
t = turtle.Turtle()
t.color('gray')
report = turtle.Turtle()
report.penup()
report.hideturtle()
report.goto(200, 200)
report.write("step: ", True, font=('courier', 18, 'normal'))
report.write('0', font=('courier', 18, 'normal'))
for idx, direction in enumerate(direction_path):
t.setheading(headings[direction])
t.forward(unit_move)
t.dot(size=4)
report.undo()
report.penup()
report.pendown()
report.write(f"{idx}", font=('courier', 18, 'normal'))
t.hideturtle()
t.color('red')
t.dot(6)
t.goto(0, 0)
def paint_path(direction_path):
headings = {'N': 90, 'S': 270, 'E': 0, 'W': 180}
unit_move = 10 # pixels
t = turtle.Turtle()
t.speed('fastest')
t.color('black')
t = turtle.Turtle()
t.color('black')
t.pensize(2)
for direction in direction_path:
t.setheading(headings[direction])
t.forward(unit_move)
t.dot(size=4)
t.hideturtle()
class Coordinate:
# offsets are (col, row) i/e (x, y)
OFFSETS = {'N': (0, 1), 'S': (0, -1), 'E': (1, 0), 'W': (-1, 0)}
COORD_TO_DIR = {(0, 1): 'N', (0, -1): 'S', (1, 0): 'E', (-1, 0): 'W'}
def __init__(self, col, row):
self.col = col
self.row = row
self.coord = (self.col, self.row)
def get_adjacent(self, direction):
"""returns a new Coordinate object adjacent to self
in the given direction
"""
d_col, d_row = Coordinate.OFFSETS[direction]
return Coordinate(self.col + d_col, self.row + d_row)
def get_direction(self, destination):
"""returns the direction to take in order to move
from self to destination"""
offcol = destination.col - self.col
offrow = destination.row - self.row
assert abs(offcol) <= 1 and abs(offrow) <= 1, "adjacent coordinates must be close by"
return Coordinate.COORD_TO_DIR[(offcol, offrow)]
def __hash__(self):
return hash(self.coord)
def __eq__(self, other):
return self.coord == other.coord
def __str__(self):
return f"Coordinate {self.coord}"
def __repr__(self):
return str(self)
ORIGIN = Coordinate(0, 0)
class Lattice:
def __init__(self):
self.adjacency = {}
def get_final_dest_and_merge_sequence_of_steps(self, sequence_of_steps,
origin=ORIGIN):
current_coordinate = origin
for direction in sequence_of_steps:
adjacent_coordinate = current_coordinate.get_adjacent(direction)
try:
self.adjacency[current_coordinate].add(adjacent_coordinate)
except KeyError:
self.adjacency[current_coordinate] = {adjacent_coordinate}
try:
self.adjacency[adjacent_coordinate].add(current_coordinate)
except KeyError:
self.adjacency[adjacent_coordinate] = {current_coordinate}
current_coordinate = adjacent_coordinate
return current_coordinate
#staticmethod
def extract_sequence_of_steps(seq_of_coordinates):
steps = []
current_coord = seq_of_coordinates[0]
for next_destination in seq_of_coordinates[1:]:
steps.append(current_coord.get_direction(next_destination))
current_coord = next_destination
return steps
def __str__(self):
adjacency = []
for k, v in self.adjacency.items():
adjacency.append(f'{k},: {v}\n')
return ''.join(adjacency)
class BFS:
def __init__(self, lattice, start_coord, end_coord):
self.lattice = lattice
self.start_coord = start_coord
self.end_coord = end_coord
self.shortest_path = None # a sequence of Coordinate
self.bfs()
def bfs(self):
queue = []
visited = set()
queue.append([self.start_coord])
while queue:
path = queue.pop(0)
print("queue: ", queue, "path: ", path)
node = path[-1]
if node == self.end_coord:
self.shortest_path = path
break
if node not in visited:
for adjacent in self.lattice.adjacency.get(node, []):
new_path = list(path)
new_path.append(adjacent)
queue.append(new_path)
visited.add(node)
if __name__ == '__main__':
walk = RandomWalk(walker=Walker, numsteps=1000)
print(walk)
tom = walk.walkers[0]
paint_walker_path(tom)
print("Done with turtle tom")
lattice = Lattice()
end_node = lattice.get_final_dest_and_merge_sequence_of_steps(tom.sequence_of_steps)
print(end_node)
print(lattice)
search = BFS(lattice, ORIGIN, end_node)
print('search: ', search.shortest_path)
shortest_tom = Lattice.extract_sequence_of_steps(search.shortest_path)
paint_path(shortest_tom)
turtle.done()

Resources