Skip to content
Merged

PRO1 #21

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions 1r/Q1/PRO1/simulador-parcials/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<timestamp>-<parcial>/` con un `.cpp` vacío por problema
(cabecera ASCII estándar de 42 ya puesta, nombrado `<CODIGO>.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/<timestamp>-<parcial>/` 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 `<CODIGO>.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
Expand All @@ -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.
Expand All @@ -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)
Expand Down
41 changes: 41 additions & 0 deletions 1r/Q1/PRO1/simulador-parcials/scripts/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 <iostream>

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" <<EOF2
PARCIAL="$PARCIAL"
PARCIAL_SLUG="$PARCIAL_SLUG"
START_TIME=$START_TIME
END_TIME=$END_TIME
EXAM_MINUTES=$EXAM_MINUTES
PROBLEMS="$PROBLEMS"
CURRENT_IDX=$CURRENT_IDX
EOF2
}
52 changes: 25 additions & 27 deletions 1r/Q1/PRO1/simulador-parcials/scripts/iniciar_examen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ de verdad y entraras en una sesion interactiva (examshell>) 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.
==================================================================
Expand Down Expand Up @@ -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 <iostream>

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" <<EOF2
PARCIAL="$parcial"
PARCIAL_SLUG="$pslug"
START_TIME=$start_time
END_TIME=$end_time
EXAM_MINUTES=$EXAM_MINUTES
EOF2
START_TIME=$(date +%s)
END_TIME=$((START_TIME + EXAM_MINUTES * 60))

guardar_estado "$intento_dir/.estado"

exec bash "$DIR/sesion_examen.sh" "$CACHE_DIR" "$INTENTOS_DIR" "$intento_dir"
72 changes: 49 additions & 23 deletions 1r/Q1/PRO1/simulador-parcials/scripts/sesion_examen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ if [ ! -f "$ESTADO" ]; then
exit 1
fi
source "$ESTADO"
read -ra PROBLEMS_ARR <<< "$PROBLEMS"

PDIR="$CACHE_DIR/$PARCIAL_SLUG"

Expand All @@ -41,21 +42,20 @@ fmt_mmss() {
printf "%02d:%02d" $(($1 / 60)) $(($1 % 60))
}

mostrar_enunciados() {
for probdir in "$PDIR"/*/; do
code=$(basename "$probdir")
echo "------------------------------------------------------------------"
echo " Problema $code"
echo "------------------------------------------------------------------"
if [ -s "$probdir/enunciado.txt" ]; then
cat "$probdir/enunciado.txt"
else
echo "(Este fichero fuente no trae un enunciado capturable como"
echo " comentario inicial; revisa el .cc original en el repo de"
echo " referencia si necesitas el enunciado completo.)"
fi
echo
done
mostrar_enunciado_actual() {
local code="${PROBLEMS_ARR[$CURRENT_IDX]}"
local probdir="$PDIR/$code"
echo "------------------------------------------------------------------"
echo " Problema $code"
echo "------------------------------------------------------------------"
if [ -s "$probdir/enunciado.txt" ]; then
cat "$probdir/enunciado.txt"
else
echo "(Este fichero fuente no trae un enunciado capturable como"
echo " comentario inicial; revisa el .cc original en el repo de"
echo " referencia si necesitas el enunciado completo.)"
fi
echo
}

estado_compilacion() {
Expand All @@ -77,23 +77,48 @@ mostrar_help() {
cat <<'EOF'
Comandos disponibles:
help Esta ayuda.
status Tiempo restante, parcial actual y estado de cada problema.
enunciado Vuelve a mostrar los enunciados completos del parcial (alias: subject).
status Tiempo restante, problema actual y estado de lo desbloqueado.
enunciado Vuelve a mostrar el enunciado del problema actual, solo ese
(alias: subject).
siguiente Pasa al siguiente problema (alias: next). Pide confirmacion
'yes' y NO se puede volver atras una vez confirmado.
grademe Compila, ejecuta (interactivo) y compara cada .cpp con la
solucion de referencia. NO es correccion automatica pass/fail.
finish Termina la sesion (pide confirmacion 'yes') y muestra el resumen.
EOF
}

mostrar_status() {
local restante
local restante total bloqueados
restante=$(tiempo_restante)
total=${#PROBLEMS_ARR[@]}
echo "Parcial: $PARCIAL"
echo "Problema $((CURRENT_IDX + 1)) de $total: ${PROBLEMS_ARR[$CURRENT_IDX]}"
echo "Tiempo restante: $(fmt_mmss "$restante") de $EXAM_MINUTES min"
echo "Enunciados en: $PDIR/*/enunciado.txt"
echo "Tus .cpp en: $INTENTO_DIR/"
echo "Estado de los problemas:"
echo "Estado de los problemas desbloqueados:"
estado_compilacion
bloqueados=$((total - CURRENT_IDX - 1))
if [ "$bloqueados" -gt 0 ]; then
echo "Quedan $bloqueados problema(s) bloqueado(s)."
fi
}

siguiente() {
local last=$((${#PROBLEMS_ARR[@]} - 1))
if [ "$CURRENT_IDX" -ge "$last" ]; then
echo "Ya estas en el ultimo problema ($((CURRENT_IDX + 1)) de $((last + 1))). Cuando termines, usa 'finish'."
return
fi
read -e -p "Escribe 'yes' para pasar al siguiente problema. No podras volver a este: " conf
if [ "$conf" != "yes" ]; then
echo "Cancelado, sigues en el problema actual."
return
fi
CURRENT_IDX=$((CURRENT_IDX + 1))
crear_cpp_problema "${PROBLEMS_ARR[$CURRENT_IDX]}" "$INTENTO_DIR"
guardar_estado "$ESTADO"
mostrar_enunciado_actual
}

resumen_final() {
Expand All @@ -107,7 +132,7 @@ resumen_final() {
echo "=================================================================="
echo " Parcial: $PARCIAL"
echo " Tiempo usado: $(fmt_mmss "$usado") de $EXAM_MINUTES min"
echo " Estado final de los problemas:"
echo " Estado final de los problemas vistos (desbloqueados):"
estado_compilacion
echo "=================================================================="
}
Expand Down Expand Up @@ -147,7 +172,7 @@ echo "=================================================================="
echo " Parcial: $PARCIAL -- tienes $EXAM_MINUTES minutos. examshell>"
echo " Escribe 'help' para ver los comandos disponibles."
echo "=================================================================="
mostrar_enunciados
mostrar_enunciado_actual

while true; do
if tiempo_agotado; then
Expand All @@ -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 ;;
"") ;;
Expand Down
Loading