Medir la dificultad de un puzle con bots
La dificultad no es algo que se pueda sentir de forma fiable en un juego que has diseñado tú. Sunny Sort la mide haciendo que seis jugadores distintos jueguen cada nivel y leyendo el desacuerdo entre ellos: cada bot está construido para fallar de una manera concreta, así que cuál de ellos gana te dice qué clase de nivel es.
Los seis jugadores
LevelAnalyzer los ejecuta todos en cada nivel y cruza los resultados.
| Jugador | Qué hace | Qué revela |
|---|---|---|
| Solucionador de haz | la mejor línea que encuentra | si el nivel se puede ganar, con cuánto margen, usando cuánto tablero |
FirstFit |
el primer movimiento legal | si gana, no hay puzle |
Hoard |
siempre junto a la pila más gorda | si gana desde una esquina, hay una estrategia dominante viva |
Greedy |
el mejor movimiento mirando uno por delante | si gana siempre, el juego es plano; si no gana nunca, es injusto o exige planificar |
Spread |
siempre lo más lejos posible | un control: demuestra que la colocación tiene consecuencias |
Random |
aleatorio | el suelo de dificultad |
El veredicto es el peor problema encontrado, no una media:
impossible → trivial → dominated → harsh → good
Un nivel precioso en cuatro dimensiones y trivialmente ganable en la quinta es trivial. Promediar escondería justo lo que merece saberse.
La puntuación de 0 a 100 penaliza después las victorias de bots tontos, el uso del tablero concentrado en una esquina y un margen demasiado generoso; premia las cascadas y las líneas ganadoras que de verdad necesitan todo el tablero.
Una métrica que mentía
La primera versión medía "celdas tocadas" y se saturaba cerca del 100% en todas partes.
El motivo es estructural: un bot solo pierde cuando el tablero se llena, así que toda derrota acaba habiendo tocado todas las celdas jugables. La métrica medía la condición de derrota, no la estrategia.
La concentración se mide ahora en la línea ganadora del solucionador y en las decisiones individuales de los bots, nunca en sus totales. Es la clase de error que merece anotarse, porque una métrica saturada no parece rota: parece un resultado consistente.
Que gane un bot tonto es concluyente. Que pierda uno bueno, no.
Un informe anterior clasificó nueve niveles como deep porque el bot voraz no los ganaba, y yo leí eso como profundidad. Era una conclusión floja: "el voraz pierde" es ausencia de superficialidad, no presencia de decisión.
Así que medí la cosa directamente. Si un nivel exige planificar, tiene que existir algún momento en que un movimiento legal pierda el nivel y otro lo mantenga vivo. Sondeando los niveles 4 a 20, muestreando turnos a lo largo de toda la partida y no solo en la apertura:
| Métrica | Resultado |
|---|---|
| Profundidad estratégica (menor anticipación que gana) | 1 en todos |
| Anchura de decisión (movimientos legales que mantienen la victoria) | 100% en todos |
| Turnos forzados (≤ 1 movimiento ganador) | 0% |
| Recuperación tras un movimiento no óptimo | 100% |
No había movimiento equivocado. En cualquier momento, cualquier cosa que hiciera el jugador seguía ganando. Aquellos niveles deep derrotaban a ese bot voraz concreto por una debilidad de su heurística —no valoraba mantener alta la cima de una pila— y no porque exigieran planificar. Un bot de un movimiento con mejor heurística los ganó todos.
Esa lectura cambió lo que vino después. Tres direcciones que parecían el siguiente paso obvio —elección de bandeja, geometría del tablero, preparar cascadas— no pueden producir decisiones mientras no haya presión. Una decisión solo existe cuando opciones distintas llevan a resultados distintos.
Lo que valen las mediciones
El sentido de todo esto es que ningún cambio de diseño entra sin un número que lo sostenga. El efecto conjunto de los cambios que las mediciones justificaron:
| Métrica | Antes | Después |
|---|---|---|
| Puntuación media, niveles 1-24 | 55,2 | 81,8 |
Niveles valorados como good |
11 de 20 | 21 de 24 |
| Niveles imposibles | 3 | 0 |
| Niveles triviales | 5, por accidente | 3, los tutoriales, a propósito |
| Movimientos del tutorial | 8-15 | 5-7 |
Cada uno de esos números sale del mismo comando, que puede ejecutar cualquiera que tenga el repositorio:
dotnet run --project src/StackSort.Tools -- analyze --from 1 --to 24
La medición no es un informe que alguien escribió una vez. Es una herramienta que vuelve a ejecutarse, y eso es lo que hace posible darse cuenta de cuándo un cambio empeora la curva.