| import random |
| import numpy as np |
| import streamlit as st |
| import plotly.graph_objects as go |
| from plotly.subplots import make_subplots |
| import time |
|
|
| class Organelle: |
| def __init__(self, type): |
| self.type = type |
|
|
| class Modification: |
| def __init__(self, name, effect): |
| self.name = name |
| self.effect = effect |
|
|
| class Cell: |
| def __init__(self, x, y, cell_type="prokaryote"): |
| self.x = x |
| self.y = y |
| self.energy = 100 |
| self.cell_type = cell_type |
| self.organelles = [] |
| self.modifications = [] |
| self.size = 1 |
| self.color = "lightblue" |
| self.division_threshold = 150 |
| |
| self.update_properties() |
|
|
| def update_properties(self): |
| if self.cell_type == "early_eukaryote": |
| self.organelles.append(Organelle("nucleus")) |
| self.color = "green" |
| self.size = 2 |
| elif self.cell_type == "advanced_eukaryote": |
| self.organelles.extend([Organelle("nucleus"), Organelle("mitochondria")]) |
| self.color = "red" |
| self.size = 3 |
| elif self.cell_type == "plant_like": |
| self.organelles.extend([Organelle("nucleus"), Organelle("mitochondria"), Organelle("chloroplast")]) |
| self.color = "darkgreen" |
| self.size = 4 |
|
|
| def move(self, environment): |
| dx = random.uniform(-1, 1) |
| dy = random.uniform(-1, 1) |
| self.x = max(0, min(environment.width - 1, self.x + dx)) |
| self.y = max(0, min(environment.height - 1, self.y + dy)) |
| self.energy -= 0.5 * self.size |
|
|
| def feed(self, environment): |
| base_energy = environment.grid[int(self.y)][int(self.x)] * 0.1 |
| if "chloroplast" in [org.type for org in self.organelles]: |
| base_energy += environment.light_level * 2 |
| |
| for mod in self.modifications: |
| base_energy *= mod.effect |
|
|
| self.energy += base_energy |
| environment.grid[int(self.y)][int(self.x)] *= 0.9 |
|
|
| def can_divide(self): |
| return self.energy > self.division_threshold |
|
|
| def divide(self): |
| if self.can_divide(): |
| self.energy /= 2 |
| new_cell = Cell(self.x, self.y, self.cell_type) |
| new_cell.organelles = self.organelles.copy() |
| new_cell.modifications = self.modifications.copy() |
| return new_cell |
| return None |
|
|
| def can_fuse(self, other): |
| return (self.cell_type == other.cell_type and |
| random.random() < 0.005) |
|
|
| def fuse(self, other): |
| new_cell_type = self.cell_type |
| if self.cell_type == "prokaryote": |
| new_cell_type = "early_eukaryote" |
| elif self.cell_type == "early_eukaryote": |
| new_cell_type = "advanced_eukaryote" |
|
|
| new_cell = Cell( |
| (self.x + other.x) / 2, |
| (self.y + other.y) / 2, |
| new_cell_type |
| ) |
| new_cell.energy = self.energy + other.energy |
| new_cell.organelles = list(set(self.organelles + other.organelles)) |
| new_cell.modifications = list(set(self.modifications + other.modifications)) |
| new_cell.update_properties() |
| return new_cell |
|
|
| def acquire_modification(self): |
| possible_mods = [ |
| Modification("Enhanced metabolism", 1.2), |
| Modification("Thick cell wall", 0.8), |
| Modification("Efficient energy storage", 1.1), |
| Modification("Rapid division", 0.9) |
| ] |
| new_mod = random.choice(possible_mods) |
| if new_mod not in self.modifications: |
| self.modifications.append(new_mod) |
| self.color = "purple" |
|
|
| class Environment: |
| def __init__(self, width, height): |
| self.width = width |
| self.height = height |
| self.grid = np.random.rand(height, width) * 10 |
| self.light_level = 5 |
| self.cells = [] |
| self.time = 0 |
| self.population_history = { |
| "prokaryote": [], "early_eukaryote": [], |
| "advanced_eukaryote": [], "plant_like": [], "modified": [] |
| } |
|
|
| def add_cell(self, cell): |
| self.cells.append(cell) |
|
|
| def update(self): |
| self.time += 1 |
| self.grid += np.random.rand(self.height, self.width) * 0.1 |
| self.light_level = 5 + np.sin(self.time / 100) * 2 |
|
|
| new_cells = [] |
| cells_to_remove = [] |
|
|
| for cell in self.cells: |
| cell.move(self) |
| cell.feed(self) |
|
|
| if cell.energy <= 0: |
| cells_to_remove.append(cell) |
| elif cell.can_divide(): |
| new_cell = cell.divide() |
| if new_cell: |
| new_cells.append(new_cell) |
|
|
| |
| for i, cell1 in enumerate(self.cells): |
| for cell2 in self.cells[i+1:]: |
| if cell1.can_fuse(cell2): |
| new_cell = cell1.fuse(cell2) |
| new_cells.append(new_cell) |
| cells_to_remove.extend([cell1, cell2]) |
|
|
| |
| self.cells.extend(new_cells) |
| self.cells = [cell for cell in self.cells if cell not in cells_to_remove] |
|
|
| |
| for cell in self.cells: |
| if random.random() < 0.0001: |
| if cell.cell_type == "early_eukaryote": |
| cell.cell_type = "advanced_eukaryote" |
| elif cell.cell_type == "advanced_eukaryote" and random.random() < 0.5: |
| cell.cell_type = "plant_like" |
| cell.update_properties() |
| |
| if random.random() < 0.0005: |
| cell.acquire_modification() |
|
|
| |
| for cell_type in self.population_history.keys(): |
| if cell_type != "modified": |
| count = len([cell for cell in self.cells if cell.cell_type == cell_type and not cell.modifications]) |
| else: |
| count = len([cell for cell in self.cells if cell.modifications]) |
| self.population_history[cell_type].append(count) |
|
|
| def get_visualization_data(self): |
| cell_data = { |
| "prokaryote": {"x": [], "y": [], "size": [], "color": "lightblue", "symbol": "circle"}, |
| "early_eukaryote": {"x": [], "y": [], "size": [], "color": "green", "symbol": "square"}, |
| "advanced_eukaryote": {"x": [], "y": [], "size": [], "color": "red", "symbol": "diamond"}, |
| "plant_like": {"x": [], "y": [], "size": [], "color": "darkgreen", "symbol": "star"}, |
| "modified": {"x": [], "y": [], "size": [], "color": "purple", "symbol": "cross"} |
| } |
|
|
| for cell in self.cells: |
| cell_type = "modified" if cell.modifications else cell.cell_type |
| cell_data[cell_type]["x"].append(cell.x) |
| cell_data[cell_type]["y"].append(cell.y) |
| cell_data[cell_type]["size"].append(cell.size * 3) |
|
|
| return cell_data, self.population_history |
|
|
| def setup_figure(env): |
| cell_types = ["prokaryote", "early_eukaryote", "advanced_eukaryote", "plant_like", "modified"] |
| fig = make_subplots(rows=2, cols=3, |
| subplot_titles=("Cell Distribution", "Total Population", |
| "Prokaryotes", "Early Eukaryotes", |
| "Advanced Eukaryotes", "Plant-like & Modified"), |
| vertical_spacing=0.1, |
| horizontal_spacing=0.05) |
|
|
| |
| for cell_type, data in env.get_visualization_data()[0].items(): |
| fig.add_trace(go.Scatter( |
| x=data["x"], y=data["y"], mode='markers', |
| marker=dict(color=data["color"], size=data["size"], symbol=data["symbol"]), |
| name=cell_type |
| ), row=1, col=1) |
|
|
| |
| for cell_type, counts in env.population_history.items(): |
| fig.add_trace(go.Scatter(y=counts, mode='lines', name=cell_type), row=1, col=2) |
|
|
| |
| for i, cell_type in enumerate(cell_types): |
| if cell_type == "modified": |
| fig.add_trace(go.Scatter(y=env.population_history[cell_type], mode='lines', |
| name=cell_type, line=dict(color="purple")), row=2, col=3) |
| elif cell_type == "plant_like": |
| fig.add_trace(go.Scatter(y=env.population_history[cell_type], mode='lines', |
| name=cell_type, line=dict(color="darkgreen")), row=2, col=3) |
| else: |
| fig.add_trace(go.Scatter(y=env.population_history[cell_type], mode='lines', |
| name=cell_type), row=2, col=i+1) |
|
|
| fig.update_xaxes(title_text="X", row=1, col=1) |
| fig.update_yaxes(title_text="Y", row=1, col=1) |
| fig.update_xaxes(title_text="Time", row=1, col=2) |
| fig.update_yaxes(title_text="Population", row=1, col=2) |
|
|
| for i in range(1, 4): |
| fig.update_xaxes(title_text="Time", row=2, col=i) |
| fig.update_yaxes(title_text="Population", row=2, col=i) |
|
|
| fig.update_layout(height=800, width=1200, title_text="Advanced Cell Evolution Simulation") |
|
|
| return fig |
|
|
| |
| st.title("Advanced Cell Evolution Simulation") |
|
|
| num_steps = st.slider("Number of simulation steps", 100, 2000, 1000) |
| initial_cells = st.slider("Initial number of cells", 10, 200, 100) |
| update_interval = st.slider("Update interval (milliseconds)", 50, 500, 100) |
|
|
| if st.button("Run Simulation"): |
| env = Environment(100, 100) |
| |
| |
| for _ in range(initial_cells): |
| cell = Cell(random.uniform(0, env.width), random.uniform(0, env.height)) |
| env.add_cell(cell) |
| |
| |
| fig = setup_figure(env) |
| chart = st.plotly_chart(fig, use_container_width=True) |
| |
| |
| for step in range(num_steps): |
| env.update() |
| |
| |
| with fig.batch_update(): |
| cell_data, population_history = env.get_visualization_data() |
| for i, (cell_type, data) in enumerate(cell_data.items()): |
| fig.data[i].x = data["x"] |
| fig.data[i].y = data["y"] |
| fig.data[i].marker.size = data["size"] |
| |
| for i, (cell_type, counts) in enumerate(population_history.items()): |
| fig.data[i+5].y = counts |
| if cell_type != "modified" and cell_type != "plant_like": |
| fig.data[i+10].y = counts |
| else: |
| fig.data[13].y = population_history["plant_like"] |
| fig.data[14].y = population_history["modified"] |
| |
| fig.layout.title.text = f"Advanced Cell Evolution Simulation (Time: {env.time})" |
| |
| |
| chart.plotly_chart(fig, use_container_width=True) |
| |
| time.sleep(update_interval / 1000) |
|
|
| st.write("Simulation complete!") |