Corrector de exámenes tipo test
Corrige los exámenes tipo test de una clase con la plantilla de respuestas: penalización por fallo, notas sobre 10, clasificación, media, aprobados, la pregunta más fallada y las que nadie acertó. Listas, cadenas, ordenación y validación de datos.
- Listas
- Cadenas
- enumerate y zip
- sort con key
- f-strings
- Validación de la entrada
Enunciado
Una profesora pasa sus exámenes tipo test a un formulario y obtiene un fichero de texto con las respuestas de cada alumno. Quiere un programa que los corrija, ordene las notas y le diga qué preguntas han salido peor, para repasarlas en clase.
Cada pregunta tiene cuatro opciones (A, B, C y D) y el alumno puede dejarla en blanco. Para que no compense contestar al azar, cada fallo resta un tercio de acierto: tres fallos anulan una pregunta bien contestada. Las preguntas en blanco no suman ni restan, y la puntuación de un examen nunca puede ser negativa.
Algunas líneas del fichero llegan mal (sin el punto y coma, con respuestas de más o de menos o con letras que no existen): el programa debe avisar de cada una y corregir las demás.
Qué tiene que hacer el programa
- La primera línea es la plantilla:
CLAVEseguido de las respuestas correctas, por ejemploCLAVE ABCDA. El número de preguntas N es la longitud de la clave. - Cada línea siguiente es un examen:
nombre;respuestas, con una letra (A, B, C o D) o un guion (en blanco) por pregunta. Se ignoran las líneas vacías y los espacios al principio y al final de cada parte. - Si una línea no tiene
;, escribeAviso: la línea L no tiene el formato nombre;respuestas, donde L es su número de línea (la de la clave es la 1). Si las respuestas no tienen exactamente N caracteres o alguno no es A, B, C, D ni guion, escribeAviso: las respuestas de nombre no son válidas y no se corrigen. En los dos casos ese examen no cuenta. - Puntuación de un examen: aciertos − fallos ÷ 3, con un mínimo de 0. La nota es esa puntuación × 10 ÷ N.
- Escribe
Corrección de N preguntasy una línea por alumno, de mayor a menor nota (a igual nota, por orden alfabético): la posición en 2 caracteres alineada a la derecha, un punto y un espacio, el nombre en 22 caracteres alineado a la izquierda y la nota con dos decimales y coma, en 6 caracteres a la derecha. - Después:
Media: X,XX,Aprobados: A de T(aprueba quien tiene un 5 o más),Pregunta más fallada: P (F fallos)(la de más respuestas incorrectas; en blanco no cuenta como fallo; si hay empate, la de número más bajo; «fallo» en singular si es 1;ningunasi nadie ha fallado nada) ySin aciertos: …con los números de las preguntas que nadie ha acertado separados por coma y espacio, oninguna. - Si no hay ningún examen válido, después de los avisos escribe solo
No hay exámenes que corregir.
Entrada
Línea 1: CLAVE respuestas. Resto de líneas: nombre;respuestas (puede haber líneas vacías o mal escritas).
Ejemplos de ejecución
Tu programa debe escribir exactamente esta salida para estas entradas. Las pruebas del editor incluyen estos ejemplos y otros casos ocultos.
Cinco exámenes de diez preguntas
Entrada
CLAVE ABCDABCDAB Lucía Gómez;ABCDABCDAB Mario Vega;ABCDABCD-- Nerea Paz;ABCAABCDBB Olga Ruiz;DCBADCBADC Pedro Sanz;-----ABCDA
Salida por consola
Corrección de 10 preguntas 1. Lucía Gómez 10,00 2. Mario Vega 8,00 3. Nerea Paz 7,33 4. Olga Ruiz 0,00 5. Pedro Sanz 0,00 Media: 5,07 Aprobados: 3 de 5 Pregunta más fallada: 9 (3 fallos) Sin aciertos: ninguna
Con líneas mal escritas
Entrada
CLAVE CCBA Ana Ruiz;CCBB Bruno Díaz;CCB Carla Mena;CCXA sin punto y coma Diego Sola;CA-B Elena Toro;C-BC
Salida por consola
Aviso: las respuestas de Bruno Díaz no son válidas y no se corrigen Aviso: las respuestas de Carla Mena no son válidas y no se corrigen Aviso: la línea 6 no tiene el formato nombre;respuestas Corrección de 4 preguntas 1. Ana Ruiz 6,67 2. Elena Toro 4,17 3. Diego Sola 0,83 Media: 3,89 Aprobados: 1 de 3 Pregunta más fallada: 4 (3 fallos) Sin aciertos: 4
Guía paso a paso
Intenta resolverlo por tu cuenta y abre un paso solo cuando te atasques: cada uno te acerca a la solución sin dártela entera.
1. Leer la clave y recorrer los exámenes
Lee toda la entrada con sys.stdin.read().split("\n"). La clave es la segunda palabra de la primera línea. Recorre el resto con enumerate(lineas[1:], start=2) para tener a mano el número de línea que piden los avisos.
2. Validar antes de corregir
Primero comprueba que haya ;; después separa nombre y respuestas con split(";", 1) y comprueba la longitud y las letras. any(r not in "ABCD-" for r in respuestas) dice si hay algún carácter que no vale.
if len(respuestas) != n or any(r not in "ABCD-" for r in respuestas):
print(f"Aviso: las respuestas de {nombre} no son válidas y no se corrigen")
continue3. Corregir pregunta a pregunta
zip(respuestas, clave) recorre a la vez la respuesta del alumno y la correcta de cada pregunta, y enumerate te da su índice para ir sumando los fallos y los aciertos de cada pregunta en dos listas de N contadores.
4. Ordenar y formatear
sort(key=lambda a: (-a[1], a[0])) ordena por nota de mayor a menor y, a igualdad, por nombre. En los f-strings, {pos:>2} alinea a la derecha en 2 caracteres y {nombre:<22} a la izquierda en 22.
5. Las estadísticas
Para la pregunta más fallada, max(range(n), key=lambda i: fallos[i]) devuelve el índice con más fallos y, en caso de empate, el primero. Las preguntas sin aciertos son los índices cuyo contador de aciertos vale 0; recuerda sumar 1 para mostrar el número de pregunta.
Resuélvelo aquí
El editor trae el esqueleto del programa. Pulsa «Ejecutar» para comprobarlo con los ejemplos y con 2 casos ocultos que buscan los errores típicos.
Ejemplo
CLAVE ABCDABCDAB Lucía Gómez;ABCDABCDAB Mario Vega;ABCDABCD-- Nerea Paz;ABCAABCDBB Olga Ruiz;DCBADCBADC Pedro Sanz;-----ABCDA
Corrección de 10 preguntas 1. Lucía Gómez 10,00 2. Mario Vega 8,00 3. Nerea Paz 7,33 4. Olga Ruiz 0,00 5. Pedro Sanz 0,00 Media: 5,07 Aprobados: 3 de 5 Pregunta más fallada: 9 (3 fallos) Sin aciertos: ninguna
Solución explicada
Ver la solución completa
1import sys
2
3
4def formato(numero):
5 """Dos decimales con coma, como se escriben las notas en España."""
6 return f"{numero:.2f}".replace(".", ",")
7
8
9def main():
10 lineas = sys.stdin.read().split("\n")
11 clave = lineas[0].split()[1]
12 n = len(clave)
13 alumnos = [] # (nombre, nota) de cada examen válido
14 fallos = [0] * n # fallos de cada pregunta
15 aciertos_pregunta = [0] * n # aciertos de cada pregunta
16
17 for num, linea in enumerate(lineas[1:], start=2):
18 linea = linea.strip()
19 if not linea:
20 continue
21 if ";" not in linea:
22 print(f"Aviso: la línea {num} no tiene el formato nombre;respuestas")
23 continue
24 nombre, respuestas = (parte.strip() for parte in linea.split(";", 1))
25 if len(respuestas) != n or any(r not in "ABCD-" for r in respuestas):
26 print(f"Aviso: las respuestas de {nombre} no son válidas y no se corrigen")
27 continue
28 aciertos = mal = 0
29 for i, (respuesta, correcta) in enumerate(zip(respuestas, clave)):
30 if respuesta == "-":
31 continue
32 if respuesta == correcta:
33 aciertos += 1
34 aciertos_pregunta[i] += 1
35 else:
36 mal += 1
37 fallos[i] += 1
38 # Tres fallos restan un acierto, pero la puntuación nunca baja de 0
39 puntos = max(0, aciertos - mal / 3)
40 alumnos.append((nombre, puntos * 10 / n))
41
42 if not alumnos:
43 print("No hay exámenes que corregir.")
44 return
45
46 alumnos.sort(key=lambda a: (-a[1], a[0]))
47 print(f"Corrección de {n} preguntas")
48 for pos, (nombre, nota) in enumerate(alumnos, start=1):
49 print(f"{pos:>2}. {nombre:<22}{formato(nota):>6}")
50
51 media = sum(nota for _, nota in alumnos) / len(alumnos)
52 aprobados = sum(1 for _, nota in alumnos if nota >= 5)
53 print(f"Media: {formato(media)}")
54 print(f"Aprobados: {aprobados} de {len(alumnos)}")
55
56 # max devuelve el primero de los empatados: la pregunta de número más bajo
57 peor = max(range(n), key=lambda i: fallos[i])
58 if fallos[peor] == 0:
59 print("Pregunta más fallada: ninguna")
60 else:
61 print(f"Pregunta más fallada: {peor + 1} ({fallos[peor]} {'fallo' if fallos[peor] == 1 else 'fallos'})")
62 sin_aciertos = [str(i + 1) for i in range(n) if aciertos_pregunta[i] == 0]
63 print("Sin aciertos: " + (", ".join(sin_aciertos) if sin_aciertos else "ninguna"))
64
65
66main()El programa recorre la entrada una sola vez y, por cada examen, actualiza tres cosas: la nota del alumno y los contadores de aciertos y fallos de cada pregunta. Así todas las estadísticas finales salen sin volver a leer nada.
La validación se hace antes de tocar ningún contador: un examen mal escrito no debe afectar a la estadística de las preguntas.
La nota se calcula con la fórmula de la penalización (aciertos - mal / 3) y max(0, …) impide que sea negativa. Ordenar por la tupla (-nota, nombre) resuelve el orden descendente y los empates en una sola línea.
La conversión a coma decimal se concentra en una función, formato, para no repetirla en cada print.
Para ir más allá
- Admite exámenes con distinto número de opciones por pregunta, indicadas en la línea de la clave.
- Muestra, para cada pregunta, el porcentaje de alumnos que eligió cada opción.
- Guarda las notas en un fichero CSV con
csv.writer, listo para abrirlo en una hoja de cálculo.