Jelajahi Sumber

Subir archivos a ''

YESSENIA 3 minggu lalu
induk
melakukan
af65d8107c
1 mengubah file dengan 473 tambahan dan 0 penghapusan
  1. 473 0
      main.py

+ 473 - 0
main.py

@@ -0,0 +1,473 @@
+from graphics import Canvas
+import random
+import time
+
+# ======================================================
+# MADE BY   : YESSENIA CHOQUEHUANCA MASIAS - COUNTRY: PERÚ
+# PROJECT   : Code Catcher - Catch the Codes
+# UNIVERSITY: STANFORD - Peru
+# COLORS    : Peru Gold/Red
+# ======================================================
+
+CANVAS_WIDTH  = 600
+CANVAS_HEIGHT = 400
+
+BALL_SIZE     = 25
+GRAVITY       = 0.9
+JUMP_STRENGTH = -22
+BOUNCE_FACTOR = 0.6
+MIN_BOUNCE_VY = 3.0
+
+CODE_W        = 110
+CODE_H        = 26
+CODE_COUNT    = 4
+CODES_TO_WIN  = 10
+
+COLOR_STANFORD_RED = "#800b0bff"
+COLOR_PERU_RED     = "#BF0000"
+COLOR_GOLD         = "#c49620ff"
+COLOR_BRIGHT_GOLD  = "#938224ff"
+COLOR_DARK_NAVY    = "#1a1a2e"
+COLOR_WHITE        = "WHITE"
+COLOR_GRAY         = "#AAAAAA"
+COLOR_BLACK        = "black"
+
+CODE_SNIPPETS = [
+    "move()",
+    "pick_beeper()",
+    "turn_left()",
+    "turn_right()",
+    "put_beeper()",
+]
+
+
+class KarelBall:
+    """
+    Pelota que se convierte en Karel parte a parte.
+    Nivel 0      → pelota blanca
+    Nivel 1-2    → cuerpo
+    Nivel 3-4    → piernas
+    Nivel 5-6    → brazos
+    Nivel 7-8    → cabeza/pantalla
+    Nivel 9-10   → Karel completo con antena
+    """
+
+    def __init__(self, canvas, x, y):
+        self.canvas = canvas
+        self.x  = x
+        self.y  = y
+        self.vx = 0
+        self.vy = 0
+        self.is_grounded = False
+        self.on_platform = None
+        self.level       = 0      # how many codes has he caught
+
+        # IDs of each drawn part
+        self.parts = {}
+        self._draw_level()
+
+    # --------------------------------------------------
+    # DRAWN
+    # --------------------------------------------------
+    def _clear(self):
+        for pid in self.parts.values():
+            self.canvas.delete(pid)
+        self.parts = {}
+
+    def _draw_level(self):
+        self._clear()
+        x, y = self.x, self.y   # top-left corner of the sprite (25x25)
+
+        # --- LEVEL 0: single ball ---
+        self.parts['body_oval'] = self.canvas.create_oval(
+            x, y, x + 25, y + 25,
+            COLOR_WHITE, COLOR_STANFORD_RED
+        )
+
+        if self.level >= 2:
+            # Gray square (replaces the oval with a rectangle on top)
+            self.parts['body'] = self.canvas.create_rectangle(
+                x + 4, y + 8, x + 21, y + 22,
+                COLOR_GRAY, COLOR_BLACK
+            )
+
+        if self.level >= 4:
+            # Left leg
+            self.parts['leg_l'] = self.canvas.create_rectangle(
+                x + 5, y + 22, x + 10, y + 30,
+                COLOR_GRAY, COLOR_BLACK
+            )
+            # Right leg
+            self.parts['leg_r'] = self.canvas.create_rectangle(
+                x + 15, y + 22, x + 20, y + 30,
+                COLOR_GRAY, COLOR_BLACK
+            )
+            # Left foot
+            self.parts['foot_l'] = self.canvas.create_rectangle(
+                x + 3, y + 28, x + 11, y + 32,
+                COLOR_BLACK, COLOR_BLACK
+            )
+            # Ceiling height
+            self.parts['foot_r'] = self.canvas.create_rectangle(
+                x + 14, y + 28, x + 22, y + 32,
+                COLOR_BLACK, COLOR_BLACK
+            )
+
+        if self.level >= 6:
+            # Left arm
+            self.parts['arm_l'] = self.canvas.create_rectangle(
+                x - 5, y + 10, x + 4, y + 15,
+                COLOR_GRAY, COLOR_BLACK
+            )
+            # Right-hand man
+            self.parts['arm_r'] = self.canvas.create_rectangle(
+                x + 21, y + 10, x + 30, y + 15,
+                COLOR_GRAY, COLOR_BLACK
+            )
+            # Left hand
+            self.parts['hand_l'] = self.canvas.create_oval(
+                x - 8, y + 8, x - 2, y + 17,
+                COLOR_BLACK, COLOR_BLACK
+            )
+            # Right hand
+            self.parts['hand_r'] = self.canvas.create_oval(
+                x + 27, y + 8, x + 33, y + 17,
+                COLOR_BLACK, COLOR_BLACK
+            )
+
+        if self.level >= 8:
+            # Head
+            self.parts['head'] = self.canvas.create_rectangle(
+                x + 5, y - 10, x + 20, y + 8,
+                COLOR_GRAY, COLOR_BLACK
+            )
+            # Screen (eye)
+            self.parts['screen'] = self.canvas.create_rectangle(
+                x + 8, y - 8, x + 17, y + 2,
+                COLOR_DARK_NAVY, COLOR_BLACK
+            )
+            # Screen resolution
+            self.parts['pixel'] = self.canvas.create_rectangle(
+                x + 10, y - 5, x + 15, y - 1,
+                COLOR_BRIGHT_GOLD, COLOR_BRIGHT_GOLD
+            )
+
+        if self.level >= 10:
+            # AntenNa
+            self.parts['antenna'] = self.canvas.create_rectangle(
+                x + 11, y - 18, x + 14, y - 10,
+                COLOR_BLACK, COLOR_BLACK
+            )
+            # Antenna tip
+            self.parts['antenna_tip'] = self.canvas.create_oval(
+                x + 9, y - 22, x + 16, y - 16,
+                COLOR_BRIGHT_GOLD, COLOR_BLACK
+            )
+
+    def _move_parts(self, dx, dy):
+        for pid in self.parts.values():
+            self.canvas.move(pid, dx, dy)
+
+    # --------------------------------------------------
+    # DEVELOPMENT
+    # --------------------------------------------------
+    def evolve(self, codes_caught):
+        self.level = codes_caught
+        self._draw_level()
+
+    # --------------------------------------------------
+    # PHYSICS
+    # --------------------------------------------------
+    def jump(self):
+        if self.is_grounded:
+            self.vy = JUMP_STRENGTH
+            self.is_grounded = False
+            self.on_platform = None
+
+    def update_physics(self, platforms):
+        if self.is_grounded and self.on_platform is not None:
+            dx = self.on_platform.drift
+            self.x += dx
+            plat_top = CANVAS_HEIGHT - self.on_platform.height
+            self.y   = plat_top - BALL_SIZE
+            self._move_parts(dx, 0)
+
+        self.vy += GRAVITY
+        old_x, old_y = self.x, self.y
+        self.y  += self.vy
+        self.x  += self.vx
+
+        self.is_grounded = False
+        self.on_platform = None
+
+        ball_bottom   = self.y + BALL_SIZE
+        ball_center_x = self.x + BALL_SIZE / 2
+
+        for platform in platforms:
+            plat_top = CANVAS_HEIGHT - platform.height
+            if (self.vy >= 0 and plat_top - 8 <= ball_bottom <= plat_top + self.vy + 2):
+                if platform.x <= ball_center_x <= platform.x + platform.width:
+                    self.y = plat_top - BALL_SIZE
+                    if abs(self.vy) > MIN_BOUNCE_VY:
+                        self.vy = -self.vy * BOUNCE_FACTOR
+                    else:
+                        self.vy = 0
+                        self.is_grounded = True
+                        self.on_platform = platform
+                    break
+
+        if self.x < 0:
+            self.x  = 0
+            self.vx = abs(self.vx) * BOUNCE_FACTOR
+        elif self.x + BALL_SIZE > CANVAS_WIDTH:
+            self.x  = CANVAS_WIDTH - BALL_SIZE
+            self.vx = -abs(self.vx) * BOUNCE_FACTOR
+
+        if self.y < 0:
+            self.y  = 0
+            self.vy = abs(self.vy) * BOUNCE_FACTOR
+
+        if self.y > CANVAS_HEIGHT:
+            p        = platforms[0]
+            self.x   = p.x + p.width / 2 - BALL_SIZE / 2
+            self.y   = CANVAS_HEIGHT - p.height - BALL_SIZE
+            self.vy  = 0
+            self.vx  = 0
+            self.is_grounded = True
+            self.on_platform = p
+
+        dx = self.x - old_x
+        dy = self.y - old_y
+        self._move_parts(dx, dy)
+
+    def get_center(self):
+        return self.x + BALL_SIZE / 2, self.y + BALL_SIZE / 2
+
+
+class GamePlatform:
+    COLORS = [
+        COLOR_STANFORD_RED,
+        COLOR_PERU_RED,
+        COLOR_GOLD,
+        COLOR_DARK_NAVY,
+        "#C0392B"
+    ]
+
+    def __init__(self, canvas, x, width, height):
+        self.canvas  = canvas
+        self.x       = x
+        self.width   = width
+        self.height  = height
+        self.color   = random.choice(self.COLORS)
+        self.drift   = random.choice([-1, 1])
+        self.rect_id = None
+        self.draw()
+
+    def draw(self):
+        top_y = CANVAS_HEIGHT - self.height
+        self.rect_id = self.canvas.create_rectangle(
+            self.x, top_y,
+            self.x + self.width, CANVAS_HEIGHT,
+            self.color, COLOR_BRIGHT_GOLD
+        )
+
+    def update(self):
+        self.x += self.drift
+        self.canvas.move(self.rect_id, self.drift, 0)
+        if self.x <= 0:
+            self.drift = abs(self.drift)
+        elif self.x + self.width >= CANVAS_WIDTH:
+            self.drift = -abs(self.drift)
+
+    def move(self, dx):
+        self.x += dx
+        self.canvas.move(self.rect_id, dx, 0)
+
+
+class CodeToken:
+    SLOTS = [
+        (100, 80),  (280, 80),  (440, 80),
+        (100, 160), (280, 160), (440, 160),
+        (180, 220), (340, 220),
+    ]
+    used_slots = []
+    @classmethod
+    def reset_slots(cls):
+        cls.used_slots = []
+
+    @classmethod
+    def get_free_slot(cls):
+        free = [s for s in cls.SLOTS if s not in cls.used_slots]
+        if not free:
+            cls.used_slots = []
+            free = cls.SLOTS[:]
+        slot = random.choice(free)
+        cls.used_slots.append(slot)
+        return slot
+
+    def __init__(self, canvas):
+        self.canvas  = canvas
+        self.active  = True
+        self.snippet = random.choice(CODE_SNIPPETS)
+        self.rect_id = None
+        self.text_id = None
+        self.slot    = None
+        self._place()
+
+    def _place(self):
+        self.slot      = CodeToken.get_free_slot()
+        self.x, self.y = self.slot
+        self.rect_id   = self.canvas.create_rectangle(
+            self.x, self.y,
+            self.x + CODE_W, self.y + CODE_H,
+            COLOR_GOLD, COLOR_BRIGHT_GOLD
+        )
+        self.text_id = self.canvas.create_text(
+            self.x + CODE_W / 2,
+            self.y + CODE_H / 2,
+            text=self.snippet,
+            font="Courier", font_size=24, color=COLOR_STANFORD_RED
+        )
+
+    def check_catch(self, ball_cx, ball_cy):
+        if not self.active:
+            return False
+        cx = self.x + CODE_W / 2
+        cy = self.y + CODE_H / 2
+        if (abs(ball_cx - cx) < CODE_W / 2 + BALL_SIZE / 2 and
+                abs(ball_cy - cy) < CODE_H / 2 + BALL_SIZE / 2):
+            self.canvas.delete(self.rect_id)
+            self.canvas.delete(self.text_id)
+            if self.slot in CodeToken.used_slots:
+                CodeToken.used_slots.remove(self.slot)
+            self.active = False
+            return True
+        return False
+
+    def respawn(self):
+        self.snippet = random.choice(CODE_SNIPPETS)
+        self._place()
+        self.active  = True
+
+
+def show_win_screen(canvas):
+    canvas.create_rectangle(
+        0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+        COLOR_DARK_NAVY, COLOR_DARK_NAVY
+    )
+    canvas.create_rectangle(
+        50, 100, 550, 310,
+        COLOR_STANFORD_RED, COLOR_BRIGHT_GOLD
+    )
+    canvas.create_text(150, 135,
+        text="YOU WIN!",
+        font="Arial", font_size=38, color=COLOR_BRIGHT_GOLD)
+    canvas.create_text(150, 175,
+        text="Karel is fully built!",
+        font="Arial", font_size=16, color=COLOR_WHITE)
+    canvas.create_text(150, 205,
+        text="You collected all 10 Karel codes!",
+        font="Arial", font_size=13, color=COLOR_WHITE)
+    canvas.create_text(150, 240,
+        text="Final Score: 100 points",
+        font="Arial", font_size=15, color=COLOR_BRIGHT_GOLD)
+    canvas.create_text(150, 268,
+        text="Keep coding!  PERU @ STANFORD - CODE IN PLACE",
+        font="Arial", font_size=11, color=COLOR_BRIGHT_GOLD)
+    canvas.create_text(150, 290,
+        text="YESSENIA CH. M.",
+        font="Arial", font_size=10, color=COLOR_WHITE)
+
+
+def main():
+    canvas = Canvas(CANVAS_WIDTH, CANVAS_HEIGHT)
+
+    CodeToken.reset_slots()
+
+    # Franja superior
+    canvas.create_rectangle(
+        0, 0, CANVAS_WIDTH, 50,
+        COLOR_STANFORD_RED, COLOR_STANFORD_RED
+    )
+
+    canvas.create_text(10, 15,
+        text="CONTROLS: [ N ] Forward  [ M ] Back  [ B ] JUMP",
+        font="Arial", font_size=11, color=COLOR_BRIGHT_GOLD)
+    canvas.create_text(10, 35,
+        text="CODE CATCHER — Collect 10 Karel codes to build Karel!",
+        font="Arial", font_size=11, color=COLOR_WHITE)
+
+    score_label = canvas.create_text(480, 25,
+        text="Codes: 0 / 10",
+        font="Arial", font_size=13, color=COLOR_BRIGHT_GOLD)
+
+    canvas.create_text(300, CANVAS_HEIGHT - 8,
+        text="YESSENIA CH.M. | PERU @ STANFORD UNIVERSITY",
+        font="Arial", font_size=11, color=COLOR_STANFORD_RED)
+
+    platforms = [
+        GamePlatform(canvas, 30,  140, 80),
+        GamePlatform(canvas, 230, 130, 130),
+        GamePlatform(canvas, 420, 120, 100),
+    ]
+
+    codes = [CodeToken(canvas) for _ in range(CODE_COUNT)]
+
+    p0   = platforms[0]
+    ball = KarelBall(canvas, p0.x + 50, CANVAS_HEIGHT - p0.height - BALL_SIZE)
+    ball.is_grounded = True
+    ball.on_platform = p0
+
+    speed        = 12
+    codes_caught = 0
+    game_over    = False
+
+    while True:
+        if game_over:
+            time.sleep(0.1)
+            continue
+
+        key = canvas.get_last_key_press()
+
+        if key:
+            key = key.lower()
+            move_speed = speed * 2 if not ball.is_grounded else speed
+            if key == 'n':
+                for platform in platforms:
+                    platform.move(-move_speed)
+            elif key == 'm':
+                for platform in platforms:
+                    platform.move(move_speed)
+            elif key == 'b':
+                ball.jump()
+
+        for platform in platforms:
+            platform.update()
+
+        ball.update_physics(platforms)
+
+        bx, by = ball.get_center()
+        for code in codes:
+            if code.check_catch(bx, by):
+                codes_caught += 1
+
+                # Karel evolves with every code he captures
+                ball.evolve(codes_caught)
+
+                canvas.delete(score_label)
+                score_label = canvas.create_text(480, 25,
+                    text=f"Codes: {codes_caught} / {CODES_TO_WIN}",
+                    font="Arial", font_size=13, color=COLOR_BRIGHT_GOLD)
+
+                if codes_caught >= CODES_TO_WIN:
+                    show_win_screen(canvas)
+                    game_over = True
+                    break
+
+                code.respawn()
+
+        time.sleep(0.04)
+
+
+if __name__ == '__main__':
+    main()