from abc import ABC, abstractmethod
from typing import List
import os
from maze_core import Maze, Cell

class Observer(ABC):
    @abstractmethod
    def update(self, event: str):
        pass

class ConsoleObserver(Observer):
    def update(self, event: str):
        print(f"{event}")
    
    def draw(self, maze: Maze, player: Cell = None, path: List[Cell] = None):
        os.system('cls' if os.name == 'nt' else 'clear')
        path_set = set(path) if path else set()
        
        for y in range(maze.height):
            row = []
            for x in range(maze.width):
                cell = maze.cell_at(x, y)
                if player and cell == player:
                    row.append('@')
                elif cell in path_set:
                    row.append('*' if not cell.is_start and not cell.is_exit else str(cell))
                else:
                    row.append(str(cell))
            print(''.join(row))
class Command(ABC):
    @abstractmethod
    def execute(self): pass
    
    @abstractmethod
    def undo(self): pass

class Player:
    def __init__(self, start: Cell):
        self.pos = start
    
    def move(self, cell: Cell):
        self.pos = cell

class MoveCommand(Command):
    def __init__(self, player: Player, new_pos: Cell):
        self.player = player
        self.new_pos = new_pos
        self.old_pos = player.pos
    
    def execute(self):
        self.player.move(self.new_pos)
    
    def undo(self):
        self.player.move(self.old_pos)