From abcc362b853c5b3bde18327b92505adbe3e3c293 Mon Sep 17 00:00:00 2001 From: Alex Garcia Rodriguez <110727609+AlexGRDev@users.noreply.github.com> Date: Mon, 5 Oct 2026 09:37:32 +0200 Subject: [PATCH] =?UTF-8?q?feat(PRO1):=20progresi=C3=B3n=20por=20niveles?= =?UTF-8?q?=20en=20el=20simulador=20(un=20problema=20a=20la=20vez,=20sin?= =?UTF-8?q?=20vuelta=20atr=C3=A1s)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1r/Q1/PRO1/simulador-parcials/README.md | 31 ++++---- .../PRO1/simulador-parcials/scripts/common.sh | 41 +++++++++++ .../scripts/iniciar_examen.sh | 52 +++++++------- .../scripts/sesion_examen.sh | 72 +++++++++++++------ 4 files changed, 132 insertions(+), 64 deletions(-) diff --git a/1r/Q1/PRO1/simulador-parcials/README.md b/1r/Q1/PRO1/simulador-parcials/README.md index 1150f76..eb4cea1 100644 --- a/1r/Q1/PRO1/simulador-parcials/README.md +++ b/1r/Q1/PRO1/simulador-parcials/README.md @@ -63,21 +63,22 @@ real, igual de fiel al examen oficial como sea posible: la sesión. Pide confirmación (`y/n`) antes de arrancar nada. 3. Animación de "conexión" (puramente estética). 4. Elige un parcial al azar entre los disponibles en cache, crea - `intentos/-/` con un `.cpp` vacío por problema - (cabecera ASCII estándar de 42 ya puesta, nombrado `.cpp`), y - pide pulsar una tecla para comenzar. **El cronómetro arranca de verdad en - ese momento**, no antes. -5. Muestra de golpe los enunciados de todos los problemas (como el examen - real, no de uno en uno) y entra en el prompt interactivo `examshell>`, - que se queda esperando comandos hasta que termines o se acabe el tiempo: + `intentos/-/` y pide pulsar una tecla para comenzar. + **El cronómetro arranca de verdad en ese momento**, no antes. +5. Los problemas se ven **uno a uno, por niveles** (como el modo Maestro42 de + 42): solo se crea el `.cpp` del primer problema (cabecera ASCII estándar + de 42 ya puesta, nombrado `.cpp`); el resto no existen todavía. + Entra en el prompt interactivo `examshell>`, que se queda esperando + comandos hasta que termines o se acabe el tiempo: | Comando | Qué hace | |---|---| | `help` | Lista de comandos. | - | `status` | Tiempo restante real, parcial actual y estado de compilación de cada problema. | - | `enunciado` (alias `subject`) | Vuelve a imprimir los enunciados completos. | - | `grademe` | Compila, ejecuta (interactivo) y compara cada `.cpp` con la solución de referencia — ver detalle abajo. | - | `finish` | Pide confirmación (`yes`) y muestra el resumen final (tiempo usado, estado de cada problema) antes de salir. | + | `status` | Tiempo restante real, en qué problema estás (p.ej. "2 de 4") y estado de compilación de los problemas ya desbloqueados. | + | `enunciado` (alias `subject`) | Vuelve a imprimir el enunciado del problema ACTUAL, solo ese — nunca los demás. | + | `siguiente` (alias `next`) | Pide confirmación (`yes`) y pasa al siguiente problema: crea su `.cpp` y muestra su enunciado. **Progresión unidireccional: una vez confirmado no hay vuelta atrás** al problema anterior. En el último problema, avisa que ya estás en el último y no avanza más. | + | `grademe` | Compila, ejecuta (interactivo) y compara cada `.cpp` ya desbloqueado con la solución de referencia — ver detalle abajo. | + | `finish` | Pide confirmación (`yes`) y muestra el resumen final (tiempo usado, estado de los problemas que llegaste a desbloquear) antes de salir. | Si el tiempo ya se acabó cuando ejecutas cualquier comando, la sesión lo avisa ("SE ACABÓ EL TIEMPO") y fuerza el cierre con resumen, no deja @@ -91,8 +92,9 @@ comando interno para invocarla sin salir de la sesión; `make grade` sigue disponible como atajo standalone para repasar después de que la sesión ya haya terminado: -- Compila cada `.cpp` del intento con los mismos flags que el resto del repo - (`clang++ -Wall -Wextra -fsanitize=address,undefined -O0`). +- Compila cada `.cpp` que exista físicamente en el intento (es decir, solo + los problemas ya desbloqueados con `siguiente`) con los mismos flags que + el resto del repo (`clang++ -Wall -Wextra -fsanitize=address,undefined -O0`). - Ejecuta tu binario de forma **interactiva**: tú introduces tu propia entrada de prueba (no hay casos de test oficiales para estos exámenes). - Justo después muestra la solución de referencia para que compares a ojo. @@ -107,7 +109,8 @@ simulador-parcials/ ├── Makefile ├── .gitignore # excluye .cache/ y los binarios de intentos/ ├── scripts/ -│ ├── common.sh # config compartida (lista de parciales, slug()) +│ ├── common.sh # config compartida (lista de parciales, slug(), +│ │ # crear_cpp_problema(), guardar_estado()) │ ├── fetch_examenes.sh # descarga y separa enunciado/solución por problema │ ├── iniciar_examen.sh # disclaimer, confirmación, elige parcial, crea intento, arranca cronómetro │ ├── sesion_examen.sh # bucle interactivo examshell> (status/enunciado/grademe/finish) diff --git a/1r/Q1/PRO1/simulador-parcials/scripts/common.sh b/1r/Q1/PRO1/simulador-parcials/scripts/common.sh index da36278..99948a8 100755 --- a/1r/Q1/PRO1/simulador-parcials/scripts/common.sh +++ b/1r/Q1/PRO1/simulador-parcials/scripts/common.sh @@ -21,3 +21,44 @@ PARCIALES=( slug() { echo "$1" | tr ' ' '_' } + +# Crea el .cpp (cabecera 42 + stub) de un problema dentro del intento. +# Usa $DIR (directorio de scripts/, ya fijado por el script que hace source +# de este fichero) para localizar header_template.cpp. +crear_cpp_problema() { + local code="$1" intento_dir="$2" + local filename="${code}.cpp" + local dest="$intento_dir/$filename" + local fecha + fecha=$(date +"%Y/%m/%d %H:%M:%S") + # Delimitador '#' en vez de '/': la fecha "YYYY/MM/DD HH:MM:SS" contiene + # barras, y con '/' como delimitador el sed de BSD (macOS) rompe. + sed -e "s#XXXXXXXXXX#${filename}#" -e "s#YYYY/MM/DD HH:MM:SS#${fecha}#g" \ + "$DIR/header_template.cpp" > "$dest" + cat >> "$dest" <<'CPPEOF' + +#include + +int main(void) +{ + return (0); +} +CPPEOF +} + +# Reescribe por completo el fichero .estado desde las variables en memoria +# actuales. Deliberadamente NO usa sed -i para tocar solo CURRENT_IDX: ya +# hubo un bug real por diferencias BSD/GNU sed con delimitadores +# conflictivos, así que se regenera entero. +guardar_estado() { + local estado_path="$1" + cat > "$estado_path" <) con estos comandos disponibles durante el examen: help Lista de comandos. - status Tiempo restante, parcial actual y estado de cada problema. - enunciado Vuelve a mostrar los enunciados completos del parcial. + status Tiempo restante, problema actual y estado de lo desbloqueado. + enunciado Vuelve a mostrar el enunciado del problema actual (solo ese). + siguiente Pasa al siguiente problema (alias: next). PIDE CONFIRMACION Y + NO SE PUEDE VOLVER ATRAS: hasta entonces no ves los demas. grademe Compila, ejecuta y compara con la solucion de referencia. finish Termina la sesion (pide confirmacion) y muestra el resumen. +Los problemas del parcial se van viendo UNO A UNO, como en Maestro42: no +se te ensenan todos de golpe, y una vez avanzas con 'siguiente' no hay +vuelta atras al problema anterior. + No hay pass/fail automatico (PRO1 no tiene jutge con casos de test para estos examenes): 'grademe' solo ayuda a la autocorreccion manual. ================================================================== @@ -79,51 +85,43 @@ sleep 0.2 type_out "Sesion establecida." echo -# --- creacion del intento: un .cpp con cabecera 42 por problema --- +# --- creacion del intento: solo el .cpp del PRIMER problema por ahora --- +# Los problemas se ven de uno en uno (como Maestro42): el resto de .cpp se +# va creando mas adelante, en sesion_examen.sh, al usar 'siguiente'. problemas=("$pdir"/*/) timestamp=$(date +%Y%m%d-%H%M%S) intento_dir="$INTENTOS_DIR/${timestamp}-${pslug}" mkdir -p "$intento_dir" echo "$parcial" > "$intento_dir/.parcial" +PROBLEMS="" for probdir in "${problemas[@]}"; do code=$(basename "$probdir") - filename="${code}.cpp" - dest="$intento_dir/$filename" - fecha=$(date +"%Y/%m/%d %H:%M:%S") - # Delimitador '#' en vez de '/': la fecha "YYYY/MM/DD HH:MM:SS" contiene - # barras, y con '/' como delimitador el sed de BSD (macOS) rompe. - sed -e "s#XXXXXXXXXX#${filename}#" -e "s#YYYY/MM/DD HH:MM:SS#${fecha}#g" \ - "$DIR/header_template.cpp" > "$dest" - cat >> "$dest" <<'CPPEOF' - -#include - -int main(void) -{ - return (0); -} -CPPEOF + PROBLEMS="$PROBLEMS $code" done +PROBLEMS="${PROBLEMS# }" +read -ra PROBLEMS_ARR <<< "$PROBLEMS" +CURRENT_IDX=0 + +crear_cpp_problema "${PROBLEMS_ARR[0]}" "$intento_dir" echo "==================================================================" echo " Vas a empezar el parcial: $parcial" echo " Modo REAL: tendras $EXAM_MINUTES minutos en cuanto pulses una tecla." +echo " Tiene ${#PROBLEMS_ARR[@]} problema(s). Se veran UNO A UNO: hasta que" +echo " no escribas 'siguiente' (confirmando, y SIN posibilidad de volver" +echo " atras) no veras el siguiente problema." echo " Intento creado en: $intento_dir" read -e -n1 -p "Pulsa una tecla para comenzar... " tecla echo echo # --- arranque real del cronometro: a partir de aqui el tiempo cuenta --- -start_time=$(date +%s) -end_time=$((start_time + EXAM_MINUTES * 60)) - -cat > "$intento_dir/.estado" <" echo " Escribe 'help' para ver los comandos disponibles." echo "==================================================================" -mostrar_enunciados +mostrar_enunciado_actual while true; do if tiempo_agotado; then @@ -165,7 +190,8 @@ while true; do case "$cmd" in help) mostrar_help ;; status) mostrar_status ;; - enunciado | subject) mostrar_enunciados ;; + enunciado | subject) mostrar_enunciado_actual ;; + siguiente | next) siguiente ;; grademe) bash "$DIR/grade.sh" "$CACHE_DIR" "$INTENTOS_DIR" "$INTENTO_DIR" ;; finish) finish manual || true ;; "") ;;