|
| 1 | +import numpy as np |
| 2 | +import matplotlib.pyplot as plt |
| 3 | +import os |
| 4 | + |
| 5 | +def simulate_emergence(): |
| 6 | + # Simulation Parameters |
| 7 | + N = 200 # Grid size |
| 8 | + dx = 1.0 # Spatial step |
| 9 | + dt = 0.01 # Time step |
| 10 | + steps = 5000 # Total steps |
| 11 | + |
| 12 | + # Physics Parameters |
| 13 | + D_C = 0.1 # Diffusion of Mass (C) |
| 14 | + D_I = 0.5 # Diffusion of Game Landscape (I) |
| 15 | + decay_I = 0.05 # How fast the game resets if empty |
| 16 | + beta = 1.5 # How much Mass (C^2) bends the Game (I) |
| 17 | + gamma = 2.0 # How strongly the Game (I) pulls the Mass (C) |
| 18 | + |
| 19 | + # Initial Conditions |
| 20 | + # Start with a small random bump of mass in the center, flat elsewhere |
| 21 | + x = np.linspace(-N//2, N//2, N) |
| 22 | + C = np.exp(-(x**2)/20) + 0.1 * np.random.rand(N) |
| 23 | + I = np.zeros(N) # Game landscape starts completely flat! |
| 24 | + |
| 25 | + # To store history for plotting |
| 26 | + history_C = [C.copy()] |
| 27 | + history_I = [I.copy()] |
| 28 | + plot_steps = [0, 1000, 3000, 4999] |
| 29 | + |
| 30 | + for step in range(steps): |
| 31 | + # 1. Calculate Spatial Gradients (Laplacian) |
| 32 | + laplacian_C = (np.roll(C, 1) - 2*C + np.roll(C, -1)) / dx**2 |
| 33 | + laplacian_I = (np.roll(I, 1) - 2*I + np.roll(I, -1)) / dx**2 |
| 34 | + |
| 35 | + # 2. Emergent Equations! |
| 36 | + |
| 37 | + # Game (I) is bent by Mass (C^2) |
| 38 | + dI_dt = D_I * laplacian_I - decay_I * I + beta * (C**2) |
| 39 | + |
| 40 | + # Mass (C) is pulled by the Game (I) and naturally diffuses |
| 41 | + # Using a simple gradient flow towards high I: C * dI/dx (simplification for visual) |
| 42 | + grad_I = (np.roll(I, -1) - np.roll(I, 1)) / (2*dx) |
| 43 | + grad_C = (np.roll(C, -1) - np.roll(C, 1)) / (2*dx) |
| 44 | + pull_force = gamma * (C * laplacian_I + grad_C * grad_I) |
| 45 | + |
| 46 | + dC_dt = D_C * laplacian_C + pull_force |
| 47 | + |
| 48 | + # 3. Time Step Update |
| 49 | + C = C + dt * dC_dt |
| 50 | + I = I + dt * dI_dt |
| 51 | + |
| 52 | + # Prevent instability in simple explicit solver |
| 53 | + C = np.clip(C, 0, 10) |
| 54 | + I = np.clip(I, 0, 50) |
| 55 | + |
| 56 | + if step in plot_steps: |
| 57 | + history_C.append(C.copy()) |
| 58 | + history_I.append(I.copy()) |
| 59 | + |
| 60 | + # Generate the Visualization |
| 61 | + plt.figure(figsize=(12, 8)) |
| 62 | + for idx, t in enumerate(plot_steps): |
| 63 | + plt.subplot(2, 2, idx+1) |
| 64 | + plt.plot(x, history_C[idx+1], label='Mass (C) [Players]', color='blue', linewidth=2) |
| 65 | + plt.plot(x, history_I[idx+1], label='Game Landscape (I) [Rules]', color='red', linestyle='--', linewidth=2) |
| 66 | + plt.title(f"Time Step: {t}") |
| 67 | + plt.xlabel("Space") |
| 68 | + plt.ylabel("Intensity") |
| 69 | + plt.legend() |
| 70 | + plt.grid(True) |
| 71 | + if idx == 0: |
| 72 | + plt.ylim(-0.5, 2) |
| 73 | + else: |
| 74 | + plt.ylim(-0.5, max(np.max(history_C[-1]), np.max(history_I[-1])) * 1.2) |
| 75 | + |
| 76 | + plt.tight_layout() |
| 77 | + output_path = os.path.abspath('Result/sandbox_emergence.png') |
| 78 | + os.makedirs(os.path.dirname(output_path), exist_ok=True) |
| 79 | + plt.savefig(output_path) |
| 80 | + print(f"Graph saved to {output_path}") |
| 81 | + |
| 82 | +if __name__ == '__main__': |
| 83 | + simulate_emergence() |
0 commit comments