V3.2 Microbial Life Simu Added
V3.2 Microbial Life Simu Added
V3.2 Microbial Life Simu Added
import pygame
pygame.init()
#color library
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN=(0,255,0)
RED=(255,0,0)
BLUE=(0,0,255)
GOLD=(255,215,0)
class Grid: #grid class containing all the set-up & update functions
def __init__(self, rows, cols, cell_size):
self.rows=rows #assigning values to instance variables for grid mapping,
all the values here should be integers
self.cols=cols
self.cell_size=cell_size
self.manualgrid=self.create_empty_grid() #creates an instance variable for
an empty grid that we can call later on
self.randomgrid=self.create_random_grid()
self.currentgrid=self.randomgrid #instance variable to be called as the
grid placeholder, we choose the random grid as the default
self.microbe_grid = self.create_empty_grid() # Track microbe types
def set_random_grid(self): #function to set the random grid as the one we are
working with
self.currentgrid=self.randomgrid
def set_manual_grid(self): #function to set the manual grid as the one we are
working with
self.currentgrid=self.manualgrid
#grid drawing
def draw_grid(self):
for row in range(self.rows):
for col in range(self.cols):
if self.currentgrid[row][col] == 1:
microbe_type = self.microbe_grid[row][col]
color = MICROBE_TYPES[microbe_type] if microbe_type else
holographic()
else:
color = BLACK
pygame.draw.rect(screen, color,(col * self.cell_size, row *
self.cell_size, self.cell_size, self.cell_size))
class Settings: #settings class designed to allow user to alter game parameters
def __init__(self):
self.fps = 10 #creation of a fps instance variable to replace our
time.sleep fps config function
self.resolution = (800, 600)
self.grid_size = (20, 20)
def update_settings(self):
running = True
options = [
"FPS",
"Resolution",
"Grid Size",
"Back"
]
selected = 0
font = pygame.font.SysFont("sans-serif", 36)
while running:
screen.fill(BLACK)
pygame.display.flip()
while input_active:
#loop to support the method's functionality through handling user input
values, updating game and preserving game consistency in case of parsing failure
screen.fill(BLACK)
prompt_text = font.render(prompt, True, WHITE)
input_text = font.render(user_input, True, GREEN)
screen.blit(prompt_text, (screen_w // 2 - prompt_text.get_width() // 2,
150))
screen.blit(input_text, (screen_w // 2 - input_text.get_width() // 2,
250))
pygame.display.flip()
#the below methods prompt the user for values, updates them and essentially
communicate the results of the loop above
def change_fps(self):
new_fps = input("Enter new FPS (current: {}): ".format(self.fps))
try:
self.fps = int(new_fps)
except ValueError:
print("Invalid input! FPS remains unchanged.")
def change_resolution(self):
new_res = input("Enter new resolution as WIDTH x HEIGHT (current: {}):
".format(self.resolution))
try:
width, height = map(int, new_res.lower().split('x'))
self.resolution = (width, height)
except ValueError:
print("Invalid input! Resolution remains unchanged.")
def change_grid_size(self):
new_size = input("Enter new grid size as ROWSxCOLS (current: {}):
".format(self.grid_size))
try:
rows, cols = map(int, new_size.lower().split('x'))
self.grid_size = (rows, cols)
except ValueError:
print("Invalid input! Grid size remains unchanged.")
def exit_settings(self):
print("Exiting settings menu.")
class Menu:
def __init__(self, title, font):
self.title=title #menu title, data type=string
self.screen=screen #global screen config variable called to be applied to
menu
self.font=font
self.options={"1": "Random Game", "2": "Manual Game", "3": "Add Nutrients",
"ESC": "Quit"} #menu options index, defined as dict
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
key_pressed = pygame.key.name(event.key).upper() #.upper() used
to avoid having to capitalize numerical inputs to access game
if key_pressed in self.options:
return key_pressed
class Game:
def __init__(self, settings):
self.settings = settings
self.rows, self.cols = self.settings.grid_size
self.cell_size = self.settings.resolution[0] // self.cols #we get cell_size
to depend on resolution & columns due to newly added dynamism of game
self.fps = self.settings.fps
self.grid = Grid(self.rows, self.cols, self.cell_size)
self.menu = Menu(
title="Game of Life",
font=pygame.font.SysFont("sans-serif", 48)
)
self.running = True
self.actions = {
"1": self.start_random_game,
"2": self.start_manual_game,
"3": self.add_nutrients, # Add nutrients
"ESC": self.quit_game
}
def show_settings(self):
self.settings.update_settings()
#update game config after settings change
self.rows, self.cols = self.settings.grid_size
self.cell_size = self.settings.resolution[0] // self.cols
self.fps = self.settings.fps
self.grid = Grid(self.rows, self.cols, self.cell_size)
def start_random_game(self):
print("Starting Random Game...") #debugging, was having issues with this
part can remove
self.grid.set_random_grid()
self.run_game_loop()
def start_manual_game(self):
print("Starting Manual Game...") #debugging
self.grid.set_manual_grid()
self.manual_placement()
self.run_game_loop()
def add_nutrients(self):
print("Adding nutrients...")
for _ in range(random.randint(5, 10)):
row, col = random.randint(0, self.rows - 1), random.randint(0,
self.cols - 1)
self.grid.currentgrid[row][col] = 1
self.grid.microbe_grid[row][col] = "Producer" # Add Producer
def quit_game(self):
print("Quitting the game...") #debugging
pygame.quit()
exit()
def manual_placement(self):
placing = True
while placing:
screen.fill(BLACK)
self.grid.draw_grid() #draw the grid based on the current state in
manual mode
pygame.display.flip()
def run_game_loop(self):
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_m:
return
screen.fill(BLACK)
self.grid.draw_grid()
self.grid.update_grid()
pygame.display.flip()
clock.tick(self.fps) #use our newly defined dynamic FPS value
def run(self):
while self.running:
choice = self.menu.display()
if choice in self.actions:
self.actions[choice]() #dynamically call the associated action
if __name__ == "__main__":
settings = Settings() #instance of the settings class, brings forth contents &
methods defined in it as an object
game = Game(settings) #instance of the game class running our settings object
as a parameter, makes sure the game runs based on the defined configs
game.run()
class MicrobialGame:
def __init__(self):
self.settings = Settings()
self.grid = Grid(self.settings.grid_size[0], self.settings.grid_size[1],
self.settings.resolution[0] // self.settings.grid_size[1])
self.running = True
def mutate_microbes(self):
"""
Introduces random mutations to existing microbes.
"""
for row in range(self.grid.rows):
for col in range(self.grid.cols):
if self.grid.currentgrid[row][col] == 1: # Only mutate live cells
if random.random() < 0.05: # 5% chance of mutation
self.grid.microbe_grid[row][col] =
random.choice(list(MICROBE_TYPES.keys()))
def add_random_events(self):
"""
Introduces random events like toxins or resource booms.
"""
if random.random() < 0.1: # 10% chance per cycle
event_type = random.choice(["toxins", "resources"])
for _ in range(random.randint(3, 7)): # Affect 3-7 cells
row = random.randint(0, self.grid.rows - 1)
col = random.randint(0, self.grid.cols - 1)
if event_type == "toxins":
self.grid.currentgrid[row][col] = 0 # Kill the cell
self.grid.microbe_grid[row][col] = None
elif event_type == "resources":
self.grid.currentgrid[row][col] = 1 # Add a Producer
self.grid.microbe_grid[row][col] = "Producer"
def run(self):
clock = pygame.time.Clock()
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
self.grid.update_grid()
self.mutate_microbes()
self.add_random_events()
screen.fill(BLACK)
self.grid.draw_grid()
pygame.display.flip()
clock.tick(self.settings.fps)
if __name__ == "__main__":
pygame.init()
microbial_game = MicrobialGame()
microbial_game.run()
pygame.quit()