Vamos jogar carrasco?

8

De acordo com esta página , a melhor estratégia para adivinhar as palavras do carrasco em inglês é calcular as chances de cada letra em uma lista de palavras que atenda às nossas condições. Mas, como sou muito preguiçosa, não quero calcular todas as palavras do dicionário sozinha. Mas, como sei que você está sempre aqui para me ajudar, tenho certeza de que será capaz de me tornar um rei de um código que fará isso por mim. E, como meu disco rígido está quase cheio, eu gostaria do menor código possível. Isso significa que este é um código-golfe, e a submissão com a menor quantidade de bytes vencerá, mas também a mais precisa! .

Entrada / Saída

Uma palavra aleatória dessa lista de palavras será usada.

Seu programa deve aceitar, em argumentos ou por entrada do usuário (pop-ups, stdin, qualquer que seja),

  • Comprimento da palavra
  • Carta incorreta já encontrada, ou 0, se acabamos de iniciar o jogo, e você não forneceu nenhuma carta incorreta.
  • Letras já encontradas E sua posição na palavra

Exemplo: ./hangsolver 6 XBZ 1P 4P 2E 6EAqui, eu escolhi a palavra "pessoas". Para maior clareza: PE _ P _ E (Letras incorretas são XB e Z)

Isso significa que, em um jogo, terei que lançar seu script várias vezes!

A saída será uma única letra, sua próxima tentativa.

Regras

  • Aquele que adivinhar 10 palavras em menos tentativas do que os outros vencerá.
  • Em caso de empate, o código mais curto em bytes vence.
  • Se ainda houver um empate, o programa mais rápido vencerá.
  • Você pode assumir que só existem estas palavras no idioma inglês
  • Vou tentar apenas palavras válidas da lista de palavras.
  • Eu tenho um bom computador, a energia da CPU não será um problema (mas tente responder o mais rápido possível!)
  • Você não pode resolver com um solucionador on-line, mas pode fazer o download da lista de palavras ou passar como argumento. Você pode assumir que ele será nomeado "wordlist.txt" e no mesmo diretório do seu script.
  • Seu código deve ser capaz de executar em um sistema operacional comum. Pode ser windows, mac ou ubuntu / debian / CentOS ou Redhat.
  • Você não pode usar um solucionador externo.
  • No entanto, você pode encurtar o URL para a lista de palavras.
  • Este código-golfe terminará no dia primeiro de setembro.
  • Você DEVE usar o método descrito acima.

Boa sorte !

Lista de palavras encontrada aqui no SE.

WayToDoor
fonte
2
O código mais curto em bytes vencerá, com melhor palpite sendo o desempate? Isso significa que meu programa que simplesmente adivinha qualquer letra aleatória que não tenha sido usada antes derrota alguém que realmente tenta adivinhar. Você pode repensar sua pontuação ou obter respostas triviais.
Level River St
"Você DEVE usar o método descrito acima.", Cito as regras. Mas vou editar para tornar esse o principal critério de vitória
WayToDoor 17/08/2015
1
Para ser claro, "usar o método descrito acima" significa adivinhar a letra que aparece no maior número de palavras possíveis que ainda não foi adivinhada?
Isaacg
Sim, exatamente. Obrigado pela edição de erros de digitação!
WayToDoor 17/08/2015
1
Os dados de entrada no seu exemplo não devem ser "6 XBZ 1P 4P 2E 6E"?
Razvan

Respostas:

5

PowerShell, 248 246 241 bytes

$a=$args;$c=$a[0];$b=$a[2..$c];((gc wordlist.txt)-match"^$((1..$c|%{$e=,"[^$($a[1])]"*$c}{$e[$_-1]=(((@($b)-match"^$_\D")[0]-split$_)[-1],$e[$_-1]-ne'')[0]}{$e-join''}))$"-join''-split'\B'|?{!(@($b)-match$_).Count}|group|sort count)[-1].Name

Ungolfed

Bem, o máximo que pude sem alterar a maneira como funciona:

$a=$args
$c=$a[0]
$b=$a[2..$c]
(
    (gc wordlist.txt) -match "^$(
        (
            1..$c | ForEach-Object -Begin {
                $e = ,"[^$($a[1])]" * $c
            } -Process {
                $e[$_-1] = (
                    ( ( @($b) -match "^$_\D" )[0] -split $_ )[-1] , $e[$_-1] -ne ''
                )[0]
            } -End {
                $e-join''
            }
        )
    )$" -join '' -split'\B' |
    Where-Object {
        -not (@($b) -match $_).Count
    } | 
    Group-Object |
    Sort-Object count
)[-1].Name

Demolir

A abordagem adotada aqui foi primeiro gerar uma expressão regular para obter as possíveis palavras da lista de palavras. Como sei o tamanho da palavra e as letras que não funcionaram, posso fazer uma expressão regular com bastante facilidade.

Portanto, no exemplo PEOPLE, 6 letras com XBZ não fazendo parte da palavra, gostaria de gerar ^PE[^XBZ]P[^XBZ]E$.

Estou explorando o fato de que Get-Content( gc) retorna uma matriz de linhas, e o -matchoperador, quando usado com uma matriz do lado esquerdo, retorna uma matriz de correspondências em vez de um bool, para que eu possa obter rapidamente uma lista de apenas palavras que são candidatos, uma vez que eu tenho o regex.

Para gerar o regex, começo com uma matriz ( $e) da classe de caracteres correspondentes negativos com $celementos ( $csendo o número de letras na palavra). Iterando os números de 1 a 1 $c, procuro uma letra correspondente nessa posição e, se ela existir, substituo o elemento $epor essa letra.

Depois de percorrer todas as posições, a matriz final é -joineditada (com uma string vazia) e temos nosso regex.

Então agora eu tenho uma variedade de todas as palavras possíveis. Uma rápida -joinsequência vazia com isso me dá uma grande sequência concatenada de todas as palavras, a que eu divido \B(não é um limite de palavras, se eu dividir em uma sequência vazia, receberei 2 elementos em branco extras), então agora tenho uma matriz de todas as letras em todas as palavras possíveis.

Tubar isso para dentro Where-Objectpermite filtrar as letras que já foram correspondidas. Esta parte foi uma verdadeira dor. Ele teve que lidar com a lista de letras correspondentes (que incluem a posição) sendo 1 elemento, mais de 1 elemento ou 0 elementos, forçando $bprimeiro uma matriz para -matchpoder operar com todas elas, mas que (infelizmente neste caso ) retorna uma matriz, então temos que verificar .Count. Usar !(thing).Counté um pouco menor que usar (thing).Count-gt0.

Seguindo em frente, agora temos um conjunto de todos os caracteres únicos (como strings e não char) de todas as palavras possíveis, menos as letras que já foram adivinhadas corretamente.

A inserção de um canal Group-Objectme dá um objeto com as contagens de cada letra; portanto, um rápido Sort-Object countacesso facilita a obtenção da contagem mais alta. Em vez de (thing|sort count -des)[0]usarmos (thing|sort count)[-1]. No PowerShell, [-1]obtém o último elemento. Neste ponto, ainda estamos lidando com os objetos que vieram, Group-Objectentão obtemos a .Namepropriedade que é a letra que mais aparece.

Notas

  • Deve funcionar com o PowerShell v3 +; quase certamente engasgará com 2.
  • Lembre-se de quando você chama um script do PowerShell, passa argumentos com espaços, não vírgulas.
  • Embora eu não tenha visto isso nas regras, parece que todo mundo está usando o nome do arquivo, wordlist.txtcaso contrário isso poderia economizar alguns bytes.
  • Velocidade não deve ser um problema. Isso parece funcionar instantaneamente para mim. A corrida mais lenta que eu pude fazer ( .\hangman.ps1 7 0) é executada em cerca de 350ms.
briantist
fonte
1
Bem-vindo à Programação de quebra-cabeças e troca de pilha de código de golfe, ótima primeira resposta! :)
Maçaneta da porta
@ Doorknob muito obrigado!
Briantist
6

Python3, 299 bytes

import sys,collections as c;x,X,N,*Z=sys.argv;print([x for x in c.Counter(''.join([''.join(x)for x in map(set,filter(lambda l:len(l)==int(X)+1and all(x not in X.lower()for x in l)and all(l[int(x[0])-1]==x[1].lower()for x in Z),open('wordlist.txt')))]))if x not in ''.join(Z).lower()and x!='\n'][0])

certeza de que isso pode ser jogado ainda mais.

Filtra a lista de palavras para possíveis correspondências, cria um mapa de frequência de caracteres e seleciona o caractere que ocorre com mais frequência que ainda não foi selecionado.

ch3ka
fonte
Você tem muitos ''.join(..)s. Se todos os elementos internos forem cadeias de comprimento 1, você poderá alterá-lo para '..'[2::5], onde os apóstrofos são reticulares.
Kade
3

Java, 646 640 631 607 606 (curto) 790 789 779 bytes (rápido)

BAIXO

import java.util.*;class I{public static void main(String[]a)throws Exception{char[]w=a[1].toCharArray(),p,q;int l=Integer.parseInt(a[0]),i,z=w.length,j;q=new char[l];for(i=2;i<a.length;i++)q[Character.getNumericValue(a[i].charAt(0))-1]=(char)(a[i].charAt(1)+32);java.io.File u=new java.io.File("wordlist.txt");Scanner s=new Scanner(u);while(s.hasNextLine()){p=s.nextLine().toCharArray();if(p.length==l)for(i=0;i<l;i++)if(p[i]==q[i]||q[i]=='\0'){if(i==l-1)y:for(i=0;i<l;i++)for(j=0;j<z;j++)if(!(p[i]==w[j])){if(j==z-1){System.out.print(p[new String(q).indexOf('\0')]);return;}}else break y;}else{break;}}}}

VELOZES

import java.util.*;class I{public static void main(String[]a)throws Exception{char[]w=a[1].toCharArray(),p,q;int l=Integer.parseInt(a[0]),i,z=w.length,j,k,o,n[]=new int[255],r[];q=new char[l];for(i=2;i<a.length;i++)q[Character.getNumericValue(a[i].charAt(0))-1]=(char)(a[i].charAt(1)+32);String m=new String(q);java.io.File u=new java.io.File("wordlist.txt");Scanner s=new Scanner(u);while(s.hasNextLine()){p=s.nextLine().toCharArray();h:if(p.length==l)for(i=0;i<l;i++)if(p[i]==q[i]||q[i]=='\0'){if(i==l-1)y:for(i=0;i<l;i++)for(j=0;j<z;j++)if(p[i]!=w[j]){if(j==z-1){for(k=0;k<l-m.replace("\0","").length();k++)n[(int)p[new String(q).indexOf('\0',k)]]++;break h;}}else break y;}else{break;}}r=n.clone();Arrays.sort(n);for(o=0;o<255;o++)System.out.print(r[o]==n[254]?(char)o:"");}}

Coloque o arquivo da lista de palavras na pasta.

Algoritmo de versão curta

  1. Carregar Args
  2. Construa a palavra que estamos tentando adivinhar {'p', 'e', ​​'\ 0', 'p', '\ 0', 'e'}
  3. Carregar WordList
  4. Percorra cada linha do WordList
  5. Pare quando achar que a palavra inteira corresponde a essa condição, em p[i] == q[i] || q[i] == '\0'que p é uma palavra da lista de palavras (matriz de caracteres) eq é a palavra que estamos tentando adivinhar
  6. Percorra caracteres errados e compare com a palavra
  7. Imprimir o primeiro caractere ausente

Algoritmo de versão longa

  1. Passos curtos 1-7
  2. Incremente a contagem de caracteres na matriz n para os caracteres ausentes
  3. Faça um loop até que todas as palavras apareçam
  4. Imprimir o caractere que teve a contagem mais alta
Roberto Anić Banić
fonte
posso remover as importações?
Roberto Anić Banić
Posso remover importações de java no código golf?
Roberto Anić Banić
tudo bem, contanto que você especificar Devo importá-los (se não for óbvio);)
WayToDoor
Kk. Vou atualizá-lo quando voltar para casa. Vou comprar um novo roteador :) e 90 pés de Cat5e
Roberto Anić Banić
1
Não acho que funcione para palavras com mais de 9 letras. Tente usar "prospectivo" da lista de palavras com a entrada "6 XBZ 1P 5P 6E 11E" Talvez alterando o primeiro loop para q [Integer.parseInt (a [i] .substring (0, a [i] .length () - 1) ) -1] = (char) (a [i] .charAt (a [i] .length () - 1) +32); Além disso, uma dica de golfe: Tente usar o Scanner s = new Scanner (novo java.io.File ("wordlist.txt"));
bmarks
2

PHP, 346 bytes

<?php $a='array_shift';$p='preg_match';$a($v=&$argv);$w=array_fill(1,$a($v),'(.)');$c=$a($v);foreach($v as$q)$p('/(\d+)(\w)/',$q,$m)&&$w[$m[1]]=$m[2];foreach(file('wordlist.txt')as$y)if($p("/^".implode($w)."$/",$y=strtoupper(trim($y)),$m)&&(!$c||!$p("/[$c]/",$y)))for($i=0;$i++<count($m);)($v=@++$g[$m[$i].$i])&&$v>@$t&&$t=$v&&$l=$m[$i];echo @$l;

Funciona da seguinte maneira:

  1. Cria um padrão regex para corresponder às letras adivinhadas até o momento
  2. Repete cada palavra do arquivo
  3. Se a palavra corresponder ao regex, garante que não contenha uma das letras incorretas
  4. Incrementa um contador para cada uma das letras possíveis dessa palavra (com base em sua posição)
  5. Produz a letra com o contador mais alto

Premissas:

  • PHP >=5.4
  • Há um wordlist.txtarquivo na pasta atual
Razvan
fonte
php hangman.php 6 YH 2E 6E 3O 1P 4P PHP Notice: Undefined offset: 2 in ./Desktop/hangman.php on line 1 Notice: Undefined offset: 2 in ./Desktop/hangman.php on line 1Tentou fazê-lo acho que as pessoas
WayToDoor
1
Obrigado por apontar isso. Houve um pequeno erro no código. Eu atualizei (ainda 346 bytes).
Razvan
1

Powershell, 153 bytes

Inspirado pela resposta do briantist .

Como outros escritores, usei o nome do arquivo wordlist.txt. Embora fosse possível escolher um nome mais curto.

param($l,$b,$c)((sls "^$(-join(1..$l|%{$p=$c|sls "$_."|% m*
("$p"[1],"[^$b$c]")[!$p]}))$" wordlist.txt|% l*e|% t*y|group|sort c*).Name-match"[^ $c]")[-1]

Script de teste com menos golfe:

$f = {

param($length,$bad,$chars)

$wordPattern=-join(1..$length|%{                  # join all subpatterns for $_ from 1 to $length
    $c=$chars|sls "$_."|% Matches                 # find subpattern in char array
    ("$c"[1],"[^$bad$chars]")[!$c]                # return a first char of subpattern if subpattern found, or bad characters
})

# Note 1: The word subpattern is similar to 'PE[^XBZ1P 4P 2E 6E]P[^XBZ1P 4P 2E 6E]E'
#         Spaces and digits does not affect the search for letters, only letters are important.
#
# Note 2: The same applies to 0. [^0] matches any letter.
#

$matches=sls "^$wordPattern$" wordlist.txt|% Line # find matched words in file wordlist.txt and return matched string only
$groups=$matches|% toCharArray|group|sort Count   # group all chars in matched words by count
$name=$groups.Name-match"[^ $chars]"              # select property Name from all grouped elements (chars itself) and return not matched to $chars only
$name[-1]                                         # return last element in the sorted array (most frequently found char)

# Note 3: The space is important in the regexp "[^ $chars]"
#         The space makes the regexp valid if the $chars array is empty

}

&$f 7 0 2o,5e,7t
&$f 7 nl 2o,5e,7t
&$f 6 XBZ 1P,4P,2E,6E

Resultado:

c
r
l

Valores variáveis ​​para &$f 7 0 2o,5e,7t:

$WordPattern: "[^02o 5e 7t]o[^02o 5e 7t][^02o 5e 7t]e[^02o 5e 7t]t"
$Matches: concept collect comment correct connect convert consent concert
$Groups:
    Count Name                      Group
    ----- ----                      -----
        1 p                         {p}
        1 v                         {v}
        1 s                         {s}
        2 m                         {m, m}
        2 l                         {l, l}
        4 r                         {r, r, r, r}
        8 n                         {n, n, n, n...}
        8 o                         {o, o, o, o...}
        8 t                         {t, t, t, t...}
        8 e                         {e, e, e, e...}
       13 c                         {c, c, c, c...}
$name: p v s m l r n c
$name[-1]: c
return: c
confuso
fonte