9 миллиардов имен Бога

74

«9 миллиардов имен Бога» - это рассказ Артура Кларка. Речь идет о группе тибетских монахов, чей орден посвящен записи всех возможных имен Бога, написанных на их собственном алфавите. По сути, они посвящены написанию каждой возможной перестановки своего алфавита, ограниченного несколькими правилами. В этой истории монастырь нанимает инженеров для написания программы, которая сделает всю работу за них. Ваша цель - написать эту программу.

Правила:

  • Алфавит монаха использует 13 символов (по моим оценкам). Вы можете использовать ABCDEFGHIJKLMили другой набор из 13 символов.

  • Минимальная длина возможного имени - 1 символ. Максимальная длина составляет 9 символов.

  • Ни один персонаж не может повторяться более 3 раз подряд. AAABAявляется действительным именем, но AAAABэто не так.

  • Ваша программа должна распечатать (в файл) каждое возможное имя в последовательности от Aдо MMMLMMMLM, разделенных любым символом не в алфавите (переводы строки, точки с запятой, что угодно).

  • Это код-гольф, и вы можете использовать любой язык. Самое короткое решение к 1 июня 2014 года выигрывает.

Изменить: имена должны начинаться с Aи заканчиваться MMMLMMMLM, последовательно проходя через все миллиарды имен. Но конкретная последовательность зависит от вас. Вы можете сначала распечатать все однобуквенные имена, затем все двухбуквенные имена и т. Д. Или вы можете распечатать все имена, начинающиеся с A, затем все имена , начинающиеся с B, или какой-либо другой шаблон. Но человек должен иметь возможность прочитать файл и подтвердить, что они все есть и в любом логическом порядке, который вы выберете, при условии, что у них есть время.

CSturgess
источник
29
Вы пытаетесь покончить с вселенной, сэр?
Болук Папуккуоглу
8
Ссылка на историю , для всех, кто заинтересован.
ThatOneGuy
1
Это подтверждает, что количество имен в данной проблеме действительно составляет 11 459 252 883 (как найдено в программе C edc65 ). Исполняющее решение Ross Милликена в MathSE генерирует следующую полиномиальную формулу для числа имен с длиной <= 9, для переменного алфавита размера к: f(k) = k^9 + k^8 + k^7 - 5*k^6 + k^5 + k^4 + 4*k^3 - 2*k^2 + k. Реализация мудреца: goo.gl/0srwhq
res
3
@ edc65 Так 105.8GBвсе сказано и сделано! Я рад, что звезды не погасли ... или, может быть, вам нужно распечатать список, чтобы это произошло ...?
recursion.ninja

Ответы:

34

Руби, 46

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

Мое оригинальное, подобное решение было длиннее и неправильным (оно выводило числа base13, что не совсем все из-за ведущих нулей), но я оставлю это здесь, потому что оно все равно получило голоса.

1.upto(13**9){|i|(s=i.to_s 13)[/(.)\1{3}/]||puts(s)}
histocrat
источник
14
Ну, я запустил твой код около часа и получил до 2 миллиардов имен и 21 ГБ текстовый файл, прежде чем увидел это и вышел из него. Я недооценил, насколько большим будет файл.
CSturgess
2
@CSturgess Ну, Руби не самый быстрый язык для такого рода вещей ...
BenjiWiebe
8
@BenjiWiebe Но все же быстрее, чем быть написанным от руки монахами!
Турофил
1
Принятие этого, потому что у него есть больше голосов.
CSturgess
4
Не публикуйте это как отдельный ответ, так как он требует огромного объема памяти (~ 30 ТБ, если мои вычисления верны), но теоретически вы можете сократить это до 43 символов с помощьюk=*?A..?M*9;puts k-k.grep(/(.)\1{3}|[N-Z]/)
Ventero
24

C 140 177 235

Старый добрый процедурный стиль, без излишеств.
Он насчитывает (без записи) 11 459 252 883 имен за 8 минут.
Затем отредактируйте с помощью времени выполнения и размера файла имен. Наблюдайте за небом ...
Время выполнения 57 минут, размер файла 126,051,781,713 (9 символов + crlf в строке). Пожалуйста, скажите мне адрес электронной почты монахов, чтобы я мог отправить им заархивированный файл для ручной проверки ...

Править Гольф немного больше, переработал чек на повторяющиеся буквы.
Все еще не самое короткое, но по крайней мере это заканчивается и генерирует требуемый результат.
Время выполнения 51 мин, размер файла 113 637 155 697 (на этот раз без пробелов)

Примечание: очевидно, что выходной файл очень сжимаемый, но мне пришлось убить 7zip, после 36 часов работы он был на уровне 70%. Weird.

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);
            }
        }
    }
}
edc65
источник
нет #includeс?
Симон Куанг
@SimonKuang, некоторые компиляторы автоматически вставляют базовые (stdio).
Пол Дрейпер
1
@ Симон, это стандарт Си. По умолчанию глобальные объекты - это int, а глобальные функции возвращают int. Visual Studio выводит предупреждение C4013 о «путах» не определено, но оно все равно действует.
edc65
4
вписывается в твит!
CincauHangus
19

Golfscript, 58 47 знаков

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

Благодаря Питеру Тейлору я избавлен от сеппуку от того, что я не победил решение Ruby! Запустите код до 10 самостоятельно , и вот доказательство того, что он пропускает числа четыре в ряд .

Клаудиу
источник
1
Простое сохранение: используйте n+вместо ''+n. Я думаю , что это в рамках правил , чтобы использовать алфавит с управляющими символами, так что вы могли бы также заменить 65+с 13+и сохранить еще один символ, называя 13:^. И я думаю, что это 13,{ stuff [...]может быть 13,1/{ stuff 4*.
Питер Тейлор
1
Первоначально я думал, что экономия будет осуществляться через фильтр, и с небольшой работой это можно сделать. С 13,вкл может быть заменен {65+}%n+}%{ backtick {\4*/,}+78,1/%1-!},на общую экономию 8, спасая вашу жизнь.
Питер Тейлор
Пока персонаж - это то, что вы можете видеть физически, это будет работать. На самом деле вы могли бы даже включить символы новой строки как символ. Просто пока есть последовательность персонажей.
CSturgess
@PeterTaylor: Вы джентльмен и ученый!
Клаудиу
После AAAMдолжно быть AAABA, а не так BAAAB?
justhalf
18

Утилиты командной строки Bash + Linux, 43 байта

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

Это использует подобную технику , чтобы мой ответ ниже, но только рассчитывает на основании 16, и обрезает все «имена» , содержащие 0, eили f, а также те , с более чем 3 -х одинаковых цифр подряд.

Преобразовать в алфавит монаха следующим образом:

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

Bash + coreutils (dc и egrep), 46 байт

Редактировать - исправленная версия

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

Это займет некоторое время, но я думаю, что это правильно.

dcсчитает вниз от 14 ^ 9 до 1 и выводит в базу 14. egrep отфильтровывает числа с более чем 3 последовательными одинаковыми цифрами. Мы также отфильтровываем любые имена с цифрами «0», поэтому получаем правильный набор букв в именах.

Вопрос указывает, что может использоваться любой алфавит, поэтому я использую [1-9] [AD]. Но для тестирования это можно преобразовать в [AM], используя tr:

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

Это дает последовательность:

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

Обратите внимание, что эта dcкоманда требует хвостовой рекурсии для работы. Это работает на версии 1.3.95 dc (Ubuntu 12.04), но не на 1.3 (Mavericks OSX).

Цифровая травма
источник
10

APL (59)

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

Написано на собственном алфавите :) Это немного долго. Это также требует много времени для запуска 9, попробуйте с меньшим числом, чтобы проверить, если хотите.

Объяснение:

  • {... }¨⍳9: для каждого номера от 1 до 9:
    • ⍳13*⍵: получить все числа от 1 до 13^⍵
    • ¯1⌽: Повернуть список влево на 1 (у нас есть 13^⍵, 1, 2..., 13^⍵-1, который превращается в по 0, 1, 2 ...модулю 13^⍵).
    • (⍵/13)⊤: кодировать каждое число в базе 13, используя цифры
    • ⎕A[1+... ]: добавить один (массивы 1-индексированы) и искать в ⎕A(алфавит)
    • ↓⍉: превратить матрицу в вектор векторов вдоль столбцов.
  • Z←⊃,/: объединить каждый внутренний вектор векторов, дав нам список возможных имен (но он пока не соответствует правилам).
  • {... : для каждого имени проверьте, соответствует ли оно правилу 4-repeat-chars:
    • 4/¨⎕A[⍳13]: для каждого символа сгенерируйте строку из 4 символов
    • ⍷∘⍵¨: для каждой строки проверьте, присутствует ли она в
    • ∨/,↑: принять логическое или все эти тесты,
    • ~: и инвертировать его, так что это 1означает, что он соответствует правилам, а 0значит, что нет.
  • Z/⍨: выберите из Zвсех элементов, которые соответствуют ruels
  • : отобразить каждый в отдельной строке
Мэринус
источник
9
Я разочарован. Учитывая его репутацию, можно подумать, что в APL для этого будет одно-символьное решение, которое не может набирать клавиатура.
Марк
7
@ Марк, я уверен, что в APL это есть, но никто не знает, что это за персонаж :)
Пол Дрейпер,
1
нужно написать это на камне, и когда будущие люди обнаружат это, они могут подумать, что это просто примитивный письменный язык.
CincauHangus
9

Perl, 70 68 66 50 символов

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

Использование:

$ perl -E 'code' > output_file

Приятно то, что отпечатки буферизуются, поэтому сначала печатаются все односимвольные решения, затем идут двухсимвольные слова и так далее.

Зайд
источник
Лучшая вещь об этом решении - сиська слева от 1.
Дэн Ханли
8

Perl - 35 байт

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

Считая Шебанг одним байтом.

Это свободный перевод ответа гистократа .

A..1x9это немного странно; это сокращение для 'A'..'111111111'. Аккумулятор никогда не достигнет значения терминала (оно содержит только буквы в верхнем регистре), но он все равно завершится, когда станет длиннее 9 символов. Это можно проверить, например, используя 1x4вместо этого.

Primo
источник
Респект! Теперь, почему я не думал об этом? ;)
Заид
Обратите внимание, что Ruby также не нужно создавать весь диапазон для его итерации. Единственная причина, по которой код в моем комментарии требует такого огромного объема памяти, заключается в том, что он превращает диапазон в массив (чтобы его можно было использовать Array#-).
Вентеро
@Ventero Ах, да, grepсделаю это. Я не совсем свободно говорю на Ruby.
Примо
6

Пиг (Вааай слишком длинный, для языка, созданного для игры в гольф)

шепотом : 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))))

Несмотря на то, что это близко к тому, как я бы сделал это на 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

Минус конечно длинное осложнение;)

ɐɔıʇǝɥʇuʎs
источник
3

Pyth , 34 символа

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

Объяснение:

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 байт

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

Japt , 21 байт

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

Попробуйте онлайн! (ссылка рассчитывается только до 14**4.)

Как это устроено

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.

Предполагается стандартная реализация ECMAScript 2017 в качестве уровня JS (и достаточно памяти для хранения массива), где Arrayобъект может иметь максимальную 2**53-1длину.

фонтанчик для питья
источник