Una cerradura de combinación ordinaria de N dígitos consta de N discos giratorios. Cada disco tiene dígitos 0-9 inscritos en orden, y debe convertirlos a la contraseña correcta para abrirlo. Obviamente, si no conoce la contraseña, deberá intentarlo como máximo 10 N veces antes de desbloquearla. Eso no es interesante.
Así que consideremos una variante del bloqueo de combinación, llámelo bloqueo que revela la distancia.
En cada intento fallido de abrir una cerradura que revela la distancia, responderá la cantidad mínima de movimientos para desbloquear.
Un movimiento se define como una rotación de una posición, por ejemplo, necesita 1 movimiento de 890
a 899
y 9 movimientos de 137
a 952
.
El reto
Dado un bloqueo que revela la distancia con su contraseña desconocida, intente abrir el bloqueo con un número mínimo de intentos (no movimientos), mientras evita que el programa se alargue demasiado.
Reglas y calificaciones
- Debe escribir un programa completo que ingrese desde stdin y salga a stdout. El programa debe hacer entrada / salida de la siguiente manera:
Start
Input an integer N (number of digits) from stdin
Do
Output a line containing decimal string of length N (your attempt) to stdout
Input an integer K (response of the lock) from stdin
While K not equal 0
End
Su programa debe manejar hasta N = 200, y debe ejecutar menos de 5 segundos en cualquier entrada.
Los ceros a la izquierda en la salida no deben omitirse.
Hay 5 datos de prueba para cada longitud, por lo que el número total de datos de prueba es 1000. Los datos de prueba se generan aleatoriamente.
La puntuación final será (número total de conjeturas en todos los datos de prueba) * ln (longitud del código en bytes + 50). La puntuación más baja gana. (ln es registro natural)
Marcaré el programa por ti. Si desea saber cómo calificaré su programa, o si desea calificarlo usted mismo, eche un vistazo a las ediciones anteriores en esta publicación .
Este desafío finalizará el 07/12/2017 a las 14:00 UTC. Publicaré mi solución entonces.
Ejecutando ejemplo
Las líneas que comienzan con >
representan la entrada y otras representan la salida del programa.
Puede tener una contraseña en mente e interactuar con su programa para probarla.
> 3 # 3-digit lock. The hidden password is 746
000 # 1st guess (by program)
> 11 # response to the 1st guess
555 # 2nd guess
> 4 # ...
755
> 2
735
> 2
744
> 2
746 # finally the correct answer! The program attempts 6 times.
> 0 # this is not necessary
Programa de muestra
EDITAR: Tal vez el formato de entrada / salida anterior no estaba claro. Aquí hay un programa de muestra en Python.
Python, 369 bytes, número total de intentos = 1005973, puntaje = 6073935
import sys
N = int(input()) # get the lock size
ans = ''
for i in range(N): # for each digit
lst = []
for j in range(10): # try all numbers
print('0' * i + str(j) + '0' * (N - i - 1)) # make a guess
result = int(input()) # receive the response
lst.append(result)
ans += str(lst.index(min(lst)))
print(ans) # output the final answer
Gracias a Jonás por simplificar el desafío.
fuente
162751*ln(388+50)=989887
.C # (.NET Core) , 617 bytes, intentos totales = 182255, puntaje = 1185166
Esperemos que C # en este formato funcione para usted. Tiene la forma de un programa completo, por lo que debería haber una forma de compilar en un ejecutable. Avíseme si hay algo que pueda hacer para que sea más fácil. Los bytes son parte de la puntuación a pesar de que se eliminó la etiqueta Code Golf, por lo que mi envío oficial elimina todos los espacios en blanco innecesarios y los nombres útiles. Mi explicación a continuación utilizará fragmentos del código no protegido:
Explicación
Este programa usa solo un método auxiliar:
Esto escribe la conjetura en stdout, luego lee la distancia desde stdin. También finaliza inmediatamente el programa si una suposición es la combinación exacta. Yo lo llamo mucho. A continuación, la configuración inicial:
Esto obtiene la duración de la combinación, luego comienza a adivinar con todos los ceros. Luego, itera a través de cada dígito en un
for
bucle.Para cada dígito, adivina 5, luego decide el siguiente paso en función de cómo cambió la distancia desde la suposición anterior (donde ese dígito era 0).
Si la distancia aumentó en 5, entonces 0 fue correcto para esa distancia. Ajuste ese dígito de nuevo a 0. Alterar la distancia registrada manualmente evita una suposición adicional.
Si la distancia disminuyó en 5, entonces 5 es el dígito correcto y pasamos al siguiente dígito inmediatamente.
Después de eso las cosas son complicadas. Usar
5
y0
para mis conjeturas iniciales significa que las posibilidades de diferencia restantes son3, 1, -1, -3
con 2 posibilidades para cada una, que necesitan una conjetura adicional para distinguir. Cada uno de estos casos toma una forma similarAlgunos de los números cambian, pero esencialmente intentamos una de las dos posibilidades y verificamos si el cambio fue el correcto para ese dígito. Si no fue así, entonces el otro dígito es correcto, así que configuramos ese dígito y luego ajustamos la diferencia manualmente.
Este método significa que debemos requerir, como máximo, 1 conjetura para los 0 iniciales, 2 conjeturas por dígito, y luego 1 conjetura final para asegurar que el último dígito no caiga.
Sin embargo, puede tener errores, funciona hasta donde he comprobado manualmente, pero eso no es garantía.Error encontrado y aplastado gracias a Colera Sufuente
37
. La salida es:00, 50, 30, 75, 75
(sí, dos 75s).<
con>
cadaif
enswitch
parece corregir el error. Si eso es lo que quieres, tu puntaje es182255*ln(617+50)=1185166
.Python 2 y 3: 175 bytes, intentos totales = 1005972, puntaje = 5448445
Este programa requiere ceil (log (n)) * 10 intentos por combinación o cada dígito toma 10 intentos (por lo tanto,
333
toma 30 intentos).Muchas gracias a Colera Su por ayudarme con la funcionalidad de entrada / salida.
Versión de Desafío de Python ( Modificado por OP ).
Escribí una versión del código de bloqueo dentro de Python. Puede seguir adelante y usarlo si está tratando de resolver esto en Python (como yo). Lo siguiente funciona en Python 2 y 3. Tenía mucho más sentido implementar el bloqueo como una clase con la que se puede probar y decidí crear una función de generador para adivinar las entradas.
fuente
LockIO
mal la clase. He enviado una solicitud de edición. En segundo lugar, creo que has leído mal el criterio de puntuación. La puntuación se calcula por los datos de prueba generados por el generador, no por ejemplo (ejecuté su programa, y el número total es 1005972). El registro natural también falta. En tercer lugar, he especificado que debe proporcionar un programa completo, por lo que también debe incluir laLockIO
parte en el recuento de bytes. Además, debe generar el resultado final, y eso también se cuenta en la puntuación.Lock
ymasterLock
es solo por conveniencia de la prueba.LockIO
es lo que realmente necesita enviar, ya que utiliza el formato de E / S requerido.R ,
277 bytes (puntaje = 1175356)258 bytes, intentos totales = 202999, puntaje = 1163205Pruébalo en línea!
Versión stdin-stdout, según lo solicitado por el OP, sin repeticiones. Gracias a Colera Su por arreglar un error inicial. Esta es una versión marginalmente más corta que la de los comentarios.
A continuación, la presentación de TIO para ejecutar un lote de pruebas dentro de TIO
R , 189 bytes
Pruébalo en línea!
Consideremos un vector de ceros como la suposición inicial. Llamemos a V la distancia entre la suposición actual y la solución. Para cada posición solo necesita verificar los cambios en V cuando reemplaza 0 con 5 y con 4. De hecho, las diferencias entre cambiar 0 con 5 se enumeran en mi vector s1. Las diferencias entre cambiar 0 con 4 se enumeran en mi vector s2. Como puede ver, estos dos vectores mapean de manera única los dígitos de la solución.
El número total de pruebas es, por lo tanto,
3 * L2 * L + 1, donde L es la longitud del código: una comprobación inicial contra todos los ceros, luego dos comprobaciones para cada dígito, una contra 5 y otra contra 4.La mejora de un factor 3 a un factor 2 se inspiró en la presentación de Kamil Drakari.
El resto del envío de TIO es repetitivo para R. El envío de TIO muestra el tiempo de ejecución y el número total de operaciones para 1000 ejecuciones con L = 1 ... 200, 5 repeticiones para cada valor de L.
fuente
Error in scan(n = 1) : scan() expected 'a real', got 'S=rep(0,L)'
cuando ejecuto.scan(file=file("stdin"),n=1)
funciona. Este programa (igual que el suyo, solo E / S corregidas) obtiene una puntuación de202999*ln(277+50)=1175356
.202999*ln(258+50) != 202999*ln(277+50)