{"id":115,"date":"2026-05-22T14:03:22","date_gmt":"2026-05-22T14:03:22","guid":{"rendered":"https:\/\/theroyalscode.com\/students\/c_menhart\/?p=115"},"modified":"2026-05-22T14:03:22","modified_gmt":"2026-05-22T14:03:22","slug":"5-22","status":"publish","type":"post","link":"https:\/\/theroyalscode.com\/students\/c_menhart\/2026\/05\/22\/5-22\/","title":{"rendered":"5\/22"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>import pygame\nimport math\nimport random\nimport json\nimport os\nfrom typing import List, Tuple, Set\nfrom enum import Enum\nfrom dataclasses import dataclass, field\n\n# Constants\nW, H = 800, 400\nGROUND = 320\nPLAYER_SIZE = 32\nPLAYER_X = 120\nGRAVITY = 0.72\nJUMP_V = -15\nCOLORS = &#91;\"#e74c3c\", \"#f1c40f\", \"#2ecc71\", \"#3498db\", \"#9b59b6\", \"#e67e22\", \"#00ffcc\", \"#ff69b4\"]\nFPS = 60\n\nclass Status(Enum):\n    START = \"start\"\n    PLAYING = \"playing\"\n    DEAD = \"dead\"\n    LEVEL_COMPLETE = \"level_complete\"\n\nclass ObstacleType(Enum):\n    SPIKE = \"spike\"\n    BLOCK = \"block\"\n    TALL = \"tall\"\n    GAP = \"gap\"\n    ROTATING_SAW = \"rotating_saw\"\n    DOUBLE_SPIKE = \"double_spike\"\n    MOVING_BLOCK = \"moving_block\"\n    CEILING = \"ceiling\"\n    NARROW_GAP = \"narrow_gap\"\n\ndef hex_to_rgb(hex_color: str) -> Tuple&#91;int, int, int]:\n    \"\"\"Convert hex color to RGB tuple.\"\"\"\n    if hex_color == \"transparent\":\n        return (0, 0, 0)\n    \n    hex_color = hex_color.lstrip(\"#\")\n    if len(hex_color) != 6:\n        return (255, 255, 255)\n    \n    try:\n        return tuple(int(hex_color&#91;i:i+2], 16) for i in (0, 2, 4))\n    except ValueError:\n        return (255, 255, 255)\n\n@dataclass\nclass Obstacle:\n    x: float\n    type: ObstacleType\n    w: int\n    h: int\n    color: str\n    rotation: float = 0\n    moving_y: float = 0\n    moving_direction: int = 1\n\n@dataclass\nclass Particle:\n    x: float\n    y: float\n    vx: float\n    vy: float\n    life: float\n    color: str\n\n@dataclass\nclass Star:\n    x: float\n    y: float\n    speed: float\n\n@dataclass\nclass GameState:\n    y: float\n    vy: float\n    on_ground: bool\n    rotation: float\n    obstacles: List&#91;Obstacle] = field(default_factory=list)\n    particles: List&#91;Particle] = field(default_factory=list)\n    stars: List&#91;Star] = field(default_factory=list)\n    score: int = 0\n    best: int = 0\n    attempts: int = 0\n    speed: float = 5\n    spawn_timer: int = 0\n    tick: int = 0\n    status: Status = Status.START\n    flash_timer: int = 0\n    color_idx: int = 0\n    level: int = 1\n    level_progress: int = 0\n    level_complete_timer: int = 0\n\ndef init_state(best: int = 0, attempts: int = 0, level: int = 1) -> GameState:\n    \"\"\"Initialize game state.\"\"\"\n    stars = &#91;\n        Star(x=random.random() * W, y=random.random() * (GROUND - 20), speed=1 + random.random() * 3)\n        for _ in range(80)\n    ]\n    return GameState(\n        y=GROUND - PLAYER_SIZE,\n        vy=0,\n        on_ground=True,\n        rotation=0,\n        obstacles=&#91;],\n        particles=&#91;],\n        stars=stars,\n        score=0,\n        best=best,\n        attempts=attempts,\n        speed=5,\n        spawn_timer=0,\n        tick=0,\n        status=Status.START,\n        flash_timer=0,\n        color_idx=0,\n        level=level,\n        level_progress=0,\n        level_complete_timer=0,\n    )\n\ndef get_level_config(level: int):\n    \"\"\"Get difficulty configuration for a level.\"\"\"\n    configs = {\n        1: {\"max_speed\": 5.5, \"spawn_interval\": 80, \"speed_increase\": 0.002, \"obstacle_types\": &#91;\"spike\", \"block\"]},\n        2: {\"max_speed\": 6.5, \"spawn_interval\": 70, \"speed_increase\": 0.003, \"obstacle_types\": &#91;\"spike\", \"block\", \"tall\"]},\n        3: {\"max_speed\": 7.5, \"spawn_interval\": 60, \"speed_increase\": 0.0035, \"obstacle_types\": &#91;\"spike\", \"block\", \"tall\", \"gap\"]},\n        4: {\"max_speed\": 8.5, \"spawn_interval\": 50, \"speed_increase\": 0.004, \"obstacle_types\": &#91;\"spike\", \"block\", \"tall\", \"gap\", \"double_spike\"]},\n        5: {\"max_speed\": 9.5, \"spawn_interval\": 45, \"speed_increase\": 0.0045, \"obstacle_types\": &#91;\"spike\", \"block\", \"tall\", \"gap\", \"double_spike\", \"rotating_saw\"]},\n        6: {\"max_speed\": 10.5, \"spawn_interval\": 40, \"speed_increase\": 0.005, \"obstacle_types\": &#91;\"spike\", \"block\", \"tall\", \"gap\", \"double_spike\", \"rotating_saw\", \"moving_block\"]},\n    }\n    return configs.get(level, configs&#91;6])\n\ndef make_obstacle(score: int, color_idx: int, level: int) -> Obstacle:\n    \"\"\"Create a random obstacle based on level.\"\"\"\n    config = get_level_config(level)\n    obstacle_types = config&#91;\"obstacle_types\"]\n    \n    r = random.random()\n    color = COLORS&#91;(color_idx + 1) % len(COLORS)]\n    \n    # Determine which type to spawn\n    if \"rotating_saw\" in obstacle_types and r &lt; 0.08:\n        return Obstacle(x=W + 40, type=ObstacleType.ROTATING_SAW, w=32, h=32, color=color)\n    elif \"moving_block\" in obstacle_types and r &lt; 0.12:\n        return Obstacle(x=W + 40, type=ObstacleType.MOVING_BLOCK, w=28, h=28, color=color, moving_y=0, moving_direction=1)\n    elif \"double_spike\" in obstacle_types and r &lt; 0.15:\n        return Obstacle(x=W + 40, type=ObstacleType.DOUBLE_SPIKE, w=28, h=56, color=color)\n    elif \"gap\" in obstacle_types and r &lt; 0.35:\n        return Obstacle(x=W + 40, type=ObstacleType.GAP, w=60, h=0, color=\"transparent\")\n    elif \"tall\" in obstacle_types and r &lt; 0.60:\n        return Obstacle(x=W + 40, type=ObstacleType.TALL, w=28, h=60, color=color)\n    elif \"block\" in obstacle_types and r &lt; 0.85:\n        return Obstacle(x=W + 40, type=ObstacleType.BLOCK, w=32, h=32, color=color)\n    else:\n        return Obstacle(x=W + 40, type=ObstacleType.SPIKE, w=28, h=28, color=color)\n\ndef draw_rounded_rect(surface: pygame.Surface, rect: pygame.Rect, color: Tuple&#91;int, int, int], radius: int):\n    \"\"\"Draw a rounded rectangle.\"\"\"\n    pygame.draw.rect(surface, color, rect, border_radius=radius)\n\ndef render(surface: pygame.Surface, state: GameState):\n    \"\"\"Render the game.\"\"\"\n    # Background gradient\n    if state.status == Status.DEAD:\n        bg_color_top = hex_to_rgb(\"#300\")\n        bg_color_bottom = hex_to_rgb(\"#100\")\n    else:\n        bg_color_top = hex_to_rgb(\"#050518\")\n        bg_color_bottom = hex_to_rgb(\"#0a0a20\")\n    \n    # Simple gradient approximation\n    for y in range(H):\n        ratio = y \/ H\n        r = int(bg_color_top&#91;0] * (1 - ratio) + bg_color_bottom&#91;0] * ratio)\n        g = int(bg_color_top&#91;1] * (1 - ratio) + bg_color_bottom&#91;1] * ratio)\n        b = int(bg_color_top&#91;2] * (1 - ratio) + bg_color_bottom&#91;2] * ratio)\n        pygame.draw.line(surface, (r, g, b), (0, y), (W, y))\n    \n    # Draw stars\n    for star in state.stars:\n        alpha = 0.3 + 0.3 * math.sin(state.tick * 0.02 + star.y)\n        star_surface = pygame.Surface((2, 2), pygame.SRCALPHA)\n        star_surface.fill((255, 255, 255, int(alpha * 255)))\n        surface.blit(star_surface, (int(star.x), int(star.y)))\n    \n    # Draw ground\n    pygame.draw.rect(surface, hex_to_rgb(\"#1a1a3e\"), (0, GROUND, W, H - GROUND))\n    \n    # Ground line\n    ground_color = hex_to_rgb(COLORS&#91;state.color_idx])\n    \n    for x in range(0, W, 40):\n        pygame.draw.line(surface, ground_color, (x, GROUND), (x, H), 1)\n    \n    for x in range(0, W, 60):\n        pygame.draw.line(surface, (255, 255, 255, 8), (x, 0), (x, GROUND), 1)\n    \n    # Draw obstacles\n    for obs in state.obstacles:\n        if obs.color == \"transparent\":\n            color = (0, 0, 0)\n        else:\n            color = hex_to_rgb(obs.color)\n        \n        if obs.type == ObstacleType.SPIKE:\n            points = &#91;\n                (obs.x, GROUND),\n                (obs.x + obs.w \/ 2, GROUND - obs.h),\n                (obs.x + obs.w, GROUND),\n            ]\n            pygame.draw.polygon(surface, color, points)\n        \n        elif obs.type == ObstacleType.DOUBLE_SPIKE:\n            # Top spike\n            points_top = &#91;\n                (obs.x, GROUND - obs.h \/\/ 2),\n                (obs.x + obs.w \/ 2, GROUND - obs.h),\n                (obs.x + obs.w, GROUND - obs.h \/\/ 2),\n            ]\n            pygame.draw.polygon(surface, color, points_top)\n            # Bottom spike (ceiling)\n            points_bottom = &#91;\n                (obs.x, GROUND - obs.h \/\/ 2),\n                (obs.x + obs.w \/ 2, GROUND - obs.h \/\/ 4),\n                (obs.x + obs.w, GROUND - obs.h \/\/ 2),\n            ]\n            pygame.draw.polygon(surface, color, points_bottom)\n        \n        elif obs.type == ObstacleType.ROTATING_SAW:\n            # Draw rotating saw\n            saw_surface = pygame.Surface((obs.w, obs.h), pygame.SRCALPHA)\n            pygame.draw.circle(saw_surface, color, (obs.w \/\/ 2, obs.h \/\/ 2), obs.w \/\/ 2)\n            # Draw saw teeth\n            for i in range(8):\n                angle = (obs.rotation + i * math.pi \/ 4)\n                x = obs.w \/\/ 2 + math.cos(angle) * (obs.w \/\/ 2 - 2)\n                y = obs.h \/\/ 2 + math.sin(angle) * (obs.h \/\/ 2 - 2)\n                pygame.draw.circle(saw_surface, (255, 100, 100), (int(x), int(y)), 2)\n            surface.blit(saw_surface, (int(obs.x), int(GROUND - obs.h)))\n        \n        elif obs.type == ObstacleType.MOVING_BLOCK:\n            rect = pygame.Rect(obs.x, GROUND - obs.h + obs.moving_y, obs.w, obs.h)\n            draw_rounded_rect(surface, rect, color, 3)\n        \n        elif obs.type == ObstacleType.GAP:\n            pygame.draw.rect(surface, (0, 0, 0), (obs.x, GROUND, obs.w, H - GROUND))\n            pygame.draw.line(surface, color, (obs.x, GROUND), (obs.x + obs.w, GROUND), 2)\n        \n        else:\n            rect = pygame.Rect(obs.x, GROUND - obs.h, obs.w, obs.h)\n            draw_rounded_rect(surface, rect, color, 3)\n    \n    # Draw particles\n    for particle in state.particles:\n        if particle.life > 0:\n            size = int(8 * particle.life)\n            if size > 0:\n                particle_surface = pygame.Surface((size * 2, size * 2), pygame.SRCALPHA)\n                color = hex_to_rgb(particle.color)\n                pygame.draw.circle(particle_surface, (*color, int(particle.life * 255)), \n                                  (size, size), size)\n                surface.blit(particle_surface, (int(particle.x - size), int(particle.y - size)))\n    \n    # Flash effect\n    if state.flash_timer > 0:\n        flash_surface = pygame.Surface((W, H), pygame.SRCALPHA)\n        flash_surface.fill((255, 50, 50, int((state.flash_timer \/ 20) * 0.5 * 255)))\n        surface.blit(flash_surface, (0, 0))\n    \n    # Draw player\n    player_surface = pygame.Surface((PLAYER_SIZE, PLAYER_SIZE), pygame.SRCALPHA)\n    color1 = hex_to_rgb(COLORS&#91;state.color_idx])\n    \n    draw_rounded_rect(player_surface, pygame.Rect(0, 0, PLAYER_SIZE, PLAYER_SIZE), color1, 5)\n    pygame.draw.line(player_surface, (255, 255, 255, 85), (8, 8), (24, 24), 2)\n    pygame.draw.line(player_surface, (255, 255, 255, 85), (24, 8), (8, 24), 2)\n    pygame.draw.circle(player_surface, (255, 255, 255), (PLAYER_SIZE \/\/ 2, PLAYER_SIZE \/\/ 2), 4)\n    \n    if not state.on_ground:\n        for i in range(1, 4):\n            pygame.draw.circle(player_surface, (*color1, int(68 \/ i)), (-i * 8, 0), int(4 \/ i))\n    \n    rotated = pygame.transform.rotate(player_surface, math.degrees(state.rotation))\n    rotated_rect = rotated.get_rect(center=(PLAYER_X + PLAYER_SIZE \/\/ 2, int(state.y + PLAYER_SIZE \/\/ 2)))\n    surface.blit(rotated, rotated_rect)\n    \n    # Draw HUD\n    hud_surface = pygame.Surface((W, 36), pygame.SRCALPHA)\n    hud_surface.fill((0, 0, 0, 140))\n    surface.blit(hud_surface, (0, 0))\n    \n    font_small = pygame.font.Font(None, 16)\n    font_tiny = pygame.font.Font(None, 11)\n    \n    # Level and Score\n    score_text = font_small.render(f\"LEVEL {state.level} | SCORE: {state.score}\", True, (255, 255, 255))\n    surface.blit(score_text, (12, 11))\n    \n    # Progress bar for level\n    level_target = 500 * state.level\n    pct = min(100, (state.score % level_target) \/\/ (level_target \/\/ 100))\n    progress_text = font_small.render(f\"{pct}%\", True, color1)\n    surface.blit(progress_text, (W \/\/ 2 - 20, 11))\n    \n    pygame.draw.rect(surface, (255, 255, 255, 51), (W \/\/ 2 - 80, 26, 160, 3))\n    pygame.draw.rect(surface, color1, (W \/\/ 2 - 80, 26, int(pct * 1.6), 3))\n    \n    # Best score\n    best_text = font_tiny.render(f\"BEST:{state.best}  ATTEMPTS:{state.attempts}\", True, (255, 255, 255, 85))\n    surface.blit(best_text, (W - 180, 11))\n    \n    # Game states\n    font_large = pygame.font.Font(None, 38)\n    font_medium = pygame.font.Font(None, 14)\n    \n    if state.status == Status.START:\n        overlay = pygame.Surface((W, H), pygame.SRCALPHA)\n        overlay.fill((0, 0, 0, 153))\n        surface.blit(overlay, (0, 0))\n        \n        title = font_large.render(\"GEOMETRY DASH\", True, hex_to_rgb(COLORS&#91;0]))\n        surface.blit(title, (W \/\/ 2 - title.get_width() \/\/ 2, H \/\/ 2 - 70))\n        \n        level_text = font_medium.render(f\"Starting Level {state.level}\", True, (200, 200, 255))\n        surface.blit(level_text, (W \/\/ 2 - level_text.get_width() \/\/ 2, H \/\/ 2 - 20))\n        \n        inst = font_medium.render(\"Tap \/ SPACE to jump over obstacles!\", True, (255, 255, 255))\n        surface.blit(inst, (W \/\/ 2 - inst.get_width() \/\/ 2, H \/\/ 2 + 4))\n        \n        blink = 0.5 + 0.5 * math.sin(state.tick * 0.1)\n        press_text = font_medium.render(\"PRESS SPACE OR TAP\", True, (74, 222, 128))\n        press_surface = pygame.Surface(press_text.get_size(), pygame.SRCALPHA)\n        press_surface.fill((0, 0, 0, 0))\n        press_surface.blit(press_text, (0, 0))\n        press_surface.set_alpha(int(blink * 255))\n        surface.blit(press_surface, (W \/\/ 2 - press_text.get_width() \/\/ 2, H \/\/ 2 + 50))\n    \n    elif state.status == Status.LEVEL_COMPLETE:\n        overlay = pygame.Surface((W, H), pygame.SRCALPHA)\n        overlay.fill((0, 0, 0, 153))\n        surface.blit(overlay, (0, 0))\n        \n        complete = font_large.render(f\"LEVEL {state.level} COMPLETE!\", True, hex_to_rgb(\"#2ecc71\"))\n        surface.blit(complete, (W \/\/ 2 - complete.get_width() \/\/ 2, H \/\/ 2 - 70))\n        \n        score_msg = font_medium.render(f\"Score: {state.score}\", True, (255, 255, 255))\n        surface.blit(score_msg, (W \/\/ 2 - score_msg.get_width() \/\/ 2, H \/\/ 2 - 4))\n        \n        next_msg = font_medium.render(f\"Next: Level {state.level + 1}\", True, hex_to_rgb(\"#f1c40f\"))\n        surface.blit(next_msg, (W \/\/ 2 - next_msg.get_width() \/\/ 2, H \/\/ 2 + 22))\n        \n        blink = 0.5 + 0.5 * math.sin(state.tick * 0.1)\n        cont = font_medium.render(\"SPACE\/Tap to continue\", True, (74, 222, 128))\n        cont_surface = pygame.Surface(cont.get_size(), pygame.SRCALPHA)\n        cont_surface.blit(cont, (0, 0))\n        cont_surface.set_alpha(int(blink * 255))\n        surface.blit(cont_surface, (W \/\/ 2 - cont.get_width() \/\/ 2, H \/\/ 2 + 60))\n    \n    elif state.status == Status.DEAD:\n        overlay = pygame.Surface((W, H), pygame.SRCALPHA)\n        overlay.fill((0, 0, 0, 153))\n        surface.blit(overlay, (0, 0))\n        \n        crashed = font_large.render(\"CRASHED!\", True, hex_to_rgb(\"#e74c3c\"))\n        surface.blit(crashed, (W \/\/ 2 - crashed.get_width() \/\/ 2, H \/\/ 2 - 70))\n        \n        score_msg = font_medium.render(f\"Level {state.level} | Score: {state.score}\", True, (255, 255, 255))\n        surface.blit(score_msg, (W \/\/ 2 - score_msg.get_width() \/\/ 2, H \/\/ 2 - 4))\n        \n        best_msg = font_medium.render(\"Best: \" + str(state.best), True, hex_to_rgb(\"#f1c40f\"))\n        surface.blit(best_msg, (W \/\/ 2 - best_msg.get_width() \/\/ 2, H \/\/ 2 + 22))\n        \n        blink = 0.5 + 0.5 * math.sin(state.tick * 0.1)\n        retry = font_medium.render(\"SPACE\/Tap to retry\", True, (74, 222, 128))\n        retry_surface = pygame.Surface(retry.get_size(), pygame.SRCALPHA)\n        retry_surface.fill((0, 0, 0, 0))\n        retry_surface.blit(retry, (0, 0))\n        retry_surface.set_alpha(int(blink * 255))\n        surface.blit(retry_surface, (W \/\/ 2 - retry.get_width() \/\/ 2, H \/\/ 2 + 60))\n\nclass GeometryDashGame:\n    def __init__(self):\n        pygame.init()\n        self.screen = pygame.display.set_mode((W, H))\n        pygame.display.set_caption(\"Geometry Dash\")\n        self.clock = pygame.time.Clock()\n        self.running = True\n        self.state = None\n        self.best = self.load_best_score()\n        self.start_new_game()\n    \n    def load_best_score(self) -> int:\n        \"\"\"Load best score from file.\"\"\"\n        try:\n            if os.path.exists(\"geodash_best.txt\"):\n                with open(\"geodash_best.txt\", \"r\") as f:\n                    return int(f.read().strip())\n        except:\n            pass\n        return 0\n    \n    def save_best_score(self):\n        \"\"\"Save best score to file.\"\"\"\n        with open(\"geodash_best.txt\", \"w\") as f:\n            f.write(str(self.state.best))\n    \n    def start_new_game(self, level: int = 1):\n        \"\"\"Start a new game.\"\"\"\n        attempts = self.state.attempts + 1 if self.state else 0\n        self.state = init_state(self.best, attempts, level)\n    \n    def jump(self):\n        \"\"\"Handle jump action.\"\"\"\n        if self.state.status == Status.START:\n            self.state.status = Status.PLAYING\n            self.state.vy = JUMP_V\n            self.state.on_ground = False\n        elif self.state.status == Status.DEAD:\n            self.start_new_game(self.state.level)\n            self.state.status = Status.PLAYING\n            self.state.vy = JUMP_V\n            self.state.on_ground = False\n        elif self.state.status == Status.LEVEL_COMPLETE:\n            self.start_new_game(self.state.level + 1)\n            self.state.status = Status.PLAYING\n            self.state.vy = JUMP_V\n            self.state.on_ground = False\n        elif self.state.on_ground:\n            self.state.vy = JUMP_V\n            self.state.on_ground = False\n    \n    def update(self):\n        \"\"\"Update game state.\"\"\"\n        state = self.state\n        state.tick += 1\n        \n        if state.flash_timer > 0:\n            state.flash_timer -= 1\n        \n        # Update particles\n        for p in state.particles:\n            p.x += p.vx\n            p.y += p.vy\n            p.vy += 0.1\n            p.life -= 0.04\n        state.particles = &#91;p for p in state.particles if p.life > 0]\n        \n        # Update stars\n        for star in state.stars:\n            star.x -= star.speed\n            if star.x &lt; 0:\n                star.x = W\n        \n        if state.status == Status.PLAYING:\n            state.score += 1\n            state.color_idx = (state.score \/\/ 200) % len(COLORS)\n            \n            config = get_level_config(state.level)\n            state.speed = min(config&#91;\"max_speed\"], 3 + state.score * config&#91;\"speed_increase\"])\n            \n            # Physics\n            state.vy += GRAVITY\n            state.y += state.vy\n            \n            if state.on_ground:\n                state.rotation += 0\n            else:\n                state.rotation += 0.1 * (1 if state.vy > 0 else -1)\n            \n            # Ground collision\n            if state.y >= GROUND - PLAYER_SIZE:\n                state.y = GROUND - PLAYER_SIZE\n                state.vy = 0\n                state.on_ground = True\n                state.rotation = round(state.rotation \/ (math.pi \/ 2)) * (math.pi \/ 2)\n            else:\n                state.on_ground = False\n            \n            # Spawn obstacles\n            state.spawn_timer += 1\n            config = get_level_config(state.level)\n            si = max(config&#91;\"spawn_interval\"] - (state.score \/\/ 500) * 3, 20)\n            if state.spawn_timer > si:\n                state.spawn_timer = 0\n                if random.random() > 0.08:\n                    state.obstacles.append(make_obstacle(state.score, state.color_idx, state.level))\n            \n            # Move obstacles and update rotating\/moving obstacles\n            for obs in state.obstacles:\n                obs.x -= state.speed\n                \n                if obs.type == ObstacleType.ROTATING_SAW:\n                    obs.rotation += 0.2\n                \n                elif obs.type == ObstacleType.MOVING_BLOCK:\n                    obs.moving_y += obs.moving_direction * 2\n                    if obs.moving_y > 20 or obs.moving_y &lt; -20:\n                        obs.moving_direction *= -1\n            \n            state.obstacles = &#91;obs for obs in state.obstacles if obs.x > -80]\n            \n            # Collision detection\n            px = PLAYER_X + 4\n            py = state.y + 4\n            pw = PLAYER_SIZE - 8\n            ph = PLAYER_SIZE - 8\n            \n            for obs in state.obstacles:\n                hit = False\n                \n                if obs.type == ObstacleType.SPIKE:\n                    mid_x = obs.x + obs.w \/ 2\n                    if px &lt; obs.x + obs.w and px + pw > obs.x:\n                        rel_x = (PLAYER_X + PLAYER_SIZE \/ 2 - mid_x) \/ (obs.w \/ 2)\n                        spike_top = GROUND - obs.h * (1 - abs(rel_x))\n                        if py + ph > spike_top:\n                            hit = True\n                \n                elif obs.type == ObstacleType.DOUBLE_SPIKE:\n                    if px &lt; obs.x + obs.w and px + pw > obs.x:\n                        mid_x = obs.x + obs.w \/ 2\n                        rel_x = (PLAYER_X + PLAYER_SIZE \/ 2 - mid_x) \/ (obs.w \/ 2)\n                        spike_top = GROUND - obs.h * (1 - abs(rel_x))\n                        spike_bottom = GROUND - obs.h \/\/ 4\n                        if (py + ph > spike_top) or (py &lt; spike_bottom):\n                            hit = True\n                \n                elif obs.type == ObstacleType.ROTATING_SAW:\n                    saw_center_x = obs.x + obs.w \/ 2\n                    saw_center_y = GROUND - obs.h \/ 2\n                    player_center_x = PLAYER_X + PLAYER_SIZE \/ 2\n                    player_center_y = state.y + PLAYER_SIZE \/ 2\n                    dist = math.sqrt((player_center_x - saw_center_x) ** 2 + (player_center_y - saw_center_y) ** 2)\n                    if dist &lt; (obs.w \/ 2 + PLAYER_SIZE \/ 2):\n                        hit = True\n                \n                elif obs.type == ObstacleType.MOVING_BLOCK:\n                    block_y = GROUND - obs.h + obs.moving_y\n                    if px &lt; obs.x + obs.w and px + pw > obs.x and py &lt; GROUND and py + ph > block_y:\n                        hit = True\n                \n                elif obs.type == ObstacleType.BLOCK or obs.type == ObstacleType.TALL:\n                    if px &lt; obs.x + obs.w and px + pw > obs.x and py &lt; GROUND and py + ph > GROUND - obs.h:\n                        hit = True\n                \n                elif obs.type == ObstacleType.GAP:\n                    if px + pw > obs.x and px &lt; obs.x + obs.w and state.on_ground:\n                        hit = True\n                \n                if hit:\n                    # Particle burst\n                    for _ in range(16):\n                        angle = random.random() * math.pi * 2\n                        state.particles.append(Particle(\n                            x=PLAYER_X + PLAYER_SIZE \/ 2,\n                            y=state.y + PLAYER_SIZE \/ 2,\n                            vx=math.cos(angle) * 4,\n                            vy=math.sin(angle) * 4,\n                            life=1,\n                            color=COLORS&#91;state.color_idx]\n                        ))\n                    \n                    # Update best score\n                    if state.score > state.best:\n                        state.best = state.score\n                        self.save_best_score()\n                        self.best = state.best\n                    \n                    state.flash_timer = 20\n                    state.status = Status.DEAD\n                    break\n            \n            # Check level completion\n            level_target = 500 * state.level\n            if state.score >= level_target:\n                state.status = Status.LEVEL_COMPLETE\n                state.level_complete_timer = 0\n    \n    def handle_events(self):\n        \"\"\"Handle input events.\"\"\"\n        for event in pygame.event.get():\n            if event.type == pygame.QUIT:\n                self.running = False\n            elif event.type == pygame.KEYDOWN:\n                if event.key == pygame.K_ESCAPE:\n                    self.running = False\n                elif event.key in (pygame.K_SPACE, pygame.K_UP):\n                    self.jump()\n            elif event.type == pygame.MOUSEBUTTONDOWN:\n                self.jump()\n    \n    def run(self):\n        \"\"\"Main game loop.\"\"\"\n        while self.running:\n            self.handle_events()\n            self.update()\n            render(self.screen, self.state)\n            pygame.display.flip()\n            self.clock.tick(FPS)\n        \n        pygame.quit()\n\nif __name__ == \"__main__\":\n    game = GeometryDashGame()\n    game.run()\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">i made it like the famous game but it sucks and i started it awhile ago and forgot about it <br><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">so i used to be a big fan of bomber 2D utra so i made this with the help of ai and google <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import pygame\nimport math\nimport random\nfrom typing import List, Tuple, Set\nfrom enum import Enum\nfrom dataclasses import dataclass, field\n\npygame.init()\n\n# Constants\nTILE = 44\nCOLS, ROWS = 16, 14\nW = COLS * TILE\nH = ROWS * TILE + 50\nFPS = 60\n\nclass CellType(Enum):\n    WALL = \"wall\"\n    BLOCK = \"block\"\n    EMPTY = \"empty\"\n\nclass Status(Enum):\n    START = \"start\"\n    PLAYING = \"playing\"\n    DEAD = \"dead\"\n    WIN = \"win\"\n\n@dataclass\nclass Bomb:\n    x: int\n    y: int\n    timer: int\n    range: int\n    owner: str = \"player\"  # \"player\" or \"enemy\"\n\n@dataclass\nclass Explosion:\n    x: int\n    y: int\n    life: int\n    dir: str\n    tick: int = 0\n\n@dataclass\nclass Enemy:\n    x: int\n    y: int\n    dir: int\n    alive: bool\n    moveTimer: int\n    type: int\n    bombTimer: int = 0\n    canDropBomb: bool = True\n\n@dataclass\nclass Particle:\n    x: float\n    y: float\n    vx: float\n    vy: float\n    life: float\n    color: Tuple&#91;int, int, int]\n    size: int\n\n@dataclass\nclass PowerUp:\n    x: int\n    y: int\n    type: str  # \"bomb\", \"range\", \"speed\", \"shield\", \"slow\", \"freeze\"\n    collected: bool\n\n@dataclass\nclass GameState:\n    grid: List&#91;List&#91;CellType]]\n    player: dict\n    bombs: List&#91;Bomb]\n    explosions: List&#91;Explosion]\n    enemies: List&#91;Enemy]\n    particles: List&#91;Particle]\n    powerups: List&#91;PowerUp]\n    score: int\n    lives: int\n    level: int\n    status: Status\n    tick: int\n    keys: Set&#91;str]\n    invTimer: int\n    bombCooldown: int\n    maxBombs: int\n    range: int\n    moveTimer: int\n    currentBombs: int\n    shield: bool\n    shieldTimer: int\n    slowEffect: float\n\nDIRS = &#91;\n    {\"dx\": 0, \"dy\": -1},\n    {\"dx\": 1, \"dy\": 0},\n    {\"dx\": 0, \"dy\": 1},\n    {\"dx\": -1, \"dy\": 0}\n]\n\nENEMY_COLORS = &#91;\n    (231, 76, 60),      # Red\n    (155, 89, 182),     # Purple\n    (241, 196, 15),     # Yellow\n    (230, 126, 34)      # Orange\n]\n\nPOWERUP_COLORS = {\n    \"bomb\": (230, 126, 34),\n    \"range\": (52, 152, 219),\n    \"speed\": (46, 204, 113),\n    \"shield\": (241, 196, 15),\n    \"slow\": (155, 89, 182),\n    \"freeze\": (52, 211, 213)\n}\n\ndef make_grid(level: int) -> List&#91;List&#91;CellType]]:\n    \"\"\"Create game grid with walls and blocks.\"\"\"\n    grid = &#91;&#91;CellType.EMPTY for _ in range(COLS)] for _ in range(ROWS)]\n    \n    for r in range(ROWS):\n        for c in range(COLS):\n            if r == 0 or r == ROWS - 1 or c == 0 or c == COLS - 1:\n                grid&#91;r]&#91;c] = CellType.WALL\n            elif r % 2 == 0 and c % 2 == 0:\n                grid&#91;r]&#91;c] = CellType.WALL\n            elif (r > 2 or c > 2) and random.random() &lt; 0.45 + level * 0.02:\n                grid&#91;r]&#91;c] = CellType.BLOCK\n    \n    # Clear starting area\n    for r in range(1, 3):\n        for c in range(1, 3):\n            grid&#91;r]&#91;c] = CellType.EMPTY\n    \n    return grid\n\ndef make_enemies(level: int) -> List&#91;Enemy]:\n    \"\"\"Create enemies for the level.\"\"\"\n    count = 4 + level * 2\n    enemies = &#91;]\n    \n    for _ in range(count):\n        while True:\n            x = 2 + random.randint(0, COLS - 5)\n            y = 2 + random.randint(0, ROWS - 5)\n            if not (x &lt; 4 and y &lt; 4):\n                break\n        \n        enemies.append(Enemy(\n            x=x, y=y, dir=random.randint(0, 3),\n            alive=True, moveTimer=0, type=random.randint(0, min(3, level) - 1),\n            bombTimer=0, canDropBomb=True\n        ))\n    \n    return enemies\n\ndef init_state(level: int = 1) -> GameState:\n    \"\"\"Initialize game state.\"\"\"\n    return GameState(\n        grid=make_grid(level),\n        player={\"x\": 1, \"y\": 1},\n        bombs=&#91;],\n        explosions=&#91;],\n        enemies=make_enemies(level),\n        particles=&#91;],\n        powerups=&#91;],\n        score=0,\n        lives=3,\n        level=level,\n        status=Status.START,\n        tick=0,\n        keys=set(),\n        invTimer=0,\n        bombCooldown=0,\n        maxBombs=2,\n        range=2,\n        moveTimer=0,\n        currentBombs=0,\n        shield=False,\n        shieldTimer=0,\n        slowEffect=1.0\n    )\n\ndef draw_particle_effect(surface: pygame.Surface, x: float, y: float, color: Tuple&#91;int, int, int], size: int, alpha: int):\n    \"\"\"Draw a particle with glow effect.\"\"\"\n    if size &lt;= 0:\n        return\n    # Glow\n    glow_surface = pygame.Surface((size * 4, size * 4), pygame.SRCALPHA)\n    pygame.draw.circle(glow_surface, (*color, alpha \/\/ 3), (size * 2, size * 2), size * 2)\n    surface.blit(glow_surface, (int(x - size * 2), int(y - size * 2)))\n    \n    # Core\n    pygame.draw.circle(surface, (*color, alpha), (int(x), int(y)), max(1, size))\n\ndef render(surface: pygame.Surface, state: GameState):\n    \"\"\"Render the game.\"\"\"\n    # Background\n    surface.fill((17, 17, 17))\n    \n    # Draw grid\n    for r in range(ROWS):\n        for c in range(COLS):\n            cx = c * TILE\n            cy = r * TILE + 50\n            cell = state.grid&#91;r]&#91;c]\n            \n            if cell == CellType.WALL:\n                # Stone wall with texture\n                pygame.draw.rect(surface, (44, 62, 80), (cx, cy, TILE, TILE))\n                pygame.draw.rect(surface, (52, 73, 94), (cx + 2, cy + 2, TILE - 4, TILE \/\/ 3))\n                pygame.draw.rect(surface, (26, 37, 47), (cx, cy, TILE, TILE), 2)\n                \n                # Wall pattern\n                for i in range(2):\n                    pygame.draw.circle(surface, (34, 49, 63), (cx + 8 + i * 15, cy + 8), 3)\n            \n            elif cell == CellType.BLOCK:\n                # Wood block with texture\n                pygame.draw.rect(surface, (139, 69, 19), (cx, cy, TILE, TILE))\n                pygame.draw.rect(surface, (160, 82, 45, 136), (cx + 3, cy + 3, TILE - 6, TILE - 6))\n                pygame.draw.rect(surface, (107, 52, 16), (cx, cy, TILE, TILE), 2)\n                \n                # Wood grain\n                pygame.draw.rect(surface, (255, 255, 255, 17), (cx + 4, cy + 4, TILE \/\/ 3, 4))\n                pygame.draw.line(surface, (107, 52, 16), (cx, cy + TILE \/\/ 2), (cx + TILE, cy + TILE \/\/ 2), 1)\n            \n            else:\n                # Empty tile with checkerboard\n                color = (26, 26, 46) if (r + c) % 2 == 0 else (22, 22, 38)\n                pygame.draw.rect(surface, color, (cx, cy, TILE, TILE))\n                pygame.draw.line(surface, (50, 50, 80), (cx, cy), (cx + TILE, cy), 1)\n    \n    # Draw explosions with particles\n    for ex in state.explosions:\n        alpha = max(0, int((ex.life \/ 20) * 200))\n        \n        # Main explosion glow\n        glow_radius = int(TILE * 0.7 * (ex.life \/ 20))\n        if glow_radius > 0:\n            glow_surface = pygame.Surface((glow_radius * 2, glow_radius * 2), pygame.SRCALPHA)\n            pygame.draw.circle(glow_surface, (241, 196, 15, alpha \/\/ 2), (glow_radius, glow_radius), glow_radius)\n            center_x = ex.x * TILE + TILE \/\/ 2\n            center_y = ex.y * TILE + TILE \/\/ 2 + 50\n            surface.blit(glow_surface, (int(center_x - glow_radius), int(center_y - glow_radius)))\n        \n        # Explosion core\n        explosion_surface = pygame.Surface((TILE, TILE), pygame.SRCALPHA)\n        color_gradient = int(255 * (ex.life \/ 20))\n        pygame.draw.circle(explosion_surface, (255, 200, 0, alpha), (TILE \/\/ 2, TILE \/\/ 2), int(TILE * 0.6))\n        pygame.draw.circle(explosion_surface, (255, 100, 0, alpha), (TILE \/\/ 2, TILE \/\/ 2), int(TILE * 0.4))\n        \n        surface.blit(explosion_surface, (ex.x * TILE, ex.y * TILE + 50))\n    \n    # Draw particles\n    for p in state.particles:\n        if p.life > 0:\n            alpha = int(p.life * 255)\n            draw_particle_effect(surface, p.x, p.y, p.color, p.size, alpha)\n    \n    # Draw bombs\n    for b in state.bombs:\n        bx = b.x * TILE + TILE \/\/ 2\n        by = b.y * TILE + TILE \/\/ 2 + 50\n        pulse = 0.9 + 0.15 * math.sin(state.tick * 0.3 * (30 \/ b.timer))\n        \n        # Bomb color based on owner\n        bomb_color = (51, 51, 51) if b.owner == \"player\" else (180, 50, 50)\n        \n        bomb_surface = pygame.Surface((TILE, TILE), pygame.SRCALPHA)\n        \n        # Body\n        pygame.draw.circle(bomb_surface, bomb_color, (TILE \/\/ 2, TILE \/\/ 2), int(TILE * 0.38))\n        pygame.draw.circle(bomb_surface, (85, 85, 85), (TILE \/\/ 2 - 4, TILE \/\/ 2 - 4), int(TILE * 0.15))\n        \n        # Fuse\n        fuse_alpha = 128 if b.timer &lt; 60 else 255\n        fuse_color = (241, 196, 15) if b.owner == \"player\" else (255, 100, 100)\n        fuse_surf = pygame.Surface((TILE, TILE), pygame.SRCALPHA)\n        pygame.draw.line(fuse_surf, (*fuse_color, fuse_alpha), (TILE \/\/ 2 + 4, TILE \/\/ 2 - int(TILE * 0.38)),\n                        (TILE \/\/ 2 + 6, TILE \/\/ 2 - int(TILE * 0.65)), 2)\n        pygame.draw.circle(fuse_surf, (*fuse_color, fuse_alpha), (TILE \/\/ 2 + 6, TILE \/\/ 2 - int(TILE * 0.65)), 3)\n        bomb_surface.blit(fuse_surf, (0, 0))\n        \n        # Scale and draw\n        scaled = pygame.transform.scale(bomb_surface, (int(TILE * pulse), int(TILE * pulse)))\n        surface.blit(scaled, (int(bx - TILE * pulse \/\/ 2), int(by - TILE * pulse \/\/ 2)))\n        \n        # Glow\n        glow_color = (241, 196, 15) if b.owner == \"player\" else (255, 100, 100)\n        glow = pygame.Surface((TILE * 2, TILE * 2), pygame.SRCALPHA)\n        pygame.draw.circle(glow, (*glow_color, 50), (TILE, TILE), int(TILE * 0.7))\n        surface.blit(glow, (int(bx - TILE), int(by - TILE)))\n    \n    # Draw powerups\n    for pu in state.powerups:\n        if not pu.collected:\n            px = pu.x * TILE + TILE \/\/ 2\n            py = pu.y * TILE + TILE \/\/ 2 + 50\n            \n            # Rotating powerup with glow\n            color = POWERUP_COLORS&#91;pu.type]\n            glow = pygame.Surface((TILE * 1.2, TILE * 1.2), pygame.SRCALPHA)\n            pygame.draw.circle(glow, (*color, 60), (int(TILE * 0.6), int(TILE * 0.6)), int(TILE * 0.5))\n            surface.blit(glow, (int(px - TILE * 0.6), int(py - TILE * 0.6)))\n            \n            # Powerup sprite\n            pu_surf = pygame.Surface((TILE - 10, TILE - 10), pygame.SRCALPHA)\n            \n            if pu.type == \"bomb\":\n                pygame.draw.circle(pu_surf, color, (TILE \/\/ 2 - 5, TILE \/\/ 2 - 5), 8)\n                pygame.draw.line(pu_surf, (255, 255, 0), (TILE \/\/ 2 - 1, TILE \/\/ 2 - 13), (TILE \/\/ 2 - 1, TILE \/\/ 2 - 15), 2)\n            elif pu.type == \"range\":\n                pygame.draw.circle(pu_surf, color, (TILE \/\/ 2 - 5, TILE \/\/ 2 - 5), 8)\n                pygame.draw.line(pu_surf, (255, 255, 255), (TILE \/\/ 2 - 12, TILE \/\/ 2 - 5), (TILE \/\/ 2 + 2, TILE \/\/ 2 - 5), 2)\n                pygame.draw.line(pu_surf, (255, 255, 255), (TILE \/\/ 2 - 5, TILE \/\/ 2 - 12), (TILE \/\/ 2 - 5, TILE \/\/ 2 + 2), 2)\n            elif pu.type == \"speed\":\n                pygame.draw.circle(pu_surf, color, (TILE \/\/ 2 - 5, TILE \/\/ 2 - 5), 8)\n                pygame.draw.polygon(pu_surf, (255, 255, 255), &#91;(TILE \/\/ 2 - 12, TILE \/\/ 2 - 5),\n                                                               (TILE \/\/ 2 - 5, TILE \/\/ 2 - 11),\n                                                               (TILE \/\/ 2 - 5, TILE \/\/ 2 + 1)])\n            elif pu.type == \"shield\":\n                pygame.draw.circle(pu_surf, color, (TILE \/\/ 2 - 5, TILE \/\/ 2 - 5), 8)\n                pygame.draw.circle(pu_surf, (255, 255, 255), (TILE \/\/ 2 - 5, TILE \/\/ 2 - 5), 12, 2)\n            elif pu.type == \"slow\":\n                pygame.draw.circle(pu_surf, color, (TILE \/\/ 2 - 5, TILE \/\/ 2 - 5), 8)\n                pygame.draw.rect(pu_surf, (255, 255, 255), (TILE \/\/ 2 - 10, TILE \/\/ 2 - 3, 10, 6))\n            elif pu.type == \"freeze\":\n                pygame.draw.circle(pu_surf, color, (TILE \/\/ 2 - 5, TILE \/\/ 2 - 5), 8)\n                pygame.draw.rect(pu_surf, (200, 220, 255), (TILE \/\/ 2 - 10, TILE \/\/ 2 - 3, 5, 6))\n                pygame.draw.rect(pu_surf, (200, 220, 255), (TILE \/\/ 2 - 2, TILE \/\/ 2 - 3, 5, 6))\n            \n            angle = state.tick * 5\n            rotated = pygame.transform.rotate(pu_surf, angle)\n            surface.blit(rotated, (int(px - rotated.get_width() \/\/ 2), int(py - rotated.get_height() \/\/ 2)))\n    \n    # Draw enemies\n    for e in state.enemies:\n        if not e.alive:\n            continue\n        \n        ex = e.x * TILE + TILE \/\/ 2\n        ey = e.y * TILE + TILE \/\/ 2 + 50\n        color = ENEMY_COLORS&#91;e.type % len(ENEMY_COLORS)]\n        \n        # Glow\n        glow = pygame.Surface((TILE * 1.5, TILE * 1.5), pygame.SRCALPHA)\n        pygame.draw.circle(glow, (*color, 80), (int(TILE * 0.75), int(TILE * 0.75)), int(TILE * 0.6))\n        surface.blit(glow, (int(ex - TILE * 0.75), int(ey - TILE * 0.75)))\n        \n        # Body\n        pygame.draw.circle(surface, color, (ex, ey), int(TILE * 0.42))\n        \n        # Eyes\n        pygame.draw.circle(surface, (0, 0, 0), (ex - 6, ey - 5), 5)\n        pygame.draw.circle(surface, (0, 0, 0), (ex + 6, ey - 5), 5)\n        pygame.draw.circle(surface, (255, 255, 255), (ex - 5, ey - 6), 2)\n        pygame.draw.circle(surface, (255, 255, 255), (ex + 7, ey - 6), 2)\n        \n        # Pupils\n        pupil_offset = int(2 * math.sin(state.tick * 0.05))\n        pygame.draw.circle(surface, (0, 0, 0), (ex - 5 + pupil_offset, ey - 6 + pupil_offset), 1)\n        pygame.draw.circle(surface, (0, 0, 0), (ex + 7 + pupil_offset, ey - 6 + pupil_offset), 1)\n        \n        # Mouth\n        pygame.draw.arc(surface, (0, 0, 0), (ex - 8, ey + 1, 16, 10), 0.2, math.pi - 0.2, 2)\n    \n    # Draw player\n    px = state.player&#91;\"x\"] * TILE + TILE \/\/ 2\n    py = state.player&#91;\"y\"] * TILE + TILE \/\/ 2 + 50\n    \n    inv_flashing = state.invTimer > 0 and (state.tick \/\/ 4) % 2 == 0\n    \n    if not inv_flashing:\n        # Shield effect\n        if state.shield:\n            shield_glow = pygame.Surface((TILE * 2, TILE * 2), pygame.SRCALPHA)\n            pygame.draw.circle(shield_glow, (241, 196, 15, 100), (TILE, TILE), int(TILE * 0.9))\n            surface.blit(shield_glow, (int(px - TILE), int(py - TILE)))\n            pygame.draw.circle(surface, (241, 196, 15), (px, py), int(TILE * 0.55), 2)\n        \n        # Glow\n        glow = pygame.Surface((TILE * 1.5, TILE * 1.5), pygame.SRCALPHA)\n        pygame.draw.circle(glow, (52, 211, 153, 100), (int(TILE * 0.75), int(TILE * 0.75)), int(TILE * 0.7))\n        surface.blit(glow, (int(px - TILE * 0.75), int(py - TILE * 0.75)))\n        \n        # Body\n        pygame.draw.circle(surface, (52, 211, 153), (px, py), int(TILE * 0.44))\n        pygame.draw.circle(surface, (0, 153, 170), (px, py), int(TILE * 0.3))\n        \n        # Eyes (animated)\n        eye_offset = int(2 * math.sin(state.tick * 0.1))\n        pygame.draw.circle(surface, (255, 255, 255), (px - 6, py - 5), 5)\n        pygame.draw.circle(surface, (255, 255, 255), (px + 6, py - 5), 5)\n        pygame.draw.circle(surface, (0, 0, 0), (px - 5 + eye_offset, py - 6), 2)\n        pygame.draw.circle(surface, (0, 0, 0), (px + 7 + eye_offset, py - 6), 2)\n        \n        # Smile\n        pygame.draw.arc(surface, (0, 0, 0), (px - 8, py + 1, 16, 10), 0.2, math.pi - 0.2, 2)\n    \n    # HUD background\n    pygame.draw.rect(surface, (0, 0, 0), (0, 0, W, 50))\n    pygame.draw.line(surface, (100, 100, 100), (0, 50), (W, 50), 1)\n    \n    # HUD text\n    font_large = pygame.font.Font(None, 18)\n    font_small = pygame.font.Font(None, 14)\n    font_tiny = pygame.font.Font(None, 12)\n    \n    score_text = font_large.render(f\"SCORE: {state.score}\", True, (52, 211, 153))\n    surface.blit(score_text, (10, 10))\n    \n    lives_text = font_large.render(\"\u2764\ufe0f \" * state.lives, True, (231, 76, 60))\n    surface.blit(lives_text, (10, 30))\n    \n    level_text = font_large.render(f\"LVL {state.level}  ENEMIES: {sum(1 for e in state.enemies if e.alive)}\", True, (241, 196, 15))\n    level_rect = level_text.get_rect(center=(W \/\/ 2, 25))\n    surface.blit(level_text, level_rect)\n    \n    # Powerup status\n    status_y = 10\n    pygame.draw.circle(surface, (230, 126, 34), (W - 180, status_y + 5), 4)\n    bomb_text = font_tiny.render(f\"x{state.currentBombs}\/{state.maxBombs}\", True, (200, 200, 200))\n    surface.blit(bomb_text, (W - 170, status_y))\n    \n    pygame.draw.line(surface, (52, 152, 219), (W - 130, status_y), (W - 110, status_y), 3)\n    range_text = font_tiny.render(f\"x{state.range}\", True, (200, 200, 200))\n    surface.blit(range_text, (W - 100, status_y))\n    \n    if state.shield:\n        pygame.draw.circle(surface, (241, 196, 15), (W - 50, status_y + 5), 4)\n        pygame.draw.circle(surface, (241, 196, 15), (W - 50, status_y + 5), 6, 1)\n        shield_text = font_tiny.render(\"ON\", True, (241, 196, 15))\n        surface.blit(shield_text, (W - 40, status_y))\n    \n    controls_text = font_small.render(\"WASD\/Arrows=Move  SPACE=Bomb\", True, (170, 170, 170))\n    surface.blit(controls_text, (W - 320, 30))\n    \n    # Game state overlays\n    if state.status == Status.START:\n        overlay = pygame.Surface((W, H), pygame.SRCALPHA)\n        overlay.fill((0, 0, 0, 166))\n        surface.blit(overlay, (0, 0))\n        \n        font_title = pygame.font.Font(None, 60)\n        font_desc = pygame.font.Font(None, 16)\n        \n        title = font_title.render(\"\ud83d\udca3 BOMBERMAN\", True, (241, 196, 15))\n        surface.blit(title, (W \/\/ 2 - title.get_width() \/\/ 2, H \/\/ 2 - 100))\n        \n        desc1 = font_desc.render(\"WASD\/Arrows to move \u00b7 SPACE to plant bomb\", True, (255, 255, 255))\n        surface.blit(desc1, (W \/\/ 2 - desc1.get_width() \/\/ 2, H \/\/ 2))\n        \n        desc2 = font_desc.render(\"Destroy blocks, defeat enemies, collect power-ups!\", True, (255, 255, 255))\n        surface.blit(desc2, (W \/\/ 2 - desc2.get_width() \/\/ 2, H \/\/ 2 + 20))\n        \n        desc3 = font_desc.render(\"Enemies drop bombs! Watch out!\", True, (255, 100, 100))\n        surface.blit(desc3, (W \/\/ 2 - desc3.get_width() \/\/ 2, H \/\/ 2 + 40))\n        \n        blink = 0.5 + 0.5 * math.sin(state.tick * 0.1)\n        start_text = font_desc.render(\"PRESS SPACE\", True, (74, 222, 128))\n        start_surf = pygame.Surface(start_text.get_size(), pygame.SRCALPHA)\n        start_surf.blit(start_text, (0, 0))\n        start_surf.set_alpha(int(blink * 255))\n        surface.blit(start_surf, (W \/\/ 2 - start_text.get_width() \/\/ 2, H \/\/ 2 + 80))\n    \n    elif state.status == Status.WIN:\n        overlay = pygame.Surface((W, H), pygame.SRCALPHA)\n        overlay.fill((0, 0, 0, 166))\n        surface.blit(overlay, (0, 0))\n        \n        font_title = pygame.font.Font(None, 60)\n        font_desc = pygame.font.Font(None, 16)\n        \n        title = font_title.render(\"LEVEL CLEAR! \ud83c\udf89\", True, (241, 196, 15))\n        surface.blit(title, (W \/\/ 2 - title.get_width() \/\/ 2, H \/\/ 2 - 100))\n        \n        score_text = font_desc.render(f\"Score: {state.score}\", True, (255, 255, 255))\n        surface.blit(score_text, (W \/\/ 2 - score_text.get_width() \/\/ 2, H \/\/ 2))\n        \n        blink = 0.5 + 0.5 * math.sin(state.tick * 0.1)\n        next_text = font_desc.render(\"SPACE for next level\", True, (74, 222, 128))\n        next_surf = pygame.Surface(next_text.get_size(), pygame.SRCALPHA)\n        next_surf.blit(next_text, (0, 0))\n        next_surf.set_alpha(int(blink * 255))\n        surface.blit(next_surf, (W \/\/ 2 - next_text.get_width() \/\/ 2, H \/\/ 2 + 60))\n    \n    elif state.status == Status.DEAD:\n        overlay = pygame.Surface((W, H), pygame.SRCALPHA)\n        overlay.fill((0, 0, 0, 166))\n        surface.blit(overlay, (0, 0))\n        \n        font_title = pygame.font.Font(None, 60)\n        font_desc = pygame.font.Font(None, 16)\n        \n        title = font_title.render(\"GAME OVER\", True, (231, 76, 60))\n        surface.blit(title, (W \/\/ 2 - title.get_width() \/\/ 2, H \/\/ 2 - 100))\n        \n        score_text = font_desc.render(f\"Score: {state.score}\", True, (255, 255, 255))\n        surface.blit(score_text, (W \/\/ 2 - score_text.get_width() \/\/ 2, H \/\/ 2))\n        \n        blink = 0.5 + 0.5 * math.sin(state.tick * 0.1)\n        retry_text = font_desc.render(\"SPACE to retry\", True, (74, 222, 128))\n        retry_surf = pygame.Surface(retry_text.get_size(), pygame.SRCALPHA)\n        retry_surf.blit(retry_text, (0, 0))\n        retry_surf.set_alpha(int(blink * 255))\n        surface.blit(retry_surf, (W \/\/ 2 - retry_text.get_width() \/\/ 2, H \/\/ 2 + 60))\n\nclass BombermanGame:\n    def __init__(self):\n        pygame.init()\n        self.screen = pygame.display.set_mode((W, H))\n        pygame.display.set_caption(\"Bomberman - Extended Edition\")\n        self.clock = pygame.time.Clock()\n        self.running = True\n        self.level = 1\n        self.state = init_state(self.level)\n    \n    def plant_bomb(self, x: int, y: int, owner: str = \"player\"):\n        \"\"\"Plant a bomb at position.\"\"\"\n        if any(b.x == x and b.y == y for b in self.state.bombs):\n            return\n        \n        if owner == \"player\":\n            if self.state.currentBombs >= self.state.maxBombs:\n                return\n            if self.state.bombCooldown > 0:\n                return\n            self.state.bombCooldown = 20\n            self.state.currentBombs += 1\n        \n        self.state.bombs.append(Bomb(\n            x=x,\n            y=y,\n            timer=150,\n            range=self.state.range,\n            owner=owner\n        ))\n    \n    def try_move(self, dx: int, dy: int):\n        \"\"\"Try to move player.\"\"\"\n        nx = self.state.player&#91;\"x\"] + dx\n        ny = self.state.player&#91;\"y\"] + dy\n        \n        if nx &lt; 0 or nx >= COLS or ny &lt; 0 or ny >= ROWS:\n            return\n        if self.state.grid&#91;ny]&#91;nx] != CellType.EMPTY:\n            return\n        if any(b.x == nx and b.y == ny for b in self.state.bombs):\n            return\n        \n        self.state.player&#91;\"x\"] = nx\n        self.state.player&#91;\"y\"] = ny\n    \n    def update(self):\n        \"\"\"Update game state.\"\"\"\n        state = self.state\n        state.tick += 1\n        \n        if state.invTimer > 0:\n            state.invTimer -= 1\n        if state.shieldTimer > 0:\n            state.shieldTimer -= 1\n            if state.shieldTimer &lt;= 0:\n                state.shield = False\n        if state.bombCooldown > 0:\n            state.bombCooldown -= 1\n        \n        if state.status == Status.PLAYING:\n            state.moveTimer += 1\n            \n            # Handle movement\n            if state.moveTimer >= 8:\n                state.moveTimer = 0\n                if \"KeyA\" in state.keys or \"ArrowLeft\" in state.keys:\n                    self.try_move(-1, 0)\n                elif \"KeyD\" in state.keys or \"ArrowRight\" in state.keys:\n                    self.try_move(1, 0)\n                elif \"KeyW\" in state.keys or \"ArrowUp\" in state.keys:\n                    self.try_move(0, -1)\n                elif \"KeyS\" in state.keys or \"ArrowDown\" in state.keys:\n                    self.try_move(0, 1)\n            \n            # Update bombs\n            for i in range(len(state.bombs) - 1, -1, -1):\n                state.bombs&#91;i].timer -= 1\n                \n                if state.bombs&#91;i].timer &lt;= 0:\n                    bomb = state.bombs.pop(i)\n                    \n                    if bomb.owner == \"player\":\n                        state.currentBombs -= 1\n                    \n                    # Explosion at bomb center\n                    state.explosions.append(Explosion(x=bomb.x, y=bomb.y, life=20, dir=\"center\"))\n                    \n                    # Particle burst at bomb\n                    for _ in range(8):\n                        angle = random.random() * 2 * math.pi\n                        speed = 2 + random.random() * 2\n                        state.particles.append(Particle(\n                            x=bomb.x * TILE + TILE \/\/ 2,\n                            y=bomb.y * TILE + TILE \/\/ 2 + 50,\n                            vx=math.cos(angle) * speed,\n                            vy=math.sin(angle) * speed,\n                            life=1.0,\n                            color=(241, 196, 15),\n                            size=4\n                        ))\n                    \n                    # Directional explosions\n                    for d in DIRS:\n                        for r in range(1, bomb.range + 1):\n                            ex = bomb.x + d&#91;\"dx\"] * r\n                            ey = bomb.y + d&#91;\"dy\"] * r\n                            \n                            if ex &lt; 0 or ex >= COLS or ey &lt; 0 or ey >= ROWS:\n                                break\n                            if state.grid&#91;ey]&#91;ex] == CellType.WALL:\n                                break\n                            \n                            state.explosions.append(Explosion(x=ex, y=ey, life=20, dir=f\"{d&#91;'dx']},{d&#91;'dy']}\"))\n                            \n                            if state.grid&#91;ey]&#91;ex] == CellType.BLOCK:\n                                state.grid&#91;ey]&#91;ex] = CellType.EMPTY\n                                state.score += 10\n                                \n                                # Power-up chance\n                                if random.random() &lt; 0.2 and r == 1:\n                                    pu_type = random.choice(&#91;\"bomb\", \"range\", \"speed\", \"shield\", \"slow\", \"freeze\"])\n                                    state.powerups.append(PowerUp(x=ex, y=ey, type=pu_type, collected=False))\n                                break\n            \n            # Update explosions and particles\n            for i in range(len(state.explosions) - 1, -1, -1):\n                state.explosions&#91;i].life -= 1\n                state.explosions&#91;i].tick += 1\n                \n                if state.explosions&#91;i].life &lt;= 0:\n                    state.explosions.pop(i)\n                    continue\n                \n                ex = state.explosions&#91;i]\n                \n                # Check enemy collision\n                for enemy in state.enemies:\n                    if enemy.alive and enemy.x == ex.x and enemy.y == ex.y:\n                        enemy.alive = False\n                        state.score += 50 + state.level * 10\n                        \n                        # Particle burst\n                        for _ in range(12):\n                            angle = random.random() * 2 * math.pi\n                            speed = 3 + random.random() * 2\n                            color = ENEMY_COLORS&#91;enemy.type % len(ENEMY_COLORS)]\n                            state.particles.append(Particle(\n                                x=enemy.x * TILE + TILE \/\/ 2,\n                                y=enemy.y * TILE + TILE \/\/ 2 + 50,\n                                vx=math.cos(angle) * speed,\n                                vy=math.sin(angle) * speed,\n                                life=1.0,\n                                color=color,\n                                size=3\n                            ))\n                \n                # Check player collision\n                if state.player&#91;\"x\"] == ex.x and state.player&#91;\"y\"] == ex.y and state.invTimer &lt;= 0:\n                    if state.shield:\n                        state.shield = False\n                        state.shieldTimer = 0\n                    else:\n                        state.lives -= 1\n                        state.invTimer = 120\n                        \n                        if state.lives &lt;= 0:\n                            state.status = Status.DEAD\n                        else:\n                            # Particle burst\n                            for _ in range(16):\n                                angle = random.random() * 2 * math.pi\n                                speed = 4 + random.random() * 2\n                                state.particles.append(Particle(\n                                    x=state.player&#91;\"x\"] * TILE + TILE \/\/ 2,\n                                    y=state.player&#91;\"y\"] * TILE + TILE \/\/ 2 + 50,\n                                    vx=math.cos(angle) * speed,\n                                    vy=math.sin(angle) * speed,\n                                    life=1.0,\n                                    color=(52, 211, 153),\n                                    size=4\n                                ))\n            \n            # Update particles\n            for p in state.particles:\n                p.x += p.vx\n                p.y += p.vy\n                p.vy += 0.2\n                p.life -= 0.04\n            state.particles = &#91;p for p in state.particles if p.life > 0]\n            \n            # Check powerup collection\n            for pu in state.powerups:\n                if not pu.collected and pu.x == state.player&#91;\"x\"] and pu.y == state.player&#91;\"y\"]:\n                    pu.collected = True\n                    if pu.type == \"bomb\":\n                        state.maxBombs = min(8, state.maxBombs + 1)\n                    elif pu.type == \"range\":\n                        state.range = min(8, state.range + 1)\n                    elif pu.type == \"speed\":\n                        pass  # Speed bonus\n                    elif pu.type == \"shield\":\n                        state.shield = True\n                        state.shieldTimer = 300\n                    elif pu.type == \"slow\":\n                        state.slowEffect = 0.5\n                    elif pu.type == \"freeze\":\n                        state.slowEffect = 0.2\n                    state.score += 25\n            \n            # Update enemies\n            for enemy in state.enemies:\n                if not enemy.alive:\n                    continue\n                \n                enemy.moveTimer += 1\n                move_every = max(5, 20 - min(12, state.level * 2))\n                move_every = int(move_every \/ state.slowEffect)\n                \n                if enemy.moveTimer >= move_every:\n                    enemy.moveTimer = 0\n                    \n                    if random.random() &lt; 0.3:\n                        enemy.dir = random.randint(0, 3)\n                    \n                    d = DIRS&#91;enemy.dir]\n                    nx = enemy.x + d&#91;\"dx\"]\n                    ny = enemy.y + d&#91;\"dy\"]\n                    \n                    if (0 &lt;= nx &lt; COLS and 0 &lt;= ny &lt; ROWS and\n                        state.grid&#91;ny]&#91;nx] == CellType.EMPTY and\n                        not any(b.x == nx and b.y == ny for b in state.bombs)):\n                        enemy.x = nx\n                        enemy.y = ny\n                    else:\n                        enemy.dir = random.randint(0, 3)\n                \n                # Enemy bomb dropping\n                enemy.bombTimer += 1\n                bomb_drop_chance = 0.005 + state.level * 0.001\n                if enemy.bombTimer > 30 and random.random() &lt; bomb_drop_chance and enemy.canDropBomb:\n                    self.plant_bomb(enemy.x, enemy.y, owner=\"enemy\")\n                    enemy.bombTimer = 0\n                    enemy.canDropBomb = False\n                elif enemy.bombTimer > 200:\n                    enemy.canDropBomb = True\n                \n                # Check player collision\n                if enemy.x == state.player&#91;\"x\"] and enemy.y == state.player&#91;\"y\"] and state.invTimer &lt;= 0:\n                    if state.shield:\n                        state.shield = False\n                        state.shieldTimer = 0\n                    else:\n                        state.lives -= 1\n                        state.invTimer = 120\n                        \n                        if state.lives &lt;= 0:\n                            state.status = Status.DEAD\n                        else:\n                            for _ in range(16):\n                                angle = random.random() * 2 * math.pi\n                                speed = 4 + random.random() * 2\n                                state.particles.append(Particle(\n                                    x=state.player&#91;\"x\"] * TILE + TILE \/\/ 2,\n                                    y=state.player&#91;\"y\"] * TILE + TILE \/\/ 2 + 50,\n                                    vx=math.cos(angle) * speed,\n                                    vy=math.sin(angle) * speed,\n                                    life=1.0,\n                                    color=(52, 211, 153),\n                                    size=4\n                                ))\n            \n            # Check level completion\n            if all(not e.alive for e in state.enemies) and state.status == Status.PLAYING:\n                state.score += state.level * 200\n                state.status = Status.WIN\n    \n    def handle_events(self):\n        \"\"\"Handle input events.\"\"\"\n        for event in pygame.event.get():\n            if event.type == pygame.QUIT:\n                self.running = False\n            elif event.type == pygame.KEYDOWN:\n                if event.key == pygame.K_ESCAPE:\n                    self.running = False\n                elif event.key == pygame.K_SPACE:\n                    if self.state.status == Status.START:\n                        self.state.status = Status.PLAYING\n                    elif self.state.status == Status.DEAD:\n                        self.level = 1\n                        self.state = init_state(self.level)\n                        self.state.status = Status.PLAYING\n                    elif self.state.status == Status.WIN:\n                        self.level += 1\n                        self.state = init_state(self.level)\n                        self.state.status = Status.PLAYING\n                    elif self.state.status == Status.PLAYING:\n                        self.plant_bomb(self.state.player&#91;\"x\"], self.state.player&#91;\"y\"])\n                elif event.key in (pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s,\n                                   pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN):\n                    key_map = {\n                        pygame.K_a: \"KeyA\",\n                        pygame.K_d: \"KeyD\",\n                        pygame.K_w: \"KeyW\",\n                        pygame.K_s: \"KeyS\",\n                        pygame.K_LEFT: \"ArrowLeft\",\n                        pygame.K_RIGHT: \"ArrowRight\",\n                        pygame.K_UP: \"ArrowUp\",\n                        pygame.K_DOWN: \"ArrowDown\"\n                    }\n                    self.state.keys.add(key_map&#91;event.key])\n            \n            elif event.type == pygame.KEYUP:\n                key_map = {\n                    pygame.K_a: \"KeyA\",\n                    pygame.K_d: \"KeyD\",\n                    pygame.K_w: \"KeyW\",\n                    pygame.K_s: \"KeyS\",\n                    pygame.K_LEFT: \"ArrowLeft\",\n                    pygame.K_RIGHT: \"ArrowRight\",\n                    pygame.K_UP: \"ArrowUp\",\n                    pygame.K_DOWN: \"ArrowDown\"\n                }\n                if event.key in key_map:\n                    self.state.keys.discard(key_map&#91;event.key])\n    \n    def run(self):\n        \"\"\"Main game loop.\"\"\"\n        while self.running:\n            self.handle_events()\n            self.update()\n            render(self.screen, self.state)\n            pygame.display.flip()\n            self.clock.tick(FPS)\n        \n        pygame.quit()\n\nif __name__ == \"__main__\":\n    game = BombermanGame()\n    game.run()\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>i made it like the famous game but it sucks and i started it awhile ago and forgot about it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-115","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/posts\/115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/comments?post=115"}],"version-history":[{"count":1,"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/posts\/115\/revisions"}],"predecessor-version":[{"id":116,"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/posts\/115\/revisions\/116"}],"wp:attachment":[{"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/media?parent=115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/categories?post=115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/c_menhart\/wp-json\/wp\/v2\/tags?post=115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}