Os 9 bilhões de nomes de Deus


74

Os 9 bilhões de nomes de Deus é um conto de Arthur C. Clarke. É sobre um grupo de monges tibetanos cuja ordem é dedicada a escrever todos os nomes possíveis de Deus, escritos em seu próprio alfabeto. Essencialmente, eles são dedicados a escrever todas as permutações possíveis de seu alfabeto, restritas por algumas regras. Na história, o mosteiro contrata alguns engenheiros para escrever um programa para fazer todo o trabalho para eles. Seu objetivo é escrever esse programa.

Regras:

  • O alfabeto do monge usa 13 caracteres (de acordo com minhas estimativas). Você pode usar ABCDEFGHIJKLMou outro conjunto de 13 caracteres.

  • O comprimento mínimo de um nome possível é de 1 caractere. O comprimento máximo é de 9 caracteres.

  • Nenhum personagem pode repetir mais de 3 vezes seguidas. AAABAé um nome válido, mas AAAABnão é.

  • Seu programa deve imprimir (em um arquivo) todos os nomes possíveis em sequência de Apara MMMLMMMLM, separados por qualquer caractere que não esteja no alfabeto (novas linhas, ponto e vírgula, qualquer que seja).

  • Isso é código-golfe e você pode usar qualquer idioma. A solução mais curta até 1º de junho de 2014 vence.

Editar: Os nomes devem começar Ae terminar com MMMLMMMLM, progredindo por todos os bilhões de nomes sequencialmente. Mas a sequência específica é com você. Você pode imprimir todos os 1-letra nomes em primeiro lugar, em seguida, todos os nomes de 2 letras, etc. Ou você pode imprimir todos os nomes que começam com A, em seguida, todos aqueles que começam com B, ou algum outro padrão. Mas um humano deve ser capaz de ler o arquivo e confirmar se está tudo lá e na ordem lógica que você escolher, supondo que ele tenha tempo.


29
Você está tentando acabar com o universo, senhor?
Boluc Papuccuoglu

8
Link para a história , para qualquer pessoa interessada.
precisa saber é o seguinte


1
Isso verifica se o número de nomes no problema atual é de fato 11.459.252.883 (conforme encontrado no programa C do edc65 ). Execução solução de Ross Millikan em MathSE gera a seguinte fórmula polinomial para o número de nomes com comprimento <= 9, para o tamanho do alfabeto variável k: f(k) = k^9 + k^8 + k^7 - 5*k^6 + k^5 + k^4 + 4*k^3 - 2*k^2 + k. Implementação Sage: goo.gl/0srwhq
res

3
@ edc65 Então 105.8GBtudo dito e feito! Fico feliz que as estrelas não tenham saído ... ou talvez você precise imprimir a lista para que isso aconteça ...?
recursion.ninja

Respostas:


34

Ruby, 46

?A.upto(?M*9){|s|s[/(.)\1{3}|[N-Z]/]||puts(s)}

Minha solução original e semelhante foi mais longa e errada (produziu números de base13, que não são todos eles devido a zeros à esquerda), mas deixarei aqui porque ele obteve votos de qualquer maneira.

1.upto(13**9){|i|(s=i.to_s 13)[/(.)\1{3}/]||puts(s)}

14
Bem, eu executei seu código por cerca de uma hora e consegui 2 bilhões de nomes e um arquivo de texto de 21 GB antes de ver e sair. Eu subestimei o tamanho do arquivo.
CSturgess

2
@CSturgess Bem, Ruby não é a língua mais rápido para este tipo de coisa lá fora ...
BenjiWiebe

8
@BenjiWiebe Mas ainda mais rápido do que ser manuscrito por monges!
Turophile

1
Aceitando este porque tem mais votos.
CSturgess

4
Não postar isso como uma resposta em separado, uma vez que requer um imensamente grande quantidade de memória (~ 30 TB, se meu cálculo é correto), mas , em teoria, você pode encurtar isso para 43 caracteres comk=*?A..?M*9;puts k-k.grep(/(.)\1{3}|[N-Z]/)
Ventero

24

C 140 177 235

Bom e velho estilo processual, sem fantasia.
Conta (sem gravação) 11.459.252.883 nomes em 8 minutos.
A seguir edite com o tempo de execução e o tamanho do arquivo de nomes. Assista ao céu ...
Tempo de execução 57 minutos, tamanho do arquivo 126.051.781.713 (9 caracteres + crlf por linha). Diga-me o endereço de e-mail dos monges, para que eu possa enviar o arquivo compactado, para verificação manual ...

Editar Golfed um pouco mais, reformulou o cheque para repetir letras.
Ainda não é o mais curto, mas pelo menos este termina e gera a saída necessária.
Tempo de execução 51 min, tamanho do arquivo 113.637.155.697 (sem espaços em branco desta vez)

Uma observação: obviamente, o arquivo de saída é muito compressível, ainda assim eu tive que matar o 7zip, depois de trabalhar 36 horas, estava em 70%. Esquisito.

char n[]="@@@@@@@@@@";p=9,q,r;main(){while(p)if(++n[p]>77)n[p--]=65;else for(r=q=p=9;r&7;)(r+=r+(n[q]!=n[q-1])),n[--q]<65&&puts(n+q+1,r=0);}

Ungolfed

char n[]="@@@@@@@@@@";
p=9,q,r;
main()
{
    while (p)
    {
        if (++n[p] > 77)
        {
            n[p--] = 65; // when max reached, set to min and move pointer to left
        }
        else 
        {
            for (r=q=p=9; r & 7 ;) // r must start as any odd number
            {
                r += r+(n[q]!=n[q-1])); // a bitmap: 1 means a difference, 000 means 4 letters equal
                n[--q] < 65 && puts(n+q+1,r=0);
            }
        }
    }
}


@ SimonKuang, alguns compiladores colocarão os básicos (stdio) automaticamente.
Paul Draper

1
@ Simon é padrão C. Por padrão, objetos globais são int e funções globais retornam int. O Visual studio gera um aviso C4013 sobre 'put' não definido, mas é válido de qualquer maneira.
edc65

4
se encaixa em um tweet!
precisa saber é o seguinte

19

Golfscript, 58 47 caracteres

"A"13
9?,{13base{65+}%n+}%{`{\4*/,}+78,1/%1-!},

Graças a Peter Taylor, sou poupado do seppuku por não vencer a solução Ruby! Execute o código até 10 você mesmo , e aqui está a prova de que ele ignora os números quatro em linha .


1
Economia fácil: use em n+vez de ''+n. Eu acho que é dentro das regras para usar um alfabeto com caracteres de controle, então você também poderia substituir 65+com 13+e salvar outro personagem nomeando 13:^. E eu acho que 13,{ stuff [...]poderia ser 13,1/{ stuff 4*.
Peter Taylor

1
Meu pensamento inicial era que a economia seria através de um filtro e, com um pouco de trabalho, isso pode ser feito. De 13,on pode ser substituída por {65+}%n+}%{ backtick {\4*/,}+78,1/%1-!},uma economia total de 8, salvando sua vida.
Peter Taylor

Contanto que o personagem seja algo que você possa ver fisicamente, ele funcionará. Na verdade, você pode até incluir novas linhas como personagem. Contanto que haja uma sequência para os personagens.
CSturgess

@ PeterTaylor: Você é um cavalheiro e um estudioso!
Claudiu

Depois AAAMdeveria ser AAABA, e não BAAAB, certo?
justhalf

18

Utilitários de linha de comando Bash + Linux, 43 bytes

jot -w%x $[16**9]|egrep -v "[0ef]|(.)\1{3}"

Este usa uma técnica semelhante à minha resposta abaixo, mas apenas conta na base 16, e retira todos os "nomes" que contêm 0, eou fbem aqueles com mais de 3 mesmos dígitos consecutivos.

Converta no alfabeto do monge da seguinte maneira:

jot -w%x $[16**9]|egrep -v "[0ef]|(.)\1{3}" | tr 1-9a-d A-M

Bash + coreutils (dc e egrep), 46 bytes

Editar - versão corrigida

dc<<<Edo9^[p1-d0\<m]dsmx|egrep -v "0|(.)\1{3}"

Vai demorar um pouco para funcionar, mas acho que está correto.

dcconta para baixo de 14 ^ 9 para 1 e sai na base 14. egrep filtra os números com mais de 3 mesmos dígitos consecutivos. Também filtramos quaisquer nomes com dígitos "0", para obter o conjunto correto de letras nos nomes.

A pergunta especifica que qualquer alfabeto pode ser usado, por isso estou usando [1-9] [AD]. Mas para o teste, isso pode ser transformado para [AM] usando tr:

dc<<<Edo9^[p1-d0\<m]dsmx|egrep -v "0|(.)\1{3}" | tr 1-9A-D A-M

Isso produz a sequência:

MMMLMMMLM MMMLMMMLL MMMLMMMLK ... AC AB AA M L K ... C B A

Observe que este dccomando requer recursão de cauda para funcionar. Isso funciona na versão dc 1.3.95 (Ubuntu 12.04), mas não na 1.3 (OSX Mavericks).


10

APL (59)

↑Z/⍨{~∨/,↑⍷∘⍵¨4/¨⎕A[⍳13]}¨Z←⊃,/{↓⍉⎕A[1+(⍵/13)⊤¯1⌽⍳13*⍵]}¨⍳9

Escrito em seu próprio alfabeto :) É um pouco longo. Também leva muito tempo para executar 9, tente com um número menor para testar se você deseja.

Explicação:

  • {... }¨⍳9: para cada número de 1 a 9:
    • ⍳13*⍵: obtenha todos os números de 1 a 13^⍵
    • ¯1⌽: Rodar a lista para a esquerda por 1 (por isso temos 13^⍵, 1, 2, ..., 13^⍵-1, que se transforma em 0, 1, 2 ...modulo 13^⍵).
    • (⍵/13)⊤: codifique cada número na base 13 usando dígitos
    • ⎕A[1+... ]: adicione uma (as matrizes são indexadas a 1) e procure ⎕A(o alfabeto)
    • ↓⍉: transforme a matriz em um vetor de vetores ao longo das colunas.
  • Z←⊃,/: junte cada vetor interno de vetores, fornecendo uma lista de nomes possíveis (mas ainda não atende às regras).
  • {... : para cada nome, teste se ele atende à regra de 4 caracteres repetidos:
    • 4/¨⎕A[⍳13]: para cada caractere, gere uma sequência de 4 desse caractere
    • ⍷∘⍵¨: para cada sequência, teste se está presente em
    • ∨/,↑: faça o lógico ou de todos esses testes,
    • ~: e inverta-o, o que 1significa que ele atende às regras e 0significa que não.
  • Z/⍨: selecione entre Ztodos os elementos que atendem às ruínas
  • : exibir cada um em uma linha separada

9
Estou desapontado. Dada a sua reputação, você pensaria que a APL teria uma solução de um caractere para isso, que nenhum teclado poderia digitar.
Mark

7
@ Mark, estou certo de que a APL tem isso, mas ninguém sabe o que o personagem é :)
Paul Draper

1
deve-se escrever isso em uma pedra e, quando os humanos futuros encontrarem isso, eles podem pensar que é apenas uma linguagem escrita primitiva.
precisa saber é o seguinte

9

Perl, 70 68 66 50 caracteres

$"=",";map/(.)\1{3}/||say,glob$i.="{@a}"for@a=A..M

Uso:

$ perl -E 'code' > output_file

O bom é que as impressões são armazenadas em buffer, para que você obtenha todas as soluções de 1 caractere primeiro, seguidas de palavras de 2 caracteres e assim por diante.


A melhor coisa sobre esta solução é o seio à esquerda do 1.
Dan Hanly

8

Perl - 35 bytes

#!perl -l
/(.)\1{3}|[N-Z]/||print for A..1x9

Contando o shebang como um byte.

Esta é uma tradução solta da resposta do histocrata .

A..1x9é um pouco estranho; isso é uma abreviação para 'A'..'111111111'. O acumulador nunca alcançará o valor do terminal (ele contém apenas letras maiúsculas), mas ainda será encerrado quando tiver mais de 9 caracteres. Isso pode ser testado, por exemplo, usando-o 1x4.


Respeito! Agora, por que não pensei nisso? ;)
Zaid

Observe que Ruby também não precisa criar o intervalo inteiro para iterá-lo. A única razão pela qual o código no meu comentário requer uma quantidade tão grande de memória é que ele transforma o intervalo em uma matriz (para que possa ser usada Array#-).
Ventero

@ Ventero Ahh sim, grepfará isso. Eu não sou totalmente fluente em Ruby.
primo

6

Pyg (Waaay muito longo, para um idioma feito para jogar golfe)

sussurros : 101 ...

Pe(*ItCh(((J(x)for x in ItPr("ABCDEFGHIJKLM",repeat=j)if not An((i*3 in x)for i in x))for j in R(14))))

Mesmo que isso esteja próximo de como eu realmente faria isso em Python:

from itertools import *
for i in range(14):
    for j in ("".join(k) for k in product("ABCDEFGHIJKLM",repeat=i) if not any((i*3 in k) for i in k)):
        print j

Menos a complicação de linha longa, é claro;)


3

Pitão , 34 caracteres

Kf<T"n"GJKFbJI>lb9Bb~Jm+bdfXVb*Y3K

Explicação:

Kf<T"n"G        K = list of letters in the alphabet before n.
JK              J = copy of K
FbJ             For b in J:
I>lb9B          If length of b > 9: break
b               print(b)
~J              J+=
~Jm+bd          J+=map(lambda d:b+d,
       XVb*Y3   index of Y*3 in reversed(b)
      fXVb*Y3K  filter for non-zero for Y in K on function index of Y*3 in reversed(b)
~Jm+bdfXVb*Y3K  J+=map(lambda d:b+d, filter(lambda Y:index of Y*3 in reversed(b), K))

2

Python 2 - 212 bytes

from itertools import chain,product as p
a='ABCDEFGHIJKLM'
q={c*4 for c in a}
c=0
for n in chain(*(p(*([a]*l)) for l in range(1,10))):
 n=''.join(n)
 if not any(u in n for u in q):print n
 c+=1
 if c==10**9:break

0

Japonês , 21 bytes

Ep9 osE kè/0|(.)\1{3}

Experimente online! (o link calcula apenas até 14**4.)

Como funciona

Ep9 osE kè/0|(.)\1{3}/

Ep9  14**9
osE  Range from 0 to n (exclusive), mapped through base-14 conversion
kè   Remove elements that match at least once...
/0|(.)\1{3}/  the regex that matches a zero or four times same char.

Assume uma implementação padrão do ECMAScript 2017 como a camada JS (e memória suficiente para armazenar a matriz), em que um Arrayobjeto pode ter o 2**53-1comprimento máximo .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.