Objetivo
Dada uma lista de senhas de três palavras, decifre todas elas. Cada vez que você adivinhar, você terá uma pista no estilo de Mastermind , representando quantos caracteres correspondem à senha e quantos estão na posição correta. O objetivo é minimizar o número total de suposições em todos os casos de teste.
Senhas
Na lista de palavras padrão do meu sistema, escolhi aleatoriamente 10.000 palavras distintas para formar o dicionário para esse desafio. Todas as palavras consistem a-z
apenas. Este dicionário pode ser encontrado aqui (em bruto ).
A partir deste dicionário, eu gerei 1000 frases secretas que consistem em três palavras aleatórias separadas por espaço cada ( apple jacks fever
por exemplo). Palavras individuais podem ser reutilizadas em cada frase secreta ( hungry hungry hippos
). Você pode encontrar a lista de senhas aqui (em bruto ), com uma por linha.
Seu programa pode usar / analisar o arquivo de dicionário da maneira que desejar. Você não pode analisar as frases secretas para otimizar esta lista específica. Seu algoritmo ainda deve funcionar, com uma lista diferente de frases
Adivinhação
Para adivinhar, você envia uma string para um verificador. Ele deve retornar apenas :
- O número de caracteres na sua string também na frase secreta ( não na posição correta)
- O número de caracteres na posição correta
Se sua string é uma combinação perfeita, ela pode gerar algo indicando isso (a minha usa -1
para o primeiro valor).
Por exemplo, se a senha é the big cat
e você acha tiger baby mauling
, o verificador deve retornar 7,1
. 7 caracteres ( ige<space>ba<space>
) estão nas duas cadeias, mas em posições diferentes, e 1 ( t
) está na mesma posição nas duas. Observe que os espaços contam.
Eu escrevi um exemplo (leia-se: não otimizado) da função em Java, mas sinta-se à vontade para escrever seu próprio, contanto que ele forneça apenas as informações necessárias.
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};
}
Pontuação
Sua pontuação é simplesmente o número de suposições que você envia ao verificador (contando a final correta) para todas as frases de teste. A pontuação mais baixa vence.
Você deve decifrar todas as frases da lista. Se o seu programa falhar em algum deles, é inválido.
Seu programa deve ser determinístico. Se executar duas vezes no mesmo conjunto de frases secretas, retornará o mesmo resultado.
No caso de empate pela primeira vez, executarei as entradas empatadas no meu computador quatro vezes cada, e o menor tempo médio para resolver todas as 1000 vitórias. Meu computador está executando o Ubuntu 14.04, com um i7-3770K e 16 GB de algum tipo de RAM, caso isso faça diferença no seu programa. Por esse motivo, e para facilitar o teste, sua resposta deve estar em um idioma que possua um compilador / intérprete que possa ser baixado da Web gratuitamente (sem incluir testes gratuitos) e que não exija inscrição / registro.
Título adaptado do XKCD
fonte
9 0
. Isso pode demorar um pouco: PRespostas:
Tempo Scala 9146 (mínimo 7, máximo 15, média 9,15): 2000 segundos
Como muitas entradas, começo obtendo o comprimento total, depois encontrando os espaços, obtendo um pouco mais de informação, reduzindo os candidatos restantes e adivinhando frases.
Inspirado na história em quadrinhos original do xkcd, tentei aplicar meu entendimento rudimentar da teoria da informação. Há um trilhão de frases possíveis ou pouco menos de 40 bits de entropia. Defino uma meta de menos de 10 palpites por frase de teste, o que significa que precisamos aprender em média quase 5 bits por consulta (já que o último é inútil). A cada palpite, recuperamos dois números e, grosso modo, quanto maior o potencial desses números, mais esperamos aprender.
Para simplificar a lógica, eu uso cada consulta com eficácia, duas perguntas separadas para que cada sequência de palpites seja composta de duas partes, um lado esquerdo interessado no número de posições corretas (estacas pretas no cérebro) e um lado direito interessado no número de caracteres corretos ( pegs totais). Aqui está um jogo típico:
Adivinhar espaços
Cada palpite de espaço pode retornar no máximo 2 pinos pretos; Tentei construir suposições para retornar 0,1 e 2 pinos com probabilidades 1 / 4,1 / 2 e 1/4, respectivamente. Acredito que este é o melhor que você pode fazer por 1,5 bits de informações esperados. Eu decidi por uma sequência alternada para o primeiro palpite, seguido pelos gerados aleatoriamente, embora geralmente valha a pena começar a adivinhar na segunda ou terceira tentativa, pois sabemos as frequências de comprimento das palavras.
Contagem de conjuntos de caracteres de aprendizagem
Para as suposições do lado direito, escolho conjuntos de caracteres aleatórios (sempre 2 de e / i / a / s) para que o número esperado retornado seja metade do comprimento da frase. Uma variação mais alta significa mais informações e, na página da Wikipedia na distribuição binomial , estou estimando cerca de 3,5 bits por consulta (pelo menos nos primeiros antes que a informação se torne redundante). Depois que o espaçamento é conhecido, eu uso seqüências aleatórias das letras mais comuns no lado esquerdo, escolhidas para não entrar em conflito com o lado direito.
Agrupando os candidatos restantes
Este jogo é uma troca de eficiência de velocidade / consulta de computação e a enumeração dos candidatos restantes pode levar um tempo muito longo sem informações estruturadas, como caracteres específicos. Otimizei essa parte coletando principalmente informações invariantes à ordem das palavras, o que me permite pré-calcular as contagens do conjunto de caracteres para cada palavra individual e compará-las com as contagens aprendidas nas consultas. Agrupo essas contagens em um inteiro longo, usando o comparador de igualdade de máquina e somador para testar todas as minhas contagens de caracteres em parralel. Foi uma grande vitória. Posso acumular até 9 contagens no Long, mas achei que a coleta de informações adicionais não valia a pena e decidi de 6 a 7.
Depois que os candidatos restantes são conhecidos, se o conjunto for razoavelmente pequeno, eu escolho aquele com o menor log esperado de candidatos restantes. Se o conjunto for grande o suficiente para consumir esse tempo, eu escolho um pequeno conjunto de amostras.
Obrigado a todos. Este foi um jogo divertido e me atraiu a me inscrever no site.
Atualização: código limpo para simplicidade e legibilidade, com pequenos ajustes no algoritmo, resultando em uma pontuação aprimorada.
Pontuação original: 9447 (min 7, 13 máx., Média 9,45): 1876 segundos
O novo código é 278 linhas de Scala, abaixo
fonte
C - total: 37171, min: 24, máx: 55, tempo: cerca de 10 segundos
Peguei emprestada a ideia de Ray para descobrir o comprimento de cada palavra, adivinhando com espaços, exceto que estou fazendo uma pesquisa binária em vez de linear, o que me poupa muitos palpites.
Depois de determinar o comprimento de uma palavra, acho que com a primeira palavra que corresponde ao seu comprimento e registro o número de posições corretas. Depois, seleciono a primeira palavra do conjunto de todas as palavras que compartilham o mesmo número de posições com a minha primeira suposição que a palavra misteriosa. Para minha terceira suposição, seleciono a primeira palavra do conjunto de todas as palavras que compartilham o mesmo número de posições com minha primeira suposição que a palavra mistério e o mesmo número de posições que minha segunda suposição com a palavra mistério, etc.
Usando esse método, sou capaz de adivinhar cada palavra, uma de cada vez, em cerca de 5 a 10 palpites. Obviamente, a terceira palavra eu tenho que fazer um pouco diferente, porque não sei o comprimento, mas o método é semelhante. Eu uso um arquivo que contém uma matriz do número de posições que cada palavra compartilha em comum que eu pré-computei. A maior parte do tempo de execução é incorrida ao carregar os dados pré-computados. Você pode baixar tudo aqui .
Também é divertido observar as palavras:
fonte
Python 3.4 - min: 21, máx: 29, total: 25146, tempo: 20min
min: 30, máx: 235, total: 41636, tempo: 4minAtualizar:
Esse método não usa aleatoriedade para que a pontuação não seja alterada.
Primeiro, use suposições como as seguintes para encontrar o primeiro e o segundo espaços na resposta.
Então, conte a ocorrência de cada letra, adivinhando
aaaaa...
,bbbbb....
... Depois disso, custará cerca de 40 etapas. De fato, não precisamos tentar todas as letras e podemos julgá-las em ordem arbitrária. Na maioria dos casos, tentar cerca de 20 letras é suficiente. Aqui eu escolho 21.Agora, ele sabe o tamanho da primeira e da segunda palavra para poder filtrar uma lista de candidatos para essas duas palavras. Normalmente, restam cerca de 100 candidatos para cada um.
Depois, apenas enumere a primeira e a segunda palavra. Depois que as duas primeiras palavras são enumeradas, podemos inferir toda a terceira palavra válida, pois sabemos que ela conta.
Para otimizar a velocidade, eu uso o
concurrent.futures
para adicionar multiprocessamento ao programa. Então você precisa do Python 3 para executá-lo e eu o testei com o Python 3.4 na minha caixa do Linux. Além disso, você precisa instalarnumpy
.fonte
Java 13.923 (min: 11, máx: 17)
Atualização: pontuação melhorada (quebrou o <14 / crack avg!), Novo código
Postagem original
Decidi me concentrar completamente na quantidade de palpites em vez de no desempenho (de acordo com as regras). Isso resultou em um programa inteligente muito lento.
Em vez de roubar os programas conhecidos, decidi escrever tudo do zero, mas acontece que algumas / a maioria das idéias são iguais.
Algoritmo
É assim que o meu funciona:
Palpites de exemplo
Aqui está um exemplo real:
Como meu código nunca realmente se concentra em palavras únicas e apenas coleta informações sobre a frase completa, ele precisa gerar muitas dessas frases, tornando-o muito lento.
Código
E finalmente, aqui está o código (feio), nem tente entendê-lo, desculpe:
fonte
Java -
18.708 consultas; 2,4 segundos11.077 consultas; 125 min.Mín: 8, Máx: 13, Consultas efetivas: 10.095
Passei muito tempo nisso. : P
O código está disponível em http://pastebin.com/7n9a50NMRev 1. disponível em http://pastebin.com/PSXU2bgaRev 2. disponível em http://pastebin.com/gRJjpbbu
Minha segunda revisão. Eu esperava quebrar a barreira dos 11K para ganhar o prêmio, mas fiquei sem tempo para otimizar esta fera.
Ele opera em um princípio totalmente separado das duas versões anteriores (e leva aproximadamente 3.500 vezes mais tempo para ser executado). O princípio geral é usar espaço e peneiração de caracteres pares / ímpares para reduzir a lista de candidatos a um tamanho gerenciável (geralmente entre 2 a 8 milhões) e, em seguida, executar consultas repetidas com o máximo poder de discriminação (ou seja, cuja distribuição de saída tenha maximizado a entropia).
Não velocidade, mas a memória é a principal limitação. Minha Java VM não me permite reservar um monte maior que 1.200 MB por algum motivo obscuro (provavelmente o Windows 7), e ajustei os parâmetros para me fornecer a melhor solução possível que não esgote esse limite. Me incomoda que uma execução adequada com os parâmetros adequados quebre 11K sem aumento significativo no tempo de execução. Eu preciso de um computador novo. : P
O que mais me incomoda é que 982 das consultas nesta implementação são inúteis "validação". Eles não têm outro propósito senão satisfazer a regra de que o oráculo deve retornar um valor especial "você conseguiu" em algum momento, embora em minha implementação a resposta correta tenha sido deduzida com certeza antes dessa consulta em 98,2% dos casos. A maioria dos outros envios sub-11K depende de técnicas de filtragem que usam cadeias candidatas como cadeias de consulta e, portanto, não sofrem a mesma penalidade.
Por esse motivo, embora minha contagem de consultas oficial seja 11.077 (abaixo dos líderes, desde que o código deles seja compatível, fiel às especificações etc.), afirmo com ousadia que meu código faz 10.095 consultas efetivas , o que significa que apenas 10.095 consultas são realmente necessário para determinar todas as frases secretas com 100% de certeza. Não tenho certeza de que nenhuma das outras implementações corresponda a isso; portanto, considerarei minha pequena vitória. ;)
fonte
.
."perpetually exhausting pool"
Java - min: 22, máx: 41, total: 28353, tempo: 4 segundos
O programa adivinha a senha em 3 etapas:
Ele também lida com um conjunto de "caracteres inválidos" que retornam um resultado zero na pesquisa e um conjunto de "caracteres válidos" que são colocados em outro lugar na frase secreta.
Abaixo de um exemplo dos valores enviados sucessivamente para adivinhação, você pode ver as 3 etapas:
O código:
fonte
PYTHON 2.7 - 156821 palpites, 0.6 segundos
Fui pela velocidade, e não pelo número mais baixo de palpites, embora imagine que meu número ainda seja menor do que, por exemplo, um ataque direto ao dicionário. Não calculo o número de letras na senha, mas no lugar errado, pois meu método não a utiliza, mas se você acha que isso me dá uma vantagem injusta, eu a implementarei. Eu simplesmente começo com uma seqüência de suposições vazia e adiciono um único sufixo de caractere que aumenta a minha lista de caracteres, verificando o resultado de 'check' para ver se o número de caracteres corretos é igual ao comprimento da suposição. Por exemplo, se a senha fosse 'ruim', eu diria:
a, b
uma
a, b, c, d
Também tentei classificar as letras pela frequência das letras em inglês, que diminuíram cerca de 35% do número de palpites, além do tempo. Eu quebrei todas as senhas em 0,82 segundos. As estatísticas são impressas no final.
EDIT: Removido um +1 e -1 disperso de dois loops while de iterações anteriores de teste, também adicionou estatísticas adicionais para menos palpites e mais palpites para uma senha individual.
EDIT2: tabela de pesquisa adicionada para a letra 'próxima' mais comum, por letra. Maior velocidade e menor contagem de adivinhações
fonte
C ++ -
1138310989 resultados!Atualizar
Corrigimos vazamentos de memória e removemos mais 1 tentativa de reduzir os tamanhos individuais do dicionário de palavras. Demora cerca de 50 minutos no meu mac pro. O código atualizado está no github.
Mudei para a estratégia de correspondência de frase, reformulei o código e atualizei-o no github https://github.com/snjyjn/mastermind
Com a correspondência baseada em frases, reduzimos para 11383 tentativas! É caro em termos de computação! Eu também não gosto da estrutura de código! E ainda está muito atrás dos outros :-(
É assim que eu estou fazendo:
Paralelamente, acrescente sequências de teste 'criadas' para obter mais informações sobre a frase. A estratégia atual é a seguinte:
uma. Use caracteres na ordem de sua frequência no dicionário.
b. Já sabemos a contagem dos mais frequentes
c. 1º teste = próximos 5 caracteres. Isso nos dá a contagem desses caracteres na frase.
d. próximas 3 sequências de teste = próximos 5 caracteres cada, cobrindo um total de 20 caracteres em 4 tentativas, além do primeiro caractere. Isso nos dá a contagem desses cinco últimos caracteres também. conjuntos com contagem de 0 são ótimos para reduzir o tamanho do dicionário!
e Agora, para o teste anterior que teve menos contagens diferentes de zero, divida a sequência em 2 e use 1 para o teste. A contagem resultante também nos fala sobre a outra divisão.
f. Agora repita os testes com caracteres (com base em 0),
Depois que os espaços forem identificados, use as restrições até o momento (o maior número possível de testes nessas tentativas) para reduzir o tamanho do dicionário. Crie também 3 sub dicionários, 1 para cada palavra.
Agora faça algumas suposições para cada palavra e teste-a.
Use estes resultados para reduzir os tamanhos de dicionário individuais.
Decore isso com os caracteres de teste também (após o comprimento) para obter mais restrições sobre a frase! Eu usei 3 palpites na versão final - 2 para a palavra 1 e 1 para a palavra 2
Isso leva o dicionário a um tamanho gerenciável. Execute um produto cruzado, aplicando todas as restrições como antes para criar um dicionário de frases.
Resolva o dicionário de frases através de uma série de suposições - desta vez usando informações de posição e de correspondência de caracteres.
Essa abordagem nos leva a 11383 tentativas:
Postagem anterior
Limpei o código e enviei-o para https://github.com/snjyjn/mastermind No processo, aprimorei-o e ainda tenho mais uma ideia para experimentar. Há uma grande diferença em relação ao que eu fiz ontem:
As estatísticas agora se parecem com:
Correio Original
Desculpas pela 'resposta', mas acabei de criar uma conta e não tenho reputação suficiente para adicionar um comentário.
Eu tenho um programa c ++, que leva cerca de 6,5 segundos e 24107 tentativas de correspondência. São cerca de 1400 linhas de c ++. Não estou satisfeito com a qualidade do código e o limpo antes de colocá-lo em outro dia. Mas no interesse da comunidade e contribuindo para a discussão, é isso que eu faço:
Leia o dicionário, obtenha algumas informações básicas sobre ele - comprimento mínimo / máximo de palavra, frequência de caracteres etc.
Primeiro identifique espaços - Isso tem 2 metades, a primeira é um conjunto de consultas que continuam a particionar o espaço (semelhante a um C. Chafouin):
Isso não é exatamente preciso, pois eu uso o comprimento mínimo / máximo das palavras e as contagens de correspondência em cada estágio, mas você entendeu. Neste ponto, ainda não há informações suficientes para obter os 2 espaços, mas tenho o suficiente para reduzi-las a um pequeno número de combinações. A partir dessas combinações, posso fazer algumas consultas específicas, que reduzirão para uma combinação.
Primeira Palavra - Obtenha um Subdictionary, que possui palavras do tamanho certo. O subdictionary tem suas próprias estatísticas. Faça algumas suposições com os caracteres mais frequentes, para que você possa contar esses caracteres na palavra. Reduza o dicionário novamente com base nesta informação. Crie uma palavra de adivinhação, com os mais diferentes caracteres, e use-a. Cada resposta causa uma redução no dicionário até termos uma correspondência exata ou o tamanho do dicionário é 1.
Segunda palavra - semelhante à primeira palavra
Terceira palavra - isso é mais diferente do outro 2. Não temos informações de tamanho para isso, mas temos todas as consultas anteriores (que mantivemos). Essas consultas permitem reduzir o dicionário. A lógica está nas linhas de:
Use o dicionário reduzido para adivinhar, com os caracteres mais diversos, e continue a reduzir o dicionário até o tamanho 1 (como nas palavras 1 e 2).
As estatísticas se parecem com:
fonte
Go - Total: 29546
Semelhante a alguns outros, com algumas otimizações.
AAAAAAAABBBBBBBBCCCCCCCC...ZZZZZZZZ
Não é particularmente rápido.
fonte
passphases
eallWords
está indefinido.Java: 58.233
(programa de referência)
Um bot simples para que todos possam vencer. Ele usa 26 suposições iniciais para cada frase para estabelecer uma contagem de caracteres. Em seguida, elimina todas as palavras que contêm letras não encontradas na frase.
Em seguida, surge um loop O (n 3 ) massivo sobre as palavras restantes. Primeiro, ele verifica cada frase candidata para ver se é um anagrama. Nesse caso, ele adivinha, ignorando os resultados, a menos que seja uma combinação perfeita. Eu já vi usar entre 28-510 palpites para qualquer frase até agora.
Isso é lento e depende inteiramente de quantas palavras podem ser eliminadas diretamente das 26 suposições iniciais. Na maioria das vezes, deixa entre 1000 e 4000 palavras para repetir. No momento, ele está em execução há cerca de 14 horas, a uma taxa de ~ 180s / frase. Eu estimo que levará 50 horas para concluir e atualizarei a pontuação naquele momento. Você provavelmente deve fazer algo mais inteligente ou mais rápido do que isso.
(atualização) Finalmente terminou, com um pouco menos de 60k palpites.
fonte
Java:
28.34026.185Mín. 15, Máx. 35, Tempo 2,5s
Desde que meu bot estúpido finalmente terminou de correr, eu queria enviar algo um pouco mais rápido. Ele roda em apenas alguns segundos, mas obtém uma boa pontuação (não vencendo muito> <).
Primeiro, ele usa uma corda grande para obter o comprimento total da frase. Em seguida, procure binário para encontrar espaços semelhantes a outros. Ao fazer isso, ele também começa a verificar as letras uma por vez (em ordem dinâmica) para eliminar palavras que contenham mais letras do que a frase inteira.
Depois de ter o tamanho das palavras, ele usa uma etapa de redução binária para restringir as opções das listas de palavras. Ele escolhe a maior lista e uma letra que contém aproximadamente metade das palavras. Ele adivinha um bloco de palavras com essa letra para determinar qual metade jogar fora. Ele também usa os resultados para se livrar das palavras nas outras listas que contêm muitas letras.
Uma vez que uma lista consiste apenas em anagramas, isso não funciona. Nesse ponto, eu apenas os percorro até restarem apenas duas (ou uma se as outras palavras não forem conhecidas).
Se eu tiver uma contagem total de quatro palavras (duas conhecidas e uma com duas opções), pulo as verificações de redução e anagrama e adivinho uma das opções como uma frase completa. Se não funcionar, tem que ser o outro, mas economizo um palpite em 50% do tempo.
Aqui está um exemplo, mostrando a primeira frase sendo quebrada:
E, claro, o código:
fonte
C # - 10649 (mínimo 8, máximo 14, média: 10,6) tempo: ~ 12 horas
Isto é o que parece:
Solver
Ele usa um solucionador de previsão. Antes de adivinhar, ele estima o número de valores distintos retornados do cérebro, considerando as frases de acesso atualmente possíveis. O palpite que maximiza o número de resultados distintos é o utilizado.
Para a fase de adivinhação espacial, considera apenas possíveis combinações de "" e ".". Para a fase de adivinhação de frases, ela cria toda a lista de frases possíveis no momento (e é por isso que é tão lenta).
Contagens de letras
Contagens de letras são lançadas com a descoberta de espaço. Os conjuntos de letras foram escolhidos por uma pesquisa gananciosa, adicionando uma letra de cada vez e amostrando frases de teste aleatórias para verificar a eficácia do conjunto.
O código está aqui: https://github.com/Tyler-Gelvin/MastermindContest
Nenhuma interface foi especificada; portanto, todas as entradas são codificadas permanentemente e os testes de unidade são a única interface. O teste "principal" é SolverFixture.SolveParallelAll.
fonte
Main
função no seu código. Tem um?SolverFixture.SolveSerialAll
é o que eu usei para obter os resultados dos testes postados acima eSolver.Solve
é o núcleo do programa. É um projeto de teste de unidade sem um ponto de entrada oficial único, portanto, semmain
função.C # - Total: 1000, Tempo de execução: 305 segundos, Média: 24, Mín: 14, Máx: 32
Wow Avg <15 que é muito bom, bem, eu não posso superar isso, mas eu dei uma facada nele, então aqui está a minha abordagem. Eu quebrei palavra por palavra e depois resolvi-os sucessivamente. Ao determinar o tamanho das duas primeiras palavras e, em seguida, fazer algumas suposições estratégicas (sempre filtrando pela palavra adivinhada anteriormente), consegui obter a resposta com um número relativamente pequeno de suposições. Durante o período em que desenvolvi isso, eu pude otimizar a maioria das partes para realizar uma pré-forma eficiente (em suposições numéricas), mas a falha está na decisão inicial do projeto de resolver logicamente uma palavra de cada vez; isso me leva a descartar partes de palpites e / ou não executar palpites da maneira mais eficiente possível, o que, por sua vez, significa que não estou ganhando este;
Ainda um design interessante (pelo menos acho que sim), uma coisa a ser observada com o código incluído, em certos casos, posso determinar a resposta sem nunca adivinhar que retorna -1, se isso for necessário, descomente a linha de código rotulada "ADICIONE GUESS AQUI (se necessário)" (e adicione +1 a todas as minhas pontuações :()
Algoritmo (pensamento do meu código do Sudo)
Então, realmente há duas partes nisso, as duas primeiras palavras e a última palavra. Isso pode não fazer sentido para ninguém além de mim, mas tentei adicionar comentários suficientes ao código, para que talvez faça mais sentido:
NextWord (uma das duas primeiras duas palavras)
{
var lengthOfPossibleWord = Determinar o comprimento da palavra (no código, veja: maneira eficiente de encontrar o comprimento)
Possibilidades da lista = Todas as palavras desse comprimento (lengthOfPossibleWord)
Adivinhe
possibilidades = possibilidades em que (para todas as suposições) {Número de caracteres na mesma posição é igual à palavra possível
(se caracteres outOfPlace for igual a 0), onde todos os caracteres são diferentes da palavra possível}
}
LastWord (Após a resolução dos dois primeiros)
{
Possibilidades de lista = Todas as palavras filtradas pelo número de caracteres offPosition na segunda palavra (no código, consulte: helperWords)
Adivinhe
possibilidades = possibilidades onde (para todas as suposições) {
O número de caracteres na mesma posição é igual à palavra possível
Soma de caracteres dentro e fora da posição == palavra possível (para todas as suposições)
O comprimento é igual a maior que (soma dos caracteres de entrada e saída da posição) da palavra possível
(se caracteres outOfPlace for igual a 0), em que todos os caracteres serão diferentes da palavra possível
}
}
Código
Observe que, para isso funcionar, é necessário incluir o ppcg_mastermind_dict.txt e o ppcg_mastermind_passes.txt no diretório em execução (ou no VS no mesmo diretório e defina "Copy to Output Directory" como true). Eu realmente peço desculpas pela qualidade do código que ainda há muito trabalho a ser feito sobre isso, mas deve funcionar.
fonte
Python - min: 87, máx: 108, total: 96063, tempo: 4s
Esta é a minha segunda postagem. Esse método usa menos tempo, mas tem uma pontuação pior. E pode ser executado usando:
Passos:
. ....
,.. ...
...Custou cerca de 90 palpites para cada senha.
fonte
Perl (ainda em execução ... a partir de agora min / avg / max de 8 / 9,2 / 11, calcule em
1500300 horas de tempo de execução total)Atualização: Alteradas as suposições iniciais para acelerar um pouco. Corrigido um erro.
Provavelmente não vai terminar antes deste concurso, mas eu também posso publicá-lo. Ele não determina o comprimento das palavras individuais, portanto, é necessário verificar o dicionário inteiro, o que ... leva algum tempo.
Com as duas primeiras suposições, determina o comprimento total, a contagem de 'e' e quantos caracteres diferentes existem.
Em seguida, tenta todas as combinações que são suficientes para essas estatísticas, bem como todas as suposições anteriores.
Esta versão recente (e última) adicionou mp e atualmente roda em um sistema de 24 núcleos.
fonte
Java 10.026 (em 2,5 horas)
Aqui está o meu código otimizado, agora multiencadeado para melhorar a velocidade:
fonte