Torneo de Drones
Esta actividad NO es un simulacro de examen. Su extensión supera lo que se solicitará en el examen de la convocatoria ordinaria. Además, en este modelo se facilita información para la autocorrección de la prueba (rúbrica detallada).
Se pretende que sirva de preparación para la prueba real ya que el formato de enunciado será similar exceptuando los detalles de la rúbrica y los elementos válidos e inválidos esperados en los sets de datos.
Contexto
La asociación DroneLeague organiza competiciones de drones en las que participan pilotos con distintos tipos de drones. Cada piloto puede competir en varias pruebas y obtener puntos según su rendimiento.
Se deberá implementar una aplicación en Python que permita gestionar pilotos, drones, pruebas y resultados.
El sistema debe desarrollarse siguiendo los principios de la Programación Orientada a Objetos.
No se permite acceder directamente a los atributos de las clases desde fuera de ellas. Se deberán utilizar propiedades, getters, setters o métodos específicos cuando sea necesario.
Archivos entregados
Se proporciona la siguiente estructura de proyecto. 🔗 Descargar Recursos
examen_final_python/
│
├── main.py
├── piloto.py
├── drones.py
├── torneo.py
├── carga_datos.py
│
├── data/
│ ├── pilotos.csv
│ └── pruebas.csv
El archivo main.py ya estará implementado y no se deberá modificar.
El alumnado deberá completar los archivos:
piloto.py
drones.py
torneo.py
carga_datos.py
Parte 1: Gestión de pilotos
Modifica el fichero piloto.py para crear la clase Piloto.
Clase Piloto
Atributos de instancia
id_piloto
nombre
categoria
puntos
id_piloto: cadena de texto.nombre: cadena de texto.categoria: puede ser"junior","senior"o"pro".puntos: número entero. Por defecto será0.
Restricciones
- El identificador no puede estar vacío.
- El nombre no puede estar vacío.
- La categoría solo podrá tener uno de estos valores:
junior
senior
pro
- Los puntos no pueden ser negativos.
- Si se intenta asignar un valor no válido, se lanzará un
ValueError.
Métodos obligatorios
sumar_puntos(cantidad)
Recibe una cantidad de puntos y la suma al piloto.
Reglas:
- La cantidad debe ser un número entero.
- La cantidad debe ser mayor que 0.
- Si la cantidad no es válida, se lanzará un
ValueError.
Métodos mágicos
__str__
Al imprimir un piloto, debe mostrarse:
<nombre> (<categoria>) - <puntos> puntos
Ejemplo:
Laura (senior) - 35 puntos
__eq__
Dos pilotos se considerarán iguales si tienen el mismo id_piloto.
Ejemplo:
piloto1 == piloto2
Devolverá True si ambos pilotos tienen el mismo identificador.
__lt__
Permitirá comparar pilotos por puntos.
piloto1 < piloto2
Devolverá True si piloto1 tiene menos puntos que piloto2.
Este método permitirá ordenar pilotos por puntuación.
Parte 2: Drones de competición
Modifica el fichero drones.py.
Se deberá crear una clase base Drone y dos clases hijas:
DroneCarrera
DroneCarga
Clase Drone
Atributo compartido
Todos los drones tendrán un atributo compartido llamado:
organizacion
Su valor por defecto será:
DroneLeague
Atributos de instancia
codigo
modelo
velocidad_maxima
autonomia
codigo: cadena de texto.modelo: cadena de texto.velocidad_maxima: número real.autonomia: número entero, en minutos.
Restricciones
- El código no puede estar vacío.
- El modelo no puede estar vacío.
- La velocidad máxima debe ser mayor que 0.
- La autonomía debe ser mayor que 0.
- Si se intenta asignar un valor no válido, se lanzará un
ValueError.
Métodos de la clase Drone
calcular_puntuacion_base()
Método polimórfico.
En la clase base debe lanzar una excepción NotImplementedError.
Método mágico
Implementa el método mágico necesario para que, al imprimir un drone, se muestre con el siguiente formato:
<modelo> - <velocidad_maxima> km/h - <autonomia> min
Ejemplo:
Falcon X - 120.0 km/h - 18 min
Clases hijas
Clase DroneCarrera
Hereda de Drone.
Atributo específico
aceleracion
Será un número real mayor que 0.
Si el valor no es válido, se lanzará un ValueError.
Método
calcular_puntuacion_base()
Debe calcular la puntuación base de la siguiente forma:
puntuacion = velocidad_maxima * 0.6 + aceleracion * 10
Clase DroneCarga
Hereda de Drone.
Atributo específico
capacidad_carga
Será un número real mayor que 0.
Si el valor no es válido, se lanzará un ValueError.
Método
calcular_puntuacion_base()
Debe calcular la puntuación base de la siguiente forma:
puntuacion = autonomia * 2 + capacidad_carga * 5
Parte 3: Pruebas del torneo
Crea una clase Prueba en el fichero torneo.py.
Clase Prueba
Atributos de instancia
id_prueba
nombre
tipo
dificultad
participantes
id_prueba: cadena de texto.nombre: cadena de texto.tipo: puede ser"velocidad","resistencia"o"precision".dificultad: número entero entre 1 y 5.participantes: lista de pilotos inscritos. Por defecto será una lista vacía.
Restricciones
- El identificador no puede estar vacío.
- El nombre no puede estar vacío.
- El tipo solo podrá tener uno de estos valores:
velocidad
resistencia
precision
- La dificultad debe estar entre 1 y 5.
- Si se intenta asignar un valor no válido, se lanzará un
ValueError.
Métodos obligatorios
inscribir_piloto(piloto)
Recibe un objeto Piloto.
Debe añadirlo a la lista de participantes.
Reglas:
- No se puede inscribir dos veces al mismo piloto.
- Si ya está inscrito, se lanzará un
ValueError.
calcular_puntos_prueba(drone)
Recibe un objeto de tipo Drone.
Debe calcular los puntos que se obtienen en la prueba usando esta fórmula:
puntos = int(drone.calcular_puntuacion_base() / dificultad)
Métodos mágicos
__len__
Debe devolver el número de pilotos inscritos en la prueba.
Ejemplo:
len(prueba)
__contains__
Debe permitir comprobar si un piloto está inscrito en una prueba.
Ejemplo:
if piloto in prueba:
print("El piloto está inscrito")
La comparación debe hacerse usando el método __eq__ de Piloto.
Parte 4: Objeto Torneo
Crea una clase Torneo en el fichero torneo.py.
La clase deberá gestionar pilotos, drones y pruebas.
Atributos
pilotos
drones
pruebas
pilotos: diccionario donde la clave será el ID del piloto y el valor será un objetoPiloto.drones: diccionario donde la clave será el código del drone y el valor será un objetoDroneCarreraoDroneCarga.pruebas: diccionario donde la clave será el ID de la prueba y el valor será un objetoPrueba.
No se podrán modificar directamente estos atributos desde fuera de la clase.
Parte 5: Métodos del torneo
La clase Torneo deberá contener los siguientes métodos.
agregar_piloto(piloto)
Añade un piloto al torneo.
Si ya existe un piloto con el mismo ID, se lanzará un ValueError.
agregar_drone(drone)
Añade un drone al torneo.
Si ya existe un drone con el mismo código, se lanzará un ValueError.
agregar_prueba(prueba)
Añade una prueba al torneo.
Si ya existe una prueba con el mismo ID, se lanzará un ValueError.
inscribir_piloto_en_prueba(id_piloto, id_prueba)
Debe inscribir un piloto en una prueba.
Reglas:
- El piloto debe existir.
- La prueba debe existir.
- El piloto no debe estar ya inscrito en esa prueba.
registrar_resultado(id_piloto, codigo_drone, id_prueba)
Debe registrar el resultado de un piloto en una prueba.
Reglas:
- El piloto debe existir.
- El drone debe existir.
- La prueba debe existir.
- El piloto debe estar inscrito en la prueba.
Si se cumplen las condiciones:
- Se calculan los puntos de la prueba.
- Se suman al piloto.
- Se devuelve la cantidad de puntos obtenidos.
clasificacion()
Debe devolver una lista de pilotos ordenada de mayor a menor puntuación.
Debe utilizar la comparación definida en Piloto.
ganador()
Debe devolver el piloto con más puntos.
Si no hay pilotos, devolverá None.
media_puntos()
Debe devolver la media de puntos de todos los pilotos.
Si no hay pilotos, devolverá 0.
pilotos_por_categoria(categoria)
Debe devolver una lista con los pilotos de la categoría indicada.
Si la categoría no es válida, se lanzará un ValueError.
Parte 6: Carga de datos
Modifica el fichero carga_datos.py.
Se deberán implementar las siguientes funciones:
cargar_pilotos(torneo, path_fichero)
Recibe:
torneo
path_fichero
Debe leer el archivo pilotos.csv, crear objetos Piloto y añadirlos al torneo.
Debe devolver el objeto torneo modificado.
Las filas incorrectas se ignorarán.
cargar_pruebas(torneo, path_fichero)
Recibe:
torneo
path_fichero
Debe leer el archivo pruebas.csv, crear objetos Prueba y añadirlos al torneo.
Debe devolver el objeto torneo modificado.
Las filas incorrectas se ignorarán.
Parte 7: Drones de prueba para main.py
Los drones no se cargarán desde fichero para reducir el tamaño del ejercicio.
Estos drones podrán crearse directamente en main.py para comprobar el funcionamiento:
drones_prueba = [
DroneCarrera(
codigo="D001",
modelo="Falcon X",
velocidad_maxima=120,
autonomia=18,
aceleracion=6.5
),
DroneCarrera(
codigo="D002",
modelo="Rayo Azul",
velocidad_maxima=105,
autonomia=20,
aceleracion=5.8
),
DroneCarga(
codigo="D003",
modelo="Atlas Carga",
velocidad_maxima=70,
autonomia=40,
capacidad_carga=8
),
DroneCarga(
codigo="D004",
modelo="Titan Box",
velocidad_maxima=60,
autonomia=55,
capacidad_carga=12
)
]
Datasets
Dataset 1: pilotos.csv
id_piloto,nombre,categoria,puntos
P001,Laura,senior,0
P002,Marcos,junior,5
P003,Sara,pro,12
P004,Diego,senior,0
P005,Nerea,pro,20
P006,Pablo,avanzado,0
P007,,junior,0
P008,Hugo,senior,-4
P009,Ana,pro,notiene
P010,Luis,junior,3
Pilotos válidos esperados
P001
P002
P003
P004
P005
P010
Pilotos que deben ignorarse
P006 → categoría no válida
P007 → nombre vacío
P008 → puntos negativos
P009 → puntos no numéricos
Dataset 2: pruebas.csv
id_prueba,nombre,tipo,dificultad
PR001,Circuito rápido,velocidad,2
PR002,Vuelta larga,resistencia,3
PR003,Aterrizaje exacto,precision,4
PR004,Carrera extrema,velocidad,5
PR005,Prueba sin tipo,acrobacia,3
PR006,Dificultad baja,resistencia,0
PR007,Dificultad alta,precision,8
PR008,,velocidad,2
PR009,Desafío técnico,precision,3
Pruebas válidas esperadas
PR001
PR002
PR003
PR004
PR009
Pruebas que deben ignorarse
PR005 → tipo no válido
PR006 → dificultad inferior a 1
PR007 → dificultad superior a 5
PR008 → nombre vacío
Comprobaciones esperadas
Estas comprobaciones pueden utilizarse en el main.py para verificar que el programa funciona correctamente.
Puntuaciones base de los drones
D001 Falcon X:
120 * 0.6 + 6.5 * 10 = 72 + 65 = 137
D002 Rayo Azul:
105 * 0.6 + 5.8 * 10 = 63 + 58 = 121
D003 Atlas Carga:
40 * 2 + 8 * 5 = 80 + 40 = 120
D004 Titan Box:
55 * 2 + 12 * 5 = 110 + 60 = 170
Ejemplos de puntos por prueba
D001 en PR001:
int(137 / 2) = 68 puntos
D004 en PR002:
int(170 / 3) = 56 puntos
D003 en PR003:
int(120 / 4) = 30 puntos
D002 en PR004:
int(121 / 5) = 24 puntos
Ejemplo de operaciones esperadas en main.py
torneo.inscribir_piloto_en_prueba("P001", "PR001")
torneo.inscribir_piloto_en_prueba("P003", "PR002")
torneo.inscribir_piloto_en_prueba("P005", "PR003")
torneo.inscribir_piloto_en_prueba("P010", "PR004")
torneo.registrar_resultado("P001", "D001", "PR001")
torneo.registrar_resultado("P003", "D004", "PR002")
torneo.registrar_resultado("P005", "D003", "PR003")
torneo.registrar_resultado("P010", "D002", "PR004")
Resultado esperado tras esas operaciones
Recordando que algunos pilotos ya venían con puntos iniciales:
P001 Laura:
0 + 68 = 68 puntos
P003 Sara:
12 + 56 = 68 puntos
P005 Nerea:
20 + 30 = 50 puntos
P010 Luis:
3 + 24 = 27 puntos
Comprobaciones adicionales
ganador() → Laura o Sara
En caso de empate, devolverá el primer piloto con la máxima puntuación según la implementación del método.
media_puntos()
Deberá calcular la media con los puntos actuales de todos los pilotos cargados.
pilotos_por_categoria("pro")
Deberá devolver a Sara y Nerea.
Métodos mágicos evaluados
Este ejercicio evalúa métodos mágicos diferentes a los modelos anteriores:
| Método mágico | Clase | Uso |
|---|---|---|
__str__ | Piloto | Representación textual |
__str__ | Drone | Representación textual |
__eq__ | Piloto | Comparar pilotos por ID |
__lt__ | Piloto | Ordenar pilotos por puntos |
__len__ | Prueba | Contar participantes inscritos |
__contains__ | Prueba | Comprobar si un piloto está inscrito |
Rúbrica de evaluación
Calificación total: 10 puntos
| Parte | Criterio | Puntuación |
|---|---|---|
| Parte 1 | Clase Piloto | 1,5 |
| Parte 2 | Clase base Drone | 1,5 |
| Parte 2 | Herencia y polimorfismo | 1,5 |
| Parte 3 | Clase Prueba y métodos mágicos | 1,5 |
| Parte 4 | Clase Torneo y lógica | 2 |
| Parte 6 | Carga de datos CSV | 1 |
| General | Calidad, organización y encapsulación | 1 |
Desglose detallado
1. Clase Piloto — 1,5 puntos
| Aspecto | Puntos |
|---|---|
| Define correctamente los atributos indicados | 0,25 |
| Valida ID, nombre, categoría y puntos | 0,35 |
Implementa correctamente sumar_puntos() | 0,25 |
Implementa correctamente __str__ | 0,20 |
Implementa correctamente __eq__ | 0,20 |
Implementa correctamente __lt__ | 0,25 |
2. Clase base Drone — 1,5 puntos
| Aspecto | Puntos |
|---|---|
Define correctamente el atributo compartido organizacion | 0,15 |
| Define correctamente los atributos de instancia | 0,25 |
| Valida código, modelo, velocidad y autonomía | 0,35 |
Implementa calcular_puntuacion_base() con NotImplementedError | 0,25 |
Implementa correctamente __str__ | 0,25 |
| Usa encapsulación básica | 0,25 |
3. Herencia y polimorfismo — 1,5 puntos
| Aspecto | Puntos |
|---|---|
DroneCarrera hereda correctamente de Drone | 0,25 |
DroneCarga hereda correctamente de Drone | 0,25 |
| Se inicializan correctamente los atributos de la clase padre | 0,25 |
| Se validan correctamente los atributos específicos | 0,25 |
DroneCarrera calcula correctamente su puntuación base | 0,25 |
DroneCarga calcula correctamente su puntuación base | 0,25 |
4. Clase Prueba y métodos mágicos — 1,5 puntos
| Aspecto | Puntos |
|---|---|
Define correctamente los atributos de Prueba | 0,25 |
| Valida ID, nombre, tipo y dificultad | 0,25 |
| Inscribe pilotos evitando duplicados | 0,25 |
| Calcula correctamente los puntos de una prueba | 0,25 |
Implementa correctamente __len__ | 0,25 |
Implementa correctamente __contains__ | 0,25 |
5. Clase Torneo y lógica — 2 puntos
| Aspecto | Puntos |
|---|---|
| Gestiona correctamente pilotos, drones y pruebas | 0,30 |
| Añade pilotos, drones y pruebas evitando duplicados | 0,30 |
| Inscribe pilotos en pruebas comprobando existencia | 0,30 |
| Registra resultados comprobando piloto, drone, prueba e inscripción | 0,45 |
| Suma correctamente los puntos al piloto | 0,25 |
| Devuelve correctamente la clasificación | 0,20 |
| Devuelve correctamente ganador, media y pilotos por categoría | 0,20 |
6. Carga de datos CSV — 1 punto
| Aspecto | Puntos |
|---|---|
Lee correctamente pilotos.csv | 0,25 |
Crea objetos Piloto válidos | 0,20 |
| Ignora pilotos inválidos sin detener el programa | 0,20 |
Lee correctamente pruebas.csv | 0,20 |
| Ignora pruebas inválidas sin detener el programa | 0,15 |
7. Calidad, organización y encapsulación — 1 punto
| Aspecto | Puntos |
|---|---|
| No accede directamente a atributos desde fuera de las clases | 0,25 |
| Código organizado por ficheros y responsabilidades | 0,20 |
| Nombres claros y coherentes | 0,15 |
| Uso adecuado de excepciones | 0,15 |
| Código legible y sin duplicación excesiva | 0,15 |
| Respeta nombres de clases, métodos y retornos solicitados | 0,10 |
Penalizaciones generales
| Situación | Penalización |
|---|---|
| El programa no ejecuta por errores de sintaxis | Hasta -3 |
| No se usa POO | Hasta -4 |
| No se implementa herencia | Hasta -1,5 |
| No se implementa polimorfismo | Hasta -1 |
| No se implementan los métodos mágicos obligatorios | Hasta -2 |
| No se leen archivos externos | Hasta -1,5 |
| No se respeta la estructura del proyecto | Hasta -1 |
| Se accede directamente a los atributos desde fuera de las clases de forma reiterada | Hasta -1 |
| El programa se detiene ante datos erróneos del dataset | Hasta -1 |
| No se respetan los nombres pedidos de clases, métodos o retornos | Hasta -1,5 |