Рубин
Rev 3, 55 байтов
i=1
'S, OJ1*$HCH(#%0'.bytes{|e|puts "%x"%i+=e*130&9011}
В качестве дальнейшего развития идеи Рандомры рассмотрим таблицу результатов и различий ниже. Таблицу различий можно сжать, как и раньше, и расширить, умножив на 65 = двоичный код 1000001 и применив маску 11001100110011. Однако Ruby не работает предсказуемо с 8-битными символами (он обычно интерпретирует их как Unicode.)
Удивительно, но последний столбец полностью ровный. Из-за этого при сжатии мы можем выполнить смещение прав на данные. Это гарантирует, что все коды являются 7-битными ASCII. В расширении мы просто умножаем на 65 * 2 = 130 вместо 65.
Первый столбец также полностью ровный. Поэтому мы можем добавить 1 к каждому элементу (32 к каждому байту), где необходимо, чтобы избежать каких-либо управляющих символов. Ненужный 1 удаляется с помощью маски 10001100110011 = 9011 вместо 11001100110011.
Solution 59 of document linked in question
Start0001
Out Diff
2223 2222
2433 0210
2433 0000
4445 2012
6555 2110
6577 0022
6687 0110
6887 0200
8897 2010
aa99 2202
caa9 2010
cab9 0010
cbbb 0102
cdbd 0202
cddd 0020
Хотя я использую 15 байтов для таблицы, я действительно использую только 6 бит каждого байта, что в сумме составляет 90 бит. На самом деле существует только 36 возможных значений для каждого байта, что составляет в общей сложности 2,21E23. Это соответствовало бы 77 битам энтропии.
Rev 2, 58 байт, используя инкрементальный подход Рандомры
i=0
'UPEIP@bPHPBETTEPRADT'.bytes{|e|puts "%x"%i+=e*65&819}
Наконец, что-то короче наивного решения. Инкрементальный подход Рандомры, с методом байтовой упаковки Rev 1.
Rev 1, 72 байта, версия для гольфа rev 0
Некоторые изменения были внесены в базовую линию, чтобы приспособить переупорядочение кода по причинам, связанным с игрой в гольф, но все же оно длится дольше, чем наивное решение.
i=0
'UPUIYD&!)$&V*).);c+*'.bytes{|e|i+=1;puts "%x"%(i/2*273+(e*65&819))}
Смещения кодируются в каждый символ магической строки в базе 4 в формате BAC
, то есть с 1, представляющим правый символ, с 16, представляющим средний символ, и левым символом, вставленным в позицию 4. Чтобы извлечь их, код ascii умножается на 65 (двоичный код 1000001), чтобы получить BACBAC
, затем он добавляется к 819 (двоичный код 1100110011), чтобы получить.A.B.C
.
У некоторых из кодов ascii установлен 7-й бит, т.е. они на 64 больше, чем требуется, чтобы избежать управляющих символов. Поскольку этот бит удаляется маской 819, это несущественно, за исключением случаев, когда значение C
равно 3, что вызывает перенос. Это должно быть исправлено только в одном месте (вместо того g
, чтобы использовать c
.)
Rev 0, версия без гольфа
a= %w{000 010 000 201 100 100 011 021 110 120 011 112 111 221 211 221 122 123 112 222}
i=2
a.each{|e|puts "%x"%(i/2*273+e.to_i(16));i+=1}
Выход
111
121
222
423
433
433
455
465
665
675
677
778
888
998
a99
aa9
abb
abc
bbc
ccc
объяснение
Из следующего решения я вычитаю базовую линию, давая смещение, которое я сохраняю как данные. Базовая линия восстанавливается в виде шестнадцатеричного числа в коде i/2*273
(273 десятичных = 111 шестнадцатеричных).
solution baseline offset
AAA AAA 000
ABA AAA 010
BBB BBB 000
DBC BBB 201
DCC CCC 100
DCC CCC 100
DEE DDD 011
DFE DDD 021
FFE EEE 110
FGE EEE 120
FGG FFF 011
GGH FFF 112
HHH GGG 111
IIH GGG 221
JII HHH 211
JJI HHH 221
JKK III 122
JKL III 123
KKL JJJ 112
LLL JJJ 222