Objetivo
Dada una lista de frases de contraseña de tres palabras, descifrarlas todas. Cada vez que adivine, se le dará una pista al estilo de Mastermind , que representa cuántos caracteres coinciden con la contraseña y cuántos están en su posición correcta. El objetivo es minimizar el número total de conjeturas en todos los casos de prueba.
Frases de contraseña
De la lista de palabras predeterminada de mi sistema, elegí al azar 10,000 palabras distintas para hacer el diccionario para este desafío. Todas las palabras consisten en a-z
solo. Este diccionario se puede encontrar aquí (sin formato ).
A partir de este diccionario, generé 1000 frases de contraseña que consisten en tres palabras aleatorias separadas por espacios cada una ( apple jacks fever
por ejemplo). Las palabras individuales se pueden reutilizar dentro de cada frase de contraseña ( hungry hungry hippos
). Puede encontrar la lista de frases de contraseña aquí (sin formato ), con una por línea.
Su programa puede usar / analizar el archivo de diccionario como quiera. No puede analizar las frases de contraseña para optimizar esta lista específica. Su algoritmo aún debería funcionar dada una lista diferente de frases
Adivinación
Para adivinar, envía una cadena a un corrector. Debe devolver solamente :
- El número de caracteres en su cadena también en la frase de contraseña ( no en la posición correcta)
- El número de caracteres en la posición correcta.
Si su cadena es una combinación perfecta, puede generar algo que indique eso (el mío usa -1
para el primer valor).
Por ejemplo, si la frase de contraseña es the big cat
y usted adivina tiger baby mauling
, el corrector debería volver 7,1
. 7 caracteres ( ige<space>ba<space>
) están en ambas cadenas pero en diferentes posiciones, y 1 ( t
) está en la misma posición en ambas. Observe que los espacios cuentan.
He escrito una función de ejemplo (lectura: no optimizada) en Java, pero siéntase libre de escribir la suya siempre que solo proporcione la información requerida.
int[] guess(String in){
int chars=0, positions=0;
String pw = currentPassword; // set elsewhere, contains current pass
for(int i=0;i<in.length()&&i<pw.length();i++){
if(in.charAt(i)==pw.charAt(i))
positions++;
}
if(positions == pw.length() && pw.length()==in.length())
return new int[]{-1,positions};
for(int i=0;i<in.length();i++){
String c = String.valueOf(in.charAt(i));
if(pw.contains(c)){
pw = pw.replaceFirst(c, "");
chars++;
}
}
chars -= positions;
return new int[]{chars,positions};
}
Puntuación
Su puntaje es simplemente el número de conjeturas que envía al corrector (contando el último y correcto) para todas las frases de prueba. El puntaje más bajo gana.
Debes descifrar todas las frases de la lista. Si su programa falla en alguno de ellos, no es válido.
Su programa debe ser determinista. Si se ejecuta dos veces en el mismo conjunto de frases de contraseña, debería devolver el mismo resultado.
En el caso de un empate para el primero, ejecutaré las entradas empatadas en mi computadora cuatro veces cada una, y el tiempo promedio más bajo para resolver los 1000 casos gana. Mi computadora ejecuta Ubuntu 14.04, con un i7-3770K y 16GB de algún tipo de RAM, en caso de que eso marque la diferencia en su programa. Por esa razón, y para facilitar las pruebas, su respuesta debe estar en un idioma que tenga un compilador / intérprete que pueda descargarse de la web de forma gratuita (sin incluir pruebas gratuitas) y no requiera registrarse / registrarse.
Título adaptado de XKCD
fuente
9 0
. Esto puede llevar un tiempo: PRespuestas:
Tiempo Scala 9146 (min 7, max 15, avg 9.15): 2000 segundos
Al igual que muchas entradas, empiezo obteniendo la longitud total, luego buscando los espacios, obteniendo un poco más de información, reduciendo a los candidatos restantes y luego adivinando frases.
Inspirado por el cómic original de xkcd, traté de aplicar mi comprensión rudimentaria de la teoría de la información. Hay un billón de frases posibles o poco menos de 40 bits de entropía. Establecí un objetivo de menos de 10 conjeturas por frase de prueba, lo que significa que debemos aprender en promedio casi 5 bits por consulta (ya que el último es inútil). Con cada suposición, obtenemos dos números y, en términos generales, cuanto mayor sea el rango potencial de esos números, más esperamos aprender.
Para simplificar la lógica, utilizo cada consulta como efectivamente dos preguntas separadas, por lo que cada cadena de adivinanzas tiene dos partes, un lado izquierdo interesado en la cantidad de posiciones correctas (clavijas negras en la mente maestra) y un lado derecho interesado en la cantidad de caracteres correctos ( clavijas totales). Aquí hay un juego típico:
Adivinando espacios
Cada conjetura de espacio puede devolver como máximo 2 clavijas negras; Traté de construir conjeturas para devolver 0,1 y 2 clavijas con probabilidades 1 / 4,1 / 2 y 1/4 respectivamente. Creo que esto es lo mejor que puede hacer para obtener 1,5 bits de información. Me decidí por una cadena alterna para la primera aproximación seguida de las generadas aleatoriamente, aunque resulta que generalmente vale la pena comenzar a adivinar en el segundo o tercer intento, ya que conocemos las frecuencias de longitud de palabra.
El juego de caracteres de aprendizaje cuenta
Para las conjeturas del lado derecho, elijo conjuntos de caracteres aleatorios (siempre 2 de e / i / a / s) para que el número esperado devuelto sea la mitad de la longitud de la frase. Una variación más alta significa más información y, desde la página de Wikipedia en la distribución binomial , estoy estimando aproximadamente 3.5 bits por consulta (al menos durante los primeros antes de que la información se vuelva redundante). Una vez que se conoce el espacio, utilizo cadenas aleatorias de las letras más comunes en el lado izquierdo, elegidas para no entrar en conflicto con el lado derecho.
Unir a los candidatos restantes
Este juego es una compensación de eficiencia de consulta / velocidad de cómputo y la enumeración de los candidatos restantes puede llevar mucho tiempo sin información estructurada como caracteres específicos. Optimicé esta parte al recopilar principalmente información que no varía con el orden de las palabras, lo que me permite calcular previamente los recuentos de juego de caracteres para cada palabra individual y compararlos con los recuentos aprendidos de las consultas. Empaquete estos conteos en un entero largo, usando el comparador de igualdad de máquina y el sumador para probar todos mis recuentos de caracteres en paralelo. Esta fue una gran victoria. Puedo empacar hasta 9 recuentos en Long, pero descubrí que recopilar información adicional no valía la pena y me decidí por 6 a 7.
Una vez que se conocen los candidatos restantes, si el conjunto es razonablemente pequeño, elijo el que tenga el registro más bajo esperado de los candidatos restantes. Si el conjunto es lo suficientemente grande como para que esto lleve mucho tiempo, elijo de un pequeño conjunto de muestras.
Gracias a todos. Este fue un juego divertido y me atrajo a inscribirme en el sitio.
Actualización: código limpio para simplificar y facilitar la lectura, con pequeños ajustes en el algoritmo, lo que resulta en una puntuación mejorada.
Puntuación original: 9447 (mínimo 7, máximo 13, promedio 9,45) tiempo: 1876 segundos
El nuevo código es 278 líneas de Scala, debajo
fuente
C - total: 37171, min: 24, max: 55, tiempo: alrededor de 10 segundos
Tomé prestada la idea de Ray para encontrar la longitud de cada palabra adivinando con espacios, excepto que estoy haciendo una búsqueda binaria en lugar de lineal, lo que me ahorra muchas conjeturas.
Una vez que determine la longitud de una palabra, supongo que con la primera palabra que coincide con su longitud y registro el número de posiciones correctas. Luego selecciono la primera palabra del conjunto de todas las palabras que comparten el mismo número de posiciones con mi primera suposición que la palabra misteriosa. Para mi tercera suposición, selecciono la primera palabra del conjunto de todas las palabras que comparten el mismo número de posiciones con mi primera suposición que la palabra misteriosa y el mismo número de posiciones que mi segunda suposición con la palabra misteriosa, etc.
Usando este método, puedo adivinar cada palabra, una a la vez, en aproximadamente 5-10 conjeturas. Obviamente, la tercera palabra que tengo que hacer es un poco diferente porque no sé su longitud, pero el método es similar. Utilizo un archivo que contiene una matriz del número de posiciones que cada palabra comparte en común que he calculado previamente. Se incurre en la mayor parte del tiempo de ejecución mientras se cargan los datos calculados previamente. Puedes descargar todo aquí .
También es divertido verlo en palabras:
fuente
Python 3.4 - min: 21, max: 29, total: 25146, tiempo: 20min
min: 30, max: 235, total: 41636, tiempo: 4minActualizar:
Este método no utiliza la aleatoriedad, por lo que la puntuación no cambiará.
Primero usa conjeturas como las siguientes para encontrar el primer y segundo espacio en la respuesta.
Luego, cuenta la aparición de cada letra adivinando
aaaaa...
,bbbbb....
... Después de esto, costará unos 40 pasos. De hecho, no necesitamos probar todas las letras y podemos probarlas en orden arbitrario. En la mayoría de los casos, basta con probar 20 letras. Aquí elijo 21.Ahora conoce la longitud de la primera palabra y la segunda palabra para que pueda filtrar una lista de candidatos para estas dos palabras. Normalmente tendrá unos 100 candidatos restantes para cada uno.
Luego simplemente enumera la primera y la segunda palabra. Una vez que se enumeran las dos primeras palabras, podemos inferir todas las terceras palabras válidas, ya que sabemos que son caracteres.
Para optimizar la velocidad, uso el
concurrent.futures
para agregar multiprocesamiento al programa. Entonces necesitas Python 3 para ejecutarlo y lo probé con Python 3.4 en mi caja de Linux. Además, necesitas instalarnumpy
.fuente
Java 13,923 (mínimo: 11, máximo: 17)
Actualización: puntuación mejorada (rompió el <14 / crack avg!), Nuevo código
Publicación original
He decidido centrarme completamente en la cantidad de conjeturas en lugar del rendimiento (dadas las reglas). Esto ha resultado en un programa inteligente muy lento.
En lugar de robar de los programas conocidos, decidí escribir todo desde cero, pero resulta que algunas / la mayoría de las ideas son las mismas.
Algoritmo
Así es como funciona el mío:
Ejemplos de conjeturas
Aquí hay un ejemplo real:
Debido a que mi código nunca se enfoca realmente en palabras simples y solo recopila información sobre la frase completa, tiene que generar muchas de esas frases haciéndolo muy lento.
Código
Y finalmente aquí está el código (feo), ni siquiera intentes entenderlo, lo siento:
fuente
Java -
18.708 consultas; 2,4 segundos11.077 consultas; 125 min.Mín .: 8, Máx .: 13, Consultas efectivas: 10,095
Pasé demasiado tiempo en esto. :PAGS
El código está disponible en http://pastebin.com/7n9a50NMRev 1. disponible en http://pastebin.com/PSXU2bgaRev 2. disponible en http://pastebin.com/gRJjpbbu
Mi segunda revision. Tenía la esperanza de romper la barrera de 11K para ganar el premio, pero se me acabó el tiempo para optimizar esta bestia.
Funciona en un principio completamente separado de las dos versiones anteriores (y tarda aproximadamente 3.500 veces más en ejecutarse). El principio general es utilizar el espacio y el tamizado de caracteres pares / impares para reducir la lista de candidatos a un tamaño manejable (generalmente entre 2 y 8 millones), y luego realizar consultas repetidas con el máximo poder de discriminación (es decir, cuya distribución de salida ha maximizado la entropía).
No es la velocidad sino la memoria la principal limitación. Mi Java VM no me permite reservar un montón de más de 1,200 MB por alguna razón oscura (probablemente Windows 7), y ajusté los parámetros para darme la mejor solución posible que no agote este límite. Me molesta que una ejecución adecuada con los parámetros adecuados rompería 11K sin un aumento significativo en el tiempo de ejecución. Necesito una nueva computadora. :PAGS
Lo que me molesta es que 982 de las consultas en esta implementación son consultas inútiles de "validación". No tienen otro propósito que satisfacer la regla de que el oráculo debe devolver un valor especial de "lo entendiste" en algún momento, aunque en mi implementación la respuesta correcta se ha deducido con certeza antes de esta consulta en el 98,2% de los casos. La mayoría de los otros envíos sub-11K se basan en técnicas de filtrado que utilizan cadenas de candidatos como cadenas de consulta y, por lo tanto, no sufren la misma penalización.
Por esta razón, aunque mi recuento oficial de consultas es de 11.077 (por debajo de los líderes, siempre que su código sea compatible, fiel a las especificaciones, etc.), afirmo audazmente que mi código realiza 10.095 consultas efectivas , lo que significa que solo 10.095 consultas son realmente necesario para determinar todas las frases de paso con 100% de certeza No estoy seguro de que ninguna de las otras implementaciones coincida con eso, por lo tanto, lo consideraré mi pequeña victoria. ;)
fuente
.
."perpetually exhausting pool"
Java - min: 22, max: 41, total: 28353, tiempo: 4 segundos
El programa adivina la contraseña en 3 pasos:
También maneja un conjunto de "caracteres malos" que devuelven un resultado cero en la búsqueda, y un conjunto de "caracteres buenos" que se colocan en otro lugar de la frase de contraseña.
Debajo de un ejemplo de los valores enviados sucesivamente para adivinar, puede ver los 3 pasos:
El código:
fuente
PYTHON 2.7 - 156821 conjeturas, 0.6 segundos
Fui por la velocidad en lugar del menor número de conjeturas, aunque calculo que mi número de conjeturas sigue siendo menor de lo que sería, por ejemplo, un ataque directo del diccionario. No calculo el número de letras en la contraseña pero en el lugar equivocado, ya que mi método no lo usa, pero si cree que esto me da una ventaja injusta, lo implementaré. Simplemente comienzo con una cadena de conjetura vacía y agrego un sufijo de un solo carácter que se incrementa sobre mi lista de caracteres, verificando el resultado de 'verificar' para ver si el número de caracteres correctos es igual a la longitud de la conjetura. Por ejemplo, si la contraseña fuera 'incorrecta', supongo que:
a, b
una
a B C D
También intenté ordenar las letras por la frecuencia de las letras en inglés, lo que redujo aproximadamente el 35% del número de conjeturas, así como el tiempo. Rompí todas las contraseñas en 0.82 segundos. Las estadísticas se imprimen al final.
EDITAR: Se eliminó un +1 y -1 parásito de dos de los bucles while de las iteraciones anteriores de las pruebas, también se agregaron estadísticas adicionales para la menor cantidad de conjeturas y la mayoría de las suposiciones para una contraseña individual.
EDIT2: tabla de búsqueda agregada para la letra 'siguiente' más común, por letra. Mayor velocidad y menor recuento de conjeturas.
fuente
C ++ -
1138310989 ¡Partidos!Actualizar
Se corrigieron las pérdidas de memoria y se eliminó 1 intento más de reducir los tamaños individuales del diccionario de palabras. Toma alrededor de 50 minutos en mi Mac Pro. El código actualizado está en github.
Cambié a la estrategia de coincidencia de frases, volví a trabajar el código y lo actualicé en github https://github.com/snjyjn/mastermind
Con la coincidencia basada en frases, ¡tenemos 11383 intentos! ¡Es costoso en términos de cálculo! ¡Tampoco me gusta la estructura del código! Y todavía está muy por detrás de los demás :-(
Así es como lo estoy haciendo:
Paralelamente, agregue cadenas de prueba 'elaboradas' para obtener más información sobre la frase. La estrategia actual es la siguiente:
a. Use caracteres en orden de frecuencia en el diccionario.
si. Ya sabemos el recuento de los más frecuentes.
C. Primera cadena de prueba = siguientes 5 caracteres. Esto nos da el recuento de estos caracteres en la frase.
re. siguientes 3 cadenas de prueba = siguientes 5 caracteres cada una, cubriendo un total de 20 caracteres en 4 intentos además del primer 1 carácter. Esto también nos da el recuento de estos últimos 5 caracteres. ¡los conjuntos con 0 recuentos son excelentes para reducir el tamaño del diccionario!
mi. Ahora, para la prueba anterior que tuvo el menor recuento distinto de cero, divida la cadena en 2 y use 1 para la prueba. El recuento resultante también nos cuenta sobre la otra división.
F. Ahora repita las pruebas con caracteres (basados en 0),
Una vez que se identifican los espacios, use las restricciones hasta ahora (tantas pruebas como se puedan hacer en estos intentos) para reducir el tamaño del diccionario. También cree 3 diccionarios secundarios, 1 para cada palabra.
Ahora haga algunas conjeturas para cada palabra y pruébela.
Utilice estos resultados para reducir los tamaños de diccionario individuales.
¡Decora esto con caracteres de prueba también (después de la longitud) para obtener más restricciones en la frase! Usé 3 conjeturas en la versión final: 2 para la palabra 1 y 1 para la palabra 2
Esto lleva el diccionario a un tamaño manejable. Realice un producto cruzado, aplicando todas las restricciones como antes para crear un diccionario de frases.
Resuelva el diccionario de frases a través de una serie de conjeturas, esta vez utilizando información de coincidencia de posición y carácter.
Este enfoque nos lleva a menos de 11383 intentos:
Publicación anterior
Limpié el código y lo subí a https://github.com/snjyjn/mastermind. En el proceso, lo mejoré y todavía tengo una idea más para probar. Hay una gran diferencia con respecto a lo que hice ayer:
Las estadísticas ahora se ven así:
Publicación original
Disculpas por la 'respuesta', pero acabo de crear una cuenta y no tengo suficiente reputación para agregar un comentario.
Tengo un programa de c ++, que toma alrededor de 6.5 segundos, y 24107 intentos de coincidencia. Son alrededor de 1400 líneas de c ++. No estoy contento con la calidad del código, y lo limpiaré antes de ponerlo en otro día más o menos. Pero en interés de la comunidad y contribuyendo a la discusión, esto es lo que hago:
Lea el diccionario, obtenga información básica sobre él: longitud de palabra mínima / máxima, frecuencia de caracteres, etc.
Primero identifique espacios: tiene 2 mitades, la primera es un conjunto de consultas que continúan dividiendo el espacio (similar a un C. Chafouin):
Esto no es exactamente exacto, ya que uso la longitud mínima / máxima de la palabra, y uso los recuentos de coincidencias en cada etapa, pero entiendes la idea. En este punto, todavía no hay información suficiente para obtener los 2 espacios, pero sí tengo suficiente para reducirlo a un pequeño número de combinaciones. A partir de esas combinaciones, puedo hacer un par de consultas específicas, que lo reducirán a 1 combinación.
Primera palabra: obtenga un subdiccionario, que tiene palabras de la longitud correcta. El subdiccionario tiene sus propias estadísticas. Haga algunas conjeturas con los caracteres más frecuentes, para obtener un recuento de estos caracteres en la palabra. Reduzca el diccionario nuevamente basado en esta información. Cree una palabra de adivinanza, que tenga los caracteres más diferentes, y úsela. Cada respuesta provoca una reducción en el diccionario hasta que tengamos una coincidencia exacta, o el diccionario sea de tamaño 1.
Segunda palabra - similar a la primera palabra
Tercera palabra: esto es muy diferente de las otras 2. No tenemos información de tamaño para esto, pero tenemos todas las consultas anteriores (que hemos guardado). Estas consultas le permiten reducir el diccionario. La lógica está en las líneas de:
Use el diccionario reducido para adivinar, con los caracteres más diversos, y continúe reduciendo el diccionario hasta el tamaño 1 (como en las palabras 1 y 2).
Las estadísticas se ven así:
fuente
Ir - Total: 29546
Similar a algunos otros, con algunas optimizaciones.
AAAAAAAABBBBBBBBCCCCCCCC...ZZZZZZZZ
No es particularmente rápido.
fuente
passphases
yallWords
no están definidos.Java: 58.233
(programa de referencia)
Un bot simple para todos. Utiliza 26 conjeturas iniciales para cada frase para establecer un recuento de caracteres. Luego elimina todas las palabras que contienen letras que no se encuentran en la frase.
Luego viene un bucle masivo O (n 3 ) sobre las palabras restantes. Primero verifica cada frase candidata para ver si es un anagrama. Si es así, lo adivina, ignorando los resultados a menos que sea una combinación perfecta. Lo he visto usar entre 28-510 conjeturas para cualquier frase dada hasta ahora.
Esto es lento y depende completamente de cuántas palabras se pueden eliminar directamente de las 26 conjeturas iniciales. La mayoría de las veces deja entre 1000-4000 palabras para recorrer. En este momento se ha estado ejecutando en algún lugar alrededor de 14 horas, a un ritmo de ~ 180s / frase. Calculo que tardará 50 horas en completarse y actualizaré el puntaje en ese momento. Usted debe probablemente hacer algo más inteligente o más filiforme que esto.
(actualización) Finalmente terminó, con un poco menos de 60k conjeturas.
fuente
Java:
28,34026,185Min 15, Max 35, Tiempo 2.5s
Como mi estúpido bot finalmente terminó de ejecutarse, quería enviar algo un poco más rápido. Se ejecuta en solo unos segundos, pero obtiene una buena puntuación (no ganando> <).
Primero usa una cadena de almohadilla grande para obtener la longitud total de la frase. Luego búsqueda binaria para encontrar espacios, similar a otros. Al hacer esto, también comienza a revisar las letras de una en una (en orden de giro) para que pueda eliminar las palabras que contienen más letras que la frase completa.
Una vez que tiene la longitud de las palabras, utiliza un paso de reducción binario para reducir las opciones para las listas de palabras. Elige la lista más grande y una letra que está en aproximadamente la mitad de las palabras. Adivina una libreta de esa letra para determinar qué mitad desechar. También utiliza los resultados para deshacerse de las palabras en las otras listas que tienen demasiadas letras.
Una vez que una lista consta solo de anagramas, esto no funciona. En ese punto, simplemente los recorro hasta que solo quedan dos (o una si no se conocen las otras palabras).
Si tengo un recuento total de cuatro palabras (dos conocidas y una con dos opciones), omito las comprobaciones de reducción y anagrama y solo adivino una de las opciones como una frase completa. Si no funciona, entonces debe ser el otro, pero ahorro una conjetura el 50% del tiempo.
Aquí hay un ejemplo, que muestra la primera frase descifrada:
Y, por supuesto, el código:
fuente
C # - 10649 (mínimo 8, máximo 14, promedio: 10.6) tiempo: ~ 12 horas
Esto es lo que parece:
Solucionador
Utiliza un solucionador con visión de futuro. Antes de adivinar, estima el número de valores distintos devueltos por la mente maestra dadas las frases de contraseña posibles actualmente. La suposición que maximiza el número de resultados distintos es la utilizada.
Para la fase de adivinanzas en el espacio, considera solo las combinaciones posibles de "" y "." Para la fase de adivinación de frases, crea la lista completa de frases de contraseña posibles actualmente (por eso es tan lenta).
Recuentos de letras
Se incluyen los recuentos de letras con el hallazgo espacial. Los conjuntos de letras fueron elegidos mediante una búsqueda codiciosa, agregando una letra a la vez y muestreando frases de prueba aleatorias para ver qué tan efectivo es el conjunto.
El código está aquí: https://github.com/Tyler-Gelvin/MastermindContest
No se especificó ninguna interfaz, por lo que todas las entradas están codificadas y las pruebas unitarias son la única interfaz. La prueba "principal" es SolverFixture.SolveParallelAll.
fuente
Main
función en tu código. ¿Tiene uno?SolverFixture.SolveSerialAll
es lo que utilicé para obtener los resultados de la prueba publicados anteriormente ySolver.Solve
es el núcleo del programa. Es un proyecto de prueba de unidad sin un único punto de entrada oficial, por lo que nomain
funciona.C # - Total: 1000, Tiempo de ejecución: 305 segundos, Promedio: 24, Mín .: 14, Máx .: 32
Wow Avg's <15 es bastante bueno, bueno, no puedo superar eso, pero lo apuñalé, así que aquí está mi enfoque. Lo separé palabra por palabra y luego los resolví sucesivamente. Al determinar la longitud de las dos primeras palabras y luego hacer algunas conjeturas estratégicas (cada vez que filtraba por la palabra adivinada previamente) pude obtener la respuesta con un número relativamente pequeño de conjeturas. Durante el período en que desarrollé esto, pude optimizar la mayoría de las partes para que se preformara eficientemente (en conjeturas numéricas), pero la falla radica en la decisión de diseño inicial de resolver lógicamente una palabra a la vez, esto me hace descartar partes de conjeturas y / o no ejecutar conjeturas de la manera más eficiente posible, lo que a su vez significa que no estoy ganando este; (.
Sigue siendo un diseño interesante (al menos eso creo), una cosa a tener en cuenta con el código incluido, en ciertos casos puedo determinar la respuesta sin tener que adivinar que devuelve -1, si es necesario, simplemente descomente la línea de código etiquetada "AGREGAR GUESS AQUÍ (si es necesario)" (y sumar hasta +1 a todas mis puntuaciones :()
Algoritmo (Mi pensamiento de código de Sudo)
Así que realmente hay dos partes en esto, las dos primeras palabras y la última palabra. Puede que esto no tenga sentido para nadie más que para mí, pero he intentado agregar suficientes comentarios al código, así que tal vez tenga más sentido:
NextWord (una de las dos primeras dos palabras)
{
var lengthOfPossibleWord = Determinar la longitud de la palabra (en el código ver: forma eficiente de encontrar la longitud)
Lista de posibilidades = Todas las palabras de esa longitud (lengthOfPossibleWord)
Adivina
posibilidades = posibilidades donde (para todas las conjeturas) {El número de caracteres en la misma posición es igual a la palabra posible
(si los caracteres outOfPlace son iguales a 0), entonces, donde todos los caracteres son diferentes de la palabra posible}
}
LastWord (después de que se resuelvan los dos primeros)
{
Posibilidades de la lista = Todas las palabras filtradas por el número de caracteres offPosition en la segunda palabra (en el código, consulte: helperWords)
Adivina
posibilidades = posibilidades donde (para todas las conjeturas) {
El número de caracteres en la misma posición es igual a la palabra posible
Suma de caracteres dentro y fuera de posición == palabra posible (para todas las suposiciones)
La longitud es igual a mayor que (Suma de caracteres dentro y fuera de posición) longitud de la palabra posible
(si los caracteres outOfPlace son iguales a 0), entonces donde todos los caracteres son diferentes de la palabra posible
}
}
Código
Tenga en cuenta que para que esto funcione, debe incluir ppcg_mastermind_dict.txt y ppcg_mastermind_passes.txt en el directorio en ejecución (o en el VS en el mismo directorio y establezca "Copiar al directorio de salida" en verdadero). Realmente me disculpo por la calidad del código, todavía hay mucho trabajo por hacer en esto, aunque debería funcionar.
fuente
Python - min: 87, max: 108, total: 96063, tiempo: 4s
Esta es mi segunda publicación. Este método usa menos tiempo pero tiene un puntaje peor. Y se puede ejecutar usando:
Pasos:
. ....
,.. ...
...Cuesta alrededor de 90 conjeturas por cada contraseña.
fuente
Perl (todavía en ejecución ... a partir de ahora min / avg / max de 8 / 9,2 / 11, estimarlo en
1500300 horas de tiempo de ejecución total)Actualización: se modificaron las conjeturas iniciales para acelerarlo un poco. Se corrigió un error.
Probablemente no termine antes de que termine este concurso, pero también podría publicarlo. No determina la longitud de las palabras individuales, por lo que debe verificar todo el diccionario, lo que ... lleva algún tiempo.
Con las dos primeras suposiciones determina la longitud total, el recuento de 'e' y cuántos caracteres diferentes hay.
Luego intenta todas las combinaciones que bastan esas estadísticas, así como todas las conjeturas anteriores.
Esta versión reciente (y última) ha agregado mp y actualmente se ejecuta en un sistema de 24 núcleos.
fuente
Java 10.026 (en 2.5 horas)
Aquí está mi código optimizado, ahora multiproceso para mejorar la velocidad:
fuente