Участник:Славянск1989

Материал из Абсурдопедии
Перейти к навигацииПерейти к поиску

import os
import sys
import random
import shutil
import time
import textwrap

if os.name == 'nt':
    os.system('chcp 65001 >nul')

def clear_screen():
    if os.name == 'nt':
        os.system('cls')
    else:
        print("\033[H\033[J", end="")

def get_input():
    if os.name == 'nt':
        import msvcrt
        while True:
            key = msvcrt.getch()
            if key in (b'\xe0', b'\x00'):
                arr = msvcrt.getch()
                if arr == b'H': return (0, -1)
                if arr == b'P': return (0, 1)
                if arr == b'K': return (-1, 0)
                if arr == b'M': return (1, 0)
            elif key == b'\x03': return None
            else:
                try:
                    k = key.decode('utf-8').lower()
                    if k == 'w': return (0, -1)
                    if k == 's': return (0, 1)
                    if k == 'a': return (-1, 0)
                    if k == 'd': return (1, 0)
                    if k == 'q': return None
                    if k == 'e' or k == ' ': return 'blow'
                except: pass
    else:
        import tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
            if ch == '\x1b':
                sys.stdin.read(1)
                arr = sys.stdin.read(1)
                if arr == 'A': return (0, -1)
                if arr == 'B': return (0, 1)
                if arr == 'D': return (-1, 0)
                if arr == 'C': return (1, 0)
            elif ch == '\x03': return None
            else:
                ch = ch.lower()
                if ch in ['w', 's', 'a', 'd', 'q', 'e', ' ']:
                    if ch == 'w': return (0, -1)
                    if ch == 's': return (0, 1)
                    if ch == 'a': return (-1, 0)
                    if ch == 'd': return (1, 0)
                    if ch == 'q': return None
                    if ch == 'e' or ch == ' ': return 'blow'
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return (0, 0)

def main():
    player_x, player_y = 0, 0
    moves = 0
    speed = 0 # <-- Скорость на старте теперь 0
    last_dx, last_dy = 0, 0
    
    mushrooms = 0
    telescopes = 0
    dead_wolves = 0
    
    total_combos = 0
    combo_streak = 0
    turns_without_mushrooms = 0
    
    grid = {}
    wolves = []
    burning_trees_cells = set()
    
    turn_events = []
    combo_msg = ""
    feedback_msg = ""
    
    dead = False
    death_msg = ""
    
    is_igniting = False

    def get_max_radius(t_count):
        rem = t_count
        V = 6
        while rem > 0:
            step = min(rem, V + 2)
            rem -= step
            if step > 0:
                V += 1
        return V

    def is_visible(dx, dy, t_count):
        if abs(dx) <= 6 and abs(dy) <= 6:
            return True
        
        rem = t_count
        V = 6
        while rem > 0:
            target_V = V + 1
            step = min(rem, V + 2)
            
            if max(abs(dx), abs(dy)) == target_V and min(abs(dx), abs(dy)) <= step - 1:
                return True
                
            rem -= step
            V += 1
            
        return False

    def ignite_tree_group(start_x, start_y):
        nonlocal dead_wolves, is_igniting
        
        if is_igniting:
            return 0, 0
            
        is_igniting = True
        try:
            burned_count = 0
            ignited_trees = 0
            
            visited = set([(start_x, start_y)])
            stack = [(start_x, start_y)]
            
            while stack:
                cx, cy = stack.pop()
                if grid.get((cx, cy)) == '🌲':
                    grid[(cx, cy)] = '🔥'
                    burning_trees_cells.add((cx, cy))
                    ignited_trees += 1
                    
                    for w in list(wolves):
                        if abs(w['x'] - cx) <= 1 and abs(w['y'] - cy) <= 1:
                            wolves.remove(w)
                            dead_wolves += 1
                            burned_count += 1
                            
                    for dx in [-1, 0, 1]:
                        for dy in [-1, 0, 1]:
                            if dx == 0 and dy == 0: continue
                            nx, ny = cx + dx, cy + dy
                            
                            if (nx, ny) not in visited:
                                if (nx, ny) not in grid:
                                    generate_cell(nx, ny)
                                    
                                if grid.get((nx, ny)) == '🌲':
                                    visited.add((nx, ny))
                                    stack.append((nx, ny))
                                
            return ignited_trees, burned_count
        finally:
            is_igniting = False

    def generate_cell(x, y):
        nonlocal is_igniting
        if (x, y) in grid:
            return
        
        if x == 0 and y == 0:
            grid[(x, y)] = '..'
            return
            
        mushroom_prob = 0.05
        telescope_prob = 0.01
        wolf_prob = max(0.0, (moves * 0.001) - (total_combos * 0.005))
        tree_prob = 0.20
        fire_prob = 0.02
            
        r = random.random()
        if r < tree_prob:
            grid[(x, y)] = '🌲'
            if not is_igniting and any((x+dx, y+dy) in burning_trees_cells for dx in [-1,0,1] for dy in [-1,0,1] if dx!=0 or dy!=0):
                _, w_b = ignite_tree_group(x, y)
                if w_b > 0:
                    turn_events.append(f"🔥 Распространяющийся пожар поглотил волков: {w_b}!")
        elif r < tree_prob + fire_prob:
            is_near_wolf = False
            for w in wolves:
                if abs(w['x'] - x) <= 1 and abs(w['y'] - y) <= 1:
                    is_near_wolf = True
                    break
            
            if not is_near_wolf:
                grid[(x, y)] = '🔥'
            else:
                grid[(x, y)] = '..'
        elif r < tree_prob + fire_prob + mushroom_prob:
            grid[(x, y)] = '🍄'
        elif r < tree_prob + fire_prob + mushroom_prob + telescope_prob:
            grid[(x, y)] = '🔭'
        elif r < tree_prob + fire_prob + mushroom_prob + telescope_prob + wolf_prob:
            is_near_fire = False
            for adx in [-1, 0, 1]:
                for ady in [-1, 0, 1]:
                    if grid.get((x + adx, y + ady)) == '🔥':
                        is_near_fire = True
                        break
            
            if not is_near_fire:
                wolves.append({'x': x, 'y': y, 'just_spawned': True})
                grid[(x, y)] = '..'
            else:
                grid[(x, y)] = '..'
        else:
            grid[(x, y)] = '..'

    def generate_viewport():
        R = get_max_radius(telescopes)
        for y in range(player_y - R, player_y + R + 1):
            for x in range(player_x - R, player_x + R + 1):
                if is_visible(x - player_x, y - player_y, telescopes):
                    generate_cell(x, y)

    def is_safe_for_wolf(nx, ny):
        if grid.get((nx, ny)) == '🌲': return False
        if grid.get((nx, ny)) == '🔥': return False
        
        for adx in [-1, 0, 1]:
            for ady in [-1, 0, 1]:
                if grid.get((nx + adx, ny + ady)) == '🔥':
                    return False
                    
        if any(other['x'] == nx and other['y'] == ny for other in wolves):
            return False
            
        return True

    def render_rain():
        clear_screen()
        term_size = shutil.get_terminal_size((80, 24))
        term_width = term_size.columns
        term_height = term_size.lines
        
        # Разбиваем стату на 3 компактные строки
        h1 = f"🍄 Грибов: {mushrooms} | 🔭 Телескопов: {telescopes}"
        h2 = f"💀 Волков: {dead_wolves} | 🔥 Комбо: {total_combos} | ⏱ Ходы: {moves}"
        h3 = f"🚀 Скор: 0 🛑 | 💨 Дуть: E/Пробел | Выход: Q"
        
        feedback = "🌧️ ПРОЛИВНОЙ ДОЖДЬ! Скорость потеряна, костры тухнут... 🌧️"
        # Переносим длинный текст с помощью textwrap (макс 45 символов, чтобы влезло на смартфонах)
        wrapped_feedback = textwrap.wrap(feedback, width=min(term_width, 45))
        
        R = get_max_radius(telescopes)
        grid_width_visual = (2 * R + 1) * 2
        grid_height = 2 * R + 1
        header_height = 3 + len(wrapped_feedback) + 1 # 3 строки статы + строки сообщения + отступ
        
        total_height = header_height + grid_height
        v_pad = max(0, (term_height - total_height) // 2)
        h_pad_grid = max(0, (term_width - grid_width_visual) // 2)
        
        print("\n" * v_pad, end="")
        
        print(" " * max(0, (term_width - len(h1)) // 2) + h1)
        print(" " * max(0, (term_width - len(h2)) // 2) + h2)
        print(" " * max(0, (term_width - len(h3)) // 2) + h3)
        for line in wrapped_feedback:
            print(" " * max(0, (term_width - len(line)) // 2) + line)
        print()
        
        for y in range(player_y - R, player_y + R + 1):
            row_str = ""
            for x in range(player_x - R, player_x + R + 1):
                if not is_visible(x - player_x, y - player_y, telescopes):
                    row_str += " "
                elif x == player_x and y == player_y:
                    row_str += "🚴‍♀️"
                else:
                    row_str += "🌧️"
            print(" " * h_pad_grid + row_str)

    def render():
        clear_screen()
        
        term_size = shutil.get_terminal_size((80, 24))
        term_width = term_size.columns
        term_height = term_size.lines
        
        dir_emoji = ""
        if last_dx == 0 and last_dy == -1: dir_emoji = "⬆️"
        elif last_dx == 0 and last_dy == 1: dir_emoji = "⬇️"
        elif last_dx == -1 and last_dy == 0: dir_emoji = "⬅️"
        elif last_dx == 1 and last_dy == 0: dir_emoji = "➡️"
        elif speed == 0: dir_emoji = "🛑"
        
        speed_str = f"{speed} {dir_emoji}".strip()
        
        # Разделение заголовков на 3 строки
        h1 = f"🍄 Грибов: {mushrooms} | 🔭 Телескопов: {telescopes}"
        h2 = f"💀 Волков: {dead_wolves} | 🔥 Комбо: {total_combos} | ⏱ Ходы: {moves}"
        h3 = f"🚀 Скор: {speed_str} | 💨 Дуть: E/Пробел | Выход: Q"
        
        if feedback_msg:
            wrapped_feedback = textwrap.wrap(feedback_msg, width=min(term_width, 45))
        else:
            wrapped_feedback = []
            
        R = get_max_radius(telescopes)
        grid_width_visual = (2 * R + 1) * 2
        grid_height = 2 * R + 1
        header_height = 3 + max(1, len(wrapped_feedback)) + 1
        
        total_height = header_height + grid_height + (3 if dead else 0)
        v_pad = max(0, (term_height - total_height) // 2)
        h_pad_grid = max(0, (term_width - grid_width_visual) // 2)
        
        print("\n" * v_pad, end="")
        
        print(" " * max(0, (term_width - len(h1)) // 2) + h1)
        print(" " * max(0, (term_width - len(h2)) // 2) + h2)
        print(" " * max(0, (term_width - len(h3)) // 2) + h3)
        
        if wrapped_feedback:
            for line in wrapped_feedback:
                print(" " * max(0, (term_width - len(line)) // 2) + line)
        else:
            print()
            
        print()
        
        for y in range(player_y - R, player_y + R + 1):
            row_str = ""
            for x in range(player_x - R, player_x + R + 1):
                if not is_visible(x - player_x, y - player_y, telescopes):
                    row_str += " "
                elif dead and x == player_x and y == player_y:
                    row_str += "💀"
                elif not dead and x == player_x and y == player_y:
                    row_str += "🚴‍♀️"
                else:
                    is_wolf = any(w['x'] == x and w['y'] == y for w in wolves)
                    if is_wolf:
                        row_str += "🐺"
                    else:
                        row_str += grid.get((x, y), '..')
            print(" " * h_pad_grid + row_str)
            
        if dead:
            msg1 = f"💀 ИГРА ОКОНЧЕНА! {death_msg}"
            wrapped_death = textwrap.wrap(msg1, width=min(term_width, 45))
            msg2 = "Нажмите любую клавишу для выхода..."
            print("\n", end="")
            for line in wrapped_death:
                print(" " * max(0, (term_width - len(line)) // 2) + line)
            print(" " * max(0, (term_width - len(msg2)) // 2) + msg2)

    generate_viewport()
    
    while True:
        if turn_events or combo_msg:
            feedback_msg = " | ".join(turn_events)
            if combo_msg:
                feedback_msg = f"{feedback_msg} {combo_msg}".strip(" | ")
        else:
            feedback_msg = ""
            
        render()
        
        turn_events = []
        combo_msg = ""
        
        if dead:
            get_input()
            break
            
        inp = get_input()
        if inp is None:
            break
        if inp == (0, 0):
            continue
            
        combo_action_this_turn = False
            
        if inp == 'blow':
            fires_around = 0
            trees_ignited_by_blow = 0
            wolves_burned_by_blow = 0
            
            for dx in [-1, 0, 1]:
                for dy in [-1, 0, 1]:
                    if dx == 0 and dy == 0: continue
                    if grid.get((player_x + dx, player_y + dy)) == '🔥':
                        fires_around += 1
                        tx, ty = player_x + 2*dx, player_y + 2*dy
                        generate_cell(tx, ty)
                        if grid.get((tx, ty)) == '🌲':
                            i_t, w_b = ignite_tree_group(tx, ty)
                            trees_ignited_by_blow += i_t
                            wolves_burned_by_blow += w_b
            
            speed = 0
            last_dx, last_dy = 0, 0
            moves += 1
            turns_without_mushrooms += 1
            
            if fires_around == 0:
                turn_events.append("💨 Вы подули, но костра рядом нет.")
            elif trees_ignited_by_blow > 0:
                combo_action_this_turn = True
                msg = f"🌲 Вы успешно подожгли лес!"
                if wolves_burned_by_blow > 0:
                    msg += f" Волки сгорели: {wolves_burned_by_blow}!"
                turn_events.append(msg)
            else:
                turn_events.append("💨 Вы подули на костёр, но ни одно дерево не загорелось.")
                
            generate_viewport()
                
        else:
            dx, dy = inp
            
            if dx == last_dx and dy == last_dy and speed > 0:
                current_speed = speed + 1
            else:
                current_speed = 1
                
            next_x, next_y = player_x + dx, player_y + dy
            generate_cell(next_x, next_y)
            
            if grid[(next_x, next_y)] == '🌲':
                continue
                
            mushrooms_this_turn = 0
            telescopes_this_turn = 0
            wolves_killed_this_turn = 0
                
            for step in range(1, current_speed + 1):
                cx = player_x + dx * step
                cy = player_y + dy * step
                generate_cell(cx, cy)
                
                if grid[(cx, cy)] == '🔥':
                    dead = True
                    death_msg = "Вы сдуру заехали прямо в костёр и сгорели заживо!"
                    player_x, player_y = cx, cy
                    break
                    
                if grid[(cx, cy)] == '🌲':
                    dead = True
                    death_msg = "Вы на огромной скорости влетели в дерево и разбились!"
                    player_x, player_y = cx, cy
                    break
                    
                wolf_here = next((w for w in wolves if w['x'] == cx and w['y'] == cy), None)
                if wolf_here:
                    if step == current_speed:
                        dead = True
                        death_msg = "Вы остановились прямо перед волком, и он вас загрыз!"
                        player_x, player_y = cx, cy
                        wolves.remove(wolf_here)
                        break
                    else:
                        wolves.remove(wolf_here)
                        dead_wolves += 1
                        wolves_killed_this_turn += 1
                        
                if grid[(cx, cy)] == '🍄':
                    mushrooms += 1
                    mushrooms_this_turn += 1
                    grid[(cx, cy)] = '..'
                elif grid[(cx, cy)] == '🔭':
                    telescopes += 1
                    telescopes_this_turn += 1
                    grid[(cx, cy)] = '..'

            if not dead:
                if wolves_killed_this_turn > 0:
                    turn_events.append(f"🐺 Вы сбили волков: {wolves_killed_this_turn}!")
                if telescopes_this_turn > 0:
                    turn_events.append(f"🔭 Вы нашли телескопы: {telescopes_this_turn}!")
                    
                if mushrooms_this_turn > 0 or wolves_killed_this_turn > 0 or telescopes_this_turn > 0:
                    combo_action_this_turn = True
                    
                if mushrooms_this_turn > 0:
                    turns_without_mushrooms = 0
                else:
                    turns_without_mushrooms += 1
                    
                player_x += dx * current_speed
                player_y += dy * current_speed
                last_dx, last_dy = dx, dy
                speed = current_speed
                moves += 1
                
                generate_viewport()
                
        if not dead:
            if combo_action_this_turn:
                combo_streak += 1
                if combo_streak >= 2:
                    total_combos += 1
                    exclamations = ["Супер!", "Огонь!", "Отлично!", "Безумие!", "Невероятно!", "Мощно!"]
                    combo_msg = f"🔥 {random.choice(exclamations)} Комбо x{combo_streak}! 🔥"
            else:
                combo_streak = 0
            
            for w in wolves:
                if w['just_spawned']:
                    w['just_spawned'] = False
                    continue
                    
                wx, wy = w['x'], w['y']
                wdx = (player_x > wx) - (player_x < wx)
                wdy = (player_y > wy) - (player_y < wy)
                
                candidates = []
                if wdx != 0 and wdy != 0:
                    candidates = [(wdx, wdy), (wdx, 0), (0, wdy)]
                elif wdx != 0:
                    candidates = [(wdx, 0), (wdx, 1), (wdx, -1)]
                elif wdy != 0:
                    candidates = [(0, wdy), (1, wdy), (-1, wdy)]
                    
                for cdx, cdy in candidates:
                    tx, ty = wx + cdx, wy + cdy
                    generate_cell(tx, ty)
                    
                    if not is_safe_for_wolf(tx, ty):
                        continue
                        
                    w['x'], w['y'] = tx, ty
                    break
                    
                if w['x'] == player_x and w['y'] == player_y:
                    dead = True
                    death_msg = "Голодный волк догнал вас и загрыз!"
                    wolves.remove(w)
                    break
                    
                if not dead and grid.get((w['x'], w['y'])) in ('🍄', '🔭'):
                    grid[(w['x'], w['y'])] = '..'

            if not dead and turns_without_mushrooms >= 10:
                render_rain()
                time.sleep(3)
                
                for pos in list(grid.keys()):
                    if grid[pos] == '🔥':
                        grid[pos] = '..'
                burning_trees_cells.clear()
                
                speed = 0
                last_dx, last_dy = 0, 0
                turns_without_mushrooms = 0
                turn_events.append("🌧️ Прошёл сильный дождь! Вы потеряли скорость, а все костры потухли.")

if __name__ == "__main__":
    main()