Files
Elvenbane/common.py

232 lines
9.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import json
import uuid
from dataclasses import dataclass, field
from copy import deepcopy
from collections import defaultdict
from heapq import heappush, heappop
import pygame
import pygame_gui
from classes import Rock
def path_exists(data, path):
current = data
for key in path:
if isinstance(current, dict) and key in current:
current = current[key]
else:
return False
return True
#def find_way(cells, start, goal):
# """Находит путь от start=(row, col) к goal=(row, col). row=y (строка), col=x (столбец)"""
# rows = len(cells)
# if rows == 0:
# return None
# cols = len(cells[0])
# def is_passable(cell):
# # Проходимо, если НЕ Rock в terrain И creature_obj отсутствует
# return (cell.terrain_obj is None or not isinstance(cell.terrain_obj, Rock))
# # Проверка границ и проходимости старт/гол
# s_row, s_col = start
# g_row, g_col = goal
# if not (0 <= s_row < rows and 0 <= s_col < cols and 0 <= g_row < rows and 0 <= g_col < cols):
# return None
# start_cell = cells[s_row][s_col]
# goal_cell = cells[g_row][g_col]
# if not is_passable(start_cell) or not is_passable(goal_cell):
# print(f"Старт/гол непроходимы: start={is_passable(start_cell)}, goal={is_passable(goal_cell)}")
# return None
# # A* поиск (используем прямые row,col вместо ID для простоты)
# directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] # вверх, вниз, лево, право
# open_set = []
# # f_score = g + h (h=манхэттен)
# h = abs(s_row - g_row) + abs(s_col - g_col)
# heappush(open_set, (h, 0, s_row, s_col)) # f, g, row, col
# came_from = {}
# g_score = defaultdict(lambda: float('inf'))
# g_score[(s_row, s_col)] = 0
# while open_set:
# _, _, row, col = heappop(open_set)
# if (row, col) == (g_row, g_col):
# # Восстанавливаем путь
# path = []
# current = (row, col)
# while current in came_from:
# path.append(current)
# current = came_from[current]
# path.append(start)
# return path[::-1]
# for dr, dc in directions:
# nr, nc = row + dr, col + dc
# if 0 <= nr < rows and 0 <= nc < cols:
# if is_passable(cells[nr][nc]):
# tentative_g = g_score[(row, col)] + 1
# pos = (nr, nc)
# if tentative_g < g_score[pos]:
# came_from[pos] = (row, col)
# g_score[pos] = tentative_g
# f = tentative_g + abs(nr - g_row) + abs(nc - g_col)
# heappush(open_set, (f, tentative_g, nr, nc))
# print("Путь не найден (нет связи)")
# return None
#def find_way(cells, start, goal):
# """Находит путь от start=(row, col) к goal=(row, col) с диагональным движением"""
# rows = len(cells)
# if rows == 0:
# return None
# cols = len(cells[0])
#
# def is_passable(cell):
# return (cell.terrain_obj is None or not isinstance(cell.terrain_obj, Rock))
#
# s_row, s_col = start
# g_row, g_col = goal
# if not (0 <= s_row < rows and 0 <= s_col < cols and 0 <= g_row < rows and 0 <= g_col < cols):
# return None
#
# start_cell = cells[s_row][s_col]
# goal_cell = cells[g_row][g_col]
# if not is_passable(start_cell) or not is_passable(goal_cell):
# print(f"Старт/гол непроходимы: start={is_passable(start_cell)}, goal={is_passable(goal_cell)}")
# return None
#
# # ★ 8 НАПРАВЛЕНИЙ: 4 основных + 4 диагональных ★
# directions = [
# (-1, 0), (1, 0), (0, -1), (0, 1), # вверх, вниз, лево, право (стоимость 1.0)
# (-1, -1), (-1, 1), (1, -1), (1, 1) # диагонали (стоимость √2 ≈ 1.414)
# ]
#
# open_set = []
# h = abs(s_row - g_row) + abs(s_col - g_col) # эвристика манхэттен
# heappush(open_set, (h, 0, s_row, s_col)) # f, g, row, col
#
# came_from = {}
# g_score = defaultdict(lambda: float('inf'))
# g_score[(s_row, s_col)] = 0
#
# while open_set:
# _, _, row, col = heappop(open_set)
# if (row, col) == (g_row, g_col):
# # Восстанавливаем путь
# path = []
# current = (row, col)
# while current in came_from:
# path.append(current)
# current = came_from[current]
# path.append(start)
# return path[::-1]
#
# for dr, dc in directions:
# nr, nc = row + dr, col + dc
# if 0 <= nr < rows and 0 <= nc < cols:
# if is_passable(cells[nr][nc]):
# # ★ РАЗНЫЕ СТОИМОСТИ ДЛЯ ДИАГОНАЛЕЙ ★
# if abs(dr) + abs(dc) == 2: # диагональ
# move_cost = 1.414 # √2
# else: # ортогональ
# move_cost = 1.0
#
# tentative_g = g_score[(row, col)] + move_cost
# pos = (nr, nc)
#
# if tentative_g < g_score[pos]:
# came_from[pos] = (row, col)
# g_score[pos] = tentative_g
#
# # ★ ЧЕБЫШЕВ для диагоналей лучше манхэттена ★
# h = max(abs(nr - g_row), abs(nc - g_col))
# f = tentative_g + h
# heappush(open_set, (f, tentative_g, nr, nc))
#
# print("Путь не найден (нет связи)")
# return None
def find_way(cells, start, goal):
"""Находит путь с диагональным движением, но БЕЗ прохода через углы"""
rows = len(cells)
if rows == 0:
return None
cols = len(cells[0])
def is_passable(cell):
return (cell.terrain_obj is None or not isinstance(cell.terrain_obj, Rock))
s_row, s_col = start
g_row, g_col = goal
if not (0 <= s_row < rows and 0 <= s_col < cols and 0 <= g_row < rows and 0 <= g_col < cols):
return None
start_cell = cells[s_row][s_col]
goal_cell = cells[g_row][g_col]
if not is_passable(start_cell) or not is_passable(goal_cell):
print(f"Старт/гол непроходимы")
return None
directions = [
(-1, 0), (1, 0), (0, -1), (0, 1), # ортогональ (1.0)
(-1, -1), (-1, 1), (1, -1), (1, 1) # диагональ (1.414)
]
def can_move_diagonal(current_r, current_c, dr, dc):
"""Проверяет, можно ли двигаться по диагонали (НЕ через угол)"""
nr, nc = current_r + dr, current_c + dc
# Ортогональные соседи ДОЛЖНЫ быть проходимыми для диагонального хода
ortho1_r, ortho1_c = current_r + dr, current_c # вертикальный сосед
ortho2_r, ortho2_c = current_r, current_c + dc # горизонтальный сосед
# Проверяем границы для ортососедей
if not (0 <= ortho1_r < rows and 0 <= ortho1_c < cols):
return False
if not (0 <= ortho2_r < rows and 0 <= ortho2_c < cols):
return False
return (is_passable(cells[ortho1_r][ortho1_c]) and
is_passable(cells[ortho2_r][ortho2_c]))
open_set = []
h = max(abs(s_row - g_row), abs(s_col - g_col))
heappush(open_set, (h, 0, s_row, s_col))
came_from = {}
g_score = defaultdict(lambda: float('inf'))
g_score[(s_row, s_col)] = 0
while open_set:
_, _, row, col = heappop(open_set)
if (row, col) == (g_row, g_col):
path = []
current = (row, col)
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
return path[::-1]
for dr, dc in directions:
nr, nc = row + dr, col + dc
if 0 <= nr < rows and 0 <= nc < cols and is_passable(cells[nr][nc]):
# ★ ПРОВЕРКА ДИАГОНАЛИ ★
if abs(dr) + abs(dc) == 2: # диагональное движение
if not can_move_diagonal(row, col, dr, dc):
continue # пропускаем запрещённую диагональ
move_cost = 1.414 if abs(dr) + abs(dc) == 2 else 1.0
tentative_g = g_score[(row, col)] + move_cost
pos = (nr, nc)
if tentative_g < g_score[pos]:
came_from[pos] = (row, col)
g_score[pos] = tentative_g
h = max(abs(nr - g_row), abs(nc - g_col))
f = tentative_g + h
heappush(open_set, (f, tentative_g, nr, nc))
print("Путь не найден")
return None