"""
Demonstration Vibe-Coding:
Klicke wiederholt irgendwo auf die schwarze Fläche.
"""

import turtle

# ---------------- Einstellungen ----------------

STEP = 12          # Abstand zwischen zwei Rasterpunkten
DELAY = 5          # Millisekunden zwischen Animationsschritten
STEPS_PER_FRAME = 4  # Höher = schnellere Bewegung

WIDTH = 700
HEIGHT = 500


# ---------------- Turtle einrichten ----------------

screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
screen.bgcolor("white")
screen.title("Dichter Turtle-Weg – Klick zum Zeichnen, Q zum Beenden")
screen.tracer(0, 0)

runner = turtle.Turtle()
runner.shape("turtle")
runner.color("#009ee3")
runner.pensize(2)
runner.speed(0)
runner.penup()
runner.goto(0, 0)
runner.pendown()

MAX_X = WIDTH // (2 * STEP) - 2
MAX_Y = HEIGHT // (2 * STEP) - 2

current = (0, 0)
visited = {current}

route = []
moving = False
pending_target = None


# ---------------- Hilfsfunktionen ----------------

def sign(number):
    if number > 0:
        return 1
    if number < 0:
        return -1
    return 0


def inclusive_range(start, stop):
    """Range einschließlich des Endwerts."""
    direction = 1 if stop >= start else -1
    return range(start, stop + direction, direction)


def grid_to_screen(cell):
    x, y = cell
    return x * STEP, y * STEP


def screen_to_grid(x, y):
    """Mausposition auf das Raster runden."""
    grid_x = round(x / STEP)
    grid_y = round(y / STEP)

    grid_x = max(-MAX_X, min(MAX_X, grid_x))
    grid_y = max(-MAX_Y, min(MAX_Y, grid_y))

    return grid_x, grid_y


def adjust_target_for_dense_path(start, target):
    """
    Bei einem Rechteck mit gerader Zeilen- und Spaltenzahl kann ein
    vollständig füllender Weg nicht immer an der gegenüberliegenden
    Ecke enden.

    Das Ziel wird dann höchstens um eine Rasterzelle verschoben.
    """
    sx, sy = start
    tx, ty = target

    columns = abs(tx - sx) + 1
    rows = abs(ty - sy) + 1

    if columns % 2 == 1 or rows % 2 == 1:
        return target

    # Ziel um höchstens STEP Pixel verschieben.
    if ty != sy:
        ty -= sign(ty - sy)
    elif tx != sx:
        tx -= sign(tx - sx)

    return tx, ty


# ---------------- Dichten Weg erzeugen ----------------

def horizontal_snake(start, target):
    """
    Füllt das Rechteck zeilenweise.

    Voraussetzung: Die Anzahl der Zeilen ist ungerade.
    """
    sx, sy = start
    tx, ty = target

    xs = list(inclusive_range(sx, tx))
    ys = list(inclusive_range(sy, ty))

    path = []

    for row_number, y in enumerate(ys):
        row = xs if row_number % 2 == 0 else reversed(xs)

        for x in row:
            path.append((x, y))

    return path


def vertical_snake(start, target):
    """
    Füllt das Rechteck spaltenweise.

    Voraussetzung: Die Anzahl der Spalten ist ungerade.
    """
    sx, sy = start
    tx, ty = target

    xs = list(inclusive_range(sx, tx))
    ys = list(inclusive_range(sy, ty))

    path = []

    for column_number, x in enumerate(xs):
        column = ys if column_number % 2 == 0 else reversed(ys)

        for y in column:
            path.append((x, y))

    return path


def create_dense_route(start, clicked_target):
    """
    Erzeugt einen dichten, lückenlosen Weg durch das Rechteck
    zwischen Start und Ziel.
    """
    target = adjust_target_for_dense_path(start, clicked_target)

    sx, sy = start
    tx, ty = target

    columns = abs(tx - sx) + 1
    rows = abs(ty - sy) + 1

    # Die Variante mit mehr Richtungswechseln wählen.
    if rows % 2 == 1 and columns >= rows:
        path = horizontal_snake(start, target)
    elif columns % 2 == 1:
        path = vertical_snake(start, target)
    else:
        path = horizontal_snake(start, target)

    return path, target


# ---------------- Bewegung ----------------

def set_turtle_direction(old_cell, new_cell):
    dx = new_cell[0] - old_cell[0]
    dy = new_cell[1] - old_cell[1]

    headings = {
        (1, 0): 0,
        (0, 1): 90,
        (-1, 0): 180,
        (0, -1): 270,
    }

    runner.setheading(headings[(dx, dy)])


def animate():
    """Zeichnet mehrere Schritte pro Bildaufbau."""
    global current
    global moving
    global pending_target

    steps_done = 0

    while route and steps_done < STEPS_PER_FRAME:
        next_cell = route.pop(0)

        set_turtle_direction(current, next_cell)

        runner.goto(grid_to_screen(next_cell))

        current = next_cell
        visited.add(current)
        steps_done += 1

    screen.update()

    if route:
        screen.ontimer(animate, DELAY)
        return

    moving = False

    if pending_target is not None:
        next_target = pending_target
        pending_target = None
        start_route(next_target)


def start_route(clicked_target):
    """Plant den vollständigen Weg und startet die Animation."""
    global route
    global moving

    if clicked_target == current:
        return

    planned_path, actual_target = create_dense_route(
        current,
        clicked_target,
    )

    # Der Startpunkt ist bereits betreten.
    planned_path = planned_path[1:]

    collisions = [
        cell
        for cell in planned_path
        if cell in visited
    ]

    if collisions:
        print(
            "Dieser Bereich überschneidet sich mit einem "
            "bereits gezeichneten Weg."
        )
        return

    if actual_target != clicked_target:
        print(
            "Das Ziel wurde um eine Rasterzelle verschoben, "
            "damit der Bereich vollständig gefüllt werden kann."
        )

    route = planned_path
    moving = True
    animate()


# ---------------- Eingabe ----------------

def clicked(x, y):
    global pending_target

    target = screen_to_grid(x, y)

    if moving:
        # Während der Bewegung wird nur der neueste Klick gespeichert.
        pending_target = target
    else:
        start_route(target)


def quit_program():
    try:
        screen.bye()
    except turtle.Terminator:
        pass

print("Klicke wiederholt irgendwo auf die schwarze Fläche.")
screen.onclick(clicked)

screen.listen()
screen.onkey(quit_program, "q")
screen.onkey(quit_program, "Q")
screen.onkey(quit_program, "Escape")

screen.update()
screen.mainloop()