algorithms
This commit is contained in:
parent
02e42ad5d0
commit
483643a4c0
100
algorithm-visualisations/Langton.py
Normal file
100
algorithm-visualisations/Langton.py
Normal file
@ -0,0 +1,100 @@
|
||||
import pygame
|
||||
|
||||
# Constants
|
||||
WIDTH, HEIGHT = 800, 600
|
||||
CELL_SIZE = 10
|
||||
GRID_COLS = WIDTH // CELL_SIZE
|
||||
GRID_ROWS = HEIGHT // CELL_SIZE
|
||||
|
||||
# Colors
|
||||
WHITE = (255, 255, 255)
|
||||
BLACK = (0, 0, 0)
|
||||
RED = (255, 0, 0)
|
||||
|
||||
# Directions: 0=Up, 1=Right, 2=Down, 3=Left
|
||||
direction_vectors = {
|
||||
0: (0, -1),
|
||||
1: (1, 0),
|
||||
2: (0, 1),
|
||||
3: (-1, 0)
|
||||
}
|
||||
direction_names = {
|
||||
0: "Up",
|
||||
1: "Right",
|
||||
2: "Down",
|
||||
3: "Left"
|
||||
}
|
||||
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("Langton's Ant Visualization with Debug Info")
|
||||
clock = pygame.time.Clock()
|
||||
font = pygame.font.SysFont("Arial", 18)
|
||||
|
||||
# Initialize grid: False means white cell, True means black cell.
|
||||
grid = [[False for _ in range(GRID_COLS)] for _ in range(GRID_ROWS)]
|
||||
|
||||
# Initialize ant at center of grid.
|
||||
ant_col = GRID_COLS // 2
|
||||
ant_row = GRID_ROWS // 2
|
||||
ant_direction = 0 # Starting direction: Up
|
||||
steps = 0
|
||||
|
||||
running = True
|
||||
while running:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
||||
# Run several simulation steps per frame.
|
||||
for _ in range(10):
|
||||
# Get the current cell's color.
|
||||
current_color = grid[ant_row][ant_col]
|
||||
|
||||
# Langton's Ant rules:
|
||||
# If on a white cell, flip it to black, turn right.
|
||||
# If on a black cell, flip it to white, turn left.
|
||||
if not current_color: # White cell
|
||||
grid[ant_row][ant_col] = True
|
||||
ant_direction = (ant_direction + 1) % 4
|
||||
else: # Black cell
|
||||
grid[ant_row][ant_col] = False
|
||||
ant_direction = (ant_direction - 1) % 4
|
||||
|
||||
# Move ant forward one cell in the current direction, with wrap-around.
|
||||
dx, dy = direction_vectors[ant_direction]
|
||||
ant_col = (ant_col + dx) % GRID_COLS
|
||||
ant_row = (ant_row + dy) % GRID_ROWS
|
||||
steps += 1
|
||||
|
||||
# Clear screen (fill with white).
|
||||
screen.fill(WHITE)
|
||||
|
||||
# Draw grid: fill black cells.
|
||||
for row in range(GRID_ROWS):
|
||||
for col in range(GRID_COLS):
|
||||
if grid[row][col]:
|
||||
rect = (col * CELL_SIZE, row * CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||
pygame.draw.rect(screen, BLACK, rect)
|
||||
|
||||
# Draw the ant as a red cell.
|
||||
ant_rect = (ant_col * CELL_SIZE, ant_row * CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||
pygame.draw.rect(screen, RED, ant_rect)
|
||||
|
||||
# Debug text (no background, just text):
|
||||
debug_text1 = font.render(f"Steps: {steps}", True, BLACK)
|
||||
debug_text2 = font.render(f"Ant Position: ({ant_col}, {ant_row})", True, BLACK)
|
||||
debug_text3 = font.render(f"Ant Direction: {direction_names[ant_direction]}", True, BLACK)
|
||||
current_cell_color = "Black" if grid[ant_row][ant_col] else "White"
|
||||
debug_text4 = font.render(f"Current Cell: {current_cell_color}", True, BLACK)
|
||||
|
||||
# Blit debug text in the top-left corner.
|
||||
screen.blit(debug_text1, (10, 10))
|
||||
screen.blit(debug_text2, (10, 30))
|
||||
screen.blit(debug_text3, (10, 50))
|
||||
screen.blit(debug_text4, (10, 70))
|
||||
|
||||
pygame.display.flip()
|
||||
clock.tick(60)
|
||||
|
||||
pygame.quit()
|
51
algorithm-visualisations/Sierpinski.py
Normal file
51
algorithm-visualisations/Sierpinski.py
Normal file
@ -0,0 +1,51 @@
|
||||
import pygame
|
||||
import random
|
||||
|
||||
# Initialize pygame
|
||||
pygame.init()
|
||||
|
||||
# Screen dimensions
|
||||
WIDTH, HEIGHT = 800, 600
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("Chaos Game - Sierpinski Triangle")
|
||||
|
||||
# Define the triangle vertices
|
||||
vertex1 = (WIDTH // 2, 50)
|
||||
vertex2 = (50, HEIGHT - 50)
|
||||
vertex3 = (WIDTH - 50, HEIGHT - 50)
|
||||
vertices = [vertex1, vertex2, vertex3]
|
||||
|
||||
# Start with a random point
|
||||
current_point = (random.randint(0, WIDTH), random.randint(0, HEIGHT))
|
||||
|
||||
# Set up the clock for controlling frame rate
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
# Fill background color (black)
|
||||
screen.fill((0, 0, 0))
|
||||
|
||||
# Main loop
|
||||
running = True
|
||||
while running:
|
||||
# Handle events (close window)
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
||||
# Plot several points per frame for a faster build-up
|
||||
for _ in range(1):
|
||||
# Choose a random vertex
|
||||
chosen_vertex = random.choice(vertices)
|
||||
# Compute the midpoint between current point and chosen vertex
|
||||
current_point = ((current_point[0] + chosen_vertex[0]) // 2,
|
||||
(current_point[1] + chosen_vertex[1]) // 2)
|
||||
# Draw the point (using a small rectangle as a pixel)
|
||||
screen.fill((255, 255, 255), (current_point[0], current_point[1], 1, 1))
|
||||
|
||||
# Update display
|
||||
pygame.display.flip()
|
||||
|
||||
# Limit to 60 frames per second
|
||||
clock.tick()
|
||||
|
||||
pygame.quit()
|
194
algorithm-visualisations/boids.py
Normal file
194
algorithm-visualisations/boids.py
Normal file
@ -0,0 +1,194 @@
|
||||
import pygame
|
||||
import random
|
||||
import math
|
||||
|
||||
# Screen dimensions and simulation parameters
|
||||
WIDTH, HEIGHT = 800, 600
|
||||
NUM_BOIDS = 30
|
||||
MAX_SPEED = 4
|
||||
MAX_FORCE = 0.05
|
||||
|
||||
NEIGHBOR_RADIUS = 50
|
||||
SEPARATION_RADIUS = 20
|
||||
|
||||
# Debug mode flag (toggle with "D")
|
||||
DEBUG_MODE = True
|
||||
|
||||
class Boid:
|
||||
def __init__(self, x, y):
|
||||
self.position = pygame.math.Vector2(x, y)
|
||||
angle = random.uniform(0, 2 * math.pi)
|
||||
self.velocity = pygame.math.Vector2(math.cos(angle), math.sin(angle))
|
||||
self.velocity.scale_to_length(random.uniform(1, MAX_SPEED))
|
||||
self.acceleration = pygame.math.Vector2(0, 0)
|
||||
|
||||
def edges(self):
|
||||
# Wrap-around behavior for screen edges
|
||||
if self.position.x > WIDTH:
|
||||
self.position.x = 0
|
||||
elif self.position.x < 0:
|
||||
self.position.x = WIDTH
|
||||
if self.position.y > HEIGHT:
|
||||
self.position.y = 0
|
||||
elif self.position.y < 0:
|
||||
self.position.y = HEIGHT
|
||||
|
||||
def update(self):
|
||||
# Update velocity and position
|
||||
self.velocity += self.acceleration
|
||||
if self.velocity.length() > MAX_SPEED:
|
||||
self.velocity.scale_to_length(MAX_SPEED)
|
||||
self.position += self.velocity
|
||||
self.acceleration *= 0
|
||||
|
||||
def apply_force(self, force):
|
||||
self.acceleration += force
|
||||
|
||||
def flock(self, boids):
|
||||
# Calculate steering vectors from the three flocking rules
|
||||
alignment = self.align(boids)
|
||||
cohesion = self.cohere(boids)
|
||||
separation = self.separate(boids)
|
||||
|
||||
# Weighing the forces
|
||||
alignment *= 1.0
|
||||
cohesion *= 0.8
|
||||
separation *= 1.5
|
||||
|
||||
self.apply_force(alignment)
|
||||
self.apply_force(cohesion)
|
||||
self.apply_force(separation)
|
||||
|
||||
def align(self, boids):
|
||||
steering = pygame.math.Vector2(0, 0)
|
||||
total = 0
|
||||
for other in boids:
|
||||
if other != self and self.position.distance_to(other.position) < NEIGHBOR_RADIUS:
|
||||
steering += other.velocity
|
||||
total += 1
|
||||
if total > 0:
|
||||
steering /= total
|
||||
if steering.length() > 0:
|
||||
steering.scale_to_length(MAX_SPEED)
|
||||
steering -= self.velocity
|
||||
if steering.length() > MAX_FORCE:
|
||||
steering.scale_to_length(MAX_FORCE)
|
||||
return steering
|
||||
|
||||
def cohere(self, boids):
|
||||
steering = pygame.math.Vector2(0, 0)
|
||||
total = 0
|
||||
for other in boids:
|
||||
if other != self and self.position.distance_to(other.position) < NEIGHBOR_RADIUS:
|
||||
steering += other.position
|
||||
total += 1
|
||||
if total > 0:
|
||||
steering /= total
|
||||
steering -= self.position
|
||||
if steering.length() > 0:
|
||||
steering.scale_to_length(MAX_SPEED)
|
||||
steering -= self.velocity
|
||||
if steering.length() > MAX_FORCE:
|
||||
steering.scale_to_length(MAX_FORCE)
|
||||
return steering
|
||||
|
||||
def separate(self, boids):
|
||||
steering = pygame.math.Vector2(0, 0)
|
||||
total = 0
|
||||
for other in boids:
|
||||
distance = self.position.distance_to(other.position)
|
||||
if other != self and distance < SEPARATION_RADIUS:
|
||||
diff = self.position - other.position
|
||||
if distance > 0:
|
||||
diff /= distance # weight by distance
|
||||
steering += diff
|
||||
total += 1
|
||||
if total > 0:
|
||||
steering /= total
|
||||
if steering.length() > 0:
|
||||
steering.scale_to_length(MAX_SPEED)
|
||||
steering -= self.velocity
|
||||
if steering.length() > MAX_FORCE:
|
||||
steering.scale_to_length(MAX_FORCE)
|
||||
return steering
|
||||
|
||||
def draw(self, screen):
|
||||
# Calculate orientation for drawing the boid as a triangle
|
||||
angle = self.velocity.angle_to(pygame.math.Vector2(1, 0))
|
||||
# Triangle points: front and two rear corners
|
||||
p1 = self.position + pygame.math.Vector2(10, 0).rotate(-angle)
|
||||
p2 = self.position + pygame.math.Vector2(-5, 5).rotate(-angle)
|
||||
p3 = self.position + pygame.math.Vector2(-5, -5).rotate(-angle)
|
||||
pygame.draw.polygon(screen, (255, 255, 255), [p1, p2, p3])
|
||||
|
||||
# If debug is enabled, draw additional information (velocity vector)
|
||||
if DEBUG_MODE:
|
||||
end_pos = self.position + self.velocity * 10
|
||||
pygame.draw.line(screen, (0, 255, 0), self.position, end_pos, 2)
|
||||
|
||||
def draw_debug_panel(screen, boids, clock):
|
||||
# Draw a semi-transparent panel in the top-left corner
|
||||
|
||||
font = pygame.font.SysFont("Arial", 14)
|
||||
# Collect debug information
|
||||
fps_text = font.render(f"FPS: {int(clock.get_fps())}", True, (255, 255, 255))
|
||||
boids_text = font.render(f"Boids: {len(boids)}", True, (255, 255, 255))
|
||||
max_speed_text = font.render(f"Max Speed: {MAX_SPEED}", True, (255, 255, 255))
|
||||
neighbor_text = font.render(f"Neighbor Radius: {NEIGHBOR_RADIUS}", True, (255, 255, 255))
|
||||
separation_text = font.render(f"Separation Radius: {SEPARATION_RADIUS}", True, (255, 255, 255))
|
||||
|
||||
# Blit debug info on the panel
|
||||
screen.blit(fps_text, (10, 10))
|
||||
screen.blit(boids_text, (10, 30))
|
||||
screen.blit(max_speed_text, (10, 50))
|
||||
screen.blit(neighbor_text, (10, 70))
|
||||
screen.blit(separation_text, (10, 90))
|
||||
|
||||
# Additionally, display details of the first boid for deeper debugging
|
||||
if boids:
|
||||
boid = boids[0]
|
||||
pos_text = font.render(f"Boid0 Pos: ({int(boid.position.x)}, {int(boid.position.y)})", True, (255, 255, 255))
|
||||
vel_text = font.render(f"Boid0 Vel: ({int(boid.velocity.x)}, {int(boid.velocity.y)})", True, (255, 255, 255))
|
||||
screen.blit(pos_text, (10, 110))
|
||||
screen.blit(vel_text, (10, 130))
|
||||
|
||||
def main():
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("Boids Simulation with Debug Menu")
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
# Create boids at random positions
|
||||
boids = [Boid(random.randint(0, WIDTH), random.randint(0, HEIGHT)) for _ in range(NUM_BOIDS)]
|
||||
|
||||
global DEBUG_MODE
|
||||
debug_toggle_key = pygame.K_d # Press D to toggle the debug menu
|
||||
|
||||
running = True
|
||||
while running:
|
||||
screen.fill((0, 0, 0))
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == debug_toggle_key:
|
||||
DEBUG_MODE = not DEBUG_MODE
|
||||
|
||||
# Update and draw each boid
|
||||
for boid in boids:
|
||||
boid.flock(boids)
|
||||
boid.update()
|
||||
boid.edges()
|
||||
boid.draw(screen)
|
||||
|
||||
# Draw debug panel if debug mode is on
|
||||
if DEBUG_MODE:
|
||||
draw_debug_panel(screen, boids, clock)
|
||||
|
||||
pygame.display.flip()
|
||||
clock.tick(60)
|
||||
|
||||
pygame.quit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
174
algorithm-visualisations/particles.py
Normal file
174
algorithm-visualisations/particles.py
Normal file
@ -0,0 +1,174 @@
|
||||
import pygame
|
||||
import random
|
||||
import math
|
||||
|
||||
# Initialize pygame
|
||||
pygame.init()
|
||||
|
||||
# Screen dimensions and panel sizes
|
||||
WIDTH, HEIGHT = 800, 600
|
||||
PANEL_HEIGHT = 150 # Bottom panel for sliders
|
||||
SIM_HEIGHT = HEIGHT - PANEL_HEIGHT # Simulation area height
|
||||
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("Particle Simulation with Adjustable Variables")
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
# Define a simple Slider class
|
||||
class Slider:
|
||||
def __init__(self, x, y, w, h, min_val, max_val, init_val, label):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.min_val = min_val
|
||||
self.max_val = max_val
|
||||
self.value = init_val
|
||||
self.label = label
|
||||
self.dragging = False
|
||||
|
||||
def handle_event(self, event):
|
||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||
if event.button == 1:
|
||||
if self.get_knob_rect().collidepoint(event.pos):
|
||||
self.dragging = True
|
||||
elif event.type == pygame.MOUSEBUTTONUP:
|
||||
if event.button == 1:
|
||||
self.dragging = False
|
||||
elif event.type == pygame.MOUSEMOTION:
|
||||
if self.dragging:
|
||||
mx = event.pos[0]
|
||||
# Clamp mx inside slider range
|
||||
relative = (mx - self.x) / self.w
|
||||
relative = max(0, min(1, relative))
|
||||
self.value = self.min_val + relative * (self.max_val - self.min_val)
|
||||
|
||||
def get_knob_rect(self):
|
||||
# Determine knob position along slider track
|
||||
relative = (self.value - self.min_val) / (self.max_val - self.min_val)
|
||||
knob_x = self.x + relative * self.w
|
||||
knob_width = 10
|
||||
knob_height = self.h
|
||||
return pygame.Rect(knob_x - knob_width // 2, self.y, knob_width, knob_height)
|
||||
|
||||
def draw(self, surface, font):
|
||||
# Draw slider track (a thin rectangle)
|
||||
track_rect = pygame.Rect(self.x, self.y + self.h // 2 - 2, self.w, 4)
|
||||
pygame.draw.rect(surface, (200, 200, 200), track_rect)
|
||||
# Draw knob
|
||||
knob_rect = self.get_knob_rect()
|
||||
pygame.draw.rect(surface, (100, 100, 100), knob_rect)
|
||||
# Draw label and current value (as plain text)
|
||||
label_surface = font.render(f"{self.label}: {self.value:.2f}", True, (0, 0, 0))
|
||||
surface.blit(label_surface, (self.x, self.y - 20))
|
||||
|
||||
# Particle class
|
||||
class Particle:
|
||||
def __init__(self, pos, velocity, lifetime, size, color=(255, 255, 255)):
|
||||
self.pos = pygame.math.Vector2(pos)
|
||||
self.vel = pygame.math.Vector2(velocity)
|
||||
self.lifetime = lifetime
|
||||
self.size = size
|
||||
self.initial_lifetime = lifetime
|
||||
self.color = color
|
||||
|
||||
def update(self, gravity):
|
||||
self.vel.y += gravity
|
||||
self.pos += self.vel
|
||||
self.lifetime -= 1
|
||||
|
||||
def is_dead(self):
|
||||
return self.lifetime <= 0
|
||||
|
||||
def draw(self, surface, glow_intensity):
|
||||
# Draw glow effect if glow_intensity is greater than zero
|
||||
if glow_intensity > 0:
|
||||
# Create a temporary surface for glow with per-pixel alpha
|
||||
glow_surface = pygame.Surface((self.size*6, self.size*6), pygame.SRCALPHA)
|
||||
glow_center = self.size * 3
|
||||
# Draw several concentric circles for the glow effect
|
||||
for i in range(1, 6):
|
||||
# Alpha decreases as the circle radius increases
|
||||
alpha = max(0, int(255 * (glow_intensity / 10) * (1 - i/6)))
|
||||
radius = int(self.size + i * 2)
|
||||
pygame.draw.circle(glow_surface,
|
||||
(self.color[0], self.color[1], self.color[2], alpha),
|
||||
(glow_center, glow_center),
|
||||
radius)
|
||||
# Blit the glow surface with additive blending
|
||||
surface.blit(glow_surface, (self.pos.x - self.size*3, self.pos.y - self.size*3), special_flags=pygame.BLEND_RGBA_ADD)
|
||||
# Draw the particle itself
|
||||
pygame.draw.circle(surface, self.color, (int(self.pos.x), int(self.pos.y)), int(self.size))
|
||||
|
||||
# Create sliders for each variable, arranged in two rows within the bottom panel.
|
||||
font = pygame.font.SysFont("Arial", 16)
|
||||
sliders = []
|
||||
# Row 1: Emission Rate, Speed, Lifetime
|
||||
sliders.append(Slider(x=20, y=SIM_HEIGHT + 10, w=200, h=20, min_val=0, max_val=50, init_val=5, label="Emission Rate"))
|
||||
sliders.append(Slider(x=240, y=SIM_HEIGHT + 10, w=200, h=20, min_val=0, max_val=10, init_val=5, label="Speed"))
|
||||
sliders.append(Slider(x=460, y=SIM_HEIGHT + 10, w=200, h=20, min_val=10, max_val=300, init_val=100, label="Lifetime"))
|
||||
# Row 2: Size, Gravity, Glow
|
||||
sliders.append(Slider(x=20, y=SIM_HEIGHT + 50, w=200, h=20, min_val=1, max_val=20, init_val=5, label="Size"))
|
||||
sliders.append(Slider(x=240, y=SIM_HEIGHT + 50, w=200, h=20, min_val=0, max_val=2, init_val=0.1, label="Gravity"))
|
||||
sliders.append(Slider(x=460, y=SIM_HEIGHT + 50, w=200, h=20, min_val=0, max_val=10, init_val=3, label="Glow"))
|
||||
|
||||
# List to hold all particles
|
||||
particles = []
|
||||
|
||||
# Emitter position (center of simulation area)
|
||||
emitter = pygame.math.Vector2(WIDTH // 2, SIM_HEIGHT // 2)
|
||||
|
||||
# Main loop
|
||||
running = True
|
||||
while running:
|
||||
# Process events (for quitting and slider events)
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
for slider in sliders:
|
||||
slider.handle_event(event)
|
||||
|
||||
# Get simulation variables from slider values
|
||||
emission_rate = sliders[0].value # particles per frame
|
||||
speed = sliders[1].value # initial speed magnitude
|
||||
lifetime = sliders[2].value # lifetime in frames
|
||||
size = sliders[3].value # particle size (radius)
|
||||
gravity = sliders[4].value # gravity acceleration
|
||||
glow = sliders[5].value # glow intensity
|
||||
|
||||
# Spawn new particles (round emission_rate to an integer count)
|
||||
for _ in range(int(emission_rate)):
|
||||
# Spawn at the emitter with a random direction
|
||||
angle = random.uniform(0, 2 * math.pi)
|
||||
velocity = pygame.math.Vector2(math.cos(angle), math.sin(angle)) * speed
|
||||
particles.append(Particle(emitter, velocity, lifetime, size))
|
||||
|
||||
# Update particles and remove dead ones
|
||||
for particle in particles[:]:
|
||||
particle.update(gravity)
|
||||
if particle.is_dead():
|
||||
particles.remove(particle)
|
||||
|
||||
# Clear simulation area (fill with black)
|
||||
screen.fill((0, 0, 0), rect=pygame.Rect(0, 0, WIDTH, SIM_HEIGHT))
|
||||
# Optionally fill the control area with a light color (or leave it as is)
|
||||
screen.fill((220, 220, 220), rect=pygame.Rect(0, SIM_HEIGHT, WIDTH, PANEL_HEIGHT))
|
||||
|
||||
# Draw all particles
|
||||
for particle in particles:
|
||||
particle.draw(screen, glow_intensity=glow)
|
||||
|
||||
# Draw slider controls in the bottom panel
|
||||
for slider in sliders:
|
||||
slider.draw(screen, font)
|
||||
|
||||
# Draw debug text (plain text, no background) at the top-left corner of the simulation area
|
||||
debug_text = (f"Particles: {len(particles)} | Emission Rate: {emission_rate:.2f} | Speed: {speed:.2f} | "
|
||||
f"Lifetime: {lifetime:.2f} | Size: {size:.2f} | Gravity: {gravity:.2f} | Glow: {glow:.2f}")
|
||||
debug_surface = font.render(debug_text, True, (255, 255, 255))
|
||||
screen.blit(debug_surface, (10, 10))
|
||||
|
||||
pygame.display.flip()
|
||||
clock.tick(60)
|
||||
|
||||
pygame.quit()
|
Loading…
Reference in New Issue
Block a user