from enum import Enum
import numpy as np


class Direction(Enum):
    UP = 0
    LEFT = 1
    RIGHT = 2
    DOWN = 3


class Field(Enum):
    NOTHING = 0
    WIN = 1

    def __str__(self) -> str:
        match self:
            case Field.NOTHING: return ""
            case Field.WIN: return ""
            case _: raise NotImplementedError("field type not implemented")


class Player:
    x_pos: int
    y_pos: int

    def __init__(self, start_x: int, start_y: int) -> None:
        self.x_pos = start_x
        self.y_pos = start_y

    def __str__(self) -> str:
        return "󰳆 "


class Map:
    map: np.ndarray
    x: int
    y: int

    def __init__(self, x: int, y: int) -> None:
        self.map = np.array([Field.NOTHING] * (x*y)).reshape(y, x)
        self.map[0][0] = Field.WIN
        self.map[-1][-1] = Field.WIN
        self.x = x
        self.y = y

    def make_player(self) -> Player:
        return Player(int(self.x/2), int(self.y/2))

    def __str__(self) -> str:
        buf = "-" + "-" * (self.x * 3) + "\n"
        for row in self.map:
            for field in row:
                buf += (f"|{field} ")
            buf += ("|\n")
        buf += "-" + "-" * self.x * 3
        return buf

    def render(self, player: Player) -> str:
        buf = "-" + "-" * self.x * 3 + "\n"
        for y, row in enumerate(self.map):
            for x, field in enumerate(row):
                if (player.x_pos, player.y_pos) == (x, y):
                    buf += ("|󰳆 ")
                else:
                    buf += (f"|{field} ")
            buf += ("|\n")
        buf += "-" + "-" * self.x * 3
        return buf

    def set_position(self, player: Player, x: int, y: int) -> bool:
        if not 0 <= x <= self.x and 0 <= y <= self.y:
            return False
        else:
            player.x_pos = x
            player.y_pos = y
            return True

    def move(self, player: Player, direction: Direction) -> bool:
        match direction:
            case Direction.UP: return self.set_position(player, player.x_pos,
                                                        player.y_pos-1)
            case Direction.DOWN: return self.set_position(player, player.x_pos,
                                                          player.y_pos+1)
            case Direction.LEFT: return self.set_position(player, player.x_pos-1,
                                                          player.y_pos)
            case Direction.RIGHT: return self.set_position(player, player.x_pos+1,
                                                           player.y_pos)


def main():
    map = Map(5, 5)
    p = map.make_player()
    print(map.render(p))
    assert map.move(p, Direction.UP)
    print(map.render(p))
    assert map.move(p, Direction.LEFT)
    assert map.move(p, Direction.LEFT)
    print(map.render(p))


if __name__ == "__main__":
    main()
