from gturtle import *
from random import randint, random, choice

# ==========================================
# SPIELAUSWAHL BEIM START
# ==========================================
choice_msg = (
    "Waehle ein Spiel durch Eingabe der Nummer:\n\n"
    "1: Breakout\n"
    "2: Flappy Bird\n"
    "3: Fruechtefangen\n"
    "4: Jump 'n' Run\n"
    "5: Snake\n"
    "6: Tetris"
)

selected_game = inputString(choice_msg)

# ==========================================
# 1. BREAKOUT
# ==========================================
if selected_game == "1":
    WIDTH = 600
    HEIGHT = 600
    X_BOUND = WIDTH // 2    # -300 bis 300
    Y_BOUND = HEIGHT // 2   # -300 bis 300

    VK_LEFT = 37
    VK_RIGHT = 39
    VK_A = 65
    VK_D = 68
    VK_SPACE = 32

    COLOR_BG = "black"
    COLOR_PADDLE = "cyan"
    COLOR_BALL = "white"
    COLOR_TEXT = "yellow"
    BRICK_COLORS = ["red", "darkOrange", "yellow", "green", "magenta"]

    PADDLE_Y = -250
    PADDLE_WIDTH = 80
    PADDLE_HEIGHT = 12
    PADDLE_SPEED = 22

    BALL_RADIUS = 7
    INITIAL_BALL_SPEED = 7.0

    BRICK_ROWS = 5
    BRICK_COLS = 8
    BRICK_WIDTH = 64
    BRICK_HEIGHT = 16
    BRICK_TOP_Y = 220

    Options.setPlaygroundSize(WIDTH, HEIGHT)
    tf = TurtleFrame()
    t = Turtle(tf)
    t.hideTurtle()
    t.speed(-1)
    tf.enableRepaint(False)

    high_score = 0

    def label_centered(text, y):
        width = t.getTextWidth(text)
        t.setPos(0 - width / 2.0, y)
        t.label(text)

    def draw_filled_rect(x, y, w, h, color):
        t.setFillColor(color)
        t.setPenColor(color)
        step = 4
        half_w = w / 2.0
        half_h = h / 2.0
        curr_y = y - half_h + step / 2.0
        while curr_y <= y + half_h:
            curr_x = x - half_w + step / 2.0
            while curr_x <= x + half_w:
                t.setPos(curr_x, curr_y)
                t.dot(step + 2)
                curr_x += step
            curr_y += step

    def draw_ball(x, y):
        t.setFillColor(COLOR_BALL)
        t.setPenColor(COLOR_BALL)
        t.setPos(x, y)
        t.dot(BALL_RADIUS * 2)

    def create_bricks():
        bricks = []
        start_x = -X_BOUND + (BRICK_WIDTH / 2.0) + 12
        for row in range(BRICK_ROWS):
            y = BRICK_TOP_Y - (row * (BRICK_HEIGHT + 6))
            color = BRICK_COLORS[row % len(BRICK_COLORS)]
            points = (BRICK_ROWS - row) * 10
            for col in range(BRICK_COLS):
                x = start_x + col * (BRICK_WIDTH + 8)
                bricks.append({
                    "x": x, "y": y,
                    "w": BRICK_WIDTH, "h": BRICK_HEIGHT,
                    "color": color, "points": points,
                    "active": True
                })
        return bricks

    def play_round():
        global high_score
        score = 0
        lives = 3
        level = 1
        paddle_x = 0
        ball_x = 0
        ball_y = PADDLE_Y + (PADDLE_HEIGHT / 2) + BALL_RADIUS + 2
        current_speed = INITIAL_BALL_SPEED
        ball_vx = 0
        ball_vy = 0
        ball_attached = True
        bricks = create_bricks()
        game_over = False

        while not game_over:
            move_dir = 0
            while tf.kbhit():
                code = tf.getKeyCode()
                if code == VK_LEFT or code == VK_A:
                    move_dir = -1
                elif code == VK_RIGHT or code == VK_D:
                    move_dir = 1
                elif code == VK_SPACE and ball_attached:
                    ball_attached = False
                    ball_vx = choice([-current_speed * 0.6, current_speed * 0.6])
                    ball_vy = current_speed

            paddle_x += move_dir * PADDLE_SPEED
            max_paddle_x = X_BOUND - (PADDLE_WIDTH / 2)
            if paddle_x < -max_paddle_x:
                paddle_x = -max_paddle_x
            if paddle_x > max_paddle_x:
                paddle_x = max_paddle_x

            if ball_attached:
                ball_x = paddle_x
                ball_y = PADDLE_Y + (PADDLE_HEIGHT / 2) + BALL_RADIUS + 2
            else:
                ball_x += ball_vx
                ball_y += ball_vy

                if ball_x - BALL_RADIUS <= -X_BOUND:
                    ball_x = -X_BOUND + BALL_RADIUS
                    ball_vx = -ball_vx
                elif ball_x + BALL_RADIUS >= X_BOUND:
                    ball_x = X_BOUND - BALL_RADIUS
                    ball_vx = -ball_vx

                if ball_y + BALL_RADIUS >= Y_BOUND:
                    ball_y = Y_BOUND - BALL_RADIUS
                    ball_vy = -ball_vy

                if ball_y - BALL_RADIUS <= -Y_BOUND:
                    lives -= 1
                    if lives <= 0:
                        game_over = True
                    else:
                        ball_attached = True

                p_top = PADDLE_Y + (PADDLE_HEIGHT / 2)
                p_bottom = PADDLE_Y - (PADDLE_HEIGHT / 2)
                p_left = paddle_x - (PADDLE_WIDTH / 2)
                p_right = paddle_x + (PADDLE_WIDTH / 2)

                if (ball_y - BALL_RADIUS <= p_top) and (ball_y + BALL_RADIUS >= p_bottom) and \
                   (ball_x + BALL_RADIUS >= p_left) and (ball_x - BALL_RADIUS <= p_right) and (ball_vy < 0):
                    hit_pos = (ball_x - paddle_x) / (PADDLE_WIDTH / 2.0)
                    hit_pos = max(-1.0, min(1.0, hit_pos))
                    ball_vx = hit_pos * (current_speed * 0.85)
                    ball_vy = current_speed
                    ball_y = p_top + BALL_RADIUS + 1

                active_bricks_count = 0
                for b in bricks:
                    if b["active"]:
                        active_bricks_count += 1
                        b_left = b["x"] - b["w"] / 2
                        b_right = b["x"] + b["w"] / 2
                        b_bottom = b["y"] - b["h"] / 2
                        b_top = b["y"] + b["h"] / 2

                        if (ball_x + BALL_RADIUS >= b_left) and (ball_x - BALL_RADIUS <= b_right) and \
                           (ball_y + BALL_RADIUS >= b_bottom) and (ball_y - BALL_RADIUS <= b_top):
                            b["active"] = False
                            score += b["points"]
                            ball_vy = -ball_vy
                            break

                if active_bricks_count == 0:
                    level += 1
                    current_speed += 1.0
                    bricks = create_bricks()
                    ball_attached = True

            tf.clear(COLOR_BG)
            for b in bricks:
                if b["active"]:
                    draw_filled_rect(b["x"], b["y"], b["w"], b["h"], b["color"])

            draw_filled_rect(paddle_x, PADDLE_Y, PADDLE_WIDTH, PADDLE_HEIGHT, COLOR_PADDLE)
            draw_ball(ball_x, ball_y)

            t.setFillColor(COLOR_TEXT)
            t.setPenColor(COLOR_TEXT)
            t.setPos(-X_BOUND + 20, Y_BOUND - 30)
            t.label("Score: " + str(score))
            t.setPos(X_BOUND - 120, Y_BOUND - 30)
            t.label("Leben: " + str(lives))

            if ball_attached and not game_over:
                label_centered("LEERTASTE zum Starten", -50)

            tf.repaint()
            tf.delay(20)

        return score

    def show_game_over(score):
        tf.clear(COLOR_BG)
        t.setFillColor(COLOR_TEXT)
        t.setPenColor(COLOR_TEXT)
        label_centered("GAME OVER", 60)
        label_centered("Punkte: " + str(score), 10)
        label_centered("Highscore: " + str(high_score), -30)
        label_centered("Druecke LEERTASTE fuer Neustart", -90)
        tf.repaint()

    def wait_for_restart():
        while True:
            if tf.kbhit():
                if tf.getKeyCode() == VK_SPACE:
                    return
            tf.delay(30)

    while True:
        final_score = play_round()
        if final_score > high_score:
            high_score = final_score
        show_game_over(final_score)
        wait_for_restart()


# ==========================================
# 2. FLAPPY BIRD
# ==========================================
elif selected_game == "2":
    Options.setPlaygroundSize(500, 700)
    tf = TurtleFrame()
    t = Turtle(tf)
    t.hideTurtle()
    t.speed(-1)
    tf.enableRepaint(False)

    VK_SPACE = 32
    VK_UP = 38

    TOP_Y = 340
    GROUND_Y = -300

    GRAVITY = -0.8
    JUMP = 11
    MAX_FALL_SPEED = -14

    PIPE_SPEED = 4
    PIPE_HALF_WIDTH = 25
    GAP = 160
    SPAWN_INTERVAL = 65

    BIRD_X = -150
    BIRD_RADIUS = 15

    high_score = 0

    def draw_column(x, y_from, y_to, color):
        t.setPenColor(color)
        t.setFillColor(color)
        step = 18
        y = y_from
        while y <= y_to:
            t.setPos(x, y)
            t.dot(PIPE_HALF_WIDTH * 2)
            y += step

    def draw_pipe_pair(px, gap_y):
        top_from = gap_y + GAP // 2
        bottom_to = gap_y - GAP // 2

        draw_column(px, top_from, TOP_Y, "green")
        draw_column(px, GROUND_Y, bottom_to, "green")

        t.setPenColor("green")
        t.setFillColor("green")
        t.setPos(px, top_from)
        t.dot(PIPE_HALF_WIDTH * 2 + 16)
        t.setPos(px, bottom_to)
        t.dot(PIPE_HALF_WIDTH * 2 + 16)

    def draw_ground():
        t.setPenColor("peru")
        t.setFillColor("peru")
        x = -260
        while x <= 260:
            t.setPos(x, GROUND_Y - 10)
            t.dot(46)
            x += 22

    def draw_bird(bird_y, tilt):
        t.setPenColor("gold")
        t.setFillColor("gold")
        t.setPos(BIRD_X, bird_y)
        t.dot(BIRD_RADIUS * 2)

        t.setPenColor("orange")
        t.setFillColor("orange")
        t.setPos(BIRD_X - 4, bird_y - 4 + tilt)
        t.dot(12)

        t.setPenColor("black")
        t.setFillColor("white")
        t.setPos(BIRD_X + 5, bird_y + 6)
        t.dot(9)
        t.setFillColor("black")
        t.setPos(BIRD_X + 7, bird_y + 6)
        t.dot(4)

        t.setPenColor("darkOrange")
        t.setFillColor("darkOrange")
        t.setPos(BIRD_X + BIRD_RADIUS + 2, bird_y - 1)
        t.dot(11)

    def label_centered(text, y):
        width = t.getTextWidth(text)
        t.setPenColor("black")
        t.setPos(0 - width / 2.0, y)
        t.label(text)

    def draw(bird_y, tilt, pipes, score):
        tf.clear("cyan")

        for pipe in pipes:
            draw_pipe_pair(pipe[0], pipe[1])

        draw_ground()
        draw_bird(bird_y, tilt)

        t.setPenColor("black")
        t.setPos(-240, 320)
        t.label("Score: " + str(score))
        t.setPos(90, 320)
        t.label("Highscore: " + str(high_score))

        tf.repaint()

    def show_game_over(score):
        tf.clear("cyan")
        label_centered("GAME OVER", 40)
        label_centered("Score: " + str(score), 0)
        label_centered("Highscore: " + str(high_score), -40)
        label_centered("Leertaste fuer Neustart", -90)
        tf.repaint()

    def wait_for_restart():
        while True:
            if tf.kbhit():
                code = tf.getKeyCode()
                if code == VK_SPACE:
                    return
            tf.delay(30)

    def play_round():
        bird_y = 0.0
        bird_dy = 0.0
        tilt = 0
        pipes = []
        score = 0
        frame = 0
        game_over = False

        while not game_over:
            jumped = False
            while tf.kbhit():
                code = tf.getKeyCode()
                if code == VK_SPACE or code == VK_UP:
                    jumped = True

            if jumped:
                bird_dy = JUMP
                tilt = -4
            else:
                tilt = 3 if bird_dy < 0 else -2

            bird_dy += GRAVITY
            if bird_dy < MAX_FALL_SPEED:
                bird_dy = MAX_FALL_SPEED
            bird_y += bird_dy

            if bird_y > TOP_Y - BIRD_RADIUS:
                bird_y = TOP_Y - BIRD_RADIUS
                bird_dy = 0
            if bird_y < GROUND_Y + BIRD_RADIUS:
                game_over = True
                break

            for pipe in pipes:
                pipe[0] -= PIPE_SPEED

            if len(pipes) > 0 and pipes[0][0] < -280:
                pipes.pop(0)

            frame += 1
            if frame % SPAWN_INTERVAL == 0:
                pipes.append([280, randint(-90, 90), False])

            for pipe in pipes:
                px = pipe[0]
                gap_y = pipe[1]
                scored = pipe[2]

                if abs(px - BIRD_X) < (PIPE_HALF_WIDTH + BIRD_RADIUS):
                    if (bird_y > gap_y + GAP // 2 - BIRD_RADIUS
                            or bird_y < gap_y - GAP // 2 + BIRD_RADIUS):
                        game_over = True

                if not scored and px < BIRD_X:
                    pipe[2] = True
                    score += 1

            draw(bird_y, tilt, pipes, score)
            tf.delay(25)

        return score

    while True:
        final_score = play_round()
        if final_score > high_score:
            high_score = final_score
        show_game_over(final_score)
        wait_for_restart()


# ==========================================
# 3. FRÜCHTEFANGEN
# ==========================================
elif selected_game == "3":
    BOUND_X = 280
    GROUND_Y = -320
    TOP_Y = 300
    LABEL_Y = 330

    Options.setPlaygroundSize(620, 700)
    tf = TurtleFrame()
    t = Turtle(tf)
    t.hideTurtle()
    t.speed(-1)
    tf.enableRepaint(False)

    VK_LEFT = 37
    VK_RIGHT = 39
    VK_A = 65
    VK_D = 68
    VK_SPACE = 32

    BOWL_Y = GROUND_Y + 40
    BOWL_HALF_WIDTH = 36
    BOWL_SPEED = 30

    FRUIT_COLORS = ["red", "orange", "yellow", "purple", "magenta"]
    OBJECT_RADIUS = 13
    BOMB_CHANCE = 0.22

    BASE_FALL_SPEED = 5.0
    MAX_FALL_SPEED = 12.0
    BASE_SPAWN_INTERVAL = 28
    MIN_SPAWN_INTERVAL = 12
    RAMP_FRAMES = 250

    START_LIVES = 3
    FRAME_DELAY = 18

    high_score = 0

    def label_centered(text, y):
        width = t.getTextWidth(text)
        t.setPos(0 - width / 2.0, y)
        t.label(text)

    def draw_ground():
        t.setPenColor("peru")
        t.setFillColor("peru")
        x = -BOUND_X
        while x <= BOUND_X:
            t.setPos(x, GROUND_Y - 10)
            t.dot(46)
            x += 22

    def draw_bowl(bowl_x):
        t.setPenColor("brown")
        t.setFillColor("brown")
        x = -BOWL_HALF_WIDTH
        while x <= BOWL_HALF_WIDTH:
            t.setPos(bowl_x + x, BOWL_Y)
            t.dot(18)
            x += 14

        t.setPos(bowl_x - BOWL_HALF_WIDTH, BOWL_Y + 12)
        t.dot(20)
        t.setPos(bowl_x + BOWL_HALF_WIDTH, BOWL_Y + 12)
        t.dot(20)

    def draw_object(obj):
        x, y, kind = obj[0], obj[1], obj[2]

        if kind == "bomb":
            t.setPenColor("black")
            t.setFillColor("black")
            t.setPos(x, y)
            t.dot(OBJECT_RADIUS * 2)
            t.setPenColor("orange")
            t.setFillColor("orange")
            t.setPos(x, y + OBJECT_RADIUS)
            t.dot(6)
        else:
            t.setPenColor(kind)
            t.setFillColor(kind)
            t.setPos(x, y)
            t.dot(OBJECT_RADIUS * 2)
            t.setPenColor("green")
            t.setFillColor("green")
            t.setPos(x, y + OBJECT_RADIUS)
            t.dot(6)

    def draw(bowl_x, objects, score, lives):
        tf.clear("cyan")
        draw_ground()

        for obj in objects:
            draw_object(obj)

        draw_bowl(bowl_x)

        t.setPenColor("black")
        t.setPos(-BOUND_X, LABEL_Y)
        t.label("Score: " + str(score))
        t.setPos(-30, LABEL_Y)
        t.label("Leben: " + str(lives))
        t.setPos(120, LABEL_Y)
        t.label("Highscore: " + str(high_score))
        tf.repaint()

    def show_game_over(score):
        tf.clear("cyan")
        t.setPenColor("black")
        label_centered("GAME OVER", 40)
        label_centered("Score: " + str(score), 0)
        label_centered("Highscore: " + str(high_score), -40)
        label_centered("Leertaste fuer Neustart", -90)
        tf.repaint()

    def wait_for_restart():
        while True:
            if tf.kbhit():
                if tf.getKeyCode() == VK_SPACE:
                    return
            tf.delay(30)

    def spawn_object():
        x = randint(-BOUND_X + 20, BOUND_X - 20)
        if random() < BOMB_CHANCE:
            return [x, float(TOP_Y), "bomb"]
        return [x, float(TOP_Y), choice(FRUIT_COLORS)]

    def play_round():
        bowl_x = 0
        objects = []
        score = 0
        lives = START_LIVES
        frame = 0
        game_over = False

        while not game_over:
            while tf.kbhit():
                code = tf.getKeyCode()
                if code == VK_LEFT or code == VK_A:
                    bowl_x -= BOWL_SPEED
                elif code == VK_RIGHT or code == VK_D:
                    bowl_x += BOWL_SPEED

            if bowl_x < -BOUND_X + BOWL_HALF_WIDTH:
                bowl_x = -BOUND_X + BOWL_HALF_WIDTH
            if bowl_x > BOUND_X - BOWL_HALF_WIDTH:
                bowl_x = BOUND_X - BOWL_HALF_WIDTH

            level = frame // RAMP_FRAMES
            fall_speed = min(BASE_FALL_SPEED + level * 0.8, MAX_FALL_SPEED)
            spawn_interval = max(BASE_SPAWN_INTERVAL - level * 2, MIN_SPAWN_INTERVAL)

            frame += 1
            if frame % spawn_interval == 0:
                objects.append(spawn_object())

            for obj in objects:
                obj[1] -= fall_speed

            remaining = []
            for obj in objects:
                x, y, kind = obj[0], obj[1], obj[2]
                hit_bowl = abs(y - BOWL_Y) < 20 and abs(x - bowl_x) < BOWL_HALF_WIDTH

                if hit_bowl:
                    if kind == "bomb":
                        lives -= 1
                    else:
                        score += 1
                elif y < GROUND_Y:
                    if kind != "bomb":
                        lives -= 1
                else:
                    remaining.append(obj)

            objects = remaining

            if lives <= 0:
                game_over = True
                break

            draw(bowl_x, objects, score, lives)
            tf.delay(FRAME_DELAY)

        return score

    while True:
        final_score = play_round()
        if final_score > high_score:
            high_score = final_score
        show_game_over(final_score)
        wait_for_restart()


# ==========================================
# 4. JUMP 'N' RUN
# ==========================================
elif selected_game == "4":
    WIDTH = 700
    HEIGHT = 450
    GROUND_Y = -110

    VK_SPACE = 32
    VK_UP = 38
    VK_DOWN = 40
    VK_S = 83

    Options.setPlaygroundSize(WIDTH, HEIGHT)
    tf = TurtleFrame()
    t = Turtle(tf)
    t.hideTurtle()
    t.speed(-1)
    tf.enableRepaint(False)

    high_score = 0

    COLOR_WHITE = "white"
    COLOR_BLACK = "black"
    COLOR_GOLD = "gold"

    COLOR_DESERT_SKY = makeColor(135, 206, 235)
    COLOR_DESERT_GROUND = makeColor(212, 164, 110)

    COLOR_TWILIGHT_SKY = makeColor(75, 45, 100)
    COLOR_TWILIGHT_GROUND = makeColor(150, 100, 80)

    COLOR_NIGHT_SKY = makeColor(15, 20, 50)
    COLOR_NIGHT_GROUND = makeColor(70, 75, 95)

    COLOR_INFERNO_SKY = makeColor(50, 10, 20)
    COLOR_INFERNO_GROUND = makeColor(210, 60, 30)

    def label_centered(text, y, color="black"):
        width = t.getTextWidth(text)
        t.setPos(0 - width / 2.0, y)
        t.setPenColor(color)
        t.label(text)

    def draw_environment(level, clouds, stars):
        if level == 1:
            sky_color, ground_color = COLOR_DESERT_SKY, COLOR_DESERT_GROUND
        elif level == 2:
            sky_color, ground_color = COLOR_TWILIGHT_SKY, COLOR_TWILIGHT_GROUND
        elif level == 3:
            sky_color, ground_color = COLOR_NIGHT_SKY, COLOR_NIGHT_GROUND
        else:
            sky_color, ground_color = COLOR_INFERNO_SKY, COLOR_INFERNO_GROUND

        tf.clear(sky_color)

        if level >= 3:
            t.setFillColor(COLOR_WHITE)
            for star in stars:
                t.setPos(star[0], star[1])
                t.dot(star[2])

        if level <= 2:
            t.setFillColor(COLOR_WHITE)
            for cloud in clouds:
                cx, cy = cloud["x"], cloud["y"]
                t.setPos(cx, cy)
                t.dot(24)
                t.setPos(cx - 12, cy - 4)
                t.dot(18)
                t.setPos(cx + 12, cy - 4)
                t.dot(18)

        t.setFillColor(ground_color)
        x = -WIDTH // 2 - 20
        while x <= WIDTH // 2 + 20:
            t.setPos(x, GROUND_Y - 15)
            t.dot(36)
            x += 18

    def draw_player(x, y, is_ducking, frame_count):
        leg_offset = 5 if (frame_count // 4) % 2 == 0 else -5

        if is_ducking:
            t.setFillColor(makeColor(230, 100, 20))
            t.setPos(x, y - 5)
            t.dot(24)
            t.setPos(x + 14, y - 5)
            t.dot(22)
            t.setPos(x + 26, y - 2)
            t.dot(16)
            t.setFillColor(COLOR_WHITE)
            t.setPos(x + 29, y)
            t.dot(5)
            t.setFillColor(COLOR_GOLD)
            t.setPos(x + 33, y - 3)
            t.dot(7)
            t.setFillColor(COLOR_BLACK)
            t.setPos(x - 4 + leg_offset, y - 16)
            t.dot(6)
            t.setPos(x + 10 - leg_offset, y - 16)
            t.dot(6)
        else:
            t.setFillColor(makeColor(230, 100, 20))
            t.setPos(x, y + 2)
            t.dot(28)
            t.setPos(x + 6, y + 16)
            t.dot(20)
            t.setPos(x + 12, y + 24)
            t.dot(16)
            t.setFillColor(COLOR_GOLD)
            t.setPos(x + 18, y + 22)
            t.dot(8)
            t.setFillColor(COLOR_WHITE)
            t.setPos(x + 14, y + 26)
            t.dot(5)
            t.setFillColor(COLOR_BLACK)
            t.setPos(x - 6 + leg_offset, y - 12)
            t.dot(7)
            t.setPos(x + 6 - leg_offset, y - 12)
            t.dot(7)

    def draw_obstacle(obs, frame_count):
        x = obs["x"]
        obs_type = obs["type"]

        if obs_type == "cactus_small":
            t.setFillColor("green")
            cy = GROUND_Y + 10
            while cy <= GROUND_Y + 38:
                t.setPos(x, cy)
                t.dot(18)
                cy += 8
            t.setPos(x - 8, GROUND_Y + 24)
            t.dot(10)
            t.setPos(x + 8, GROUND_Y + 28)
            t.dot(10)

        elif obs_type == "cactus_tall":
            t.setFillColor("darkOrange" if obs.get("inferno") else "green")
            cy = GROUND_Y + 10
            while cy <= GROUND_Y + 62:
                t.setPos(x, cy)
                t.dot(22)
                cy += 8
            t.setPos(x - 10, GROUND_Y + 35)
            t.dot(12)
            t.setPos(x + 10, GROUND_Y + 48)
            t.dot(12)

        elif obs_type == "bird":
            y = obs["y"]
            wing_flap = 8 if (frame_count // 5) % 2 == 0 else -8
            t.setFillColor("magenta")
            t.setPos(x, y)
            t.dot(20)
            t.setPos(x - 12, y + 2)
            t.dot(14)
            t.setFillColor(COLOR_GOLD)
            t.setPos(x - 18, y + 2)
            t.dot(8)
            t.setFillColor("purple")
            t.setPos(x + 2, y + wing_flap)
            t.dot(14)
            t.setPos(x + 6, y + wing_flap * 1.4)
            t.dot(10)

    def draw_ui(score, level, level_name, msg_timer):
        t.setFillColor(COLOR_BLACK)
        for bx in range(-WIDTH // 2 - 10, WIDTH // 2 + 20, 15):
            t.setPos(bx, HEIGHT // 2 - 25)
            t.dot(32)

        t.setPos(-WIDTH // 2 + 20, HEIGHT // 2 - 32)
        t.setPenColor(COLOR_WHITE)
        t.label("SCORE: " + str(score) + "   |   HIGHSCORE: " + str(high_score))

        t.setPos(WIDTH // 2 - 230, HEIGHT // 2 - 32)
        t.setPenColor(COLOR_GOLD)
        t.label("LVL " + str(level) + ": " + level_name)

        if msg_timer > 0:
            label_centered("LEVEL " + str(level) + " - " + level_name, 50, COLOR_GOLD)

    def show_game_over(score, level):
        tf.clear(COLOR_NIGHT_SKY)
        label_centered("GAME OVER", 60, "red")
        label_centered("Erreichtes Level: " + str(level), 10, COLOR_WHITE)
        label_centered("Score: " + str(score), -30, COLOR_WHITE)
        label_centered("Highscore: " + str(high_score), -70, COLOR_GOLD)
        label_centered("Druecke LEERTASTE zum Neustart", -120, COLOR_WHITE)
        tf.repaint()

    def wait_for_restart():
        while True:
            if tf.kbhit():
                code = tf.getKeyCode()
                if code == VK_SPACE:
                    return
            tf.delay(30)

    def play_round():
        player_x = -200
        player_y = GROUND_Y + 15
        player_vy = 0
        gravity = -1.7
        jump_strength = 19
        is_jumping = False
        duck_timer = 0

        clouds = [{"x": randint(-WIDTH//2, WIDTH//2), "y": randint(60, 160)} for _ in range(4)]
        stars = [(randint(-WIDTH//2, WIDTH//2), randint(20, HEIGHT//2 - 40), randint(2, 5)) for _ in range(25)]

        obstacles = []
        spawn_timer = 0

        score = 0
        frame_count = 0
        game_over = False

        level = 1
        level_name = "WUESTE"
        msg_timer = 40
        speed = 8.0
        min_spawn_time = 45

        while not game_over:
            frame_count += 1
            if msg_timer > 0:
                msg_timer -= 1

            jump_requested = False
            while tf.kbhit():
                code = tf.getKeyCode()
                if code in (VK_SPACE, VK_UP) and not is_jumping:
                    jump_requested = True
                elif code in (VK_DOWN, VK_S):
                    duck_timer = 6

            if jump_requested:
                player_vy = jump_strength
                is_jumping = True

            is_ducking = (duck_timer > 0) and not is_jumping
            if duck_timer > 0:
                duck_timer -= 1

            player_y += player_vy
            player_vy += gravity

            if is_jumping and (duck_timer > 0):
                player_vy -= 2.0

            if player_y <= GROUND_Y + 15:
                player_y = GROUND_Y + 15
                player_vy = 0
                is_jumping = False

            old_level = level
            if score < 150:
                level = 1
                level_name = "WUESTE"
                speed = 8.5
                min_spawn_time = 42
            elif score < 350:
                level = 2
                level_name = "DAEMMERUNG"
                speed = 11.0
                min_spawn_time = 35
            elif score < 650:
                level = 3
                level_name = "NACHTSCHATTEN"
                speed = 13.5
                min_spawn_time = 28
            else:
                level = 4
                level_name = "INFERNO CHAOS"
                speed = 16.5 + (score - 650) * 0.005
                min_spawn_time = 22

            if level != old_level:
                msg_timer = 45

            for cloud in clouds:
                cloud["x"] -= speed * 0.3
                if cloud["x"] < -WIDTH // 2 - 30:
                    cloud["x"] = WIDTH // 2 + 30
                    cloud["y"] = randint(60, 160)

            spawn_timer += 1
            if spawn_timer > min_spawn_time and random() < 0.06:
                spawn_x = WIDTH // 2 + 40

                if level == 1:
                    obs_type = choice(["cactus_small", "cactus_tall"])
                    obstacles.append({"x": spawn_x, "type": obs_type, "y": 0})
                elif level == 2:
                    obs_type = choice(["cactus_small", "cactus_tall", "bird"])
                    bird_y = GROUND_Y + 42 if random() < 0.5 else GROUND_Y + 80
                    obstacles.append({"x": spawn_x, "type": obs_type, "y": bird_y})
                else:
                    obs_type = choice(["cactus_small", "cactus_tall", "bird", "bird"])
                    bird_y = GROUND_Y + 40 if random() < 0.6 else GROUND_Y + 82
                    obstacles.append({"x": spawn_x, "type": obs_type, "y": bird_y, "inferno": (level == 4)})

                spawn_timer = 0

            for obs in obstacles:
                obs["x"] -= speed

            if len(obstacles) > 0 and obstacles[0]["x"] < -WIDTH // 2 - 40:
                obstacles.pop(0)
                score += 15

            for obs in obstacles:
                x_dist = abs(player_x - obs["x"])
                obs_type = obs["type"]

                if obs_type == "cactus_small":
                    if x_dist < 22 and player_y < GROUND_Y + 40:
                        game_over = True
                elif obs_type == "cactus_tall":
                    if x_dist < 24 and player_y < GROUND_Y + 64:
                        game_over = True
                elif obs_type == "bird":
                    bird_y = obs["y"]
                    if x_dist < 26:
                        if is_ducking:
                            if player_y + 10 > bird_y - 12:
                                game_over = True
                        else:
                            if abs((player_y + 15) - bird_y) < 22:
                                game_over = True

            draw_environment(level, clouds, stars)

            for obs in obstacles:
                draw_obstacle(obs, frame_count)

            draw_player(player_x, player_y, is_ducking, frame_count)
            draw_ui(score, level, level_name, msg_timer)

            tf.repaint()
            tf.delay(20)

        return score, level

    while True:
        final_score, final_level = play_round()
        if final_score > high_score:
            high_score = final_score
        show_game_over(final_score, final_level)
        wait_for_restart()


# ==========================================
# 5. SNAKE
# ==========================================
elif selected_game == "5":
    CELL = 40
    CELLS_PER_SIDE = 8
    BOUND = CELL * CELLS_PER_SIDE

    TEXT_Y = BOUND + 30
    WINDOW_SIZE = int(2 * BOUND + 120)

    Options.setPlaygroundSize(WINDOW_SIZE, WINDOW_SIZE)
    tf = TurtleFrame()
    t = Turtle(tf)
    t.hideTurtle()
    t.speed(-1)
    tf.enableRepaint(False)

    VK_UP = 38
    VK_DOWN = 40
    VK_LEFT = 37
    VK_RIGHT = 39
    VK_W = 87
    VK_A = 65
    VK_S = 83
    VK_D = 68
    VK_SPACE = 32

    high_score = 0

    def label_centered(text, y):
        width = t.getTextWidth(text)
        t.setPos(0 - width / 2.0, y)
        t.label(text)

    def draw_grid():
        grid_color = makeColor(60, 60, 60)
        t.setPenColor(grid_color)

        half_cell = CELL / 2.0
        grid_min = -BOUND - half_cell
        grid_max = BOUND + half_cell

        x = grid_min
        while x <= grid_max + 1:
            t.penUp()
            t.setPos(x, grid_min)
            t.penDown()
            t.moveTo(x, grid_max)
            x += CELL

        y = grid_min
        while y <= grid_max + 1:
            t.penUp()
            t.setPos(grid_min, y)
            t.penDown()
            t.moveTo(grid_max, y)
            y += CELL

        t.penUp()

    def draw(snake, food, score):
        tf.clear("black")
        draw_grid()

        t.setPenColor("red")
        t.setFillColor("red")
        t.setPos(food[0], food[1])
        t.dot(CELL - 6)

        for i in range(len(snake)):
            seg = snake[i]
            if i == 0:
                t.setPenColor("yellow")
                t.setFillColor("yellow")
            else:
                t.setPenColor("green")
                t.setFillColor("green")
            t.setPos(seg[0], seg[1])
            t.dot(CELL - 8)

        t.setPenColor("white")
        t.setPos(-BOUND, TEXT_Y)
        t.label("Score: " + str(score))
        t.setPos(BOUND * 0.35, TEXT_Y)
        t.label("Highscore: " + str(high_score))
        tf.repaint()

    def show_game_over(score):
        tf.clear("black")
        t.setPenColor("white")
        label_centered("GAME OVER", 60)
        label_centered("Score: " + str(score), 0)
        label_centered("Highscore: " + str(high_score), -60)
        label_centered("Leertaste fuer Neustart", -120)
        tf.repaint()

    def wait_for_restart():
        while True:
            if tf.kbhit():
                code = tf.getKeyCode()
                if code == VK_SPACE:
                    return
            tf.delay(30)

    def new_food(snake):
        limit = CELLS_PER_SIDE - 1
        while True:
            candidate = [randint(-limit, limit) * CELL, randint(-limit, limit) * CELL]
            if candidate not in snake:
                return candidate

    def play_round():
        snake = [[0, 0], [-CELL, 0], [-2 * CELL, 0]]
        direction = "right"
        food = new_food(snake)
        score = 0
        game_over = False

        while not game_over:
            while tf.kbhit():
                code = tf.getKeyCode()
                if (code == VK_UP or code == VK_W) and direction != "down":
                    direction = "up"
                elif (code == VK_DOWN or code == VK_S) and direction != "up":
                    direction = "down"
                elif (code == VK_LEFT or code == VK_A) and direction != "right":
                    direction = "left"
                elif (code == VK_RIGHT or code == VK_D) and direction != "left":
                    direction = "right"

            head_x = snake[0][0]
            head_y = snake[0][1]

            if direction == "up":
                head_y += CELL
            elif direction == "down":
                head_y -= CELL
            elif direction == "left":
                head_x -= CELL
            elif direction == "right":
                head_x += CELL

            new_head = [head_x, head_y]

            if head_x < -BOUND or head_x > BOUND or head_y < -BOUND or head_y > BOUND:
                game_over = True
                break

            if new_head in snake[:-1]:
                game_over = True
                break

            snake.insert(0, new_head)

            if head_x == food[0] and head_y == food[1]:
                score += 10
                food = new_food(snake)
            else:
                snake.pop()

            draw(snake, food, score)
            tf.delay(110)

        return score

    while True:
        final_score = play_round()
        if final_score > high_score:
            high_score = final_score
        show_game_over(final_score)
        wait_for_restart()


# ==========================================
# 6. TETRIS
# ==========================================
elif selected_game == "6":
    BREITE = 600
    HOEHE = 700

    COLS = 10
    ROWS = 20
    CELL_SIZE = 24

    GRID_WIDTH = COLS * CELL_SIZE
    GRID_HEIGHT = ROWS * CELL_SIZE

    OFFSET_X = -GRID_WIDTH // 2
    OFFSET_Y = -GRID_HEIGHT // 2

    KEY_LEFT = 37
    KEY_UP = 38
    KEY_RIGHT = 39
    KEY_DOWN = 40
    KEY_SPACE = 32

    COLOR_BG = "black"
    COLOR_GRID = "purple"
    COLOR_EMPTY = "black"

    PIECES = {
        'I': {'shape': [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], 'color': "cyan"},
        'J': {'shape': [[1, 0, 0], [1, 1, 1], [0, 0, 0]], 'color': "blue"},
        'L': {'shape': [[0, 0, 1], [1, 1, 1], [0, 0, 0]], 'color': "orange"},
        'O': {'shape': [[1, 1], [1, 1]], 'color': "yellow"},
        'S': {'shape': [[0, 1, 1], [1, 1, 0], [0, 0, 0]], 'color': "green"},
        'T': {'shape': [[0, 1, 0], [1, 1, 1], [0, 0, 0]], 'color': "magenta"},
        'Z': {'shape': [[1, 1, 0], [0, 1, 1], [0, 0, 0]], 'color': "red"}
    }

    Options.setPlaygroundSize(BREITE, HOEHE)
    tf = TurtleFrame()
    t = Turtle(tf)
    t.hideTurtle()
    t.speed(-1)
    tf.enableRepaint(False)

    high_score = 0

    def label_centered(text, y):
        width = t.getTextWidth(text)
        t.setPos(0 - width / 2.0, y)
        t.label(text)

    def draw_cell(col, row, color):
        x = OFFSET_X + col * CELL_SIZE + CELL_SIZE // 2
        y = OFFSET_Y + row * CELL_SIZE + CELL_SIZE // 2
        t.setPos(x, y)
        t.setPenColor(color)
        t.dot(CELL_SIZE - 2)

    def draw_grid_boundaries():
        t.setPenColor(COLOR_GRID)
        for r in range(ROWS):
            x_left = OFFSET_X - CELL_SIZE // 2
            x_right = OFFSET_X + GRID_WIDTH + CELL_SIZE // 2
            y = OFFSET_Y + r * CELL_SIZE + CELL_SIZE // 2
            t.setPos(x_left, y)
            t.dot(CELL_SIZE // 2)
            t.setPos(x_right, y)
            t.dot(CELL_SIZE // 2)

        for c in range(-1, COLS + 1):
            x = OFFSET_X + c * CELL_SIZE + CELL_SIZE // 2
            y = OFFSET_Y - CELL_SIZE // 2
            t.setPos(x, y)
            t.dot(CELL_SIZE // 2)

    def rotate(shape):
        size = len(shape)
        rotated = [[0] * size for _ in range(size)]
        for r in range(size):
            for c in range(size):
                rotated[c][size - 1 - r] = shape[r][c]
        return rotated

    def is_valid_position(grid, shape, pos_x, pos_y):
        for r in range(len(shape)):
            for c in range(len(shape[r])):
                if shape[r][c]:
                    grid_x = pos_x + c
                    grid_y = pos_y - r

                    if grid_x < 0 or grid_x >= COLS or grid_y < 0:
                        return False
                    if grid_y < ROWS and grid[grid_y][grid_x] is not None:
                        return False
        return True

    def draw(grid, current_piece, piece_x, piece_y, score, level):
        tf.clear(COLOR_BG)
        draw_grid_boundaries()

        for r in range(ROWS):
            for c in range(COLS):
                if grid[r][c] is not None:
                    draw_cell(c, r, grid[r][c])

        if current_piece:
            shape = current_piece['shape']
            color = current_piece['color']
            for r in range(len(shape)):
                for c in range(len(shape[r])):
                    if shape[r][c]:
                        gx = piece_x + c
                        gy = piece_y - r
                        if 0 <= gy < ROWS and 0 <= gx < COLS:
                            draw_cell(gx, gy, color)

        t.setPenColor("white")
        label_centered("TETRIS", HOEHE // 2 - 50)

        t.setPos(GRID_WIDTH // 2 + 30, 50)
        t.label("Score: " + str(score))
        t.setPos(GRID_WIDTH // 2 + 30, 10)
        t.label("Level: " + str(level))
        t.setPos(GRID_WIDTH // 2 + 30, -30)
        t.label("Highscore: " + str(high_score))

        tf.repaint()

    def show_game_over(score):
        tf.clear(COLOR_BG)
        t.setPenColor("red")
        label_centered("GAME OVER", 60)
        t.setPenColor("white")
        label_centered("Punkte: " + str(score), 10)
        label_centered("Highscore: " + str(high_score), -30)
        label_centered("Leertaste fuer Neustart", -90)
        tf.repaint()

    def wait_for_restart():
        while True:
            if tf.kbhit():
                if tf.getKeyCode() == KEY_SPACE:
                    return
            tf.delay(30)

    def play_round():
        global high_score

        grid = [[None for _ in range(COLS)] for _ in range(ROWS)]

        score = 0
        lines_cleared_total = 0
        level = 1
        game_over = False

        def spawn_piece():
            p_name = choice(list(PIECES.keys()))
            piece = {
                'shape': PIECES[p_name]['shape'],
                'color': PIECES[p_name]['color']
            }
            start_x = COLS // 2 - len(piece['shape']) // 2
            start_y = ROWS - 1
            return piece, start_x, start_y

        current_piece, piece_x, piece_y = spawn_piece()

        if not is_valid_position(grid, current_piece['shape'], piece_x, piece_y):
            game_over = True

        drop_counter = 0

        while not game_over:
            drop_speed = max(1, 12 - level * 2)

            while tf.kbhit():
                code = tf.getKeyCode()
                if code == KEY_LEFT:
                    if is_valid_position(grid, current_piece['shape'], piece_x - 1, piece_y):
                        piece_x -= 1
                elif code == KEY_RIGHT:
                    if is_valid_position(grid, current_piece['shape'], piece_x + 1, piece_y):
                        piece_x += 1
                elif code == KEY_UP:
                    rotated_shape = rotate(current_piece['shape'])
                    if is_valid_position(grid, rotated_shape, piece_x, piece_y):
                        current_piece['shape'] = rotated_shape
                elif code == KEY_DOWN:
                    if is_valid_position(grid, current_piece['shape'], piece_x, piece_y - 1):
                        piece_y -= 1
                        score += 1
                        drop_counter = 0

            drop_counter += 1
            if drop_counter >= drop_speed:
                drop_counter = 0
                if is_valid_position(grid, current_piece['shape'], piece_x, piece_y - 1):
                    piece_y -= 1
                else:
                    shape = current_piece['shape']
                    color = current_piece['color']
                    for r in range(len(shape)):
                        for c in range(len(shape[r])):
                            if shape[r][c]:
                                gy = piece_y - r
                                gx = piece_x + c
                                if 0 <= gy < ROWS and 0 <= gx < COLS:
                                    grid[gy][gx] = color

                    full_lines = 0
                    r = 0
                    while r < ROWS:
                        if None not in grid[r]:
                            full_lines += 1
                            del grid[r]
                            grid.append([None for _ in range(COLS)])
                        else:
                            r += 1

                    if full_lines == 1:
                        score += 100 * level
                    elif full_lines == 2:
                        score += 300 * level
                    elif full_lines == 3:
                        score += 500 * level
                    elif full_lines == 4:
                        score += 800 * level

                    lines_cleared_total += full_lines
                    level = 1 + (lines_cleared_total // 10)

                    current_piece, piece_x, piece_y = spawn_piece()
                    if not is_valid_position(grid, current_piece['shape'], piece_x, piece_y):
                        game_over = True

            draw(grid, current_piece, piece_x, piece_y, score, level)
            tf.delay(20)

        return score

    while True:
        final_score = play_round()
        if final_score > high_score:
            high_score = final_score
        show_game_over(final_score)
        wait_for_restart()