Saltar al contenido
Inicio 100 Días de Código en Python — Día 21: El Juego de la Serpiente (Parte 2) — Herencia y Slicing

100 Días de Código en Python — Día 21: El Juego de la Serpiente (Parte 2) — Herencia y Slicing

Nivel: Grado décimo Área: Tecnología e Informática Modalidad: Tutorial práctico Fuente: Curso "100 Days of Code: The Complete Python Pro Bootcamp" (Angela Yu, App Brewery). Contenido del Día 21 (nivel intermedio).

Este tutorial adapta pedagógicamente el Día 21. Las secciones 📝 Ejercicio original del curso provienen de los archivos del curso. Los retos 🟢🟡🟠🔴, el proyecto extra y el proyecto integrador son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.

Nota sobre las verificaciones: los ejemplos de herencia (Animal y Fish) y de slicing se ejecutaron con Python 3.14, y los resultados que aparecen aquí son los obtenidos. También se calcularon las distancias de colisión de la serpiente. Los programas con ventana se revisaron siguiendo la lógica del código y la documentación oficial (se abre en otra pestaña). Ejecútalos en tu computador para ver el resultado.


Tabla de contenidos

  1. Antes de empezar
  2. Herencia de clases
  3. La comida: heredar de Turtle y detectar colisiones
  4. El marcador: escribir texto en la pantalla
  5. Fin del juego: colisión con la pared
  6. Crecer y chocar con la cola
  7. Slicing: cortar listas y tuplas
  8. 🚀 Proyecto del día: el juego de la serpiente completo
  9. 🌟 Proyecto extra: el Recolector de Reciclaje
  10. 🏆 Proyecto integrador del Día 21: la Familia de Personajes del Videojuego
  11. 🧩 Comprueba lo aprendido
  12. 🤖 Programar con apoyo de IA
  13. 🛠️ Correcciones técnicas al material original
  14. 📋 Matriz de trazabilidad
  15. 📦 Evidencias de aprendizaje del Día 21

0. Antes de empezar

(Fuentes: 152 - Day 21 Goals- what we will make by the end of the day.md, 159 - Stay motivated by remembering the reason you signed up.md)

Ayer completamos los pasos 1 a 3 del juego. Hoy aprenderemos dos conceptos nuevos, herencia de clases y slicing, y con ellos terminaremos los pasos 4 a 7: comida, marcador, choque con la pared y choque con la cola.

Mensaje de cierre del curso: este curso es un maratón, no una carrera de velocidad. A partir de aquí se necesita motivación propia. Piensa en por qué quieres aprender a programar: un proyecto que quieres que exista, un mejor futuro, una carrera. Recordar esa razón te ayudará a seguir cuando las cosas se pongan difíciles.

💡 Actividad de inicio: escribe en tu cuaderno una frase: "Quiero aprender a programar porque…". Guárdala para releerla más adelante.

Prerequisito general: el juego de la serpiente del Día 20 funcionando, clases con __init__ y self (Días 16 y 17), índices negativos de listas (Día 4) y f-strings (Día 2).


1. Herencia de clases

(Fuente: 153 - Class Inheritance.md)

🎯 Objetivo de aprendizaje

  • Crear una clase que herede atributos y métodos de otra.
  • Ampliar un método heredado sin reescribirlo desde cero.

🧠 ¿Qué aprenderemos?

Superclase, subclase, super().__init__() y sobrescritura de métodos.

📖 Explicación conceptual

La analogía del curso: programaste un Robot Chef que sabe hornear, mezclar y medir. Ahora tu restaurante necesita un Chef Pastelero, que sabe todo lo que sabe un chef y además amasa y bate huevos. No lo construyes desde cero: tomas lo que ya sabe el chef y le agregas. Eso es la herencia.

Se hereda:

  • La apariencia (atributos), como heredar los ojos de tu mamá.
  • El comportamiento (métodos), como cortar tomates igual que tu papá.

Sintaxis:

Python
class Animal:                       # superclase (la "clase madre")
    def __init__(self):
        self.num_eyes = 2

    def breathe(self):
        print("Inhala, exhala")


class Fish(Animal):                 # 1) la superclase va entre paréntesis
    def __init__(self):
        super().__init__()          # 2) inicializa todo lo de Animal

    def swim(self):
        print("Moviéndose en el agua")
Python
nemo = Fish()
nemo.swim()              # Moviéndose en el agua  (método propio)
nemo.breathe()           # Inhala, exhala          (método heredado)
print(nemo.num_eyes)     # 2                       (atributo heredado)

🔎 Ejemplo explicado: ampliar un método heredado

Un pez respira, pero bajo el agua. Queremos lo que hace breathe de Animal más algo propio:

Python
class Fish(Animal):
    def __init__(self):
        super().__init__()

    def breathe(self):
        super().breathe()                  # primero, lo que hace Animal
        print("haciéndolo bajo el agua")   # después, lo propio del pez

Resultado verificado de nemo.breathe():

Texto
Inhala, exhala
haciéndolo bajo el agua

Cuando una subclase define un método con el mismo nombre que uno de la superclase, lo sobrescribe. Con super().metodo() puedes reutilizar la versión original dentro de la nueva.

¿Por qué es útil? Puedes construir sobre una clase existente, tuya o de otra persona (como Turtle), "sin reinventar la rueda".

⚠️ Errores frecuentes

Error Qué ocurre (verificado) Solución
Olvidar super().__init__() en el __init__ de la subclase AttributeError: 'Fish' object has no attribute 'num_eyes': el método heredado existe, pero los atributos de la superclase nunca se crearon Llama siempre super().__init__() al inicio del __init__
Escribir class Fish(Animal()): Se intenta heredar de un objeto, no de una clase; da error La superclase va sin paréntesis
Sobrescribir un método sin querer Se pierde el comportamiento original Revisa los nombres de la superclase antes de crear un método

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1 — Aplicación: crea Bird(Animal) con un método fly() y comprueba que también respira.
  • 🟡 Reto 2 — Ampliación: agrega a Animal un parámetro name en __init__. ¿Cómo cambia la llamada a super().__init__(...) en Fish?
  • 🟠 Reto 3 — Desafío: crea Estudiante con nombre y presentarse(), y Monitor(Estudiante) que, además de presentarse, diga de qué materia es monitor usando super().presentarse().
  • 🔴 Reto 4 — Pensamiento computacional: diseña en papel una jerarquía de clases para los vehículos de tu ciudad (bicicleta, moto, bus, taxi). ¿Qué atributos y métodos van en la superclase y cuáles en cada subclase?

2. La comida: heredar de Turtle y detectar colisiones

(Fuente: 154 - Detect Collisions with Food.md)

📝 Ejercicio original del curso

Enunciado: crear food.py con una clase Food que herede de Turtle, se dibuje como un pequeño círculo azul en una posición aleatoria y se mueva a otra posición aleatoria cada vez que la serpiente la toque.

🔍 Antes de programar

  • ¿Por qué heredar de Turtle en lugar de guardar una tortuga como atributo (self.food = Turtle())?
  • La ventana es de 600 × 600. ¿Entre qué valores deben estar X e Y para que la comida no quede pegada a la pared?
  • ¿Cómo sabes que dos tortugas "se tocan"?

Solución del curso, paso a paso

Python
from turtle import Turtle
import random


class Food(Turtle):
    def __init__(self):
        super().__init__()
        self.shape("circle")
        self.penup()
        self.shapesize(stretch_len=0.5, stretch_wid=0.5)   # 20 × 20 → 10 × 10
        self.color("blue")
        self.speed("fastest")          # para no ver la animación al moverse
        self.refresh()

    def refresh(self):
        random_x = random.randint(-280, 280)
        random_y = random.randint(-280, 280)
        self.goto(random_x, random_y)
  • Food es una tortuga mejorada: por eso escribe self.shape(...) y self.goto(...) directamente.
  • PyCharm ayuda: al agregar la herencia, advierte "falta la llamada al __init__ de la superclase" y ofrece agregarla con la bombilla.
  • Cuidado con el nombre: el curso advierte que el método no debe llamarse reset, porque Turtle ya tiene un método reset y lo estarías sobrescribiendo sin querer (Tema 1).

Detectar la colisión en main.py, dentro del bucle del juego:

Python
if snake.head.distance(food) < 15:
    food.refresh()

distance() es un método de Turtle que mide la distancia a unas coordenadas o a otra tortuga. La comida mide 10 × 10, así que una distancia menor que 15 indica un choque con un pequeño margen.

🛠️ Nota técnica (análisis verificado): el curso dice que 15 "funcionó después de hacer pruebas" y que se puede bajar a 10. Hay una razón matemática para no bajarlo: la cabeza de la serpiente siempre está en coordenadas múltiplos de 20, pero la comida aparece en cualquier entero. En el peor caso, la comida queda a 10 píxeles de la cuadrícula en X y en Y, y la distancia mínima posible es √(10² + 10²) ≈ 14,14. Con un umbral de 15 siempre se puede comer la comida; con 10, habría comidas imposibles de alcanzar.

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: cambia la forma y el color de la comida.
  • 🟡 Reto 2: haz que la comida aparezca solo en la cuadrícula de 20 (pista: random.randint(-14, 14) * 20). ¿Qué umbral de distancia podrías usar ahora?
  • 🟠 Reto 3: evita que la comida aparezca encima del cuerpo de la serpiente: refresh debe recibir los segmentos y repetir el sorteo si hay choque.
  • 🔴 Reto 4: crea GoldenFood(Food), una comida dorada que vale 3 puntos y cambia de lugar sola cada 5 segundos si nadie la come.

3. El marcador: escribir texto en la pantalla

(Fuente: 155 - Create a Scoreboard and Keep Score.md)

📝 Ejercicio original del curso

Enunciado: crear scoreboard.py con una clase Scoreboard que herede de Turtle, guarde el puntaje, lo muestre arriba de la pantalla y lo aumente en 1 cada vez que la serpiente come.

Método clave de la documentación:

Python
turtle.write(arg, move=False, align="left", font=("Arial", 8, "normal"))

font es una tupla: (nombre de la fuente, tamaño, estilo).

Cómo lo construye el curso (y los errores que encuentra)

  1. self.score = 0 y self.write(f"Score: {self.score}", align="center", font=("Arial", 24, "normal")).
  2. Error 1: PyCharm advierte "se esperaba una tupla" cuando font se escribe como un solo string. Se corrige con paréntesis.
  3. Error 2: el texto no se ve porque se escribe en negro sobre negro. self.color("white") debe ir antes de write: cambiar el color después no modifica lo ya escrito.
  4. self.hideturtle() para que no se vea la flecha.
  5. Error 3: goto(0, 270) después de escribir no mueve el texto. El orden es: penup(), goto() y luego write(). Sin penup(), además dibuja una línea.
  6. Error 4: al aumentar el puntaje, los números se escriben uno encima del otro. Solución: self.clear() antes de escribir el nuevo puntaje.
  7. Evitar código repetido: el write aparecía en dos lugares, así que se crea update_scoreboard().
  8. Constantes: ALIGNMENT = "center" y FONT = ("Courier", 24, "normal"), más "de videojuego".

Estructura final (en palabras): __init__ configura color, penup, goto, hideturtle y llama update_scoreboard(). increase_score() suma 1, llama clear() y update_scoreboard().

Lección importante: en Turtle, el orden de las instrucciones importa. Configura primero (color, posición) y escribe después.

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: muestra también la longitud de la serpiente en el marcador.
  • 🟡 Reto 2: muestra el puntaje en la esquina superior izquierda con align="left". ¿Qué coordenadas usas?
  • 🟠 Reto 3: crea LivesBoard(Scoreboard) que herede del marcador y agregue un contador de vidas.
  • 🔴 Reto 4: cada 5 puntos, el juego sube de nivel y la serpiente va más rápido. ¿Qué objeto debe saber el nivel? ¿Cómo se entera main.py?

4. Fin del juego: colisión con la pared

(Fuente: 156 - Detect Collisions with the Wall.md)

📝 Ejercicio original del curso

Enunciado: terminar el juego cuando la cabeza se acerque demasiado a cualquiera de las cuatro paredes.

Razonamiento: la ventana va de −300 a 300 en ambos ejes. Se define un "cuadro límite" en ±280:

Python
if snake.head.xcor() > 280 or snake.head.xcor() < -280 or snake.head.ycor() > 280 or snake.head.ycor() < -280:
    game_is_on = False
    scoreboard.game_over()

El curso aclara que 280 no es un número perfecto: salió de muchas pruebas, algo muy común al programar juegos.

Problema de experiencia de usuario: si la serpiente solo se detiene, parece que el juego se congeló. Por eso se crea game_over() en Scoreboard: va a (0, 0) y escribe "GAME OVER" con la misma fuente. Como no se llama clear(), el puntaje final sigue visible arriba.

Análisis de esta adaptación: como la cabeza siempre está en múltiplos de 20, xcor() > 280 se cumple exactamente cuando la cabeza llega a 300. Es decir, la serpiente pierde cuando su cabeza queda a medio salir de la ventana.

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: reescribe la condición con una función fuera_de_limites(tortuga, limite) que devuelva True o False.
  • 🟡 Reto 2: dibuja un borde visible en ±290 con una tortuga auxiliar, para que el jugador vea la pared.
  • 🟠 Reto 3: crea un modo sin paredes: al salir por un lado, la serpiente aparece por el opuesto. ¿Qué segmentos debes mover?
  • 🔴 Reto 4: agrega obstáculos (bloques grises) en posiciones fijas. Diseña cómo guardarlos y cómo detectar el choque de forma general.

5. Crecer y chocar con la cola

(Fuente: 157 - Detect Collisions with your own Tail.md)

📝 Ejercicio original del curso

Parte A — hacer crecer la serpiente. Se reorganiza Snake:

Método Qué hace
add_segment(position) Crea un segmento cuadrado blanco en position y lo agrega a self.segments
create_snake() Llama add_segment para cada posición inicial
extend() Llama self.add_segment(self.segments[-1].position()): el nuevo segmento aparece donde está el último
  • self.segments[-1] usa un índice negativo (Día 4): el último elemento de la lista.
  • position() es un método de Turtle que devuelve las coordenadas (x, y).
  • En el siguiente fotograma, el nuevo segmento se queda en su lugar mientras el resto avanza, y así la serpiente crece un cuadro.

En main.py, al comer: food.refresh(), snake.extend() y scoreboard.increase_score().

Parte B — detectar el choque con la cola:

Python
for segment in snake.segments:
    if segment == snake.head:
        pass
    elif snake.head.distance(segment) < 10:
        game_is_on = False
        scoreboard.game_over()

¿Por qué el if segment == snake.head: pass? El curso lo descubre al probar: sin esa condición, el juego termina de inmediato, porque la cabeza también está en la lista y su distancia a sí misma es 0.

Análisis de esta adaptación: aquí el umbral de 10 sí funciona sin problemas, porque todos los segmentos están sobre la cuadrícula de 20: la distancia entre la cabeza y otro segmento es 0 (choque) o al menos 20.

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: haz que la serpiente crezca 2 segmentos por cada comida.
  • 🟡 Reto 2: imprime en la consola cuántos segmentos tiene la serpiente al perder.
  • 🟠 Reto 3: escribe collides_with_tail() como método de Snake que devuelva True o False. ¿Por qué es mejor que esa lógica viva en la clase?
  • 🔴 Reto 4: recuerda el error del giro rápido del Día 20. Ahora que existe el choque con la cola, ¿qué consecuencia tiene para el jugador? Corrígelo en tu versión.

6. Slicing: cortar listas y tuplas

(Fuente: 158 - How to Slice Lists & Tuples in Python.md)

🎯 Objetivo de aprendizaje

  • Obtener partes de una lista o tupla con la notación [inicio:fin:paso].
  • Usar slicing para simplificar el código de la serpiente.

📖 Explicación conceptual

Imagina las teclas de un piano:

Python
piano_keys = ["a", "b", "c", "d", "e", "f", "g"]

¿Cómo pensar las posiciones del corte? El curso propone imaginar que los números están entre los elementos, como las marcas de una regla:

Texto
 | a | b | c | d | e | f | g |
 0   1   2   3   4   5   6   7

Así, [2:5] corta de la marca 2 a la marca 5 y da c, d, e.

Código Resultado (verificado) Significado
piano_keys[2:5] ['c', 'd', 'e'] De la posición 2 hasta antes de la 5
piano_keys[2:] ['c', 'd', 'e', 'f', 'g'] Desde la 2 hasta el final
piano_keys[:5] ['a', 'b', 'c', 'd', 'e'] Desde el inicio hasta antes de la 5
piano_keys[2:5:2] ['c', 'e'] De 2 a 5, saltando de 2 en 2
piano_keys[::2] ['a', 'c', 'e', 'g'] Todo, de 2 en 2
piano_keys[::-1] ['g', 'f', 'e', 'd', 'c', 'b', 'a'] Todo, al revés

También funciona con tuplas:

Python
piano_tuple = ("do", "re", "mi", "fa", "sol", "la", "si")
print(piano_tuple[2:5])     # ('mi', 'fa', 'sol')  (verificado)

Relación con range: la lógica inicio:fin:paso es la misma que la de range(inicio, fin, paso) del Día 20: el fin no se incluye.

📝 Ejercicio original del curso: simplificar el choque con la cola

Enunciado: usar slicing para eliminar el if segment == snake.head: pass.

Solución del curso: snake.segments[1:] es toda la lista excepto la cabeza:

Python
for segment in snake.segments[1:]:
    if snake.head.distance(segment) < 10:
        game_is_on = False
        scoreboard.game_over()

El programa funciona igual, pero el código es más corto y más claro.

⚠️ Errores frecuentes

Error Qué ocurre
Creer que [2:5] incluye la posición 5 Falta un elemento. El fin nunca se incluye
Escribir lista[1, 3] TypeError: la notación usa dos puntos, no comas
Pensar que el slice modifica la lista original No la modifica: crea una nueva lista

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: con dias = ["lun", "mar", "mié", "jue", "vie", "sáb", "dom"], obtén los días de semana, el fin de semana y los días en orden inverso.
  • 🟡 Reto 2: escribe es_palindromo(palabra) con una sola línea usando [::-1]. Pruébala con "reconocer" y "oso".
  • 🟠 Reto 3: dada la lista de notas de un estudiante, obtén las tres últimas con índices negativos ([-3:]).
  • 🔴 Reto 4: en la serpiente, ¿el primer segmento que la cabeza puede tocar de verdad es el índice 1? Piensa en la geometría: ¿podría la cabeza chocar con los segmentos 1, 2 o 3? Propón un slice más eficiente y justifícalo.

7. 🚀 Proyecto del día: el juego de la serpiente completo

(Fuentes: 152 a 158, junto con el proyecto del Día 20)

Problema

Completar el juego con los pasos 4 a 7: comida, marcador, pared y cola.

Requisitos funcionales

  1. Comida azul de 10 × 10 en posición aleatoria que cambia de lugar al ser comida.
  2. Marcador centrado arriba que aumenta en 1 con cada comida.
  3. La serpiente crece un segmento por comida.
  4. El juego termina al chocar con la pared o con la cola, mostrando "GAME OVER" y el puntaje final.

Restricciones técnicas

Tres clases en tres archivos (Snake, Food(Turtle) y Scoreboard(Turtle)), constantes para textos y fuentes, slicing para la cola.

Construcción paso a paso

Versión Qué se agrega Sección
1 Food y detección con distance 2
2 Scoreboard con clear y update_scoreboard 3
3 Pared y game_over 4
4 extend y choque con la cola 5
Final Simplificación con segments[1:] 6

Diagrama de las clases del proyecto:

Texto
      Turtle  (módulo turtle)
      /    \
   Food   Scoreboard        Snake  ──contiene──▶  [Turtle, Turtle, Turtle, ...]
 (hereda) (hereda)         (composición: TIENE tortugas, no ES una)

Para analizar: Food y Scoreboard son tortugas (herencia). Snake tiene una lista de tortugas (composición). ¿Por qué tiene sentido que Snake no herede de Turtle?

Pruebas

Caso Resultado esperado
Comer una comida La comida cambia de lugar, el puntaje sube 1 y la serpiente crece
Llegar al borde derecho GAME OVER y la serpiente se detiene
Serpiente larga que gira en U sobre sí misma GAME OVER
Iniciar el juego No termina de inmediato (la cabeza no choca consigo misma)
Comida que aparece en una esquina difícil Siempre se puede comer (umbral 15, sección 2)

🧪 Prueba y depuración

Este scoreboard.py tiene cuatro errores. Encuéntralos y explica el síntoma de cada uno:

Python
from turtle import Turtle
ALIGNMENT = "center"
FONT = "Courier", "24", "normal"

class Scoreboard(Turtle):
    def __init__(self):
        self.score = 0
        self.write(f"Score: {self.score}", align=ALIGNMENT, font=FONT)
        self.color("white")
        self.goto(0, 270)

    def increase_score(self):
        self.score += 1
        self.write(f"Score: {self.score}", align=ALIGNMENT, font=FONT)

(Pistas: falta algo de la herencia; el orden de configuración (color y posición después de escribir); un lápiz que sigue abajo al ir a (0, 270); texto superpuesto. Preguntas extra: la línea de FONT no tiene paréntesis, ¿es una tupla de todos modos? Compruébalo con type(FONT). Y el tamaño está escrito como texto ("24"): pruébalo en tu computador; aunque funcione, ¿por qué es mejor escribir un número?)

⭐ Extensión del proyecto

  • Reiniciar la partida con la tecla "r" sin cerrar el programa.
  • Colores distintos para la cabeza y el cuerpo.
  • Guardar el récord (¡justo lo que haremos el Día 24!).

8. 🌟 Proyecto extra: el Recolector de Reciclaje

Situación

El comité ambiental del colegio quiere un juego para la campaña de reciclaje: un camión recolector (con remolques que crecen como la serpiente) debe recoger residuos, pero solo los reciclables.

Requisitos

  1. Una superclase Residuo(Turtle) con posición aleatoria, refresh() y un atributo puntos.
  2. Tres subclases con herencia:
    • Plastico(Residuo): amarillo, +1 punto.
    • Papel(Residuo): azul, +1 punto.
    • Organico(Residuo): verde, −2 puntos y no hace crecer el camión.
  3. En pantalla hay siempre un residuo de cada tipo, guardados en una lista. La colisión se revisa con un solo bucle sobre la lista.
  4. El marcador muestra puntos y kilos reciclados (1 kg por residuo reciclable).
  5. Pierdes al chocar con la pared, con los remolques o al llegar a −5 puntos.

Decisiones que debes tomar

  • ¿Qué método sobrescribe cada subclase y cuál hereda sin cambios?
  • ¿Cómo evitas preguntar if tipo == "plastico" en main.py? (Pista: que cada residuo sepa sus puntos y si hace crecer al camión.)

Reflexión

¿Cuántas líneas te ahorró la herencia? ¿Qué pasaría si mañana hay que agregar "Vidrio"?


9. 🏆 Proyecto integrador del Día 21: la Familia de Personajes del Videojuego

Proyecto integrador creado para esta adaptación. Integra herencia, sobrescritura con super(), composición, slicing, colisiones, marcador y eventos (Días 19 a 21).

Situación problema

El club de programación diseña un videojuego de laberinto. Necesita una familia de personajes que compartan comportamiento y se diferencien en lo que cada uno sabe hacer.

Pregunta orientadora

¿Cómo usar la herencia para agregar nuevos personajes sin modificar el código de los que ya existen?

Requerimientos

  1. Personaje(Turtle): posición, velocidad, mover() y choca_con(otro).
  2. Jugador(Personaje): controlado con las flechas, con vidas.
  3. Enemigo(Personaje): se mueve solo en una dirección y rebota en las paredes. Sobrescribe mover() usando super().mover().
  4. EnemigoPerseguidor(Enemigo): sobrescribe mover() para orientarse hacia el jugador con towards().
  5. Moneda(Turtle): al tocarla, suma puntos y cambia de lugar.
  6. Un Marcador(Turtle) con puntos, vidas y "GAME OVER".
  7. Un historial de las últimas 5 posiciones del jugador (usa slicing para quedarte solo con ellas) y muéstralo al perder una vida.

Etapas de desarrollo

  1. Diagrama de clases en papel (qué hereda de qué y qué métodos se sobrescriben).
  2. Personaje y Jugador.
  3. Enemigos y colisiones.
  4. Monedas, marcador y vidas.
  5. Historial con slicing.

Entregables

  • Código en varios archivos, uno por clase.
  • Diagrama de herencia con los métodos sobrescritos marcados.
  • Explicación de por qué EnemigoPerseguidor no necesitó copiar código de Enemigo.

Casos de prueba

Caso Esperado
El jugador toca una moneda Suma puntos y la moneda cambia de lugar
Un enemigo toca la pared Rebota
El jugador pierde las 3 vidas GAME OVER con el puntaje
Se agrega una nueva subclase de enemigo main.py solo cambia en la línea que la crea

Criterios técnicos

  • Cada subclase llama super().__init__().
  • Ningún método se copia y pega entre clases.
  • Las constantes (tamaños, velocidades, textos) están en mayúsculas al inicio de cada archivo.

10. 🧩 Comprueba lo aprendido

Conceptuales

  1. ¿Qué diferencia hay entre heredar de Turtle y tener una tortuga como atributo?
  2. ¿Para qué sirve super()?
  3. ¿Por qué el marcador necesita clear() antes de escribir?

Análisis de código

Python
class A:
    def hola(self):
        return "A"

class B(A):
    def hola(self):
        return super().hola() + "B"

class C(B):
    def hola(self):
        return super().hola() + "C"

print(C().hola())

¿Qué imprime? Explica el recorrido.

Predicción

Python
n = [10, 20, 30, 40, 50, 60]
print(n[1:4], n[::3], n[-2:], n[4:1:-1])

Depuración

Python
class Food(Turtle):
    def __init__(self):
        self.shape("circle")
        super().__init__()

¿Qué problema tiene el orden de estas líneas?

Modificación

Cambia el choque con la pared para que la serpiente pierda solo si sale más allá de ±300. ¿Qué ves en pantalla antes del GAME OVER?

Creación

Crea Temporizador(Turtle) que muestre en la esquina los segundos que lleva la partida, actualizándose en cada fotograma sin superponer el texto.


11. 🤖 Programar con apoyo de IA

Actividad: la IA frente a la herencia.

  1. Pide a una IA que cree la clase Food heredando de Turtle.
  2. Revisa: ¿llama super().__init__()? ¿Usa algún nombre de método que ya exista en Turtle (como reset, clear o write) y lo sobrescribe sin querer? Busca la lista de métodos en la documentación oficial (se abre en otra pestaña).
  3. Pregúntale qué umbral de distancia usar para detectar la comida y por qué. Compara su respuesta con el análisis de la sección 2 (√200 ≈ 14,14). ¿Te dio una razón o solo un número?
  4. Escribe en tu cuaderno qué parte de su respuesta verificaste y cómo.

12. 🛠️ Correcciones técnicas al material original

Archivo Afirmación o comportamiento del curso Observación Tratamiento
154 El umbral de 15 se eligió por pruebas y puede bajarse a 10 Con comida en cualquier entero y la cabeza en múltiplos de 20, la distancia mínima puede ser 14,14; con 10 habría comidas inalcanzables (cálculo verificado) Nota técnica del Tema 2
154 La comida aparece en cualquier lugar Puede aparecer encima del cuerpo de la serpiente Reto 3 del Tema 2
157 El choque con la cola funciona con las condiciones de dirección del Día 20 El error del giro rápido del Día 20 ahora provoca un GAME OVER injusto Reto 4 del Tema 5
158 El slice de la tupla da "mi, fa, …" (la transcripción está incompleta) El resultado completo es ('mi', 'fa', 'sol') (verificado) Tema 6

13. 📋 Matriz de trazabilidad

Contenido original Archivo de origen Concepto desarrollado Ejercicio original Reto adicional Proyecto relacionado
Objetivos del día 152 Sección 0 — — Sección 7
Herencia, super(), sobrescritura (Animal, Fish) 153 Tema 1 Fish(Animal) con breathe Retos 1–4 del Tema 1 Secciones 8 y 9
Food(Turtle), shapesize, distance, refresh 154 Tema 2 Clase Food y colisión Retos 1–4 del Tema 2 Secciones 7, 8 y 9
Scoreboard(Turtle), write, clear, constantes 155 Tema 3 Marcador Retos 1–4 del Tema 3 y depuración Secciones 7, 8 y 9
Colisión con la pared, game_over 156 Tema 4 Límites en ±280 Retos 1–4 del Tema 4 Secciones 7 y 8
extend, add_segment, colisión con la cola 157 Tema 5 Crecer y chocar con la cola Retos 1–4 del Tema 5 Secciones 7 y 8
Slicing de listas y tuplas 158 Tema 6 segments[1:] Retos 1–4 del Tema 6 Secciones 7 y 9
Motivación: el maratón 159 Sección 0 — Actividad de inicio —
(No existe en el curso original) — — — Recolector de Reciclaje Sección 8
(No existe en el curso original) — — — Familia de Personajes Sección 9

14. 📦 Evidencias de aprendizaje del Día 21

  • Juego de la serpiente completo, con captura de un GAME OVER y tu puntaje.
  • Diagrama de clases del proyecto que diferencie herencia y composición.
  • Explicación escrita del umbral de 15 píxeles (√200).
  • Los resultados de los retos de slicing del Tema 6.
  • Proyecto extra (Recolector de Reciclaje) o integrador (Familia de Personajes).
  • La frase "Quiero aprender a programar porque…".
  • Cuaderno de errores: super().__init__() olvidado, texto negro sobre fondo negro, texto superpuesto sin clear(), font que no es una tupla, GAME OVER inmediato por la cabeza y el método reset sobrescrito.