Механизированный симулятор эволюции
Механизированный симулятор эволюции — другой взгляд на тему, которая уже много времени будоражит мозги великих деятелей науки. Другой по той причине, что уже есть эта игра, для игры в которую не нужно копировать код. С другой стороны её аффтор забил на неё.
Геймплей[править]
Ваша задача — выиграть. Это можно сделать, набрав максимум очков. (Если что, y = yes, n = no)
Подготовка[править]
Сначала игра спрашивает, сколько ходов вы хотите. Оптимально 3–7. Если ввести 100, игра не сломается, но вы — да.
Потом спрашивают количество ботов от 0 до 10. Если 0 — вы играете сами с собой, что символично. Если 10 — вы играете против десяти гениев, которые к третьему ходу создадут больше видов, чем существует в реальной зоологии.
Уровни ботов:
Минимальный — бот-овощ. Ничего не делает, но существует.
Простой — иногда что-то делает, но без огонька.
Средний — уже начинает шевелиться.
Сложный — плодится и мигрирует.
Максимальный — создаёт дохрена видов за ход. Возможно, вы будете первым человеком, выигравшим в битве с ним на время > 5 ходов.
Существа[править]
У каждого вида есть размер, популяция, интеллект, скорость, вооружение, защита, маскировка, обзор, хищность и зона.
Максимальная популяция зависит от размера: чем ты больше, тем меньше вас влезает в экосистему. Размер 1 — 1024 особи, размер 10 — 2 особи. То есть гигантизм — это и эволюционный успех, и демографическая ошибка.
Травоядные плодятся сами: мелкие быстро, крупные медленно. Хищники плодятся, только если пожрут. Если хищник не пожрал — population = 0. Без права на пересдачу.
Маскировка зависит от размера: мелкие хорошо прячутся, крупные — плохо. Потому что слона не видно, только если он стоит в Эрмитаже.
Экосистемы[править]
Есть семь зон: мелководье, глубоководье, реки, болота, леса, степи, пустыни. Они соединены так, что из пустыни можно прийти в реки, леса и степи. Так что в пустыне, видимо, растут леса. Не спрашивайте как.
Охота возможна только внутри одной зоны. Если ты в глубоководье, а еда на мелководье, ты можешь только смотреть и грустить.
При миграции игра показывает ASCII-арт зоны. Выглядит так, будто по клавиатуре играли как на рояле.
Ход[править]
Боты создают новые виды. Чем выше уровень, тем БОЛЬШЕ.
Игрок создаёт новые виды. Если у вида популяция ≥ 2, можно отщипнуть две особи и получить новый вид с популяцией 1. Это называется «эволюция», а по сути — почкование с потерей численности.
Миграция. Можно переселить вид в соседнюю зону и получить новую картинку.
Смена статуса. Со второго хода можно стать хищником. Или перестать. Или снова стать. Никто не запрещает быть хищником-травоядным-хищником, как в жизни.
Карты. Игроку дают 2–5 карт. Среди них могут быть: «Увеличение размера», «Когти», «Панцирь», «Крылья», «Мозговые извилины», «Очень быстрое размножение» (+70 популяции, −4 размера), «Обжорство» (+3 размер, +5 броня, −4 скорость, −3 интеллект). Если отказаться — дают +1 популяцию. Отказ от карты — тоже карта, но для бедных.
Боты просто жмут случайно, как кот по клавиатуре.
Охота[править]
Хищник выбирает жертву. Игрок тыкает номер бота и вида. Бот выбирает случайно.
Перед охотой можно использовать интеллект: временно ослабить жертву по обзору, скорости, вооружению и защите. Интеллект — это не чтобы думать, а чтобы делать другим хуже.
Условия успешной охоты:
зона совпадает;
зрение хищника ≥ маскировки жертвы;
зрение жертвы ≤ маскировки хищника;
скорость хищника > скорости жертвы;
вооружение × размер ≥ защита × размер жертвы;
вооружение жертвы × размер ≤ защита × размер хищника.
Если всё ок — хищник съедает до своей популяции особей жертвы и столько же прибавляет себе. Если три попытки провалились — хищник умирает от голода. Три промаха, и ты труп. Естественный отбор, детка.
Финал[править]
Очки считаются так: размер × популяция + интеллект. Хищникам бонус: +25 при размере 1–5, +50 при размере 6–10. Победитель — у кого больше.
Если игрок проиграл, игра пишет: «Не печальтесь, в следующий раз вы учтёте ошибки и выиграете». Это ложь, но приятная.
Стратегии для одного вида[править]
Стать хищником и жрать всех. Но если промахнулся — умри.
Стать травоядным и размножаться до 1024. Потом тебя съедают, но ты был плодовит.
Качать интеллект и унижать жертву перед охотой. Это не интеллект, это токсичность.
Мигрировать в пустыню. Там никто не живёт, кроме тебя и кактуса.
Создавать новые виды, пока таблица не перестанет влезать в экран. Вы скоро запутаетесь с видами и будете тыкать наугад
Интересные факты[править]
Графика в этой игре вроде-бы есть, но это высказывание натянуто за уши.
Карта «Очень быстрое размножение» даёт +70 популяции и −4 размера. После неё ты не вид, а облако мошек.
«Обжорство» даёт +5 защиты и −4 скорости. Ты превращаешься в бронированную подушку, которую никто не хочет есть, но и ты никого не догонишь.
В коде пустыни соединены с лесами. Так что в пустыне растут леса. Не спрашивайте.
Если все ваши виды вымерли, игра выходит. Это не баг, это ускоренная эволюция.
Код игры[править]
import random
import sys
# ---------- Константы экосистем ----------
ZONES = ["shallow", "deep", "rivers", "swamps", "forests", "steppes", "deserts"]
ZONE_NAMES_RU = {
"shallow": "Мелководье",
"deep": "Глубоководье",
"rivers": "Реки",
"swamps": "Болота",
"forests": "Леса",
"steppes": "Степи",
"deserts": "Пустыни"
}
ZONE_CONNECTIONS = {
"shallow": ["deep", "rivers"],
"deep": ["shallow"],
"rivers": ["shallow", "swamps", "deserts"],
"swamps": ["rivers", "forests", "steppes"],
"forests": ["swamps", "deserts"],
"steppes": ["swamps", "deserts"],
"deserts": ["rivers", "forests", "steppes"]
}
# ---------- Ввод количества ходов ----------
turns = int(input("Сколько ходов должна длиться игра (оптимально 3–7): "))
# ---------- Ввод количества ботов и их уровней сложности ----------
while True:
try:
num_bots = int(input("Введите количество ботов (0–10): "))
if 0 <= num_bots <= 10:
break
else:
print("Число должно быть от 0 до 10.")
except ValueError:
print("Введите целое число.")
LEVEL_NAMES = {
1: "Минимальный",
2: "Простой",
3: "Средний",
4: "Сложный",
5: "Максимальный"
}
LEVEL_PARAMS = {
1: (None, None, 0, 0),
2: (3, 4, 1, 1),
3: (2, 3, 1, 5),
4: (1, 2, 1, 15),
5: (1, 1, None, None)
}
bot_configs = []
for i in range(num_bots):
print(f"\nБот {i+1}:")
while True:
choice = input("Выберите уровень сложности (1-Минимальный, 2-Простой, 3-Средний, 4-Сложный, 5-Максимальный), по умолчанию 2: ").strip()
if choice == "":
level = 2
break
try:
level = int(choice)
if 1 <= level <= 5:
break
else:
print("Введите число от 1 до 5.")
except ValueError:
print("Введите число.")
if level == 1:
counter = 0
elif level == 5:
counter = 1
else:
interval_min, interval_max, _, _ = LEVEL_PARAMS[level]
counter = random.randint(interval_min, interval_max)
bot_configs.append({
'level': level,
'counter': counter
})
# ---------- Классы ----------
class Creature:
def __init__(self, name="Существо", zone="shallow"):
self.name = name
self.size = 1
self.population = 1
self.intelligence = 1
self.speed = 1
self.weapons = 1
self.armor = 1
self.camouflage = 1
self.vision = 1
self.is_predator = False
self.zone = zone
def is_alive(self):
return self.population > 0
def max_population(self):
return 1024 // (2 ** (self.size - 1))
def growth_rate(self):
size = self.size
if size == 1:
return 10
elif size == 2:
return 8
elif size == 3:
return 6
elif size == 4:
return 4
elif size == 5:
return 3
elif size == 6:
return 2
else:
return 1
def max_camouflage(self):
return max(1, 11 - self.size)
def clamp_camouflage(self):
max_c = self.max_camouflage()
if self.camouflage > max_c:
self.camouflage = max_c
def apply_effects(self, effects):
for attr, delta in effects.items():
if hasattr(self, attr) and attr != 'is_predator' and attr != 'zone':
current = getattr(self, attr)
new_val = current + delta
if attr == 'population':
self.add_population(delta)
elif attr == 'size':
new_val = max(1, min(10, new_val))
setattr(self, attr, new_val)
self.clamp_camouflage()
elif attr == 'camouflage':
max_c = self.max_camouflage()
new_val = max(1, min(max_c, new_val))
setattr(self, attr, new_val)
else:
new_val = max(1, min(10, new_val))
setattr(self, attr, new_val)
def add_population(self, delta):
new_val = self.population + delta
max_pop = self.max_population()
new_val = max(0, min(max_pop, new_val))
self.population = new_val
def total_score(self):
return (self.size * self.population) + self.intelligence
def final_score(self):
base = self.total_score()
if self.is_predator:
if self.size <= 5:
base += 25
else:
base += 50
return base
def __str__(self):
status = "Хищник" if self.is_predator else "Травоядное"
alive = "жив" if self.is_alive() else "ВЫМЕР"
zone_ru = ZONE_NAMES_RU.get(self.zone, self.zone)
return (f"{self.name} ({status}, {alive}, зона={zone_ru}): "
f"Размер={self.size}, Популяция={self.population}, "
f"Интеллект={self.intelligence}, Скорость={self.speed}, "
f"Вооружение={self.weapons}, Защита={self.armor}, "
f"Маскировка={self.camouflage}, Обзор={self.vision}")
class Card:
def __init__(self, name, effects):
self.name = name
self.effects = effects
def apply(self, creature):
creature.apply_effects(self.effects)
def __str__(self):
return self.name
# ---------- Пул карт ----------
def create_card_pool():
base_pool = [
Card("Увеличение размера", {"size": 1}),
Card("Увеличение популяции", {"population": 3}),
Card("Когти", {"weapons": 2, "speed": -1}),
Card("Панцирь", {"armor": 3, "speed": -2}),
Card("Крылья", {"speed": 4, "size": -1}),
Card("Камуфляж", {"camouflage": 2}),
Card("Острое зрение", {"vision": 2}),
Card("Мозговые извилины", {"intelligence": 2}),
Card("Рога", {"weapons": 1, "armor": 1, "speed": -1}),
Card("Шипы", {"armor": 1, "weapons": 1, "speed": -1}),
Card("Ядовитые зубы", {"weapons": 2}),
Card("Толстая кожа", {"armor": 2, "speed": -1}),
]
new_cards = [
Card("Быстрое размножение", {"population": 3, "size": -1}),
Card("Очень быстрое размножение", {"population": 70, "size": -4}),
Card("Грива", {"armor": 2, "speed": -1}),
Card("Развитый мозг", {"intelligence": 2}),
Card("Острые когти", {"weapons": 2, "speed": -1}),
Card("Длинные ноги", {"speed": 1, "size": 1}),
Card("Засада", {"camouflage": 3, "population": -1}),
Card("Эхолокация", {"vision": 2, "intelligence": 1}),
Card("Ядовитые шипы", {"weapons": 1, "armor": 1}),
Card("Крепкий скелет", {"size": 1, "armor": 1}),
Card("Повышенная плодовитость", {"population": 3, "size": -1}),
Card("Создание орудий труда", {"intelligence": 2, "speed": -1, "weapons": 2}),
Card("Ночное зрение", {"vision": 2}),
Card("Терморегуляция", {"size": 1, "speed": 1}),
Card("Совершенные органы чувств", {"vision": 2}),
Card("Социальность", {"population": 2, "intelligence": 1}),
Card("Хищнические инстинкты", {"weapons": 2, "speed": 1}),
Card("Защитная окраска", {"camouflage": 2}),
Card("Мускулистость", {"speed": 2, "weapons": 1, "size": 1}),
Card("Регенерация", {"armor": 2, "population": 1}),
Card("Симбиоз", {"population": 1, "camouflage": 1}),
Card("Стратегическое мышление", {"intelligence": 3, "speed": -2}),
Card("Сверхчувствительность", {"vision": 3}),
Card("Токсичная кровь", {"armor": 1}),
Card("Колючки", {"armor": 2, "speed": -1}),
Card("Карликовость", {"size": -3, "population": 2}),
Card("Гигантизм", {"size": 2, "population": -1}),
Card("Использование чужих раковин", {"size": 2, "armor": 3, "speed": -2}),
Card("Парус", {"size": 3, "armor": -1, "speed": -2}),
Card("Обжорство", {"size": 3, "armor": 5, "speed": -4, "intelligence": -3}),
Card("Сворачивание", {"size": 1, "armor": 1}),
]
return base_pool + new_cards
def random_card(pool):
return random.choice(pool)
def generate_cards(pool, count):
return [random_card(pool) for _ in range(count)]
# ---------- Вспомогательные функции ----------
PARAM_NAMES_RU = {
"size": "Размер",
"population": "Популяция",
"intelligence": "Интеллект",
"speed": "Скорость",
"weapons": "Вооружение",
"armor": "Защита",
"camouflage": "Маскировка",
"vision": "Обзор"
}
def print_header():
print("\n" + "=" * 60)
print(" ЭВОЛЮЦИЯ: Хищники и экосистемы")
print("=" * 60)
def print_stats(all_creatures):
alive = [c for c in all_creatures if c.is_alive()]
if not alive:
print("Все существа вымерли!")
return
headers = ["Вид", "Тип", "Зона", "Размер", "Попул.", "Мозг", "Скорость", "Вооруж.", "Защит", "Маск.", "Обзор", "Сум"]
param_keys = ["size", "population", "intelligence", "speed", "weapons", "armor", "camouflage", "vision"]
rows = []
for c in alive:
type_str = "Х" if c.is_predator else "Т"
zone_ru = ZONE_NAMES_RU.get(c.zone, c.zone)[:4]
name = c.name[:20]
values = [str(getattr(c, key)) for key in param_keys]
total = str(c.total_score())
rows.append([name, type_str, zone_ru] + values + [total])
col_widths = [len(h) for h in headers]
for row in rows:
for i, cell in enumerate(row):
col_widths[i] = max(col_widths[i], len(cell))
col_widths = [w + 2 for w in col_widths]
def format_row(cells):
return "| " + " | ".join(cell.ljust(col_widths[i]) for i, cell in enumerate(cells)) + " |"
def separator():
return "+" + "+".join("-" * (w+2) for w in col_widths) + "+"
def print_header_table():
print(separator())
print(format_row(headers))
print(separator())
n = len(rows)
print("\nТекущее состояние (живые виды):")
print_header_table()
for i, row in enumerate(rows):
print(format_row(row))
row_num = i + 1
if n >= 10 and row_num != n:
if row_num % 20 == 0:
print(separator())
print_header_table()
elif row_num % 5 == 0:
print(separator())
print(separator())
def get_player_action(card, creature):
while True:
print(f"\nКарта: {card.name}")
effects_parts = []
for key, val in card.effects.items():
ru_name = PARAM_NAMES_RU.get(key, key)
sign = "+" if val >= 0 else ""
effects_parts.append(f"{ru_name}: {sign}{val}")
effects_str = ", ".join(effects_parts)
print(f"Эффекты: {effects_str}")
choice = input("Применить? (y/n): ").strip().lower()
if choice in ('y', 'n'):
return choice == 'y'
print("Введите 'y' или 'n'.")
def bot_turn_for_creature(creature, pool, card_count):
cards = generate_cards(pool, card_count)
for card in cards:
if random.random() < 0.5:
card.apply(creature)
else:
creature.add_population(1)
# ---------- Функции для интеллекта ----------
def apply_temporary_debuff(prey, allocation):
old_values = {}
for attr, amount in allocation.items():
if attr in ['vision', 'speed', 'weapons', 'armor']:
old = getattr(prey, attr)
old_values[attr] = old
new_val = max(1, old - amount)
setattr(prey, attr, new_val)
return old_values
def restore_parameters(prey, old_values):
for attr, val in old_values.items():
setattr(prey, attr, val)
def can_hunt(predator, prey):
if predator is prey:
return False
if not predator.is_alive() or not prey.is_alive():
return False
if predator.zone != prey.zone:
return False
if predator.vision < prey.camouflage:
return False
if prey.vision > predator.camouflage:
return False
if predator.speed <= prey.speed:
return False
pred_weapon_eff = predator.weapons * predator.size
prey_armor_eff = prey.armor * prey.size
prey_weapon_eff = prey.weapons * prey.size
pred_armor_eff = predator.armor * predator.size
if pred_weapon_eff < prey_armor_eff:
return False
if prey_weapon_eff > pred_armor_eff:
return False
return True
# ---------- Выбор цели для игрока ----------
def choose_prey_for_player(predator, all_creatures, player_creatures, bot_species_list):
prey_options = [c for c in all_creatures if c.is_alive() and c is not predator and c.zone == predator.zone]
if not prey_options:
print("Нет доступной добычи в вашей зоне.")
return None
print("\nДоступные цели для охоты (в вашей зоне):")
for bot_idx, bot_species in enumerate(bot_species_list, start=1):
bot_alive = [c for c in bot_species if c.is_alive() and c is not predator and c.zone == predator.zone]
if bot_alive:
print(f" Бот{bot_idx}:")
for idx, c in enumerate(bot_alive, start=1):
print(f" {bot_idx} {idx} -> {c.name} (поп.{c.population})")
player_alive = [c for c in player_creatures if c.is_alive() and c is not predator and c.zone == predator.zone]
if player_alive:
print(" Игрок:")
for idx, c in enumerate(player_alive, start=1):
print(f" И {idx} -> {c.name} (поп.{c.population})")
while True:
inp = input("Введите 'номер_бота номер_вида' (например, '1 3') или 'И номер_вида' для своего вида, или 0 для пропуска: ").strip()
if inp == '0':
return None
parts = inp.split()
if len(parts) == 2:
if parts[0].upper() == 'И':
try:
idx = int(parts[1]) - 1
if 0 <= idx < len(player_alive):
return player_alive[idx]
else:
print("Неверный номер вида игрока.")
except ValueError:
print("Введите число после 'И'.")
else:
try:
bot_num = int(parts[0]) - 1
species_idx = int(parts[1]) - 1
if 0 <= bot_num < len(bot_species_list):
bot_alive = [c for c in bot_species_list[bot_num] if c.is_alive() and c is not predator and c.zone == predator.zone]
if 0 <= species_idx < len(bot_alive):
return bot_alive[species_idx]
else:
print("Неверный номер вида для этого бота.")
else:
print("Неверный номер бота (допустимо 1..{})".format(len(bot_species_list)))
except ValueError:
print("Введите числа.")
else:
print("Введите два значения через пробел.")
# ---------- Решение бота использовать интеллект ----------
def bot_decide_intelligence(predator, prey):
if predator.intelligence <= 0:
return None
if can_hunt(predator, prey):
return None
attrs = ['vision', 'speed', 'weapons', 'armor']
import copy
test_prey = copy.copy(prey)
alloc = {}
for attr in attrs:
max_dec = getattr(test_prey, attr) - 1
dec = min(predator.intelligence, max_dec)
alloc[attr] = dec
setattr(test_prey, attr, getattr(test_prey, attr) - dec)
if can_hunt(predator, test_prey):
return alloc
else:
return None
# ---------- Фаза охоты ----------
def hunting_phase(all_creatures, player_creatures, bot_species_list):
predators = [c for c in all_creatures if c.is_alive() and c.is_predator]
random.shuffle(predators)
for predator in predators:
is_player = predator in player_creatures
if is_player:
print(f"\nХищник игрока: {predator.name} (зона {ZONE_NAMES_RU[predator.zone]})")
prey = choose_prey_for_player(predator, all_creatures, player_creatures, bot_species_list)
if prey is None:
print("Охота пропущена. Хищник умирает от голода.")
predator.population = 0
continue
else:
alive_prey = [c for c in all_creatures if c.is_alive() and c is not predator and c.zone == predator.zone]
if not alive_prey:
predator.population = 0
continue
prey = random.choice(alive_prey)
use_intel = False
allocation = {}
if is_player:
choice = input(f"Использовать интеллект ({predator.intelligence}) для ослабления {prey.name}? (y/n): ").strip().lower()
if choice == 'y' and predator.intelligence > 0:
use_intel = True
max_intel = predator.intelligence
print(f"Интеллект: {max_intel}. Распределите очки по параметрам (обзор, скорость, вооружение, защита).")
while True:
try:
inp = input("Введите четыре числа через пробел (сумма <= {}): ".format(max_intel)).strip().split()
if len(inp) != 4:
print("Нужно ровно четыре числа.")
continue
nums = [int(x) for x in inp]
if sum(nums) > max_intel:
print(f"Сумма {sum(nums)} превышает интеллект {max_intel}.")
continue
if any(n < 0 for n in nums):
print("Числа должны быть неотрицательными.")
continue
allocation = {'vision': nums[0], 'speed': nums[1], 'weapons': nums[2], 'armor': nums[3]}
break
except ValueError:
print("Введите целые числа.")
else:
alloc = bot_decide_intelligence(predator, prey)
if alloc is not None:
use_intel = True
allocation = alloc
print(f"{predator.name} использует интеллект для ослабления {prey.name}.")
old_values = {}
if use_intel and allocation:
old_values = apply_temporary_debuff(prey, allocation)
print(f"Ослабление применено: {prey.name} параметры уменьшены.")
hunt_success = False # флаг, была ли хотя бы одна успешная атака
for attempt in range(1, 4): # три попытки
if not prey.is_alive():
break
if can_hunt(predator, prey):
# Сколько особей съедает хищник (не больше, чем есть у жертвы)
eat = predator.population
if eat > prey.population:
eat = prey.population
if eat <= 0:
# Если популяция хищника = 0, он мёртв, выходим
break
prey.add_population(-eat)
predator.add_population(eat)
hunt_success = True
# Вывод сообщения об успешной охоте
if is_player:
print(f"Успешная охота! {predator.name} съедает {eat} особей {prey.name}.")
else:
print(f"{predator.name} успешно охотится на {prey.name} и съедает {eat} особей.")
else:
# Неудачная попытка (сообщение можно не выводить, чтобы не засорять, но для наглядности оставим)
if is_player:
print(f"Попытка {attempt} не удалась: {predator.name} не смог поймать {prey.name}.")
else:
# Для ботов выводим только если включена отладка, здесь пропускаем
pass
# Если ни одна атака не удалась, хищник умирает от голода
if not hunt_success and predator.is_alive():
predator.population = 0
if is_player:
print(f"{predator.name} не смог добыть пищу и вымер от голодания.")
else:
print(f"{predator.name} не смог добыть пищу и вымер.")
# Восстанавливаем параметры жертвы после ослабления (если применялось)
if old_values:
restore_parameters(prey, old_values)
def grow_herbivores(all_creatures):
for c in all_creatures:
if c.is_alive() and not c.is_predator:
c.add_population(c.growth_rate())
# ---------- Смена статуса ----------
def player_switch_predator(creature, turn, all_creatures):
if turn <= 1 or not creature.is_alive():
return
while True:
print(f"\n{creature.name}: сейчас вы {'хищник' if creature.is_predator else 'травоядное'}.")
choice = input("Хотите сменить статус? (y/n): ").strip().lower()
if choice == 'n':
break
elif choice == 'y':
if creature.is_predator:
creature.is_predator = False
print("Теперь травоядное.")
break
else:
creature.is_predator = True
print("Теперь хищник!")
break
else:
print("Введите 'y' или 'n'.")
def bot_switch_predator(creature, turn, all_creatures):
if turn <= 1 or not creature.is_alive():
return
if random.random() < 0.5:
if not creature.is_predator:
if has_any_prey(creature, all_creatures):
creature.is_predator = True
else:
creature.is_predator = False
def has_any_prey(predator, all_creatures):
for other in all_creatures:
if other is not predator and other.is_alive() and other.zone == predator.zone:
if can_hunt(predator, other):
return True
return False
# ---------- Создание новых видов ----------
def create_new_species_from_parent(parent, new_name):
if parent.population < 2:
return None
parent.add_population(-2)
child = Creature(new_name, zone=parent.zone)
for attr in ['size', 'intelligence', 'speed', 'weapons', 'armor', 'camouflage', 'vision', 'is_predator']:
setattr(child, attr, getattr(parent, attr))
child.population = 1
child.clamp_camouflage()
return child
def player_create_new_species(player_creatures):
candidates = [c for c in player_creatures if c.is_alive() and c.population >= 2]
if not candidates:
print("Нет видов с популяцией ≥ 2, нельзя создать новый вид.")
return
print("\n--- Создание новых видов (игрок) ---")
print("Введите номера видов (через пробел), из которых хотите создать по одному новому виду.")
print("Например: '1 1 3' создаст 2 вида из первого и 1 из третьего.")
print("Доступные виды:")
for i, c in enumerate(candidates, start=1):
max_new = c.population // 2
print(f"{i}. {c.name} (популяция: {c.population}, можно создать максимум {max_new})")
while True:
inp = input("Введите номера (или 0 для отмены): ").strip()
if inp == '0':
return
parts = inp.split()
if not parts:
print("Введите хотя бы одно число.")
continue
valid = True
indices = []
for p in parts:
try:
num = int(p)
if num <= 0:
print("Номера должны быть положительными.")
valid = False
break
indices.append(num)
except ValueError:
print(f"'{p}' не является числом.")
valid = False
break
if not valid:
continue
created = 0
for idx in indices:
if idx < 1 or idx > len(candidates):
print(f"Номер {idx} вне допустимого диапазона (1..{len(candidates)}), пропускаем.")
continue
parent = candidates[idx - 1]
if not parent.is_alive() or parent.population < 2:
print(f"Родитель {parent.name} уже не может дать потомство (популяция < 2), пропускаем.")
continue
new_name = f"Игрок, вид{len(player_creatures)+1}"
child = create_new_species_from_parent(parent, new_name)
if child is None:
print(f"Не удалось создать вид из {parent.name}.")
continue
player_creatures.append(child)
created += 1
print(f"Создан новый вид: {child.name} (популяция 1, унаследован от {parent.name}, зона {ZONE_NAMES_RU[child.zone]})")
print(f"Создано {created} новых видов.")
def create_new_species_for_bot(bot_species, bot_name):
candidates = [c for c in bot_species if c.is_alive() and c.population >= 2]
if not candidates:
return False
parent = random.choice(candidates)
new_name = f"{bot_name}, вид{len(bot_species)+1}"
child = create_new_species_from_parent(parent, new_name)
if child is None:
return False
bot_species.append(child)
return True
def remove_dead(species_list):
species_list[:] = [c for c in species_list if c.is_alive()]
# ---------- Миграция ----------
def print_zone_art(zone):
"""Выводит ASCII-картинку для зоны и приветствие."""
zone_ru = ZONE_NAMES_RU.get(zone, zone)
print(f"\nДобро пожаловать в {zone_ru}!\n")
if zone == "shallow":
print(" @ 𓅯 ")
print("𓇗_𓅰_/_ 𓅯")
print("^^^^^^\__𓅯 𓅯 _𓅻___")
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print(" ⬳ 𓆝 𖦹 𓆉︎ 𓆟")
print(" 𓆟 𓇗 𓆑 𓇗 𓆛 𓍼 𓆞 ")
print("__𓆨_𓇗_𓆜__𓇗𓆨___𓆟____𓇗_____𓇗__")
elif zone == "rivers":
print("█████_𓅯__//%\\\\____~~~~~~~~__")
print("████___☘__☘_𓅯__~~~~~~~~~~~~☘_")
print("^^^^\\__𓅯~~~~~𓅯~~~~~~_𓅻__𓆨___")
print("_𓆏__~~~~~~~~~~~~~~~~/_𓅟___𓅢_")
print(" ⬳ 𓆊 𓆝 𓆉︎ 𓇗 ▟████████")
print(" 𓆟 𓇗 𓆑 𓇗 𓆛 ▟███████████")
print("__𓆨_𓇗_𓆜__𓇗𓆨___▟█████████████")
elif zone == "deep":
print("⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆⛆")
print("⛆⛆⛆𓍼⛆⛆⛆𖡎⛆⛆⛆⛆ 𓆜 ⛆⛆")
print("⛆⛆⛆⛆⛆⛆𖡎⛆⛆⛆⛆⛆⛆⛆⛆𖡎⛆")
print("⛆⛆⛆⛆⛆𖡎⛆⛆⛆⛆⛆⛆⛆⛆𖡎⛆⛆")
print("⛆⛆⛆⛆𖡎⛆⛆⛆⛆⛆ 𓆜 ⛆𖡎⛆⛆")
print("⛆⛆⛆𖡎⛆⛆⛆⛆⛆⛆⛆⛆𖡎⛆⛆⛆⛆")
print("⛆⛆𖡎𓆨⛆⛆⛆⛆⛆⛆⛆𖡎⛆⛆⛆⛆⛆")
elif zone == "swamps":
print("☁☁☁☁☁☁☁☁☁☁☁☁☁☁☁☁☁")
print("⛆ލ⛆↯⛆⛆⛆ᔪ⛆⛆⛆ލ⛆⛆↯⛆⛆")
print("𖡼𖤣𖥧𖡼𓋼𖤣𖥧𓋼𓍊𖡼𖤣𖥧𖡼𓋼𖤣𖥧𓋼𓍊")
print("𓍊𓋼~𓅯 𖥧𓍊𖡼𖤣~𓍊𓋼𖥧~𓍊𖥧𖡼𖤣")
print("𓅻𓍊𓋼𓍊𓋼𓍊_𓅤_𖥧_𓆉︎_𓅻_𖥧𓅭")
print("~~𓆏~~~𖤣𖥧𓆏~~~𖤣𖥧~𓆌~")
print("𓆜/𓆝 \\/𓆜 𓆝 )/ 𓆜 ")
elif zone == "forests":
print("☁ ☁ ☁ ☁☁ ☁ ☁")
print(" 𓅯 𓅯 ⛆ᔪ 𓅯 ")
print("𖥧𖤣𖥧𖡼𓋼𖤣𖥧𓋼𓍊𖡼𖤣𖥧𖡼𓋼𖤣𖥧𓋼𓍊")
print("𖥧𓋼𓍊𖡼𓋼𖤣𖥧𓋼𓍊𖡼𖤣𖥧𖡼𓋼𖤣𖥧𓋼𓍊")
print("𖡼𓋼𖤣𖥧𓋼𓍊𖡼𖤣𖥧𖡼𓋼𖤣𖥧𓋼𓍊𖡼𖤣𖥧")
print("𖤣𖥧𖡼𓅪𖤣𖥧𓋼𓍊𓅇𖤣𖥧𖡼𓋼𖤣𖥧𓋼𓍊𖤣")
print("𓅼𖤣𖥧𓃦𓋼𖤣𖥧𓆈𓍊𖡼𖤣𖥧𓃹𓋼𖤣𖥧𓋼𓆤")
elif zone == "steppes":
print(" ☼ ")
print("༄༄༄༄༄༄༄༄༄༄༄༄༄༄༄༄༄༄")
print("◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞")
print("ᖗᖘ૬୭ໂໃໄ⌇ᖗᖘ૬୭ໄ𓃶ᖗ૬ມີເກມທີ່ດີ")
print("∭६३ᖘ૬१२𓃲५७९ϡ𓃶ᖘ૬୭ঐঙৡ∭६")
print("ໂໃໄ𓃶❀ໂᖘ૬୭ໄ𓃹ᖘ૬୭☘︎𓃶ᖘ૬୭❀𓃶")
print("𓃦∭६३𓆚∭𓃶ᖗᖘ☘︎𓃶ໃໄ⌇𓃹ᖘ૬୭☘︎𓅼")
elif zone == "deserts":
print(" ☼ ")
print("")
print("◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞◞")
print("🏜 🏜 🏜 🏜 🏜 🏜 🏜 🏜 🏜 🏜")
print("🏝 𖣂🏜 🏜 🏜 𓅇 🏜 🏝𖣂 🏜 🏜")
print("𓆱𓆱𓆱𓃲𓃲𓃲𓃲𓃲𓆱𓆱𓃹𓆱𓆱 𓆱𓃶𓆱𓆱")
print("𓆨𓆱𓆱𓆱🕷𓆱𓆱𓆱𓆨𓆱𓆱𓆱𓆱𓆱𓆱🕷𓆨")
else:
print(f"(Картинка для зоны {zone_ru} не найдена)")
def player_migration(player_creatures):
alive = [c for c in player_creatures if c.is_alive()]
if not alive:
return
print("\n--- Миграция видов (игрок) ---")
print("Вы можете переселить некоторые виды в соседние экосистемы.")
print("Введите номера видов (через пробел), которые хотите передвигать, или 0 для пропуска.")
for i, c in enumerate(alive, start=1):
zone_ru = ZONE_NAMES_RU.get(c.zone, c.zone)
print(f"{i}. {c.name} (зона: {zone_ru}, популяция: {c.population})")
while True:
inp = input("Введите номера (или 0 для завершения): ").strip()
if inp == '0':
return
parts = inp.split()
if not parts:
print("Введите номера.")
continue
indices = []
try:
for p in parts:
num = int(p)
if num <= 0:
print("Номера должны быть положительными.")
raise ValueError
indices.append(num)
except ValueError:
continue
for idx in indices:
if idx < 1 or idx > len(alive):
print(f"Номер {idx} вне диапазона, пропускаем.")
continue
creature = alive[idx - 1]
zone_ru = ZONE_NAMES_RU.get(creature.zone, creature.zone)
neighbors = ZONE_CONNECTIONS.get(creature.zone, [])
if not neighbors:
print(f"У зоны {zone_ru} нет соседей, миграция невозможна.")
continue
print(f"\nПеремещаем {creature.name} из {zone_ru}.")
print("Доступные соседние зоны:")
for j, nz in enumerate(neighbors, start=1):
print(f" {j}. {ZONE_NAMES_RU.get(nz, nz)}")
while True:
choice = input("Выберите номер новой зоны (0 - отмена): ").strip()
if choice == '0':
break
try:
n_idx = int(choice) - 1
if 0 <= n_idx < len(neighbors):
new_zone = neighbors[n_idx]
creature.zone = new_zone
print(f"{creature.name} перемещён в {ZONE_NAMES_RU[new_zone]}.")
# Показываем картинку новой зоны
print_zone_art(new_zone)
break
else:
print("Неверный номер.")
except ValueError:
print("Введите число.")
def bot_migrate(bot_species):
alive = [c for c in bot_species if c.is_alive()]
if not alive:
return
creature = random.choice(alive)
neighbors = ZONE_CONNECTIONS.get(creature.zone, [])
if not neighbors:
return
new_zone = random.choice(neighbors)
creature.zone = new_zone
# ---------- Основная игра ----------
def main():
random.seed()
# Создаём начальные виды
player_creatures = [Creature("Игрок, вид1", zone="shallow")]
bot_species_list = []
for i in range(num_bots):
bot_species_list.append([Creature(f"Бот{i+1}, вид1", zone="shallow")])
bot_migrate_counters = [random.randint(1, 3) for _ in range(num_bots)]
card_pool = create_card_pool()
print_header()
print(f"Игра будет длиться {turns} ходов.")
print("Цель: набрать максимальную сумму очков (суммируются все ваши виды).")
print("В начале каждого хода можно создать несколько новых видов от разных предков.")
print("Боты могут создавать новые виды в зависимости от выбранного уровня сложности.")
print("Выершие виды автоматически удаляются.")
print("Механика интеллекта: хищник может ослабить параметры жертвы перед охотой.")
print("Игрок (и бот) может стать хищником со 2-го хода.")
print("Охота полностью контролируется игроком – выбор цели и её ослабление.")
print("Максимальная популяция зависит от размера (1->1024, 2->512, ... 10->2).")
print("Прирост численности травоядных обратно-пропорционален размеру.")
print("Максимальная маскировка теперь зависит от размера (у мелких лучше).")
print("Хищники получают бонус в финальном счёте: +25 (размер 1-5) и +50 (размер 6-10).")
print("Добавлены экосистемы: мелководье, глубоководье, реки, болота, леса, степи, пустыни.")
print("Виды могут мигрировать между соседними зонами. Охота возможна только внутри одной зоны.")
input("Нажмите Enter, чтобы начать...")
# Показываем приветственную картинку мелководья
print_zone_art("shallow")
for turn in range(1, turns + 1):
print(f"\n---< Ход {turn} >---")
# 0. Создание новых видов у ботов (с учётом уровней сложности)
for i, bot_species in enumerate(bot_species_list):
config = bot_configs[i]
level = config['level']
if level == 1:
continue
config['counter'] -= 1
if config['counter'] <= 0:
if level == 5:
num_to_create = 20
else:
_, _, count_min, count_max = LEVEL_PARAMS[level]
num_to_create = random.randint(count_min, count_max)
created = 0
for _ in range(num_to_create):
if create_new_species_for_bot(bot_species, f"Бот{i+1}"):
created += 1
else:
break
if created > 0:
print(f"Бот{i+1} создал {created} новых видов!")
if level == 5:
config['counter'] = 1
else:
interval_min, interval_max, _, _ = LEVEL_PARAMS[level]
config['counter'] = random.randint(interval_min, interval_max)
# 1. Создание новых видов у игрока
player_create_new_species(player_creatures)
# 2. Миграция для игрока
player_migration(player_creatures)
# 3. Миграция для ботов
for i, bot_species in enumerate(bot_species_list):
bot_migrate_counters[i] -= 1
if bot_migrate_counters[i] <= 0:
bot_migrate(bot_species)
bot_migrate_counters[i] = random.randint(1, 3)
# Собираем всех существ
all_creatures = player_creatures + [c for bot in bot_species_list for c in bot]
# 4. Смена статуса для игрока
for creature in player_creatures:
if creature.is_alive():
player_switch_predator(creature, turn, all_creatures)
# Смена статуса для ботов
for bot_species in bot_species_list:
for creature in bot_species:
if creature.is_alive():
bot_switch_predator(creature, turn, all_creatures)
# 5. Показываем состояние
print_stats(all_creatures)
# 6. Ход каждого вида игрока
for creature in player_creatures:
if not creature.is_alive():
continue
print(f"\n--- Ход вида {creature.name} ---")
cards_for_player = random.randint(2, 5)
player_cards = generate_cards(card_pool, cards_for_player)
print(f"Вы получили {len(player_cards)} карт для {creature.name}:")
for i, card in enumerate(player_cards, 1):
print(f"\nКарта {i}/{len(player_cards)}:")
if get_player_action(card, creature):
card.apply(creature)
print("Карта применена.")
else:
print("Карта заменена на увеличение популяции.")
creature.add_population(1)
# 7. Ходы ботов
for bot_species in bot_species_list:
for creature in bot_species:
if not creature.is_alive():
continue
card_count = random.randint(2, 5)
bot_turn_for_creature(creature, card_pool, card_count)
# 8. Обновляем список всех существ
all_creatures = player_creatures + [c for bot in bot_species_list for c in bot]
# 9. Выводим обновлённую таблицу перед охотой
print("\n---< Состояние перед охотой >---")
print_stats(all_creatures)
# 10. Фаза охоты
print("\n---< Фаза охоты >---")
hunting_phase(all_creatures, player_creatures, bot_species_list)
# Проверяем, жив ли хоть один вид игрока
player_alive = any(c.is_alive() for c in player_creatures)
if not player_alive:
print("\nВсе ваши виды вымерли! Игра окончена.")
sys.exit(0)
# 11. Прирост травоядных
grow_herbivores(all_creatures)
# 12. Удаляем мёртвых из всех списков
remove_dead(player_creatures)
for bot_species in bot_species_list:
remove_dead(bot_species)
print(f"\n---< Конец хода {turn} >---")
input("Нажмите Enter для следующего хода...")
# Финальная статистика
print("\n" + "=" * 60)
print("ИГРА ОКОНЧЕНА!")
print("=" * 60)
all_creatures = player_creatures + [c for bot in bot_species_list for c in bot]
print_stats(all_creatures)
player_score = sum(c.final_score() for c in player_creatures)
bot_scores = []
for i, bot_species in enumerate(bot_species_list):
score = sum(c.final_score() for c in bot_species)
bot_scores.append((f"Бот{i+1}", score))
print(f"\nИтоговые суммы очков (с бонусами хищников):")
print(f"Игрок: {player_score}")
for name, score in bot_scores:
print(f"{name}: {score}")
all_participants = [("Игрок", player_score)] + bot_scores
max_score = max(score for _, score in all_participants)
winners = [name for name, score in all_participants if score == max_score]
if len(winners) == 1:
print(f"\nПобедитель: {winners[0]} с суммой {max_score} очков!")
if winners[0] == "Игрок":
print("Поздравляем!")
else:
print("Не печальтесь, ведь в следующий раз вы учтёте ошибки и выиграете!")
print("Попробуйте снова!")
else:
print(f"\nНичья между {', '.join(winners)} с суммой {max_score} очков!")
if __name__ == "__main__":
main()