# server.py import http.server import socketserver import random import numpy as np from PIL import Image, ImageDraw import io import json from urllib.parse import parse_qs, urlparse import threading import time # ============== НАСТРОЙКИ ============== WORLD_SIZE = 40 CELL_SIZE = 10 MAX_CREATURES = 50 PORT = 7890 UPDATE_INTERVAL = 0.3 # ============== НЕЙРОСЕТЬ (10 входов -> 5 выходов) ============== class SimpleBrain: def __init__(self): # 10 входов (исправлено!), 5 выходов self.weights = np.random.randn(10, 5) * 0.5 self.bias = np.random.randn(5) * 0.5 def forward(self, inputs): x = np.array(inputs) output = np.tanh(np.dot(x, self.weights) + self.bias) return output def copy(self): new_brain = SimpleBrain() new_brain.weights = self.weights.copy() new_brain.bias = self.bias.copy() return new_brain def mutate(self): if random.random() < 0.2: self.weights += np.random.randn(10, 5) * 0.3 if random.random() < 0.2: self.bias += np.random.randn(5) * 0.3 # ============== СУЩЕСТВО ============== class Creature: def __init__(self, x, y, color, team): self.x = x self.y = y self.color = color self.team = team self.health = 100 self.energy = 80 self.food = 50 self.water = 50 self.resources = 0 self.age = 0 self.alive = True self.fitness = 0 self.brain = SimpleBrain() def think(self, world, creatures): # ---- ВХОДНЫЕ ДАННЫЕ (10 штук) ---- hunger = 1.0 - self.food / 100.0 thirst = 1.0 - self.water / 100.0 health = self.health / 100.0 energy = self.energy / 100.0 # Смотрим вокруг (4 направления: вверх, вниз, влево, вправо) nearby = [] for dx, dy in [(0, -1), (0, 1), (-1, 0), (1, 0)]: nx, ny = self.x + dx, self.y + dy if 0 <= nx < WORLD_SIZE and 0 <= ny < WORLD_SIZE: cell = world[nx, ny] if cell[0] == 34 and cell[1] == 139 and cell[2] == 34: # дерево nearby.append(1.0) elif cell[0] == 0 and cell[1] == 150 and cell[2] == 0: # ягоды nearby.append(2.0) elif cell[0] == 128 and cell[1] == 128 and cell[2] == 128: # камень nearby.append(0.5) else: nearby.append(0.0) else: nearby.append(0.0) # Свои и враги partners = 0 enemies = 0 for other in creatures: if other is self or not other.alive: continue dist = abs(self.x - other.x) + abs(self.y - other.y) if dist < 3: if other.team == self.team: partners = max(partners, 1.0 - dist/3.0) else: enemies = max(enemies, 1.0 - dist/3.0) # Собираем 10 входов inputs = [ hunger, # 1 thirst, # 2 health, # 3 energy, # 4 partners, # 5 enemies, # 6 nearby[0] if len(nearby) > 0 else 0.0, # 7 - вверх nearby[1] if len(nearby) > 1 else 0.0, # 8 - вниз nearby[2] if len(nearby) > 2 else 0.0, # 9 - влево nearby[3] if len(nearby) > 3 else 0.0 # 10 - вправо ] # ---- ПРЯМОЙ ПРОХОД ---- output = self.brain.forward(inputs) # ---- ДЕЙСТВИЯ ---- dx = int(round(output[0] * 2)) dy = int(round(output[1] * 2)) build = output[2] > 0.3 reproduce = output[3] > 0.5 attack = output[4] > 0.4 self.move(dx, dy) if build and self.resources >= 2: self.build(world) if reproduce and self.food > 50 and self.energy > 60: return self.reproduce(creatures) if attack: self.attack(creatures) return None def move(self, dx, dy): self.x = max(0, min(WORLD_SIZE-1, self.x + dx)) self.y = max(0, min(WORLD_SIZE-1, self.y + dy)) self.energy -= 0.3 self.food -= 0.2 self.water -= 0.1 self.age += 1 def build(self, world): self.resources -= 2 for dx, dy in [(1,0), (-1,0), (0,1), (0,-1)]: nx, ny = self.x + dx, self.y + dy if 0 <= nx < WORLD_SIZE and 0 <= ny < WORLD_SIZE: cell = world[nx, ny] if cell[0] == 100 and cell[1] == 200 and cell[2] == 100: world[nx, ny] = [139, 69, 19] self.fitness += 15 return True return False def reproduce(self, creatures): if len(creatures) >= MAX_CREATURES: return None child_brain = self.brain.copy() child_brain.mutate() child = Creature( self.x + random.randint(-2, 2), self.y + random.randint(-2, 2), self.color, self.team ) child.brain = child_brain child.food = 30 child.water = 30 child.energy = 40 self.food -= 30 self.energy -= 20 self.fitness += 25 creatures.append(child) return child def attack(self, creatures): for other in creatures: if other is not self and other.alive and other.team != self.team: dist = abs(self.x - other.x) + abs(self.y - other.y) if dist <= 1: other.health -= 15 self.energy -= 5 self.food -= 2 self.fitness += 8 return True return False def eat(self, world): cell = world[self.x, self.y] if cell[0] == 0 and cell[1] == 150 and cell[2] == 0: self.food = min(100, self.food + 30) self.health = min(100, self.health + 8) world[self.x, self.y] = [100, 200, 100] self.fitness += 12 return True elif cell[0] == 34 and cell[1] == 139 and cell[2] == 34: self.food = min(100, self.food + 15) self.health = min(100, self.health + 5) world[self.x, self.y] = [100, 200, 100] self.fitness += 8 return True return False def drink(self, world): cell = world[self.x, self.y] if cell[0] == 0 and cell[1] == 100 and cell[2] == 255: self.water = min(100, self.water + 40) self.health = min(100, self.health + 5) if random.random() < 0.3: world[self.x, self.y] = [100, 200, 100] self.fitness += 5 return True return False def collect_stone(self, world): cell = world[self.x, self.y] if cell[0] == 128 and cell[1] == 128 and cell[2] == 128: self.resources += 1 world[self.x, self.y] = [100, 200, 100] self.fitness += 10 return True return False def update(self): self.food -= 0.3 self.water -= 0.2 self.health -= 0.1 self.energy -= 0.2 if self.food <= 0: self.health -= 2 if self.water <= 0: self.health -= 1.5 if self.health <= 0 or self.energy <= 0: self.alive = False return False if self.age > 300: self.alive = False return False return True # ============== МИР ============== def create_world(): world = np.zeros((WORLD_SIZE, WORLD_SIZE, 3), dtype=np.uint8) world[:, :] = [100, 200, 100] # Деревья for _ in range(20): for _ in range(30): x, y = random.randint(0, WORLD_SIZE-1), random.randint(0, WORLD_SIZE-1) if world[x, y][0] == 100 and world[x, y][1] == 200 and world[x, y][2] == 100: world[x, y] = [34, 139, 34] break # Ягоды (еда) for _ in range(15): for _ in range(30): x, y = random.randint(0, WORLD_SIZE-1), random.randint(0, WORLD_SIZE-1) if world[x, y][0] == 100 and world[x, y][1] == 200 and world[x, y][2] == 100: world[x, y] = [0, 150, 0] break # Камни for _ in range(10): for _ in range(30): x, y = random.randint(0, WORLD_SIZE-1), random.randint(0, WORLD_SIZE-1) if world[x, y][0] == 100 and world[x, y][1] == 200 and world[x, y][2] == 100: world[x, y] = [128, 128, 128] break # Вода for _ in range(5): for _ in range(30): x, y = random.randint(0, WORLD_SIZE-1), random.randint(0, WORLD_SIZE-1) if world[x, y][0] == 100 and world[x, y][1] == 200 and world[x, y][2] == 100: world[x, y] = [0, 100, 255] break creatures = [] # Красные for i in range(3): creatures.append(Creature(5 + i*2, 5 + i*2, [255, 50, 50], "red")) # Синие for i in range(3): creatures.append(Creature(WORLD_SIZE-5 - i*2, WORLD_SIZE-5 - i*2, [50, 50, 255], "blue")) # Золотые for i in range(2): creatures.append(Creature(WORLD_SIZE//2 + i*2, WORLD_SIZE//2 + i*2, [255, 215, 0], "gold")) return world, creatures # ============== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ============== world, creatures = create_world() step_counter = 0 # ============== СИМУЛЯЦИЯ ============== def simulate_step(): global world, creatures, step_counter new_creatures = [] for creature in creatures[:]: if not creature.alive: continue creature.eat(world) creature.drink(world) creature.collect_stone(world) child = creature.think(world, creatures) if child: new_creatures.append(child) if not creature.update(): creature.alive = False world[creature.x, creature.y] = [200, 100, 100] creatures.extend(new_creatures) creatures = [c for c in creatures if c.alive] # Восстановление ягод if step_counter % 5 == 0: for _ in range(2): for _ in range(20): x, y = random.randint(0, WORLD_SIZE-1), random.randint(0, WORLD_SIZE-1) if world[x, y][0] == 100 and world[x, y][1] == 200 and world[x, y][2] == 100: world[x, y] = [0, 150, 0] break # Отбор if len(creatures) > MAX_CREATURES: creatures.sort(key=lambda c: c.fitness, reverse=True) for c in creatures[MAX_CREATURES:]: c.alive = False creatures = [c for c in creatures if c.alive] step_counter += 1 def render_world(): img = Image.new('RGB', (WORLD_SIZE * 12, WORLD_SIZE * 12 + 60), (30, 30, 30)) draw = ImageDraw.Draw(img) for i in range(WORLD_SIZE): for j in range(WORLD_SIZE): x, y = i * 12, j * 12 draw.rectangle([x, y, x + 12, y + 12], fill=tuple(world[i, j].tolist())) for creature in creatures: if not creature.alive: continue x, y = creature.x * 12, creature.y * 12 draw.ellipse([x+2, y+2, x+10, y+10], fill=tuple(creature.color), outline=(255,255,255)) hw = int((creature.health / 100) * 10) fw = int((creature.food / 100) * 10) ww = int((creature.water / 100) * 10) draw.rectangle([x+1, y-4, x + hw, y-2], fill=(255, 0, 0)) draw.rectangle([x+1, y-2, x + fw, y], fill=(255, 165, 0)) draw.rectangle([x+1, y, x + ww, y+2], fill=(0, 200, 255)) y_offset = WORLD_SIZE * 12 + 10 red = sum(1 for c in creatures if c.alive and c.team == "red") blue = sum(1 for c in creatures if c.alive and c.team == "blue") gold = sum(1 for c in creatures if c.alive and c.team == "gold") trees = sum(1 for i in range(WORLD_SIZE) for j in range(WORLD_SIZE) if world[i, j][0] == 34 and world[i, j][1] == 139 and world[i, j][2] == 34) foods = sum(1 for i in range(WORLD_SIZE) for j in range(WORLD_SIZE) if world[i, j][0] == 0 and world[i, j][1] == 150 and world[i, j][2] == 0) stones = sum(1 for i in range(WORLD_SIZE) for j in range(WORLD_SIZE) if world[i, j][0] == 128 and world[i, j][1] == 128 and world[i, j][2] == 128) best = max([c.fitness for c in creatures if c.alive] + [0]) draw.text([10, y_offset], f"Шаг: {step_counter} | Существ: {len(creatures)}", fill=(255,255,255)) draw.text([10, y_offset + 20], f"🔴: {red} | 🔵: {blue} | 🟡: {gold}", fill=(255,255,255)) draw.text([10, y_offset + 40], f"🌳: {trees} | 🫐: {foods} | 🪨: {stones} | ⭐: {best}", fill=(255,255,255)) return img # ============== ПОТОК СИМУЛЯЦИИ ============== def simulation_loop(): while True: try: simulate_step() time.sleep(UPDATE_INTERVAL) except Exception as e: print(f"Ошибка в симуляции: {e}") time.sleep(1) # ============== HTTP СЕРВЕР ============== HTML_TEMPLATE = """