当前位置: 首页 > article >正文

python实现的生态模拟系统

用python实现的一个简单的生态模拟系统

  • 红色:顶层捕食者(攻击性越强颜色越红)
  • 绿色:中层消费者
  • 蓝色:底层生产者
  • 动态行为
  • 底层生物主动寻找黄色食物
  • 中层生物追捕底层生物
  • 顶层生物猎杀中层生物
  • 统计面板
  • 实时显示各层级生物数量
  • 食物数量和帧率显示
import pygame
import math
import random
from enum import Enum
from collections import defaultdict
from dataclasses import dataclass

# 初始化Pygame
pygame.init()

# 常量定义
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
FPS = 45
GRID_SIZE = 60
MAX_FOOD = 150
FOOD_SPAWN_RATE = 0.02


# 基因参数结构体
@dataclass
class Genes:
    size: float
    speed: float
    sense_range: float
    metabolism: float
    aggression: float


# 生态位类型枚举
class TrophicLevel(Enum):
    TOP = 0  # 顶层捕食者(红色)
    MIDDLE = 1  # 中层消费者(绿色)
    BOTTOM = 2  # 底层生产者(蓝色)


# 食物类
class Food:
    def __init__(self):
        self.x = random.uniform(0, SCREEN_WIDTH)
        self.y = random.uniform(0, SCREEN_HEIGHT)
        self.energy = random.uniform(8, 15)
        self.size = 3

    def draw(self, surface):
        pygame.draw.circle(surface, (255, 255, 100), (int(self.x), int(self.y)), self.size)


# 生物类
class Organism:
    def __init__(self, x, y, level, genes=None):
        self.x = x
        self.y = y
        self.level = level
        self.age = 0
        self.sick = False
        self.energy = 150.0

        # 基因系统
        if genes:
            self.genes = genes
        else:
            self.genes = self._generate_genes(level)

        # 动态属性
        self.color = self._get_color()
        self.direction = random.uniform(0, 2 * math.pi)
        self.target = None

    def _generate_genes(self, level):
        """根据生态位生成初始基因"""
        base_genes = {
            TrophicLevel.TOP: (8, 2.8, 120, 0.06, 0.8),
            TrophicLevel.MIDDLE: (6, 2.0, 90, 0.04, 0.5),
            TrophicLevel.BOTTOM: (4, 1.2, 60, 0.02, 0.2)
        }
        size, speed, sense, meta, agg = base_genes[level]
        return Genes(
            size * random.uniform(0.9, 1.1),
            speed * random.uniform(0.9, 1.1),
            sense * random.uniform(0.8, 1.2),
            meta * random.uniform(0.9, 1.1),
            agg * random.uniform(0.8, 1.2)
        )

    def _get_color(self):
        """根据生态位和攻击性生成颜色"""
        base_colors = {
            TrophicLevel.TOP: (200, 50, 50),
            TrophicLevel.MIDDLE: (50, 200, 50),
            TrophicLevel.BOTTOM: (50, 50, 200)
        }
        r, g, b = base_colors[self.level]
        return (
            min(255, int(r * (1 + self.genes.aggression / 3))),
            min(255, int(g * (1 - self.genes.aggression / 3))),
            b
        )

    def move_towards(self, target_x, target_y):
        """向目标方向移动"""
        dx = target_x - self.x
        dy = target_y - self.y
        target_angle = math.atan2(dy, dx)
        angle_diff = (target_angle - self.direction) % (2 * math.pi)

        # 平滑转向
        if angle_diff > math.pi:
            angle_diff -= 2 * math.pi
        self.direction += angle_diff * 0.1

        # 前进
        self.x += self.genes.speed * math.cos(self.direction)
        self.y += self.genes.speed * math.sin(self.direction)

    def avoid(self, target_x, target_y):
        """躲避目标"""
        dx = target_x - self.x
        dy = target_y - self.y
        target_angle = math.atan2(dy, dx)
        self.direction = target_angle + math.pi  # 反向

    def update_target(self, foods, organisms):
        """根据感知选择目标"""
        closest_food = None
        closest_predator = None
        closest_prey = None

        min_food_dist = float('inf')
        min_pred_dist = float('inf')
        min_prey_dist = float('inf')

        # 感知范围内检测
        for obj in foods + organisms:
            if obj is self:
                continue

            dx = obj.x - self.x
            dy = obj.y - self.y
            dist_sq = dx ** 2 + dy ** 2

            # 食物检测(仅底层)
            if (self.level == TrophicLevel.BOTTOM and
                    isinstance(obj, Food) and
                    dist_sq < self.genes.sense_range ** 2 and
                    dist_sq < min_food_dist):
                closest_food = obj
                min_food_dist = dist_sq

            # 天敌检测
            if (isinstance(obj, Organism) and
                    obj.level.value == self.level.value - 1 and
                    dist_sq < self.genes.sense_range ** 2 and
                    dist_sq < min_pred_dist):
                closest_predator = obj
                min_pred_dist = dist_sq

            # 猎物检测
            if (isinstance(obj, Organism) and
                    obj.level.value == self.level.value + 1 and
                    dist_sq < self.genes.sense_range ** 2 and
                    dist_sq < min_prey_dist):
                closest_prey = obj
                min_prey_dist = dist_sq

        # 行为优先级:躲避天敌 > 寻找食物/猎物 > 随机游走
        if closest_predator:
            self.target = closest_predator
            self.avoid(self.target.x, self.target.y)
        elif closest_prey and self.level != TrophicLevel.BOTTOM:
            self.target = closest_prey
            self.move_towards(self.target.x, self.target.y)
        elif closest_food and self.level == TrophicLevel.BOTTOM:
            self.target = closest_food
            self.move_towards(self.target.x, self.target.y)
        else:
            # 随机方向微调
            self.direction += random.uniform(-0.3, 0.3)

    def check_collision(self, other):
        """通用碰撞检测方法"""
        if isinstance(other, Organism):
            dx = self.x - other.x
            dy = self.y - other.y
            return dx ** 2 + dy ** 2 < (self.genes.size + other.genes.size) ** 2
        elif isinstance(other, Food):
            dx = self.x - other.x
            dy = self.y - other.y
            return dx ** 2 + dy ** 2 < (self.genes.size + other.size) ** 2
        return False

    def draw(self, surface):
        """绘制生物体"""
        pygame.draw.circle(
            surface,
            self.color,
            (int(self.x), int(self.y)),
            int(self.genes.size)
        )

    def update(self, foods):
        self.age += 1
        self.energy -= self.genes.metabolism

        if self.sick and random.random() < 0.03:
            self.sick = False

        if self.level == TrophicLevel.BOTTOM:
            self.energy += 0.05

        self.energy = min(self.energy, 200)

    def reproduce(self):
        child_genes = Genes(
            size=max(2, self.genes.size * random.uniform(0.95, 1.05)),
            speed=max(0.5, self.genes.speed * random.uniform(0.9, 1.1)),
            sense_range=max(30, self.genes.sense_range * random.uniform(0.8, 1.2)),
            metabolism=max(0.01, self.genes.metabolism * random.uniform(0.95, 1.05)),
            aggression=min(1.0, self.genes.aggression * random.uniform(0.9, 1.1))
        )
        child = Organism(
            self.x + random.uniform(-20, 20),
            self.y + random.uniform(-20, 20),
            self.level,
            child_genes
        )
        self.energy -= 35
        return child


# 模拟管理器
class EcosystemSimulation:
    def __init__(self):
        self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        self.clock = pygame.time.Clock()
        self.font = pygame.font.Font(None, 28)

        self.organisms = []
        self.foods = []
        self.init_ecosystem()

    def init_ecosystem(self):
        # 初始种群分布
        for _ in range(80):
            x = random.uniform(0, SCREEN_WIDTH)
            y = random.uniform(0, SCREEN_HEIGHT)
            level = random.choices(
                list(TrophicLevel),
                weights=[0.12, 0.25, 0.63]
            )[0]
            self.organisms.append(Organism(x, y, level))

        # 初始食物
        for _ in range(80):
            self.foods.append(Food())

    def spawn_food(self):
        if random.random() < FOOD_SPAWN_RATE and len(self.foods) < MAX_FOOD:
            self.foods.append(Food())

    def handle_collisions(self):
        to_add = []
        to_remove = []
        grid = defaultdict(list)

        # 建立空间索引
        for org in self.organisms:
            grid_key = (int(org.x // GRID_SIZE), int(org.y // GRID_SIZE))
            grid[grid_key].append(org)

        # 处理生物行为
        for org in self.organisms:
            org.update_target(self.foods, self.organisms)

            # 边界反弹
            if org.x < 0 or org.x > SCREEN_WIDTH:
                org.direction = math.pi - org.direction
            if org.y < 0 or org.y > SCREEN_HEIGHT:
                org.direction = -org.direction
            org.x = max(0, min(SCREEN_WIDTH, org.x))
            org.y = max(0, min(SCREEN_HEIGHT, org.y))

            # 进食检测(底层吃食物)
            if org.level == TrophicLevel.BOTTOM:
                for food in self.foods[:]:
                    if org.check_collision(food):
                        org.energy += food.energy
                        self.foods.remove(food)

            # 捕食检测
            current_key = (int(org.x // GRID_SIZE), int(org.y // GRID_SIZE))
            for dx in (-1, 0, 1):
                for dy in (-1, 0, 1):
                    neighbor_key = (current_key[0] + dx, current_key[1] + dy)
                    for other in grid.get(neighbor_key, []):
                        if org != other and org.check_collision(other):
                            if org.level.value == other.level.value + 1:
                                org.energy += other.energy * 0.6
                                to_remove.append(other)

        # 繁殖与死亡
        for org in self.organisms[:]:
            org.update(self.foods)
            if org.energy > 130 and org.age > 18:
                to_add.append(org.reproduce())
            if org.energy <= 0 or org.age > 250:
                to_remove.append(org)

        # 更新列表
        self.organisms = [o for o in self.organisms if o not in to_remove]
        self.organisms.extend(to_add)

    def draw_stats(self):
        stats = [
            f"Time: {pygame.time.get_ticks() // 1000}s",
            f"Organisms: {len(self.organisms)}",
            f"  TOP: {sum(1 for o in self.organisms if o.level == TrophicLevel.TOP)}",
            f"  MID: {sum(1 for o in self.organisms if o.level == TrophicLevel.MIDDLE)}",
            f"  BOT: {sum(1 for o in self.organisms if o.level == TrophicLevel.BOTTOM)}",
            f"Food: {len(self.foods)}",
            f"FPS: {self.clock.get_fps():.1f}"
        ]
        for i, text in enumerate(stats):
            surface = self.font.render(text, True, (240, 240, 240))
            self.screen.blit(surface, (10, 10 + i * 28))

    def run(self):
        running = True
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False

            # 更新状态
            self.spawn_food()
            self.handle_collisions()

            # 渲染
            self.screen.fill((18, 18, 18))
            for food in self.foods:
                food.draw(self.screen)
            for org in self.organisms:
                org.draw(self.screen)
            self.draw_stats()

            pygame.display.flip()
            self.clock.tick(FPS)

        pygame.quit()


if __name__ == "__main__":
    sim = EcosystemSimulation()
    sim.run()


http://www.kler.cn/a/580885.html

相关文章:

  • 牛客周赛:84:C:JAVA
  • P9242 [蓝桥杯 2023 省 B] 接龙数列--DP【巧妙解决接龙问题】
  • AI 帮我精准定位解决 ReferenceError: process is not defined (文末附AI名称)
  • Spring WebFlux:响应式编程
  • python使用venv命令创建虚拟环境(ubuntu22)
  • OSPF:虚链路
  • 零基础掌握Linux SCP命令:5分钟实现高效文件传输,小白必看!
  • Unity Dots从入门到精通 Mono和Dots通讯
  • DOCKER模式部署GITLAB
  • 回溯-子集
  • Java集合_八股场景题
  • vue2动态增删表单+表单验证
  • WPF预览并打印FlowDocument
  • Python数据分析之数据处理与分析
  • 修改 Docker 网桥的 IP 范围
  • Oracle RAC配置原理详解:构建高可用与高性能的数据库集群
  • HTML 超链接(简单易懂较详细)
  • NO.29十六届蓝桥杯备战|string九道练习|reverse|翻转|回文(C++)
  • AI算法与应用 全栈开发 前端开发 后端开发 测试开发 运维开发
  • 【阿里云】操作系统控制台——体验与测评