Game of life, pydroid v.2
import pygame
import pickle
import os
import copy
# — Configuration —
SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600
CELL_SIZE = 10
GRID_WIDTH = SCREEN_WIDTH // CELL_SIZE
GRID_HEIGHT = (SCREEN_HEIGHT – 100) // CELL_SIZE # Reserve space for buttons
# Colors
COLOR_WHITE = (255, 255, 255)
COLOR_BLACK = (0, 0, 0)
COLOR_GRAY = (40, 40, 40)
COLOR_GREEN = (0, 255, 0)
COLOR_BLUE = (30, 144, 255)
COLOR_RED = (255, 69, 0)
# — Game of Life Logic (using standard lists) —
def create_grid(width, height):
“””Creates a 2D list to represent the grid.”””
return [[0 for _ in range(height)] for _ in range(width)]
def next_generation(grid):
“””Computes the next generation of the grid based on the rules.”””
width = len(grid)
height = len(grid[0])
new_grid = copy.deepcopy(grid) # Use deepcopy for lists of lists
for x in range(width):
for y in range(height):
# Count live neighbors, handling wrapping at the edges (toroidal array)
total = 0
for i in range(-1, 2):
for j in range(-1, 2):
if i == 0 and j == 0:
continue
# Calculate wrapped coordinates
nx, ny = (x + i) % width, (y + j) % height
total += grid[nx][ny]
# Apply Conway’s rules
if grid[x][y] == 1:
if (total < 2) or (total > 3):
new_grid[x][y] = 0
else:
if total == 3:
new_grid[x][y] = 1
return new_grid
# — Classic Patterns —
def get_patterns():
“””Returns a dictionary of classic Game of Life patterns.”””
patterns = {
“Gosper Glider Gun”: [
(5, 1), (5, 2), (6, 1), (6, 2), (5, 11), (6, 11), (7, 11),
(4, 12), (8, 12), (3, 13), (9, 13), (3, 14), (9, 14), (6, 15),
(4, 16), (8, 16), (5, 17), (6, 17), (7, 17), (6, 18),
(3, 21), (4, 21), (5, 21), (3, 22), (4, 22), (5, 22),
(2, 23), (6, 23), (1, 25), (2, 25), (6, 25), (7, 25),
(3, 35), (4, 35), (3, 36), (4, 36)
],
“Glider”: [(0, 1), (1, 2), (2, 0), (2, 1), (2, 2)],
“Pulsar”: [
(2,4),(3,4),(4,4),(8,4),(9,4),(10,4), (2,5),(7,5),(9,5),(14,5),
(2,6),(7,6),(9,6),(14,6), (4,7),(5,7),(6,7),(10,7),(11,7),(12,7),
(4,9),(5,9),(6,9),(10,9),(11,9),(12,9), (2,10),(7,10),(9,10),(14,10),
(2,11),(7,11),(9,11),(14,11), (2,12),(3,12),(4,12),(8,12),(9,12),(10,12)
],
“Clear”: []
}
return patterns
def place_pattern(grid, pattern_name, offset_x=10, offset_y=5):
“””Places a pattern onto the grid.”””
patterns = get_patterns()
pattern = patterns.get(pattern_name)
width = len(grid)
height = len(grid[0])
# Clear grid before placing pattern
for x in range(width):
for y in range(height):
grid[x][y] = 0
if pattern:
for pos in pattern:
# Ensure pattern fits on screen
if 0 <= pos[0] + offset_x < width and 0 <= pos[1] + offset_y < height:
grid[pos[0] + offset_x][pos[1] + offset_y] = 1
# — Pygame Setup —
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption(“Conway’s Game of Life”)
clock = pygame.time.Clock()
font = pygame.font.SysFont(“sans”, 20)
# — Button Class —
class Button:
def __init__(self, x, y, width, height, text, color):
self.rect = pygame.Rect(x, y, width, height)
self.text = text
self.color = color
def draw(self, surface):
pygame.draw.rect(surface, self.color, self.rect)
pygame.draw.rect(surface, COLOR_WHITE, self.rect, 2)
text_surf = font.render(self.text, True, COLOR_WHITE)
text_rect = text_surf.get_rect(center=self.rect.center)
surface.blit(text_surf, text_rect)
def is_clicked(self, pos):
return self.rect.collidepoint(pos)
# — UI Elements —
buttons = {
“play_pause”: Button(10, SCREEN_HEIGHT – 80, 100, 30, “Play”, COLOR_BLUE),
“step”: Button(120, SCREEN_HEIGHT – 80, 70, 30, “Step”, COLOR_BLUE),
“save”: Button(10, SCREEN_HEIGHT – 40, 70, 30, “Save”, COLOR_BLUE),
“load”: Button(90, SCREEN_HEIGHT – 40, 70, 30, “Load”, COLOR_BLUE),
}
pattern_buttons = {}
pattern_names = list(get_patterns().keys())
x_offset = 200
for i, name in enumerate(pattern_names):
pattern_buttons[name] = Button(x_offset + (i * 120), SCREEN_HEIGHT – 80, 110, 30, name, COLOR_GRAY)
# — Main Game Loop —
def main():
grid = create_grid(GRID_WIDTH, GRID_HEIGHT)
running = True
paused = True
drawing = False
speed = 10 # Generations per second
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT: running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_AC_BACK: running = False
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
on_button = any(btn.is_clicked(pos) for btn in list(buttons.values()) + list(pattern_buttons.values()))
if on_button:
# Handle UI buttons
if buttons[“play_pause”].is_clicked(pos):
paused = not paused
buttons[“play_pause”].text = “Play” if paused else “Pause”
buttons[“play_pause”].color = COLOR_BLUE if paused else COLOR_RED
elif buttons[“step”].is_clicked(pos) and paused:
grid = next_generation(grid)
elif buttons[“save”].is_clicked(pos):
try:
with open(“life_save.dat”, “wb”) as f:
pickle.dump(grid, f)
print(“Grid saved!”)
except Exception as e:
print(f”Error saving file: {e}”)
elif buttons[“load”].is_clicked(pos):
try:
if os.path.exists(“life_save.dat”):
with open(“life_save.dat”, “rb”) as f:
grid = pickle.load(f)
print(“Grid loaded!”)
except Exception as e:
print(f”Error loading file: {e}”)
for name, btn in pattern_buttons.items():
if btn.is_clicked(pos):
place_pattern(grid, name)
else:
# Handle drawing on the grid
drawing = True
x, y = pos[0] // CELL_SIZE, pos[1] // CELL_SIZE
if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
grid[x][y] = 1 – grid[x][y] # Toggle cell
if event.type == pygame.MOUSEBUTTONUP:
drawing = False
if event.type == pygame.MOUSEMOTION and drawing:
pos = pygame.mouse.get_pos()
x, y = pos[0] // CELL_SIZE, pos[1] // CELL_SIZE
if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT:
grid[x][y] = 1 # Draw live cells
if not paused:
grid = next_generation(grid)
# — Drawing —
screen.fill(COLOR_BLACK)
for x in range(GRID_WIDTH):
for y in range(GRID_HEIGHT):
if grid[x][y] == 1:
pygame.draw.rect(screen, COLOR_GREEN, (x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE))
pygame.draw.rect(screen, COLOR_GRAY, (x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE), 1)
pygame.draw.rect(screen, (50,50,50), (0, SCREEN_HEIGHT – 100, SCREEN_WIDTH, 100))
for btn in buttons.values():
btn.draw(screen)
for btn in pattern_buttons.values():
btn.draw(screen)
pygame.display.flip()
clock.tick(speed)
pygame.quit()
if __name__ == ‘__main__’:
main()