This commit is contained in:
2026-02-11 17:44:26 +03:00
parent baeaea69f8
commit 1388a5fd6b
17 changed files with 2188 additions and 177 deletions

15
game_balance/__init__.py Normal file
View File

@@ -0,0 +1,15 @@
from game_balance.config import BalanceConfig
from game_balance.assets_config import AssetsConfig
from game_balance.players_config import PlayersConfig
from game_balance.game_config import GameConfig
from game_balance.economy_config import EconomyConfig
from game_balance.events_config import EventsConfig
__all__ = [
'BalanceConfig',
'AssetsConfig',
'PlayersConfig',
'GameConfig',
'EconomyConfig',
'EventsConfig'
]

View File

@@ -0,0 +1,252 @@
"""
НАСТРОЙКИ АКТИВОВ
"""
class AssetsConfig:
# Категории активов
ASSET_CATEGORIES = {
'bonds': {'name': 'Облигации', 'color': '#4CAF50', 'icon': '🏦'},
'stocks': {'name': 'Акции', 'color': '#2196F3', 'icon': '📈'},
'real_estate': {'name': 'Недвижимость', 'color': '#FF9800', 'icon': '🏠'},
'crypto': {'name': 'Криптовалюта', 'color': '#9C27B0', 'icon': '💰'},
'commodities': {'name': 'Сырье', 'color': '#795548', 'icon': ''},
'business': {'name': 'Бизнес', 'color': '#F44336', 'icon': '🏢'},
'unique': {'name': 'Уникальные', 'color': '#FFD700', 'icon': '🏆'},
}
# Список всех активов
ASSETS = {
# ОБЛИГАЦИИ
'gov_bonds': {
'name': 'Государственные облигации',
'category': 'bonds',
'base_price': 10000,
'volatility': 0.05,
'income_per_month': 0.01,
'risk_level': 1,
'liquidity': 10,
'total_quantity': None,
'max_per_player': None,
'min_purchase': 1,
'description': 'Самый надежный актив. Защита от кризисов.'
},
# АКЦИИ
'stock_gazprom': {
'name': 'Акции Газпрома',
'category': 'stocks',
'base_price': 1000,
'volatility': 0.15,
'income_per_month': 0.03,
'risk_level': 3,
'liquidity': 8,
'total_quantity': 10000,
'max_per_player': 2000,
'min_purchase': 10,
'description': 'Голубые фишки. Стабильные дивиденды.'
},
'stock_sberbank': {
'name': 'Акции Сбербанка',
'category': 'stocks',
'base_price': 300,
'volatility': 0.18,
'income_per_month': 0.04,
'risk_level': 4,
'liquidity': 9,
'total_quantity': 15000,
'max_per_player': 3000,
'min_purchase': 10,
'description': 'Крупнейший банк. Высокая ликвидность.'
},
'stock_yandex': {
'name': 'Акции Яндекса',
'category': 'stocks',
'base_price': 3500,
'volatility': 0.25,
'income_per_month': 0.00,
'risk_level': 6,
'liquidity': 7,
'total_quantity': 5000,
'max_per_player': 1000,
'min_purchase': 1,
'description': 'IT-гигант. Высокий рост, высокая волатильность.'
},
# НЕДВИЖИМОСТЬ
'apartment_small': {
'name': 'Небольшая квартира',
'category': 'real_estate',
'base_price': 5000000,
'volatility': 0.10,
'income_per_month': 0.02,
'risk_level': 2,
'liquidity': 4,
'total_quantity': 12,
'max_per_player': 3,
'min_purchase': 1,
'description': 'Стабильный доход от аренды.'
},
'apartment_elite': {
'name': 'Элитная квартира',
'category': 'real_estate',
'base_price': 15000000,
'volatility': 0.08,
'income_per_month': 0.03,
'risk_level': 2,
'liquidity': 2,
'total_quantity': 3,
'max_per_player': 1,
'min_purchase': 1,
'description': 'Статусный актив. Низкая волатильность.'
},
# КРИПТОВАЛЮТА
'bitcoin': {
'name': 'Биткоин',
'category': 'crypto',
'base_price': 2000000,
'volatility': 0.35,
'income_per_month': 0.00,
'risk_level': 9,
'liquidity': 7,
'total_quantity': None,
'max_per_player': None,
'min_purchase': 0.001,
'description': 'Высокорисковый актив. Только спекуляции.'
},
# СЫРЬЕ
'oil': {
'name': 'Нефть Brent',
'category': 'commodities',
'base_price': 5500,
'volatility': 0.25,
'income_per_month': 0.00,
'risk_level': 6,
'liquidity': 6,
'total_quantity': 200,
'max_per_player': 40,
'min_purchase': 10,
'description': 'Зависит от политики. Высокая волатильность.'
},
'natural_gas': {
'name': 'Природный газ',
'category': 'commodities',
'base_price': 3000,
'volatility': 0.20,
'income_per_month': 0.00,
'risk_level': 5,
'liquidity': 5,
'total_quantity': 300,
'max_per_player': 50,
'min_purchase': 100,
'description': 'Сезонный актив. Пик зимой.'
},
# БИЗНЕС
'coffee_shop': {
'name': 'Кофейня',
'category': 'business',
'base_price': 2000000,
'volatility': 0.12,
'income_per_month': 0.05,
'risk_level': 5,
'liquidity': 3,
'total_quantity': 8,
'max_per_player': 2,
'min_purchase': 1,
'description': 'Пассивный бизнес. Средний риск.'
},
'it_startup': {
'name': 'IT-стартап',
'category': 'business',
'base_price': 1000000,
'volatility': 0.40,
'income_per_month': 0.00,
'risk_level': 10,
'liquidity': 1,
'total_quantity': 4,
'max_per_player': 1,
'min_purchase': 1,
'description': 'Венчурные инвестиции. Может взлететь или провалиться.'
},
# УНИКАЛЬНЫЕ
'shopping_mall': {
'name': 'Торговый центр',
'category': 'unique',
'base_price': 50000000,
'volatility': 0.10,
'income_per_month': 0.06,
'risk_level': 4,
'liquidity': 1,
'total_quantity': 1,
'max_per_player': 1,
'min_purchase': 1,
'description': 'Ключевой актив. Контроль над малым бизнесом.',
'special_rules': {
'can_be_fractional': True,
'min_fraction': 0.1,
'control_bonus': 0.1
}
},
'oil_field': {
'name': 'Нефтяное месторождение',
'category': 'unique',
'base_price': 100000000,
'volatility': 0.20,
'income_per_month': 0.08,
'risk_level': 7,
'liquidity': 1,
'total_quantity': 1,
'max_per_player': 1,
'min_purchase': 1,
'description': 'Стратегический актив. Контроль над ценами на нефть.',
'special_rules': {
'affects_other_assets': ['oil'],
'price_influence': 0.15
}
}
}
@staticmethod
def calculate_price(asset_data, demand_factor, month, total_players):
"""Расчет текущей цены актива"""
base_price = asset_data['base_price']
volatility = asset_data['volatility']
# Базовое изменение от спроса
price = base_price * (1 + demand_factor * volatility)
# Инфляция (0.5% в месяц)
price *= (1.005 ** month)
# Ограничения
price = max(price, base_price * 0.1) # Не ниже 10% от базы
price = min(price, base_price * 5) # Не выше 500% от базы
# Округление
if price < 1000:
return round(price, 2)
elif price < 1000000:
return round(price, 0)
else:
return round(price, -3)
@staticmethod
def calculate_income(asset_data, player_share, total_owners):
"""Расчет доходности с учетом баланса"""
base_income = asset_data['income_per_month']
if base_income <= 0:
return 0
# Штраф за концентрацию (если много владельцев у одного игрока)
if total_owners > 0:
concentration_penalty = (player_share ** 2) * 0.2
income = base_income * (1 - concentration_penalty)
else:
income = base_income
return max(income, 0.001) # Минимум 0.1%

34
game_balance/config.py Normal file
View File

@@ -0,0 +1,34 @@
"""
КОНФИГУРАЦИЯ БАЛАНСА ИГРЫ "КАПИТАЛ & РЫНОК"
"""
class BalanceConfig:
# Текущий режим баланса
BALANCE_MODE = "standard" # standard, easy, hard, tournament
@classmethod
def load_balance_mode(cls, mode):
"""Загрузка определенного режима баланса"""
if mode == "easy":
from game_balance.test_balance.easy_mode import EasyBalance
return EasyBalance()
elif mode == "hard":
from game_balance.test_balance.hard_mode import HardBalance
return HardBalance()
elif mode == "tournament":
from game_balance.test_balance.tournament import TournamentBalance
return TournamentBalance()
else:
from game_balance.test_balance.standard_mode import StandardBalance
return StandardBalance()
@classmethod
def get_available_modes(cls):
"""Возвращает список доступных режимов"""
return {
'standard': 'Стандартный',
'easy': 'Легкий (новички)',
'hard': 'Сложный (эксперты)',
'tournament': 'Турнирный'
}

View File

@@ -0,0 +1,74 @@
"""
ЭКОНОМИЧЕСКИЕ ПАРАМЕТРЫ
"""
class EconomyConfig:
# Налоговая система
TAX_SYSTEM = {
'income_tax': [
{'threshold': 0, 'rate': 0.00},
{'threshold': 50000, 'rate': 0.10},
{'threshold': 200000, 'rate': 0.15},
{'threshold': 500000, 'rate': 0.20},
{'threshold': 1000000, 'rate': 0.25}
],
'wealth_tax': {
'threshold': 5000000,
'rate': 0.01
},
'monopoly_tax': {
'threshold': 0.4,
'rate': 0.03
},
'transaction_fee': 0.01,
'auction_fee': 0.02,
}
# Кредитная система
LOAN_SYSTEM = {
'max_loan_multiplier': 10.0,
'interest_rates': {
'standard': 0.05,
'crisis': 0.10,
'black_market': 0.15,
},
'repayment_periods': [3, 6, 12, 24],
'late_fee': 0.02,
'default_threshold': 3,
}
# Макроэкономика
MACROECONOMICS = {
'base_inflation': 0.005,
'inflation_multipliers': {
'crisis': 1.5,
'boom': 0.7,
'default': 2.0,
},
'central_bank_rate': 0.04,
}
# Корреляции активов - ИСПРАВЛЕНО: ключи-строки вместо кортежей
ASSET_CORRELATIONS = {
'stock_gazprom:oil': 0.6,
'stock_sberbank:stock_gazprom': 0.4,
'oil:natural_gas': 0.7,
'apartment_small:apartment_elite': 0.5,
'gold:bitcoin': -0.3,
'gov_bonds:stock_gazprom': -0.2,
}
@staticmethod
def get_correlation(asset1, asset2):
"""Получить корреляцию между активами"""
# Пробуем прямой ключ
key1 = f"{asset1}:{asset2}"
if key1 in EconomyConfig.ASSET_CORRELATIONS:
return EconomyConfig.ASSET_CORRELATIONS[key1]
# Пробуем обратный ключ
key2 = f"{asset2}:{asset1}"
if key2 in EconomyConfig.ASSET_CORRELATIONS:
return EconomyConfig.ASSET_CORRELATIONS[key2]
return 0 # Нет корреляции

View File

@@ -0,0 +1,102 @@
"""
СОБЫТИЯ И КРИЗИСЫ
"""
class EventsConfig:
# Типы событий
EVENT_TYPES = {
'economic': {'name': 'Экономические', 'frequency': 0.4, 'color': '#FF9800'},
'political': {'name': 'Политические', 'frequency': 0.3, 'color': '#F44336'},
'natural': {'name': 'Природные', 'frequency': 0.15, 'color': '#4CAF50'},
'technological': {'name': 'Технологические', 'frequency': 0.15, 'color': '#2196F3'}
}
# События
EVENTS = {
'oil_boom': {
'name': 'Бум нефти',
'type': 'economic',
'probability': 0.08,
'effects': {
'oil': {'price_change': 0.30, 'duration': 2},
'stock_gazprom': {'price_change': 0.15, 'duration': 2},
},
'description': 'Цены на нефть взлетели на 30%'
},
'financial_crisis': {
'name': 'Финансовый кризис',
'type': 'economic',
'probability': 0.10,
'effects': {
'ALL': {'price_change': -0.20, 'duration': 2},
'gov_bonds': {'price_change': 0.05, 'duration': 2},
},
'description': 'Кризис ликвидности на рынках'
},
'sanctions': {
'name': 'Международные санкции',
'type': 'political',
'probability': 0.07,
'effects': {
'stock_gazprom': {'price_change': -0.35, 'duration': 3},
'stock_sberbank': {'price_change': -0.25, 'duration': 3},
},
'description': 'Новые санкции против российских компаний'
},
'tech_revolution': {
'name': 'Технологическая революция',
'type': 'technological',
'probability': 0.05,
'effects': {
'it_startup': {'price_change': 0.50, 'duration': 3},
'stock_yandex': {'price_change': 0.25, 'duration': 2},
'bitcoin': {'price_change': 0.20, 'duration': 1},
},
'description': 'Прорыв в IT-технологиях'
},
'elections': {
'name': 'Президентские выборы',
'type': 'political',
'probability': 0.06,
'effects': {
'ALL': {'price_change': -0.10, 'duration': 1},
'gov_bonds': {'price_change': 0.05, 'duration': 1},
},
'description': 'Неопределенность перед выборами'
},
'earthquake': {
'name': 'Землетрясение',
'type': 'natural',
'probability': 0.03,
'effects': {
'real_estate': {'price_change': -0.25, 'duration': 3},
},
'description': 'Разрушена инфраструктура в ключевом регионе'
}
}
# Кризисы
CRISES = {
'hyperinflation': {
'name': 'Гиперинфляция',
'probability': 0.02,
'conditions': ['month > 6'],
'effects': {
'ALL': {'price_change': 0.50, 'duration': 3},
'cash': {'value_change': -0.30, 'duration': 3},
},
'description': 'Гиперинфляция! Цены растут на 50% в месяц'
},
'market_crash': {
'name': 'Обвал рынка',
'probability': 0.025,
'conditions': ['month > 4'],
'effects': {
'stocks': {'price_change': -0.60, 'duration': 4},
'real_estate': {'price_change': -0.40, 'duration': 6},
'crypto': {'price_change': -0.80, 'duration': 2},
},
'description': 'Лопнул финансовый пузырь. Рынки рухнули'
}
}

View File

@@ -0,0 +1,43 @@
"""
НАСТРОЙКИ ИГРОВОГО ПРОЦЕССА
"""
class GameConfig:
# Основные параметры
GAME_NAME = "Капитал & Рынок"
VERSION = "1.0.0"
DEFAULT_TOTAL_MONTHS = 12
MIN_TOTAL_MONTHS = 6
MAX_TOTAL_MONTHS = 24
# Тайминги фаз (секунды)
PHASE_DURATIONS = {
'action': 120,
'market': 30,
'event': 30,
'results': 45
}
# Режимы скорости
SPEED_MODES = {
'slow': 2.0,
'normal': 1.0,
'fast': 0.5,
'blitz': 0.25
}
# Настройки комнат
MAX_PLAYERS_PER_ROOM = 10
MIN_PLAYERS_TO_START = 2
MIN_PLAYERS_TO_CONTINUE = 2
# Ограничения
MAX_TRANSACTIONS_PER_PHASE = 20
MIN_BID_AMOUNT = 1000
# Настройки интерфейса
DEFAULT_LANGUAGE = 'ru'
CURRENCY_SYMBOL = ''
CURRENCY_CODE = 'RUB'

View File

@@ -0,0 +1,158 @@
"""
НАСТРОЙКИ ИГРОКОВ
"""
class PlayersConfig:
# Стартовые условия
STARTING_CAPITAL = 100000
TARGET_CAPITAL = 50000000
# Способности игроков
ABILITIES = {
'crisis_investor': {
'name': 'Кризисный инвестор',
'description': '+20% к доходу при падении рынка более 10%',
'cooldown': 3,
'effect': {
'type': 'crisis_bonus',
'value': 0.2,
'condition': 'market_drop > 0.1'
}
},
'lobbyist': {
'name': 'Лоббист',
'description': 'Может временно снизить налоги на 5%',
'cooldown': 2,
'effect': {
'type': 'tax_reduction',
'value': 0.05,
'duration': 1
}
},
'predictor': {
'name': 'Предсказатель',
'description': 'Видит следующее случайное событие за 1 месяц',
'cooldown': 4,
'effect': {
'type': 'event_preview',
'lookahead': 1
}
},
'golden_pillow': {
'name': 'Золотая подушка',
'description': 'Может защитить 20% капитала от любых потерь',
'cooldown': 6,
'effect': {
'type': 'capital_protection',
'percentage': 0.2,
'duration': 1
}
},
'shadow_accountant': {
'name': 'Теневая бухгалтерия',
'description': 'Раз в игру уменьшить налоги на 50%',
'cooldown': None,
'effect': {
'type': 'tax_evasion',
'value': 0.5
}
},
'credit_magnate': {
'name': 'Кредитный магнат',
'description': 'Может давать кредиты другим игрокам под свой процент',
'cooldown': 1,
'effect': {
'type': 'lend_money',
'max_amount_multiplier': 0.5
}
},
'bear_raid': {
'name': 'Медвежий набег',
'description': 'Вызвать искусственное падение цены актива на 15%',
'cooldown': 4,
'effect': {
'type': 'price_manipulation',
'direction': 'down',
'value': 0.15
}
},
'fake_news': {
'name': 'Фейковые новости',
'description': 'Подменить одно случайное событие',
'cooldown': 6,
'effect': {
'type': 'event_manipulation',
'scope': 'next_event'
}
},
'dividend_king': {
'name': 'Король дивидендов',
'description': '+10% дохода от всех дивидендных активов',
'cooldown': 0,
'effect': {
'type': 'dividend_bonus',
'value': 0.1
}
},
'raider_capture': {
'name': 'Рейдерский захват',
'description': 'Попытаться отобрать 5% капитала у лидера',
'cooldown': 3,
'effect': {
'type': 'capital_raid',
'percentage': 0.05,
'success_chance': 0.6,
'penalty': 0.1
}
},
'mafia_connections': {
'name': 'Мафиозные связи',
'description': 'Отменить одно негативное событие для себя',
'cooldown': 5,
'effect': {
'type': 'event_block',
'condition': 'negative_event'
}
},
'economic_advisor': {
'name': 'Экономический советник',
'description': 'Раз в 3 месяца изменить налоговую ставку для всех',
'cooldown': 3,
'effect': {
'type': 'tax_policy',
'change_range': (-0.05, 0.05)
}
},
'currency_speculator': {
'name': 'Валютный спекулянт',
'description': 'На 1 месяц отвязать рубль от нефти',
'cooldown': 4,
'effect': {
'type': 'correlation_break',
'assets': ['oil', 'stock_gazprom'],
'duration': 1
}
}
}
# Ограничения по владению
MAX_ASSETS_PER_TYPE = {
'bonds': None,
'stocks': 0.4,
'real_estate': 0.5,
'crypto': None,
'commodities': 0.3,
'business': 0.4,
'unique': 1.0,
}
# Лимиты по месяцам
PURCHASE_LIMITS_BY_MONTH = {
1: 0.1,
2: 0.2,
3: 0.4,
4: 0.6,
5: 0.8,
6: 1.0,
}

View File

@@ -0,0 +1,11 @@
from game_balance.test_balance.easy_mode import EasyBalance
from game_balance.test_balance.hard_mode import HardBalance
from game_balance.test_balance.tournament import TournamentBalance
from game_balance.test_balance.standard_mode import StandardBalance
__all__ = [
'EasyBalance',
'HardBalance',
'TournamentBalance',
'StandardBalance'
]

View File

@@ -0,0 +1,73 @@
"""
ЛЕГКИЙ РЕЖИМ БАЛАНСА
Для новичков
"""
from game_balance.test_balance.standard_mode import StandardBalance
class EasyBalance(StandardBalance):
"""Облегченный режим"""
@classmethod
def get_assets_config(cls):
config = super().get_assets_config()
# Делаем активы дешевле и стабильнее
for asset_id, asset_data in config.items():
if asset_data.get('base_price'):
asset_data['base_price'] *= 0.5
if asset_data.get('volatility'):
asset_data['volatility'] *= 0.7
if asset_data.get('income_per_month'):
asset_data['income_per_month'] *= 1.3
return config
@classmethod
def get_players_config(cls):
config = super().get_players_config()
config['STARTING_CAPITAL'] = 200000
config['TARGET_CAPITAL'] = 25000000
# Более мягкие ограничения
config['MAX_ASSETS_PER_TYPE'] = {
'bonds': None,
'stocks': 0.6,
'real_estate': 0.7,
'crypto': None,
'commodities': 0.5,
'business': 0.6,
'unique': 1.0,
}
# Быстрое снятие лимитов
config['PURCHASE_LIMITS_BY_MONTH'] = {
1: 0.3,
2: 0.6,
3: 1.0,
}
return config
@classmethod
def get_economy_config(cls):
config = super().get_economy_config()
# Меньше налогов
config['TAX_SYSTEM']['income_tax'] = [
{'threshold': 0, 'rate': 0.00},
{'threshold': 100000, 'rate': 0.05},
{'threshold': 500000, 'rate': 0.10},
{'threshold': 2000000, 'rate': 0.15},
{'threshold': 5000000, 'rate': 0.20},
]
config['TAX_SYSTEM']['wealth_tax']['threshold'] = 10000000
# Ниже ставки по кредитам
config['LOAN_SYSTEM']['interest_rates']['standard'] = 0.03
# Меньше инфляции
config['MACROECONOMICS']['base_inflation'] = 0.002
return config

View File

@@ -0,0 +1,73 @@
"""
ЛЕГКИЙ РЕЖИМ БАЛАНСА
Для новичков
"""
from game_balance.test_balance.standard_mode import StandardBalance
class HardBalance(StandardBalance):
"""Облегченный режим"""
@classmethod
def get_assets_config(cls):
config = super().get_assets_config()
# Делаем активы дешевле и стабильнее
for asset_id, asset_data in config.items():
if asset_data.get('base_price'):
asset_data['base_price'] *= 0.5
if asset_data.get('volatility'):
asset_data['volatility'] *= 0.7
if asset_data.get('income_per_month'):
asset_data['income_per_month'] *= 1.3
return config
@classmethod
def get_players_config(cls):
config = super().get_players_config()
config['STARTING_CAPITAL'] = 200000
config['TARGET_CAPITAL'] = 25000000
# Более мягкие ограничения
config['MAX_ASSETS_PER_TYPE'] = {
'bonds': None,
'stocks': 0.6,
'real_estate': 0.7,
'crypto': None,
'commodities': 0.5,
'business': 0.6,
'unique': 1.0,
}
# Быстрое снятие лимитов
config['PURCHASE_LIMITS_BY_MONTH'] = {
1: 0.3,
2: 0.6,
3: 1.0,
}
return config
@classmethod
def get_economy_config(cls):
config = super().get_economy_config()
# Меньше налогов
config['TAX_SYSTEM']['income_tax'] = [
{'threshold': 0, 'rate': 0.00},
{'threshold': 100000, 'rate': 0.05},
{'threshold': 500000, 'rate': 0.10},
{'threshold': 2000000, 'rate': 0.15},
{'threshold': 5000000, 'rate': 0.20},
]
config['TAX_SYSTEM']['wealth_tax']['threshold'] = 10000000
# Ниже ставки по кредитам
config['LOAN_SYSTEM']['interest_rates']['standard'] = 0.03
# Меньше инфляции
config['MACROECONOMICS']['base_inflation'] = 0.002
return config

View File

@@ -0,0 +1,61 @@
"""
СТАНДАРТНЫЙ РЕЖИМ БАЛАНСА
Используется по умолчанию
"""
from game_balance.assets_config import AssetsConfig
from game_balance.players_config import PlayersConfig
from game_balance.economy_config import EconomyConfig
from game_balance.events_config import EventsConfig
from game_balance.game_config import GameConfig
class StandardBalance:
"""Стандартный сбалансированный режим"""
@classmethod
def get_assets_config(cls):
"""Возвращает конфигурацию активов"""
return AssetsConfig.ASSETS.copy()
@classmethod
def get_players_config(cls):
"""Возвращает конфигурацию игроков"""
return {
'STARTING_CAPITAL': PlayersConfig.STARTING_CAPITAL,
'TARGET_CAPITAL': PlayersConfig.TARGET_CAPITAL,
'MAX_ASSETS_PER_TYPE': PlayersConfig.MAX_ASSETS_PER_TYPE.copy(),
'PURCHASE_LIMITS_BY_MONTH': PlayersConfig.PURCHASE_LIMITS_BY_MONTH.copy(),
'ABILITIES': PlayersConfig.ABILITIES.copy()
}
@classmethod
def get_economy_config(cls):
"""Возвращает экономическую конфигурацию"""
return {
'TAX_SYSTEM': EconomyConfig.TAX_SYSTEM.copy(),
'LOAN_SYSTEM': EconomyConfig.LOAN_SYSTEM.copy(),
'MACROECONOMICS': EconomyConfig.MACROECONOMICS.copy(),
'ASSET_CORRELATIONS': EconomyConfig.ASSET_CORRELATIONS.copy()
}
@classmethod
def get_events_config(cls):
"""Возвращает конфигурацию событий"""
return {
'EVENT_TYPES': EventsConfig.EVENT_TYPES.copy(),
'EVENTS': EventsConfig.EVENTS.copy(),
'CRISES': EventsConfig.CRISES.copy()
}
@classmethod
def get_game_config(cls):
"""Возвращает игровую конфигурацию"""
return {
'PHASE_DURATIONS': GameConfig.PHASE_DURATIONS.copy(),
'SPEED_MODES': GameConfig.SPEED_MODES.copy(),
'MAX_PLAYERS_PER_ROOM': GameConfig.MAX_PLAYERS_PER_ROOM,
'MIN_PLAYERS_TO_START': GameConfig.MIN_PLAYERS_TO_START,
'MIN_PLAYERS_TO_CONTINUE': GameConfig.MIN_PLAYERS_TO_CONTINUE,
'MAX_TRANSACTIONS_PER_PHASE': GameConfig.MAX_TRANSACTIONS_PER_PHASE,
'MIN_BID_AMOUNT': GameConfig.MIN_BID_AMOUNT
}

View File

@@ -0,0 +1,83 @@
"""
ТУРНИРНЫЙ РЕЖИМ БАЛАНСА
Для соревнований
"""
from game_balance.test_balance.standard_mode import StandardBalance
class TournamentBalance(StandardBalance):
"""Турнирный режим"""
@classmethod
def get_assets_config(cls):
config = super().get_assets_config()
# Балансировка цен
price_adjustments = {
'gov_bonds': 1.0,
'stock_gazprom': 0.8,
'stock_sberbank': 0.8,
'apartment_small': 0.7,
'apartment_elite': 0.6,
'bitcoin': 1.2,
'oil': 1.0,
'coffee_shop': 0.8,
'it_startup': 1.0,
'shopping_mall': 0.5,
'oil_field': 0.4,
}
for asset_id, multiplier in price_adjustments.items():
if asset_id in config and config[asset_id].get('base_price'):
config[asset_id]['base_price'] *= multiplier
return config
@classmethod
def get_players_config(cls):
config = super().get_players_config()
config['STARTING_CAPITAL'] = 500000
config['TARGET_CAPITAL'] = 100000000
# Жесткие ограничения против монополий
config['MAX_ASSETS_PER_TYPE'] = {
'bonds': 0.5,
'stocks': 0.3,
'real_estate': 0.4,
'crypto': 0.5,
'commodities': 0.3,
'business': 0.4,
'unique': 0.5,
}
# Быстрый старт
config['PURCHASE_LIMITS_BY_MONTH'] = {
1: 0.5,
2: 1.0,
}
return config
@classmethod
def get_economy_config(cls):
config = super().get_economy_config()
# Высокие налоги
config['TAX_SYSTEM']['income_tax'] = [
{'threshold': 0, 'rate': 0.00},
{'threshold': 100000, 'rate': 0.15},
{'threshold': 500000, 'rate': 0.25},
{'threshold': 2000000, 'rate': 0.35},
{'threshold': 5000000, 'rate': 0.45},
]
config['TAX_SYSTEM']['wealth_tax']['rate'] = 0.02
config['TAX_SYSTEM']['transaction_fee'] = 0.02
# Высокие ставки
config['LOAN_SYSTEM']['interest_rates']['standard'] = 0.08
# Высокая инфляция
config['MACROECONOMICS']['base_inflation'] = 0.01
return config

124
game_balance/validator.py Normal file
View File

@@ -0,0 +1,124 @@
"""
ВАЛИДАТОР БАЛАНСА
Проверяет корректность настроек
"""
class BalanceValidator:
@staticmethod
def validate_assets(assets):
"""Проверка конфигурации активов"""
errors = []
if not isinstance(assets, dict):
errors.append("Assets config must be a dictionary")
return errors
for asset_id, asset_data in assets.items():
if not isinstance(asset_data, dict):
errors.append(f"Asset {asset_id}: data must be a dictionary")
continue
# Проверка обязательных полей
required_fields = ['name', 'category', 'base_price', 'volatility']
for field in required_fields:
if field not in asset_data:
errors.append(f"Asset {asset_id}: missing required field '{field}'")
# Проверка цены
price = asset_data.get('base_price', 0)
if not isinstance(price, (int, float)) or price <= 0:
errors.append(f"Asset {asset_id}: base_price must be positive number")
# Проверка волатильности
volatility = asset_data.get('volatility', 0)
if not isinstance(volatility, (int, float)) or volatility < 0 or volatility > 1:
errors.append(f"Asset {asset_id}: volatility must be between 0 and 1")
# Проверка доходности
income = asset_data.get('income_per_month', 0)
if not isinstance(income, (int, float)) or income < 0 or income > 0.5:
errors.append(f"Asset {asset_id}: income_per_month must be between 0 and 0.5")
# Проверка количества
total = asset_data.get('total_quantity')
if total is not None:
if not isinstance(total, (int, float)) or total <= 0:
errors.append(f"Asset {asset_id}: total_quantity must be positive or None")
return errors
@staticmethod
def validate_economy(economy_config):
"""Проверка экономической конфигурации"""
errors = []
if not isinstance(economy_config, dict):
errors.append("Economy config must be a dictionary")
return errors
# Проверка налогов
tax_system = economy_config.get('TAX_SYSTEM', {})
income_tax = tax_system.get('income_tax', [])
if not isinstance(income_tax, list):
errors.append("income_tax must be a list")
else:
last_threshold = -1
for i, bracket in enumerate(income_tax):
if not isinstance(bracket, dict):
errors.append(f"Tax bracket {i}: must be a dictionary")
continue
threshold = bracket.get('threshold', 0)
if threshold <= last_threshold:
errors.append(f"Tax brackets must be in ascending order at index {i}")
last_threshold = threshold
# Проверка кредитов
loan_system = economy_config.get('LOAN_SYSTEM', {})
max_multiplier = loan_system.get('max_loan_multiplier', 0)
if not isinstance(max_multiplier, (int, float)) or max_multiplier <= 0:
errors.append("max_loan_multiplier must be positive")
# Проверка корреляций
correlations = economy_config.get('ASSET_CORRELATIONS', {})
if not isinstance(correlations, dict):
errors.append("ASSET_CORRELATIONS must be a dictionary")
else:
for key, value in correlations.items():
if not isinstance(key, str):
errors.append(f"Correlation key must be string, got {type(key)}")
if not isinstance(value, (int, float)) or value < -1 or value > 1:
errors.append(f"Correlation value must be between -1 and 1, got {value}")
return errors
@staticmethod
def validate_balance_mode(balance):
"""Полная проверка режима баланса"""
all_errors = []
# Проверяем наличие необходимых методов
required_methods = ['get_assets_config', 'get_players_config', 'get_economy_config']
for method in required_methods:
if not hasattr(balance, method):
all_errors.append(f"Balance mode missing required method: {method}")
return all_errors
try:
# Проверка активов
assets = balance.get_assets_config()
all_errors.extend(BalanceValidator.validate_assets(assets))
# Проверка экономики
economy = balance.get_economy_config()
all_errors.extend(BalanceValidator.validate_economy(economy))
# Проверка конфигурации игроков
players = balance.get_players_config()
if not isinstance(players, dict):
all_errors.append("Players config must be a dictionary")
except Exception as e:
all_errors.append(f"Error validating balance: {str(e)}")
return all_errors