Este tutorial adapta pedagógicamente el Día 86. La sección 📝 Contenido original del curso proviene del único archivo de la carpeta:
dia86-tarea5.md(enunciado y pregunta de reflexión, en inglés; aquí traducido). El curso no ofrece guía ni solución, y este tutorial no entrega la aplicación terminada. Todo lo que no está en ese archivo (definición de "palabra estándar", fórmulas de PPM y precisión, manejo del tiempo y de eventos de teclado en Tkinter, código de ejemplo, retos 🟢🟡🟠🔴, proyecto extra y la etapa 5 de Mi Portafolio Profesional) es creación de esta adaptación.
Nota sobre las verificaciones: el 28 de septiembre de 2026, con Python 3.14 y Tk 8.6, se ejecutaron las funciones de cálculo de la sección 3 (por ejemplo: 200 caracteres en 60 segundos dan 40 PPM; una frase de 13 caracteres escrita sin errores en 6 segundos da 26 PPM netas) y se comprobó una cuenta regresiva con
ventana.after(...). La ventana completa de la sección 4 es un esqueleto para completar.
Tabla de contenidos
- La tarea: medir cuántas palabras por minuto escribes
- Analizar el problema antes de programar
- 📖 Medir: palabras por minuto y precisión
- 📖 Tiempo y teclado en Tkinter:
afterybind - 🚀 Proyecto del día: construcción por versiones
- 🌟 Proyecto extra: entrenador de vocabulario en inglés
- 🏗️ Mi Portafolio Profesional — Etapa 5
- 🧩 Comprueba lo aprendido
- 🤖 Programar con apoyo de IA
- 🛠️ Observaciones sobre el material original
- 📋 Matriz de trazabilidad
- 📦 Evidencias de aprendizaje del Día 86
1. La tarea: medir cuántas palabras por minuto escribes
(Fuente: dia86-tarea5.md)
📝 Contenido original del curso
Usando Tkinter y lo que aprendiste sobre aplicaciones gráficas con Python, construye una aplicación de escritorio que evalúe tu velocidad de escritura. Dale al usuario un texto de muestra y detecta cuántas palabras por minuto puede escribir.
La velocidad promedio de escritura es de 40 palabras por minuto; con práctica puedes llegar a 100. (El enunciado enlaza un artículo de typing.com sobre la velocidad promedio y una versión web del test: typing-speed-test.aoeu.eu.)
Si tienes más tiempo, convierte tu test en un entrenador de mecanografía, con puntajes máximos y más textos de muestra. Puedes diseñar el programa como quieras.
Pregunta de la tarea — Momento de reflexión: cómo abordaste el proyecto; qué fue difícil y qué fácil; cómo mejorarías; tu mayor aprendizaje; qué harías distinto.
Prerequisitos: Tkinter y el temporizador del Pomodoro con
after(Días 27–28); manejo de archivos y JSON (Días 24 y 30); listas, cadenas yrandom(Días 2 y 4); funciones con retorno (Día 10).
2. Analizar el problema antes de programar
(Sección creada para esta adaptación.)
🔍 Antes de programar
| Pregunta | Respuesta que debes construir tú |
|---|---|
| ¿Qué información tenemos? | Un texto de muestra |
| ¿Qué necesitamos obtener? | Lo que escribe el usuario y cuánto tiempo tarda |
| ¿Cuándo empieza a contar el tiempo? | ¿Al abrir la app? ¿Al pulsar "Empezar"? ¿Con la primera tecla? (decide y justifica) |
| ¿Cuándo termina? | ¿A los 60 segundos? ¿Cuando termina el texto? |
| ¿Qué resultado esperamos? | Palabras por minuto y, para ser justos, precisión (errores) |
| ¿Qué condiciones hay que tener en cuenta? | Errores de escritura, borrar con Retroceso, pegar texto (¡trampa!), tiempo 0 |
Dos formatos de test
| Formato | Cómo funciona | Ventaja | Desventaja |
|---|---|---|---|
| Tiempo fijo (60 s) | Escribe todo lo que puedas en un minuto | Resultado comparable entre personas | Necesitas textos largos |
| Texto fijo | Escribe una frase completa; se mide el tiempo | Más simple de programar | Frases cortas dan resultados muy variables |
3. 📖 Medir: palabras por minuto y precisión
(Sección creada para esta adaptación. Funciones verificadas.)
🎯 Objetivo de aprendizaje
Traducir una definición (palabras por minuto) a una fórmula y a una función que se pueda probar.
📖 Explicación conceptual
¿Qué es una "palabra"? Si contamos palabras reales, escribir "sol" no vale lo mismo que "electroencefalograma". Por eso los tests de mecanografía usan la palabra estándar = 5 caracteres (incluidos espacios y signos).
| Medida | Fórmula | Qué mide |
|---|---|---|
| PPM brutas | (caracteres escritos ÷ 5) ÷ minutos | Velocidad, aunque haya errores |
| PPM netas | (caracteres correctos ÷ 5) ÷ minutos | Velocidad útil |
| Precisión | caracteres correctos ÷ caracteres escritos × 100 | Porcentaje de aciertos |
Ejemplo a mano: escribes 200 caracteres en 60 s → 200 ÷ 5 = 40 palabras en 1 minuto → 40 PPM. Si fueron 30 s: 40 ÷ 0,5 = 80 PPM.
🔎 Ejemplo explicado
def contar_correctos(modelo, escrito):
return sum(1 for a, b in zip(modelo, escrito) if a == b)
def ppm_brutas(escrito, segundos):
if segundos <= 0:
return 0
return (len(escrito) / 5) / (segundos / 60)zip(modelo, escrito)recorre ambos textos a la par: primer carácter con primer carácter, etc. Se detiene en el más corto.sum(1 for ... if a == b)cuenta cuántas parejas coinciden (una expresión generadora, pariente de la comprensión de listas del Día 26).if segundos <= 0: return 0evita unZeroDivisionErrorsi el tiempo no ha empezado.
Tu turno: escribe ppm_netas(modelo, escrito, segundos) y precision(modelo, escrito) (cuidado con el texto vacío). Comprueba: ppm_netas("el perro come", "el perro come", 6) debe dar 26.0.
⚠️ Una limitación importante (analízala)
La comparación posición a posición es muy estricta: si el usuario omite una letra, todo lo que sigue queda "corrido" y cuenta como error. Comprobado: contar_correctos("hola", "hla") da 1, aunque solo faltó una letra.
Alternativas (elige una y justifícala en tu diario):
- Comparar palabra por palabra (
modelo.split()yescrito.split()): una palabra mal escrita no arrastra a las demás. - No dejar avanzar mientras haya un error (como algunos tests en línea): el usuario debe corregir con Retroceso.
- Usar
difflib.SequenceMatcher(biblioteca estándar) para medir el parecido: más justo, pero más difícil de explicar.
⚠️ Errores frecuentes
| Error | Qué ocurre | Solución |
|---|---|---|
| Dividir por segundos en lugar de minutos | Resultados 60 veces menores | segundos / 60 |
Contar palabras con split() para las PPM |
Las palabras cortas "valen" igual que las largas | Palabra estándar = 5 caracteres |
Medir el tiempo con time.time() en saltos de 1 s |
Poca exactitud en textos cortos | time.perf_counter() mide con más precisión |
| División por cero | El programa se cierra al terminar "demasiado rápido" o sin empezar | Comprueba segundos <= 0 |
4. 📖 Tiempo y teclado en Tkinter: after y bind
(Sección creada para esta adaptación. after verificado con una cuenta regresiva; la ventana completa es un esqueleto.)
Dos herramientas clave
| Herramienta | Para qué | Ejemplo |
|---|---|---|
ventana.after(ms, funcion) |
Ejecutar funcion dentro de ms milisegundos sin congelar la ventana |
Cuenta regresiva de 60 s (como el Pomodoro del Día 28) |
widget.bind("<KeyRelease>", funcion) |
Ejecutar funcion cada vez que se suelta una tecla en ese widget |
Comparar lo escrito con el modelo y colorear errores |
⚠️ Nunca uses
time.sleep()en una app Tkinter: congela la ventana entera.afterprograma la tarea y deja quemainloopsiga atendiendo al usuario.
🔎 Esqueleto
import time
import tkinter as tk
TEXTO = "La práctica constante mejora la velocidad y la precisión."
DURACION = 60
ventana = tk.Tk()
ventana.title("Test de mecanografía")
tk.Label(ventana, text=TEXTO, wraplength=500, font=("Arial", 14)).pack(pady=10)
entrada = tk.Text(ventana, height=4, width=60, font=("Arial", 14))
entrada.pack()
reloj = tk.Label(ventana, text=f"{DURACION} s")
reloj.pack()
inicio = None
def al_teclear(evento):
global inicio
if inicio is None: # la primera tecla inicia el reloj
inicio = time.perf_counter()
cuenta_regresiva(DURACION)
escrito = entrada.get("1.0", "end-1c")
# Tu turno: comparar con TEXTO y actualizar una etiqueta de errores
def cuenta_regresiva(restante):
reloj.config(text=f"{restante} s")
if restante > 0:
ventana.after(1000, cuenta_regresiva, restante - 1)
else:
entrada.config(state="disabled")
# Tu turno: calcular y mostrar PPM y precisión
entrada.bind("<KeyRelease>", al_teclear)
ventana.mainloop()Puntos clave:
entrada.get("1.0", "end-1c"): en unText,"1.0"es línea 1, carácter 0;"end-1c"quita el salto de línea que Tkinter agrega siempre al final.after(1000, cuenta_regresiva, restante - 1): los argumentos extra se pasan a la función. La función se reprograma a sí misma cada segundo.state="disabled"impide seguir escribiendo cuando se acaba el tiempo.
Resaltar errores (idea): un Text admite etiquetas (tags) de formato. Con entrada.tag_config("error", background="#ffb3b3") y entrada.tag_add("error", "1.5", "1.6") pintas de rojo el carácter 5. Elimina las marcas anteriores con tag_remove antes de volver a pintar.
⚠️ Errores frecuentes
| Error | Qué ocurre | Solución |
|---|---|---|
| Iniciar la cuenta regresiva en cada tecla | El reloj va cada vez más rápido (varias cuentas en paralelo) | Iníciala solo una vez (if inicio is None) |
time.sleep(1) en un ciclo |
La ventana se congela | after |
entrada.get() sin índices en un Text |
TypeError |
En Text se usa get("1.0", "end-1c"); en Entry, get() |
Reiniciar el test sin cancelar el after pendiente |
Aparecen dos relojes | Guarda el identificador que devuelve after y usa after_cancel |
5. 🚀 Proyecto del día: construcción por versiones
(Desarrolla la tarea dia86-tarea5.md. Las versiones son una propuesta de esta adaptación.)
Problema
Construir una aplicación de escritorio que muestre un texto, mida la velocidad de escritura del usuario y le dé su resultado.
Contexto
En la clase de tecnología se quiere medir el progreso en mecanografía durante el periodo, sin depender de páginas web con publicidad.
Objetivo
Una app Tkinter que mida PPM netas y precisión, con varios textos y un registro de mejores puntajes.
Requisitos funcionales
- Muestra un texto de muestra elegido al azar de una lista (o de un archivo).
- El tiempo empieza con la primera tecla y termina a los 60 s (o al completar el texto, según tu diseño).
- Muestra PPM netas y precisión al final.
- Permite reiniciar con otro texto.
Restricciones técnicas
- Cálculos en funciones separadas y probadas con
assert(sección 3). - Tiempo con
after, nunca consleep. - Textos de muestra en un archivo (
textos.txtotextos.json), no escritos dentro del código.
Planificación
- Comprender cómo funciona un test real (prueba la versión web del enunciado). 2. Entradas: teclas del usuario. 3. Procesos: iniciar reloj → comparar → terminar → calcular. 4. Salidas: PPM, precisión, errores resaltados. 5. Dividir en cálculos, interfaz y datos. 6. Bocetar la ventana. 7. Implementar. 8. Probar. 9. Corregir. 10. Mejorar.
Construcción paso a paso
- Versión 1 — Cálculos en consola: las funciones de la sección 3 con sus pruebas. Simula:
ppm_netas(modelo, escrito, 45). - Versión 2 — Ventana: texto de muestra, área de escritura, reloj que baja al teclear la primera letra.
- Versión 3 — Resultado: al terminar el tiempo, bloquear la escritura y mostrar PPM y precisión.
- Versión 4 — Retroalimentación en vivo: resaltar errores mientras se escribe.
- Versión 5 — Varios textos y reinicio: textos desde archivo, botón "Otra vez" (con
after_cancel). - Versión final — Mejores puntajes: guardar en
puntajes.jsonlos 5 mejores (fecha, PPM, precisión);README.mdy diario.
Pruebas
| # | Caso | Resultado esperado |
|---|---|---|
| 1 | 200 caracteres en 60 s | 40 PPM brutas |
| 2 | Texto perfecto de 13 caracteres en 6 s | 26 PPM netas, 100 % de precisión |
| 3 | Terminar sin escribir nada | 0 PPM, sin errores de división |
| 4 | Pulsar teclas muy rápido al inicio | Solo un reloj, que baja de 1 en 1 |
| 5 | Pegar el texto con Ctrl + V | Tu app lo detecta o lo impide (decide cómo) |
| 6 | Reiniciar a mitad de un test | El reloj anterior se detiene |
| 7 | Borrar puntajes.json y abrir la app |
Funciona y crea el archivo (Día 30: FileNotFoundError) |
🧪 Prueba y depuración
def al_teclear(evento):
inicio = time.time()
cuenta_regresiva(60)
escrito = entrada.get()
ppm = len(escrito.split()) / (time.time() - inicio)Encuentra cuatro problemas: inicio se reinicia en cada tecla (y es local); la cuenta regresiva se lanza en cada tecla; get() sin índices falla en un Text; y las PPM usan palabras reales, segundos en vez de minutos y un tiempo casi cero (división por un número diminuto o por cero).
⭐ Extensión del proyecto
- 🟢 Reto 1 — Aplicación: muestra también las PPM en vivo cada segundo.
- 🟡 Reto 2 — Ampliación: tabla de mejores puntajes por usuario (nombre o alias) en JSON.
- 🟠 Reto 3 — Desafío: estadísticas de errores: ¿qué letras falla más el usuario? Guárdalas y muestra las 5 peores al final (pista: diccionario o
collections.Counter). - 🔴 Reto 4 — Pensamiento computacional: con las estadísticas del reto 3, genera textos de práctica que incluyan con más frecuencia las letras que el usuario falla. Diseña la estrategia y comprueba en 3 sesiones si la precisión mejora.
6. 🌟 Proyecto extra: entrenador de vocabulario en inglés
(Proyecto creado para esta adaptación; no existe en el curso original.)
Situación
El área de inglés quiere una app para practicar la ortografía de palabras del periodo: se muestra la palabra en español (o se escucha, como extensión) y el estudiante escribe la traducción contra reloj.
Requisitos
- Leer las palabras desde un CSV (español, inglés) (Día 25; parecido a las tarjetas del Día 31).
- Límite de 10 segundos por palabra con
after; si se acaba, cuenta como error y pasa a la siguiente. - Al final: aciertos, errores y la lista de palabras falladas, guardada para repasarla.
Decisiones que debes tomar (y justificar)
- ¿Aceptas "Colour" y "color"? ¿Mayúsculas? ¿Espacios al final?
- ¿Cómo haces que las palabras falladas aparezcan con más frecuencia en la próxima sesión?
Casos de prueba
- Responder a los 9,9 s cuenta; a los 10 s, no.
- Una respuesta con espacios de más (
" dog ") se acepta.
7. 🏗️ Mi Portafolio Profesional — Etapa 5
(Proyecto integrador creado para esta adaptación; etapas anteriores en los Días 82 a 85.)
Etapa 5 (hoy):
- Repositorio del test de mecanografía con
calculos.py(y sus pruebas),app.py,textos.jsonyREADME.mdcon una captura y tus PPM de la primera y la última prueba. - En el
README.md, explica cómo mides las PPM y la precisión, y la limitación que elegiste resolver (sección 3). DIARIO.mddel Día 86 y ficha enproyectos.json.- Revisión intermedia: ya tienes 5 proyectos. Usa la rúbrica del Día 83 y elige los 3 que destacarías en tu sitio.
8. 🧩 Comprueba lo aprendido
Conceptuales
- ¿Por qué se usa la "palabra estándar" de 5 caracteres?
- ¿Qué diferencia hay entre PPM brutas y netas?
- ¿Por qué
time.sleepcongela una app Tkinter yafterno? - ¿Para qué sirve
after_cancel?
Análisis de código
sum(1 for a, b in zip("gato", "gata") if a == b)¿Qué devuelve y por qué?
Predicción
¿Cuántas PPM brutas obtiene quien escribe 150 caracteres en 45 segundos?
Depuración
"Mi reloj baja de 2 en 2 y a veces de 3 en 3." ¿Cuál es la causa más probable?
Modificación
Cambia el formato del test a "texto fijo": el tiempo termina cuando lo escrito es igual al modelo.
Creación
Escribe comparar_palabras(modelo, escrito) que devuelva cuántas palabras están bien escritas, comparando palabra por palabra.
9. 🤖 Programar con apoyo de IA
Ciclo de trabajo: formula el problema → inténtalo tú primero → consulta a la IA sobre un punto concreto → lee y entiende → prueba → compara con la documentación oficial → modifica → explica con tus palabras.
Actividad 1 — Comprobar una definición. Pregunta a una IA cómo se calculan las palabras por minuto. ¿Menciona los 5 caracteres? Contrástalo con al menos una fuente confiable y anota si coinciden.
Actividad 2 — Revisar un cálculo. Pide a una IA una función de PPM y aplícale las pruebas 1 a 3 de la sección 5. ¿Maneja el tiempo cero?
Actividad 3 — Documentación. Pregunta cómo resaltar texto en un tkinter.Text. Compara con la documentación de Tkinter (métodos tag_config, tag_add, tag_remove) y anota cualquier diferencia.
Declara el uso: sección "Uso de IA" en el README.md.
10. 🛠️ Observaciones sobre el material original
| Archivo | Observación | Tratamiento |
|---|---|---|
dia86-tarea5.md |
No define qué es una "palabra" ni cómo tratar los errores | Sección 3: palabra estándar, PPM brutas y netas, precisión y sus limitaciones |
dia86-tarea5.md |
Cita 40 PPM de promedio y 100 con práctica (según un blog de typing.com) | Se conserva como referencia orientativa; varía según la fuente, el idioma y el teclado |
dia86-tarea5.md |
Enlaza versiones web externas | Se conservan como referencia para comprender el problema |
dia86-tarea5.md |
"Entrenador con puntajes máximos y más textos" como extra | Versiones 5 y final, y retos 2 a 4 |
11. 📋 Matriz de trazabilidad
| Contenido original | Archivo de origen | Concepto desarrollado | Ejercicio original | Reto adicional | Proyecto relacionado |
|---|---|---|---|---|---|
| App Tkinter que evalúa la velocidad de escritura con un texto de muestra | dia86-tarea5.md |
Secciones 2 y 4 | Test de velocidad | Retos 1 y 3 | Secciones 5 y 7 |
| Palabras por minuto; promedio 40, hasta 100 | dia86-tarea5.md |
Sección 3 | Test de velocidad | Predicción de la sección 8 | Sección 5 |
| Extra: entrenador con puntajes máximos y más textos | dia86-tarea5.md |
Sección 5 (versiones 5 y final) | Reto opcional | Retos 2 y 4 | Sección 5 |
| Momento de reflexión | dia86-tarea5.md |
Sección 5 (versión final) | Pregunta de reflexión | — | Sección 7 |
| (No existe en el curso original) | — | after, bind, etiquetas de Text |
— | Entrenador de vocabulario | Sección 6 |
12. 📦 Evidencias de aprendizaje del Día 86
- La app funcionando (captura o video corto de un test completo).
- Las pruebas de los cálculos superadas.
- Registro de tus PPM y precisión en varias sesiones (¿mejoraste?).
DIARIO.mddel Día 86, repositorio y ficha en el portafolio.- Cuaderno de errores: segundos frente a minutos, división por cero, varios
afteren paralelo,sleepque congela la ventana,getdeTextsin índices, comparación posición a posición demasiado estricta.