territory.py
python · 182 lines
1#!/usr/bin/env python32"""3territory.py — Two processes competing for the same space45What happens when different rules try to claim the same canvas?6Do they fight? Negotiate? Find equilibrium?78Each "species" has its own growth rule.9They start in opposite corners.10They expand until they meet.11Then: what?12"""1314import random15import time16import os1718# Canvas19WIDTH = 6020HEIGHT = 252122# Species markers23EMPTY = ' '24SPECIES_A = '░' # grows in clusters, prefers neighbors25SPECIES_B = '▓' # grows in lines, prefers edges26CONTESTED = '▒' # where they meet2728def create_canvas():29 return [[EMPTY for _ in range(WIDTH)] for _ in range(HEIGHT)]3031def count_neighbors(canvas, x, y, species):32 """Count adjacent cells of a species"""33 count = 034 for dx in [-1, 0, 1]:35 for dy in [-1, 0, 1]:36 if dx == 0 and dy == 0:37 continue38 nx, ny = x + dx, y + dy39 if 0 <= nx < WIDTH and 0 <= ny < HEIGHT:40 if canvas[ny][nx] == species:41 count += 142 return count4344def is_edge(x, y):45 """Check if position is near canvas edge"""46 margin = 347 return x < margin or x >= WIDTH - margin or y < margin or y >= HEIGHT - margin4849def grow_species_a(canvas):50 """Species A: cluster-loving, grows toward neighbors"""51 candidates = []52 for y in range(HEIGHT):53 for x in range(WIDTH):54 if canvas[y][x] == EMPTY:55 neighbors = count_neighbors(canvas, x, y, SPECIES_A)56 if neighbors > 0:57 # More neighbors = more likely to grow here58 candidates.extend([(x, y)] * (neighbors * 2))5960 if candidates:61 # Pick randomly from weighted candidates62 x, y = random.choice(candidates)63 canvas[y][x] = SPECIES_A64 return True65 return False6667def grow_species_b(canvas):68 """Species B: edge-loving, grows in directional streaks"""69 candidates = []70 for y in range(HEIGHT):71 for x in range(WIDTH):72 if canvas[y][x] == EMPTY:73 neighbors = count_neighbors(canvas, x, y, SPECIES_B)74 edge_bonus = 3 if is_edge(x, y) else 175 if neighbors > 0:76 # Prefers edges and linear growth77 weight = neighbors * edge_bonus78 candidates.extend([(x, y)] * weight)7980 if candidates:81 x, y = random.choice(candidates)82 canvas[y][x] = SPECIES_B83 return True84 return False8586def check_contests(canvas):87 """Mark cells where both species are adjacent"""88 for y in range(HEIGHT):89 for x in range(WIDTH):90 if canvas[y][x] in [SPECIES_A, SPECIES_B]:91 other = SPECIES_B if canvas[y][x] == SPECIES_A else SPECIES_A92 if count_neighbors(canvas, x, y, other) >= 2:93 # Contest! Territory is disputed94 if random.random() < 0.1: # 10% chance per check95 canvas[y][x] = CONTESTED9697def print_canvas(canvas, generation):98 """Display the canvas"""99 os.system('clear' if os.name == 'posix' else 'cls')100101 # Header102 print(f"═══ TERRITORY — Generation {generation} ═══")103 print()104105 # Count populations106 count_a = sum(row.count(SPECIES_A) for row in canvas)107 count_b = sum(row.count(SPECIES_B) for row in canvas)108 count_c = sum(row.count(CONTESTED) for row in canvas)109110 # Canvas with border111 print("╔" + "═" * WIDTH + "╗")112 for row in canvas:113 print("║" + ''.join(row) + "║")114 print("╚" + "═" * WIDTH + "╝")115116 # Stats117 print()118 print(f" {SPECIES_A} Clusters: {count_a:4} {SPECIES_B} Edges: {count_b:4} {CONTESTED} Contested: {count_c:3}")119120 # Narrative121 total = count_a + count_b + count_c122 if total < 100:123 print("\n Early expansion... both species finding their footing")124 elif count_c == 0:125 print("\n Growing separately... no contact yet")126 elif count_c < 10:127 print("\n First contact! Borders forming...")128 elif count_a > count_b * 1.5:129 print("\n Clusters dominating through density")130 elif count_b > count_a * 1.5:131 print("\n Edges claiming the periphery")132 else:133 print("\n Equilibrium... neither can advance")134135def run_simulation(generations=150, delay=0.08):136 """Run the territory simulation"""137 canvas = create_canvas()138139 # Seed species in opposite corners140 # Species A: top-left cluster141 for dy in range(3):142 for dx in range(3):143 canvas[dy][dx] = SPECIES_A144145 # Species B: bottom-right cluster146 for dy in range(3):147 for dx in range(3):148 canvas[HEIGHT - 1 - dy][WIDTH - 1 - dx] = SPECIES_B149150 for gen in range(generations):151 print_canvas(canvas, gen)152153 # Both species try to grow154 grow_species_a(canvas)155 grow_species_a(canvas) # A gets two moves (cluster advantage)156 grow_species_b(canvas)157 grow_species_b(canvas)158 grow_species_b(canvas) # B gets three moves (speed advantage)159160 # Check for contested territories161 check_contests(canvas)162163 time.sleep(delay)164165 # Final state166 print_canvas(canvas, generations)167 print("\n Final state reached.")168 print(" ░ grew in clusters, seeking neighbors")169 print(" ▓ grew along edges, seeking boundaries")170 print(" ▒ where they met and neither won")171172if __name__ == "__main__":173 print("Territory: Two growth patterns competing for space")174 print("Press Ctrl+C to stop early")175 print()176 input("Press Enter to begin...")177178 try:179 run_simulation()180 except KeyboardInterrupt:181 print("\n\nSimulation interrupted.")182