Ver 1.1
This commit is contained in:
parent
d0fd828c39
commit
e0ba49f02e
184
README.md
184
README.md
@ -1,126 +1,144 @@
|
|||||||
# Шахматы с Открытым Миром (HP + Бонусы + Бой)
|
# Шахматы с Открытым Миром 1.1
|
||||||
|
|
||||||
**Версия:** 1.5
|
Добро пожаловать в **Шахматы с Открытым Миром 1.1** – инновационную версию классической игры, обогащённую новыми механиками, бонусами и динамическим туманом войны. Погрузитесь в захватывающий мир стратегии, где каждое решение может изменить ход партии!
|
||||||
**Дата Обновления:** 2025-04-27
|
|
||||||
|
|
||||||
## Обзор
|
## Содержание
|
||||||
|
|
||||||
**Шахматы с Открытым Миром (HP + Бонусы + Бой)** — это инновационная вариация классических шахмат, сочетающая в себе элементы RPG, такие как здоровье (HP) фигур, различные бонусы и боевые столкновения. Дополнительно в игре реализован механизм **тумана войны**, который добавляет стратегическую глубину и динамику игровому процессу.
|
1. [Основные Правила](#основные-правила)
|
||||||
|
2. [Механики Игры](#механики-игры)
|
||||||
|
- [Туман Войны](#туман-войны)
|
||||||
|
- [Бонусные Поля](#бонусные-поля)
|
||||||
|
- [Бои и HP Фигур](#бои-и-hp-фигур)
|
||||||
|
3. [Механика Времени](#механика-времени)
|
||||||
|
4. [Процедурная Генерация Бонусов](#процедурная-генерация-бонусов)
|
||||||
|
5. [Баланс Фигур](#баланс-фигур)
|
||||||
|
6. [Обновления и Изменения](#обновления-и-изменения)
|
||||||
|
|
||||||
## Основные Особенности
|
---
|
||||||
|
|
||||||
- **Здоровье (HP) Фигур:** Каждая фигура обладает текущим и максимальным здоровьем. Фигуры могут получать урон и восстанавливаться.
|
## Основные Правила
|
||||||
- **Бонусные Клетки:** На игровом поле случайным образом появляются бонусы, которые могут повышать здоровье, наносить урон или предоставлять другие преимущества.
|
|
||||||
- **Туман Войны:** Некоторые части игрового поля скрыты от игроков и открываются по мере продвижения фигур. Бонусы могут появляться как в видимых, так и в скрытых областях через механизм тумана войны.
|
|
||||||
- **Бой:** При столкновении фигур происходит бой, исход которого зависит от их текущего здоровья.
|
|
||||||
- **Смена Ходов:** Игра пошаговая. Белые ходят первыми, затем ходят чёрные.
|
|
||||||
- **Победа:** Побеждает тот, чей король останется последним на поле.
|
|
||||||
|
|
||||||
## Правила Игры
|
**Шахматы с Открытым Миром** сохраняют основные принципы классической шахматной игры:
|
||||||
|
|
||||||
### 1. Цель Игры
|
- **Фигуры и Расстановка**: Игра включает короля, ферзя, ладьи, слонов, коней и пешек для каждой стороны.
|
||||||
|
- **Цель Игры**: Захватить короля противника.
|
||||||
|
|
||||||
Целью игры является уничтожение короля противника. Как только король одного из игроков погибает, игра завершается победой противоположного игрока.
|
Однако, в этой версии добавлены уникальные механики, которые делают игру более динамичной и стратегически глубокой.
|
||||||
|
|
||||||
### 2. Здоровье Фигур
|
---
|
||||||
|
|
||||||
- **Король:** Максимальное здоровье — 5 HP.
|
## Механики Игры
|
||||||
- **Ладья, Конь, Слон, Ферзь:** Максимальное здоровье — 3 HP.
|
|
||||||
- **Пешка:** Максимальное здоровье — 1 HP.
|
|
||||||
|
|
||||||
Фигуры могут получать урон во время боя или при прохождении через специальные бонусные клетки. Если здоровье фигуры падает до 0, она удаляется с поля.
|
### Туман Войны
|
||||||
|
|
||||||
### 3. Бонусные Клетки
|
Туман войны добавляет элемент неопределённости на поле боя:
|
||||||
|
|
||||||
На игровом поле случайным образом генерируются бонусные клетки различных типов:
|
- **Открытые и Закрытые Клетки**: Изначально большая часть поля скрыта. Клетки открываются, когда фигуры приближаются.
|
||||||
|
- **Обновление Тумана**: Каждая клетка, не находящаяся в радиусе 2 клеток от любой фигуры, через 5 ходов становится закрытой.
|
||||||
|
- **Предварительное Закрытие**: Клетки, которые скоро закроются, отмечаются светло-серым цветом.
|
||||||
|
|
||||||
- **`regen` (Регенерация):** Восстанавливает 1–2 HP выбранной фигуры (не короля).
|
### Бонусные Поля
|
||||||
- **`hp_upgrade` (Повышение HP):** Увеличивает максимальное здоровье фигуры на 1 без восстановления текущего HP (не королю).
|
|
||||||
- **`damage` (Урон):** Наносит случайный урон (0–5) фигуре, проходящей через клетку.
|
|
||||||
- **`king_hp_upgrade` (Повышение HP Короля):** Повышает максимальное здоровье короля или восстанавливает его HP до максимума.
|
|
||||||
- **`add_piece` (Добавление Фигуры):** Позволяет добавить новую фигуру того же типа рядом с текущей фигурой, если это возможно.
|
|
||||||
|
|
||||||
**Важно:**
|
Поле содержит специальные клетки, предоставляющие бонусы:
|
||||||
|
|
||||||
- При **начальной генерации** бонусы **не** появляются под стартовыми позициями фигур.
|
- **Типы Бонусов**:
|
||||||
- В дальнейшем бонусы могут появляться в **любых** свободных клетках, включая стартовые ряды, через механизм тумана войны.
|
- **Регенерация (regen)**: Восстанавливает 1-2 HP фигуре (кроме короля).
|
||||||
|
- **Повышение HP (hp_upgrade)**: Увеличивает максимальный HP фигуры на 1 (кроме короля).
|
||||||
|
- **Урон (damage)**: Наносит 1-5 урона фигуре.
|
||||||
|
- **Повышение HP Короля (king_hp_upgrade)**: Увеличивает или восстанавливает HP короля.
|
||||||
|
- **Добавление Фигуры (add_piece)**: Добавляет новую фигуру рядом с текущей, если возможно.
|
||||||
|
|
||||||
### 4. Туман Войны
|
- **Генерация Бонусов**:
|
||||||
|
- Бонусные поля генерируются процедурно при выходе клеток из тумана войны.
|
||||||
|
- Шанс появления бонуса составляет **10%** для каждой новой открытой клетки.
|
||||||
|
- Тип бонуса определяется следующими вероятностями:
|
||||||
|
- Регенерация: 42%
|
||||||
|
- Повышение HP: 32%
|
||||||
|
- Урон: 20%
|
||||||
|
- Повышение HP Короля: 5%
|
||||||
|
- Добавление Фигуры: 1%
|
||||||
|
|
||||||
- **Механика:**
|
### Бои и HP Фигур
|
||||||
- Клетки, находящиеся в зоне видимости фигур (расстояние до 2 клеток), остаются открытыми.
|
|
||||||
- Клетки, выходящие за пределы зоны видимости, скрываются под туманом войны через **5 ходов** после последнего обнаружения.
|
|
||||||
- Перед закрытием клетки помечаются светло-серым цветом, указывая на предстоящее сокрытие.
|
|
||||||
|
|
||||||
- **Бонусы через Туман Войны:**
|
Каждая фигура имеет **HP (здоровье)**, определяющее её выживаемость:
|
||||||
- При повторном открытии клеток через туман войны существует **10%** шанс появления нового бонуса, если клетка свободна и не занята фигурой.
|
|
||||||
|
|
||||||
### 5. Бой
|
- **Инициализация HP**:
|
||||||
|
- **Король**: 5 HP
|
||||||
|
- **Ферзь, Ладья, Слон, Конь**: 3 HP
|
||||||
|
- **Пешка**: 1 HP
|
||||||
|
|
||||||
Когда фигура перемещается на клетку, занятую вражеской фигурой, происходит бой:
|
- **Взаимодействие Фигур**:
|
||||||
|
- **Атака**: Когда фигура перемещается на клетку с вражеской фигурой, начинается бой.
|
||||||
|
- **Исход Боя**:
|
||||||
|
- Если HP атакующего меньше HP защитника: Защитник теряет HP атакующего, атакующий погибает.
|
||||||
|
- Если HP атакующего больше HP защитника: Атакующий теряет HP защитника, защитник погибает.
|
||||||
|
- Если HP равны: Атакующий остаётся с 1 HP, защитник погибает.
|
||||||
|
|
||||||
- **Исход боя:**
|
- **Убийство Короля**: Захват короля противника завершает игру.
|
||||||
- **Если HP атакующей < HP защитника:** Защитник теряет HP равный HP атакующей, атакующая погибает.
|
|
||||||
- **Если HP атакующей > HP защитника:** Атакующая теряет HP равный HP защитника, защитник погибает.
|
|
||||||
- **Если HP атакующей == HP защитника:** Атакующая побеждает, защитник погибает, а атакующая остается с 1 HP.
|
|
||||||
|
|
||||||
- **Примеры:**
|
---
|
||||||
- **Атакующая (HP=2) vs Защитник (HP=3):** Защитник становится с HP=1, атакующая уничтожается.
|
|
||||||
- **Атакующая (HP=4) vs Защитник (HP=2):** Атакующая остается с HP=2, защитник уничтожается.
|
|
||||||
- **Атакующая (HP=3) vs Защитник (HP=3):** Защитник уничтожается, атакующая остается с HP=1.
|
|
||||||
|
|
||||||
### 6. Специальные Бонусы
|
## Механика Времени
|
||||||
|
|
||||||
- **`regen`:** Восстанавливает 1–2 HP выбранной фигуры (не короля).
|
**Время на ход** добавляет дополнительное давление и стратегию в игру:
|
||||||
- **`hp_upgrade`:** Увеличивает максимальное здоровье фигуры на 1 без восстановления текущего HP (не королю).
|
|
||||||
- **`king_hp_upgrade`:** Повышает максимальное здоровье короля или восстанавливает его HP до максимума.
|
|
||||||
- **`damage`:** Наносит случайный урон (0–5) фигуре, проходящей через клетку.
|
|
||||||
- **`add_piece`:** Позволяет добавить новую фигуру того же типа рядом с текущей фигурой, если это возможно.
|
|
||||||
|
|
||||||
### 7. Смена Ходов
|
- **Лимит Времени**: Каждый игрок имеет **2 минуты** на свой ход.
|
||||||
|
- **Отсчёт Времени**:
|
||||||
|
- Таймер отображается в правом нижнем углу.
|
||||||
|
- При истечении времени, таймер становится красным.
|
||||||
|
- **Повторный Пропуск**: Если игрок снова пропустит свой ход, он автоматически проигрывает.
|
||||||
|
- **Переключение Хода**: После каждого хода время сбрасывается для следующего игрока.
|
||||||
|
|
||||||
Игра является пошаговой:
|
---
|
||||||
|
|
||||||
1. **Ход Белых:**
|
## Процедурная Генерация Бонусов
|
||||||
- Выбирается фигура белых, доступная для хода.
|
|
||||||
- Выбирается возможная клетка для перемещения.
|
|
||||||
- Выполняется перемещение и применяются эффекты бонусов/боя.
|
|
||||||
|
|
||||||
2. **Ход Чёрных:**
|
|
||||||
- Аналогично, выбирается фигура чёрных и выполняется ход.
|
|
||||||
|
|
||||||
Смена хода происходит после завершения всех действий текущего игрока.
|
Бонусные поля генерируются динамически, делая каждую игру уникальной:
|
||||||
|
|
||||||
### 8. Победа
|
- **Когда Генерируются Бонусы**:
|
||||||
|
- При выходе клетки из тумана войны, с вероятностью **10%** может появиться бонусное поле.
|
||||||
|
|
||||||
|
- **Тип Бонуса**:
|
||||||
|
- Тип бонуса выбирается на основе текущих вероятностей.
|
||||||
|
- После **100 ходов**, вероятность появления бонусов типа "урон" (красные поля) постепенно увеличивается до **50%**, делая игру более опасной.
|
||||||
|
|
||||||
Побеждает тот, чей король остаётся последним на поле. Игра завершается, когда король одного из игроков погибает.
|
---
|
||||||
|
|
||||||
## Установка и Запуск
|
## Баланс Фигур
|
||||||
|
|
||||||
### Требования
|
Для поддержания баланса и динамики игры, движение некоторых фигур было изменено:
|
||||||
|
|
||||||
- **Python 3.x**
|
- **Ферзь и Ладья**:
|
||||||
- **Pygame** библиотека
|
- **Ранее**: Могли перемещаться до **5 клеток** за ход.
|
||||||
|
- **Сейчас**: Могут перемещаться до **3 клеток** за ход.
|
||||||
|
|
||||||
### Установка
|
Это изменение делает игру более стратегичной, ограничивая возможности мощных фигур и стимулируя разнообразие тактик.
|
||||||
|
|
||||||
1. **Клонирование Репозитория:**
|
---
|
||||||
|
|
||||||
```bash
|
## Обновления и Изменения
|
||||||
git clone https://github.com/ваш-репозиторий/шахматы-с-открытым-миром.git
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Установка Зависимостей:**
|
### Версия 1.1
|
||||||
|
|
||||||
Убедитесь, что у вас установлен Python 3 и Pygame. Установить Pygame можно с помощью pip:
|
1. **Баланс Красных Полей**:
|
||||||
|
- **Урон**: Теперь красные поля наносят от **1 до 5 урона**, исключая возможность отсутствия урона.
|
||||||
|
- **Исправление Бага**: При прохождении через красное поле и гибели фигуры, ход корректно переходит к противнику.
|
||||||
|
|
||||||
```bash
|
2. **Процедурная Генерация Бонусов**:
|
||||||
pip install pygame
|
- Бонусные поля теперь генерируются **процедурно** при выходе клеток из тумана войны.
|
||||||
```
|
- **Вероятность Появления**: Каждая новая открытая клетка имеет **10%** шанс стать бонусной.
|
||||||
|
- **Тип Бонуса**: Выбор типа бонуса осуществляется согласно текущим вероятностям.
|
||||||
|
|
||||||
### Запуск Игры
|
3. **Баланс Фигур с Свободным Передвижением**:
|
||||||
|
- **Ферзь и Ладья** теперь могут перемещаться до **3 клеток** вместо 5, обеспечивая более сбалансированную игру.
|
||||||
|
|
||||||
Перейдите в директорию с клонированным репозиторием и запустите игру:
|
4. **Механика Повышения Вероятности Красных Полей**:
|
||||||
|
- После **100 ходов**, вероятность появления бонусных полей типа "урон" постепенно увеличивается до **50%**.
|
||||||
|
- **Отображение Ходов**: Внизу экрана отображается счётчик ходов. После 100 ходов счётчик становится красным, сигнализируя о начале увеличения опасности.
|
||||||
|
|
||||||
```bash
|
5. **Механика Времени на Ход**:
|
||||||
python chess_game.py
|
- Каждый игрок имеет **2 минуты** на свой ход.
|
||||||
|
- **Отображение Таймера**: Таймер находится в правом нижнем углу экрана.
|
||||||
|
- **Переполнение Времени**:
|
||||||
|
- При первом переполнении таймер становится красным.
|
||||||
|
- При втором переполнении, игрок автоматически проигрывает.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import pygame
|
import pygame
|
||||||
import sys
|
import sys
|
||||||
import random
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
pygame.init()
|
pygame.init()
|
||||||
|
|
||||||
@ -35,6 +36,10 @@ COLOR_TURN_TEXT = (255, 255, 255) # Белый
|
|||||||
# Новый цвет для пометки клеток, которые скоро уйдут в туман войны
|
# Новый цвет для пометки клеток, которые скоро уйдут в туман войны
|
||||||
COLOR_PRE_FOG = (169, 169, 169) # Светло-серый
|
COLOR_PRE_FOG = (169, 169, 169) # Светло-серый
|
||||||
|
|
||||||
|
# Цвет таймера
|
||||||
|
COLOR_TIMER_NORMAL = (255, 255, 255) # Белый
|
||||||
|
COLOR_TIMER_WARNING = (255, 0, 0) # Красный
|
||||||
|
|
||||||
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
|
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
|
||||||
pygame.display.set_caption("Шахматы с открытым миром 1.0")
|
pygame.display.set_caption("Шахматы с открытым миром 1.0")
|
||||||
|
|
||||||
@ -42,6 +47,8 @@ pygame.display.set_caption("Шахматы с открытым миром 1.0")
|
|||||||
font = pygame.font.SysFont(None, CELL_SIZE // 2)
|
font = pygame.font.SysFont(None, CELL_SIZE // 2)
|
||||||
victory_font = pygame.font.SysFont(None, 60)
|
victory_font = pygame.font.SysFont(None, 60)
|
||||||
turn_font = pygame.font.SysFont(None, 30)
|
turn_font = pygame.font.SysFont(None, 30)
|
||||||
|
counter_font = pygame.font.SysFont(None, 30)
|
||||||
|
timer_font = pygame.font.SysFont(None, 25)
|
||||||
|
|
||||||
# --- Глобальное множество открытых клеток (туман войны) ---
|
# --- Глобальное множество открытых клеток (туман войны) ---
|
||||||
global_revealed = set()
|
global_revealed = set()
|
||||||
@ -61,7 +68,7 @@ piece_symbols = {
|
|||||||
bonus_cells = {}
|
bonus_cells = {}
|
||||||
|
|
||||||
# Вероятности появления различных типов бонусов
|
# Вероятности появления различных типов бонусов
|
||||||
bonus_probabilities = {
|
base_bonus_probabilities = {
|
||||||
'regen': 0.42, # 42%
|
'regen': 0.42, # 42%
|
||||||
'hp_upgrade': 0.32, # 32%
|
'hp_upgrade': 0.32, # 32%
|
||||||
'damage': 0.2, # 20%
|
'damage': 0.2, # 20%
|
||||||
@ -69,6 +76,8 @@ bonus_probabilities = {
|
|||||||
'add_piece': 0.01 # 1%
|
'add_piece': 0.01 # 1%
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bonus_probabilities = base_bonus_probabilities.copy()
|
||||||
|
|
||||||
# Функция для выбора бонуса на основе вероятностей
|
# Функция для выбора бонуса на основе вероятностей
|
||||||
def choose_bonus_type():
|
def choose_bonus_type():
|
||||||
rand = random.random()
|
rand = random.random()
|
||||||
@ -79,87 +88,6 @@ def choose_bonus_type():
|
|||||||
return bonus_type
|
return bonus_type
|
||||||
return 'regen' # По умолчанию
|
return 'regen' # По умолчанию
|
||||||
|
|
||||||
def initialize_bonus_cells(pieces, num_each=10):
|
|
||||||
"""
|
|
||||||
Создаём случайно бонусных клеток.
|
|
||||||
Включает три типа изначально: 'hp_upgrade', 'regen', 'king_hp_upgrade'.
|
|
||||||
Бонусы не размещаются под стартовыми позициями фигур.
|
|
||||||
"""
|
|
||||||
global bonus_cells
|
|
||||||
all_positions = [(x, y) for x in range(GRID_WIDTH) for y in range(GRID_HEIGHT)]
|
|
||||||
random.shuffle(all_positions)
|
|
||||||
i_pos = 0
|
|
||||||
types = ['hp_upgrade', 'regen', 'king_hp_upgrade']
|
|
||||||
for t in types:
|
|
||||||
for _ in range(num_each):
|
|
||||||
while i_pos < len(all_positions):
|
|
||||||
(xx, yy) = all_positions[i_pos]
|
|
||||||
i_pos += 1
|
|
||||||
# Проверка, чтобы клетка не занята фигурой
|
|
||||||
if not any(p.x == xx and p.y == yy for p in pieces):
|
|
||||||
bonus_cells[(xx, yy)] = {'type': t}
|
|
||||||
break
|
|
||||||
|
|
||||||
def apply_bonus(piece, bonus_type, pieces):
|
|
||||||
"""Применяем эффект бонуса к фигуре piece в зависимости от типа."""
|
|
||||||
if bonus_type == 'regen':
|
|
||||||
# Регенерация (1..2) для НЕ короля
|
|
||||||
if piece.name != 'king':
|
|
||||||
amt = random.randint(1, 2)
|
|
||||||
piece.hp = min(piece.hp + amt, piece.max_hp)
|
|
||||||
|
|
||||||
elif bonus_type == 'hp_upgrade':
|
|
||||||
# Повышение max_hp только НЕ королю без восстановления HP
|
|
||||||
if piece.name != 'king':
|
|
||||||
piece.max_hp += 1
|
|
||||||
# piece.hp остается неизменным
|
|
||||||
|
|
||||||
elif bonus_type == 'king_hp_upgrade':
|
|
||||||
# Только для короля, бонус активируется другим игроком
|
|
||||||
if piece.name != 'king':
|
|
||||||
# Найти короля той же команды
|
|
||||||
king = next((p for p in pieces if p.name == 'king' and p.color == piece.color), None)
|
|
||||||
if king:
|
|
||||||
if king.hp == king.max_hp:
|
|
||||||
# Если король на полном здоровье,
|
|
||||||
# то увеличиваем max_hp на 1
|
|
||||||
king.max_hp += 1
|
|
||||||
king.hp = king.max_hp
|
|
||||||
else:
|
|
||||||
# Если король не на полном, то
|
|
||||||
# просто восстанавливаем HP до max
|
|
||||||
king.hp = min(king.hp + 1, king.max_hp)
|
|
||||||
|
|
||||||
elif bonus_type == 'damage':
|
|
||||||
# Нанесение урона (0..5)
|
|
||||||
damage = random.randint(0, 5)
|
|
||||||
piece.hp = max(piece.hp - damage, 0)
|
|
||||||
if piece.hp == 0:
|
|
||||||
# Удаляем фигуру, если HP равен 0
|
|
||||||
pieces.remove(piece)
|
|
||||||
if piece.name == 'king':
|
|
||||||
global winner, game_over
|
|
||||||
winner = 'black' if piece.color == 'white' else 'white'
|
|
||||||
game_over = True
|
|
||||||
|
|
||||||
elif bonus_type == 'add_piece':
|
|
||||||
# Добавление новой фигуры рядом, если возможно и не король
|
|
||||||
if piece.name != 'king':
|
|
||||||
# Определяем возможные соседние клетки
|
|
||||||
directions = [(-1,0),(1,0),(0,-1),(0,1), (-1,-1),(1,-1),(1,1),(-1,1)]
|
|
||||||
random.shuffle(directions)
|
|
||||||
for dx, dy in directions:
|
|
||||||
nx = piece.x + dx
|
|
||||||
ny = piece.y + dy
|
|
||||||
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
|
||||||
# Проверяем, что клетка пуста
|
|
||||||
if not any(p.x == nx and p.y == ny for p in pieces) and (nx, ny) not in bonus_cells:
|
|
||||||
# Создаём новую фигуру того же типа
|
|
||||||
new_piece = Piece(piece.name, piece.color, nx, ny)
|
|
||||||
pieces.append(new_piece)
|
|
||||||
break
|
|
||||||
# Если не удалось разместить, бонус не активируется
|
|
||||||
|
|
||||||
# === МЕХАНИКА БОЯ ===
|
# === МЕХАНИКА БОЯ ===
|
||||||
def resolve_combat(attacker, defender):
|
def resolve_combat(attacker, defender):
|
||||||
"""
|
"""
|
||||||
@ -233,7 +161,7 @@ class Piece:
|
|||||||
moves.append((nx, ny))
|
moves.append((nx, ny))
|
||||||
|
|
||||||
elif self.name in ['rook', 'bishop', 'queen']:
|
elif self.name in ['rook', 'bishop', 'queen']:
|
||||||
# Ограничиваем движение до 5 клеток
|
# Ограничиваем движение до 3 клеток
|
||||||
if self.name == 'rook':
|
if self.name == 'rook':
|
||||||
directions = [(-1,0),(1,0),(0,-1),(0,1)]
|
directions = [(-1,0),(1,0),(0,-1),(0,1)]
|
||||||
elif self.name == 'bishop':
|
elif self.name == 'bishop':
|
||||||
@ -244,7 +172,7 @@ class Piece:
|
|||||||
(-1,-1),(1,-1),(1,1),(-1,1)
|
(-1,-1),(1,-1),(1,1),(-1,1)
|
||||||
]
|
]
|
||||||
for dx, dy in directions:
|
for dx, dy in directions:
|
||||||
for step in range(1, 6): # До 5 клеток
|
for step in range(1, 4): # До 3 клеток
|
||||||
nx = self.x + dx * step
|
nx = self.x + dx * step
|
||||||
ny = self.y + dy * step
|
ny = self.y + dy * step
|
||||||
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
||||||
@ -311,9 +239,11 @@ def initialize_pieces():
|
|||||||
|
|
||||||
return pieces
|
return pieces
|
||||||
|
|
||||||
# Инициализация фигур до инициализации бонусов
|
# Инициализация фигур
|
||||||
pieces = initialize_pieces()
|
pieces = initialize_pieces()
|
||||||
initialize_bonus_cells(pieces, num_each=10)
|
|
||||||
|
# Remove initial bonus cell generation
|
||||||
|
# initialize_bonus_cells(pieces, num_each=10)
|
||||||
|
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves = []
|
possible_moves = []
|
||||||
@ -326,6 +256,66 @@ BONUS_GENERATION_CHANCE = 0.1 # 10% шанс появления бонуса п
|
|||||||
|
|
||||||
# --- Система ходов ---
|
# --- Система ходов ---
|
||||||
current_turn = 'white' # Начинаем с белых
|
current_turn = 'white' # Начинаем с белых
|
||||||
|
turn_count = 0
|
||||||
|
|
||||||
|
# --- Механика повышения вероятности красных полей ---
|
||||||
|
def update_bonus_probabilities():
|
||||||
|
global bonus_probabilities
|
||||||
|
if turn_count <= 100:
|
||||||
|
bonus_probabilities = base_bonus_probabilities.copy()
|
||||||
|
else:
|
||||||
|
# Calculate how much to increase 'damage' probability
|
||||||
|
extra_turns = turn_count - 100
|
||||||
|
# Let's say over the next 200 turns, it increases to 50%
|
||||||
|
max_extra = 200
|
||||||
|
increase_per_turn = (0.50 - base_bonus_probabilities['damage']) / max_extra
|
||||||
|
new_damage_prob = min(base_bonus_probabilities['damage'] + increase_per_turn * extra_turns, 0.50)
|
||||||
|
# Adjust other probabilities accordingly
|
||||||
|
remaining_prob = 1 - new_damage_prob
|
||||||
|
total_other_probs = sum(base_bonus_probabilities[bt] for bt in base_bonus_probabilities if bt != 'damage')
|
||||||
|
bonus_probabilities = {}
|
||||||
|
for bt, prob in base_bonus_probabilities.items():
|
||||||
|
if bt == 'damage':
|
||||||
|
bonus_probabilities[bt] = new_damage_prob
|
||||||
|
else:
|
||||||
|
bonus_probabilities[bt] = prob / total_other_probs * remaining_prob
|
||||||
|
|
||||||
|
# --- Механика времени на ход ---
|
||||||
|
TURN_TIME_LIMIT = 120 # seconds
|
||||||
|
timer_start_time = time.time()
|
||||||
|
timer_expired = False
|
||||||
|
player_timeouts = {'white': 0, 'black': 0}
|
||||||
|
|
||||||
|
def reset_timer():
|
||||||
|
global timer_start_time, timer_expired
|
||||||
|
timer_start_time = time.time()
|
||||||
|
timer_expired = False
|
||||||
|
|
||||||
|
def get_time_left():
|
||||||
|
elapsed = time.time() - timer_start_time
|
||||||
|
return max(0, TURN_TIME_LIMIT - int(elapsed))
|
||||||
|
|
||||||
|
def check_timer():
|
||||||
|
global timer_expired, game_over, winner
|
||||||
|
time_left = get_time_left()
|
||||||
|
if time_left <= 0 and not timer_expired:
|
||||||
|
timer_expired = True
|
||||||
|
player_timeouts[current_turn] += 1
|
||||||
|
if player_timeouts[current_turn] >= 2:
|
||||||
|
# Opponent wins
|
||||||
|
winner = 'black' if current_turn == 'white' else 'white'
|
||||||
|
game_over = True
|
||||||
|
else:
|
||||||
|
# Switch turn
|
||||||
|
switch_turn()
|
||||||
|
|
||||||
|
def switch_turn():
|
||||||
|
global current_turn, turn_count, timer_expired
|
||||||
|
current_turn = 'black' if current_turn == 'white' else 'white'
|
||||||
|
turn_count += 1
|
||||||
|
reset_timer()
|
||||||
|
timer_expired = False
|
||||||
|
update_bonus_probabilities()
|
||||||
|
|
||||||
def update_fog():
|
def update_fog():
|
||||||
"""
|
"""
|
||||||
@ -491,14 +481,98 @@ def display_turn(current_turn):
|
|||||||
text = turn_font.render(f"Текущий ход: {current_turn.capitalize()}", True, COLOR_TURN_TEXT)
|
text = turn_font.render(f"Текущий ход: {current_turn.capitalize()}", True, COLOR_TURN_TEXT)
|
||||||
screen.blit(text, (10, WINDOW_HEIGHT - 30))
|
screen.blit(text, (10, WINDOW_HEIGHT - 30))
|
||||||
|
|
||||||
running = True
|
def display_turn_counter():
|
||||||
clock = pygame.time.Clock()
|
global turn_count
|
||||||
|
if turn_count < 100:
|
||||||
|
color = (255, 255, 255)
|
||||||
|
else:
|
||||||
|
color = (255, 0, 0)
|
||||||
|
text = counter_font.render(f"Ход: {turn_count}", True, color)
|
||||||
|
text_rect = text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT - 15))
|
||||||
|
screen.blit(text, text_rect)
|
||||||
|
|
||||||
|
def display_timer():
|
||||||
|
time_left = get_time_left()
|
||||||
|
minutes = time_left // 60
|
||||||
|
seconds = time_left % 60
|
||||||
|
timer_text = f"{minutes:02}:{seconds:02}"
|
||||||
|
if timer_expired and player_timeouts[current_turn] >=1:
|
||||||
|
color = COLOR_TIMER_WARNING
|
||||||
|
else:
|
||||||
|
color = COLOR_TIMER_NORMAL
|
||||||
|
text = timer_font.render(timer_text, True, color)
|
||||||
|
text_rect = text.get_rect(bottomright=(WINDOW_WIDTH - 10, WINDOW_HEIGHT - 10))
|
||||||
|
screen.blit(text, text_rect)
|
||||||
|
|
||||||
|
def apply_bonus(piece, bonus_type, pieces):
|
||||||
|
"""Применяем эффект бонуса к фигуре piece в зависимости от типа."""
|
||||||
|
if bonus_type == 'regen':
|
||||||
|
# Регенерация (1..2) для НЕ короля
|
||||||
|
if piece.name != 'king':
|
||||||
|
amt = random.randint(1, 2)
|
||||||
|
piece.hp = min(piece.hp + amt, piece.max_hp)
|
||||||
|
|
||||||
|
elif bonus_type == 'hp_upgrade':
|
||||||
|
# Повышение max_hp только НЕ королю без восстановления HP
|
||||||
|
if piece.name != 'king':
|
||||||
|
piece.max_hp += 1
|
||||||
|
# piece.hp остается неизменным
|
||||||
|
|
||||||
|
elif bonus_type == 'king_hp_upgrade':
|
||||||
|
# Только для короля, бонус активируется другим игроком
|
||||||
|
if piece.name != 'king':
|
||||||
|
# Найти короля той же команды
|
||||||
|
king = next((p for p in pieces if p.name == 'king' and p.color == piece.color), None)
|
||||||
|
if king:
|
||||||
|
if king.hp == king.max_hp:
|
||||||
|
# Если король на полном здоровье,
|
||||||
|
# то увеличиваем max_hp на 1
|
||||||
|
king.max_hp += 1
|
||||||
|
king.hp = king.max_hp
|
||||||
|
else:
|
||||||
|
# Если король не на полном, то
|
||||||
|
# просто восстанавливаем HP до max
|
||||||
|
king.hp = min(king.hp + 1, king.max_hp)
|
||||||
|
|
||||||
|
elif bonus_type == 'damage':
|
||||||
|
# Нанесение урона (1..5)
|
||||||
|
damage = random.randint(1, 5)
|
||||||
|
piece.hp = max(piece.hp - damage, 0)
|
||||||
|
if piece.hp == 0:
|
||||||
|
# Удаляем фигуру, если HP равен 0
|
||||||
|
pieces.remove(piece)
|
||||||
|
if piece.name == 'king':
|
||||||
|
global winner, game_over
|
||||||
|
winner = 'black' if piece.color == 'white' else 'white'
|
||||||
|
game_over = True
|
||||||
|
|
||||||
|
elif bonus_type == 'add_piece':
|
||||||
|
# Добавление новой фигуры рядом, если возможно и не король
|
||||||
|
if piece.name != 'king':
|
||||||
|
# Определяем возможные соседние клетки
|
||||||
|
directions = [(-1,0),(1,0),(0,-1),(0,1), (-1,-1),(1,-1),(1,1),(-1,1)]
|
||||||
|
random.shuffle(directions)
|
||||||
|
for dx, dy in directions:
|
||||||
|
nx = piece.x + dx
|
||||||
|
ny = piece.y + dy
|
||||||
|
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
||||||
|
# Проверяем, что клетка пуста
|
||||||
|
if not any(p.x == nx and p.y == ny for p in pieces) and (nx, ny) not in bonus_cells:
|
||||||
|
# Создаём новую фигуру того же типа
|
||||||
|
new_piece = Piece(piece.name, piece.color, nx, ny)
|
||||||
|
pieces.append(new_piece)
|
||||||
|
break
|
||||||
|
# Если не удалось разместить, бонус не активируется
|
||||||
|
|
||||||
# Инициализируем туман войны в начале игры
|
# Инициализируем туман войны в начале игры
|
||||||
update_fog()
|
update_fog()
|
||||||
|
|
||||||
|
running = True
|
||||||
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
clock.tick(30)
|
clock.tick(30)
|
||||||
|
check_timer()
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
running = False
|
running = False
|
||||||
@ -539,7 +613,7 @@ while running:
|
|||||||
# После изменения позиций фигур обновляем туман войны
|
# После изменения позиций фигур обновляем туман войны
|
||||||
update_fog()
|
update_fog()
|
||||||
# Смена хода
|
# Смена хода
|
||||||
current_turn = 'black' if current_turn == 'white' else 'white'
|
switch_turn()
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
# Атакующая жива, перемещаем её
|
# Атакующая жива, перемещаем её
|
||||||
@ -560,7 +634,7 @@ while running:
|
|||||||
survived = True
|
survived = True
|
||||||
for pos in path:
|
for pos in path:
|
||||||
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
||||||
damage = random.randint(0,5)
|
damage = random.randint(1,5) # Исправлено на 1..5
|
||||||
attacker.hp = max(attacker.hp - damage, 0)
|
attacker.hp = max(attacker.hp - damage, 0)
|
||||||
# Удаляем 'damage' клетку как использованную
|
# Удаляем 'damage' клетку как использованную
|
||||||
del bonus_cells[pos]
|
del bonus_cells[pos]
|
||||||
@ -569,6 +643,8 @@ while running:
|
|||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
survived = False
|
survived = False
|
||||||
|
# Смена хода, так как игрок погиб
|
||||||
|
switch_turn()
|
||||||
break
|
break
|
||||||
if survived:
|
if survived:
|
||||||
attacker.x = gx
|
attacker.x = gx
|
||||||
@ -577,7 +653,7 @@ while running:
|
|||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
# Смена хода
|
# Смена хода
|
||||||
current_turn = 'black' if current_turn == 'white' else 'white'
|
switch_turn()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Пустая клетка — просто ходим
|
# Пустая клетка — просто ходим
|
||||||
@ -598,7 +674,7 @@ while running:
|
|||||||
survived = True
|
survived = True
|
||||||
for pos in path:
|
for pos in path:
|
||||||
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
||||||
damage = random.randint(0,5)
|
damage = random.randint(1,5) # Исправлено на 1..5
|
||||||
selected_piece.hp = max(selected_piece.hp - damage, 0)
|
selected_piece.hp = max(selected_piece.hp - damage, 0)
|
||||||
# Удаляем 'damage' клетку как использованную
|
# Удаляем 'damage' клетку как использованную
|
||||||
del bonus_cells[pos]
|
del bonus_cells[pos]
|
||||||
@ -607,6 +683,8 @@ while running:
|
|||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
survived = False
|
survived = False
|
||||||
|
# Смена хода, так как игрок погиб
|
||||||
|
switch_turn()
|
||||||
break
|
break
|
||||||
if survived:
|
if survived:
|
||||||
selected_piece.x = gx
|
selected_piece.x = gx
|
||||||
@ -615,7 +693,7 @@ while running:
|
|||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
# Смена хода
|
# Смена хода
|
||||||
current_turn = 'black' if current_turn == 'white' else 'white'
|
switch_turn()
|
||||||
|
|
||||||
# После успешного хода обновляем туман войны
|
# После успешного хода обновляем туман войны
|
||||||
update_fog()
|
update_fog()
|
||||||
@ -642,6 +720,8 @@ while running:
|
|||||||
display_victory(winner)
|
display_victory(winner)
|
||||||
else:
|
else:
|
||||||
display_turn(current_turn)
|
display_turn(current_turn)
|
||||||
|
display_turn_counter()
|
||||||
|
display_timer()
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
|
||||||
pygame.quit()
|
pygame.quit()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user