ASCII искусство распаковки из числа base-n


24

Это вдохновлено ответом 05AB1E от Magic Octupus Urn .

Имеется два аргумента, положительное целое число и строка / список символов:

  1. Переведите число в base-n, где n - длина строки.
  2. Для каждого символа замените каждое появление индекса этого символа в числе base-n этим символом.
  3. Распечатать или вернуть новую строку.

Примеры:

Input:
2740, ["|","_"]
2740 -> 101010110100 in base 2
     -> Replace 0s with "|" and 1s with "_"
Output: _|_|_|__|_||

Input:
698911, ["c","h","a","o"]
698911 ->  2222220133 in base 4
       ->  Replace 0s with "c", 1s with "h", 2s with "a", and 3s with "o"
Output -> "aaaaaachoo"

Input:
1928149325670647244912100789213626616560861130859431492905908574660758972167966, [" ","\n","|","_","-"]
Output:
    __   __    
   |  |_|  |   
___|       |___
-   -   -   -  
 - - - - - - - 
- - - - - - - -
_______________

Input: 3446503265645381015412, [':', '\n', '.', '_', '=', ' ', ')', '(', ',']
Output:
_===_
(.,.)
( : )
( : )

Правила:

  • IO гибкий .
    • Вы можете взять число в любой базе, если оно согласовано между входами
    • Список символов должен быть индексирован 0, хотя 0 - первый символ, а n-1 - последний.
  • Возможными символами могут быть любые печатные символы ASCII, а также пробелы, такие как символы табуляции и перевода строки.
  • Данный список символов будет иметь длину в диапазоне 2-10включительно. То есть самое маленькое основание является двоичным, а самое большое - десятичным (здесь не надоедливые буквы )
  • Стандартные лазейки запрещены
  • Не стесняйтесь отвечать, даже если ваш язык не выдерживает больших тестовых случаев.

Поскольку это , выигрывает самый короткий код для каждого языка. ( Я знаю, что у всех языков игры в гольф есть встроенные встроенные байты ;)



3
Да, я чувствую себя честью. 05AB1E ascii-art была моей любимой некоторое время назад.
Волшебная Урна Осьминога

Вы можете создать новый вызов: найти перестановку символов в массиве, чтобы минимизировать количество :)
mazzy

Ответы:


8

05AB1E , 7 6 байтов

gв¹sèJ

Поскольку он был вдохновлен ответом 05AB1E, ответ, данный в 05AB1E, кажется подходящим. :)

-1 байт благодаря @Enigma , удалив foreach и сделав это неявно.

Попробуйте онлайн или проверьте все контрольные примеры .

Объяснение:

g         # `l`: Take the length of the first (string) input
 в        # And then take the second input in base `l`
          # For each digit `y` of this base-converted number:
  ¹sè     #  Push the `y`'th character of the first input
     J    # Join everything together (and output implicitly)

1
gв¹sèJсохранить байт.
Emigna

@ Emigna Спасибо. Не могу поверить, что я не думал о ¹sèсебе сейчас (я знал, что изменение на ?a Jдаст тот же результат в этом случае.)
Кевин Круйссен

6

Java 8, 72 50 байт

a->n->n.toString(a.length).chars().map(c->a[c-48])

-22 байта благодаря @ OlivierGrégoire , возвращая IntStreamвместо печати напрямую.

Попробуйте онлайн .

Объяснение:

a->n->                  // Method with char-array and BigInteger parameters
  n.toString(a.length)  //  Convert the input-number to Base `amount_of_characters`
   .chars()             //  Loop over it's digits (as characters)
   .map(c->a[c          //   Convert each character to the `i`'th character of the input
              -48])     //   by first converting the digit-character to index-integer `i`

2
a->n->n.toString(a.length).chars().map(c->a[c-48])(50 байт), поскольку "IO гибок"
Оливье Грегуар

String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69 байт) рекурсивный, для развлечения.
Оливье Грегуар

6

Python 3 , 49 байт

Пока не могу комментировать, поэтому выкладываю ответ Python 2, адаптированный к Python 3.5.

f=lambda n,s:n and f(n//len(s),s)+s[n%len(s)]or''

2
Добро пожаловать в PPCG! Не стесняйтесь включать ссылку TIO, чтобы помочь продемонстрировать ваше решение.
Джо Кинг,

5

Japt, 2 байта

Может принимать второй вход в виде массива или строки. Сбой последних 2 тестовых случаев, так как числа превышают максимальное целое число JavaScript. Замените sна, ìчтобы вместо него вывести массив символов.

sV

Попытайся


5

Haskell , 40 39 байт

0!_=[]
n!l=cycle l!!n:div n(length l)!l

Попробуйте онлайн!

Поскольку Intтип Хаскелла ограничен 9223372036854775807, это не подходит для больших чисел.

-1 байт благодаря Лайкони .

Ungolfed

(!) :: Int -> [Char] -> [Char]

0 ! _ = []  -- If the number is 0, we reached the end. Base case: empty string
n ! l = 
  let newN = (n `div` length l) in   -- divide n by the base
    cycle l!!n                       -- return the char encoded by the LSD ... 
    : newN!l                         -- ... prepended to the rest of the output (computed recursively)

Попробуйте онлайн!


Хорошая идея использовать cycleвместо mod! div n(length l)сохраняет байт.
Лайкони

4

MATL , 2 байта

YA

Попробуйте онлайн!

Входные данные - это число и строка.

Сбой для превышения чисел 2^53из-за точности с плавающей точкой.

объяснение

Что YAзнаете, встроенная (базовая конверсия с указанными целевыми символами).


4

JavaScript (ES6), 48 байт

Вводит синтаксис карри (c)(n), где c - список символов, а n - целое число.

Безопасно только для n <2 53 .

c=>n=>n.toString(c.length).replace(/./g,i=>c[i])

Попробуйте онлайн!


JavaScript (ES6), 99 байт

С поддержкой больших целых

Вводит в синтаксисе карри (c)(a), где c - список символов, a - список десятичных цифр (в виде целых чисел).

c=>g=(a,p=0,b=c.length,r=0)=>1/a[p]?g(a.map((d,i)=>(r=d+r*10,d=r/b|0,r%=b,d|i-p||p++,d)),p)+c[r]:''

Попробуйте онлайн!


4

32-разрядный машинный код x86 (32-разрядные целые числа): 17 байт.

(также см. другие версии ниже, включая 16 байтов для 32-битной или 64-битной версии с соглашением о вызовах DF = 1.)

Вызывающая сторона передает аргументы в регистрах, включая указатель на конец выходного буфера (как мой ответ C ; см. Его_itoa для обоснования и объяснения алгоритма.) Это делает внутренняя часть glibc , так что это не просто придумано для code-golf. Регистры передачи аргументов близки к x86-64 System V, за исключением того, что у нас есть аргумент в EAX вместо EDX.

По возвращении EDI указывает на первый байт строки C с нулем в конце в выходном буфере. Обычный регистр возвращаемых значений - EAX / RAX, но на языке ассемблера вы можете использовать любое удобное для вызова соглашение о вызовах. ( xchg eax,ediв конце добавил бы 1 байт).

Вызывающий может вычислить явную длину, если он хочет, из buffer_end - edi. Но я не думаю, что мы можем оправдать исключение терминатора, если функция не возвращает оба указателя start + end или указатель + length. Это сэкономило бы 3 байта в этой версии, но я не думаю, что это оправдано.

  • EAX = n = номер для декодирования. (Для idiv. Другие аргументы не являются неявными операндами.)
  • EDI = конец буфера вывода (64-битная версия все еще использует dec edi, поэтому должна быть в низком 4GiB)
  • ESI / RSI = таблица поиска, она же LUT. не забитый
  • ECX = длина стола = база. не забитый

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (Отредактировано вручную, чтобы уменьшить комментарии, нумерация строк странная.)

   32-bit: 17 bytes        ;  64-bit: 18 bytes
                           ; same source assembles as 32 or 64-bit
 3                         %ifidn __OUTPUT_FORMAT__, elf32
 5                         %define rdi edi
 6   address               %define rsi esi
11          machine        %endif
14          code           %define DEF(funcname) funcname: global funcname
16          bytes           
22                         ;;; returns: pointer in RDI to the start of a 0-terminated string
24                         ;;; clobbers:; EDX (tmp remainder)
25                         DEF(ascii_compress_nostring)
27 00000000 C60700             mov     BYTE [rdi], 0
28                         .loop:                    ; do{
29 00000003 99                 cdq                    ; 1 byte shorter than   xor edx,edx / div
30 00000004 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
31                         
32 00000006 8A1416             mov     dl, [rsi + rdx]   ; dl = LUT[n%B]
33 00000009 4F                 dec     edi               ; --output  ; 2B in x86-64
34 0000000A 8817               mov     [rdi], dl         ; *output = dl
35                         
36 0000000C 85C0               test    eax,eax           ; div/idiv don't write flags in practice, and the manual says they're undefined.
37 0000000E 75F3               jnz     .loop         ; }while(n);
38                         
39 00000010 C3                 ret
           0x11 bytes = 17
40 00000011 11             .size: db $ - .start

Удивительно, что самая простая версия, в которой практически нет компромиссов между скоростью и размером, является наименьшей, но std/ cldстоит 2 байта, чтобы использовать stosbее в порядке убывания и при этом следовать общему соглашению о вызовах DF = 0. (И STOS уменьшается после сохранения, оставляя указатель, указывающий один байт, слишком низким при выходе из цикла, что обходится нам лишними байтами для обхода.)

Версии:

Я придумал 4 существенно разных уловки реализации (использование простой movзагрузки / сохранения (см. Выше), использование lea/ movsb(аккуратно, но не оптимально), использование xchg/ xlatb/ stosb/ xchg, и тот, который входит в цикл с хаком с перекрывающимися инструкциями. См. Код ниже) , Последнему нужен трейлинг 0в таблице поиска для копирования в качестве ограничителя выходной строки, поэтому я считаю это как +1 байт. В зависимости от 32/64-битного (1 байт incили нет) и от того, можем ли мы предположить, что вызывающая сторона устанавливает DF = 1 ( stosbнисходящий) или что-то еще, разные версии (привязаны) являются самыми короткими.

DF = 1 для сохранения в порядке убывания делает выигрыш для xchg / stosb / xchg, но вызывающий часто этого не хочет; Это похоже на то, чтобы разгрузить вызывающего абонента трудным образом. (В отличие от пользовательских регистров передачи аргументов и возвращаемых значений, которые обычно не требуют от вызывающего asm дополнительной работы.) Но в 64-битном коде, cld/ scasbработает как inc rdi, избегая усечения выходного указателя до 32-битного, поэтому иногда неудобно сохранять DF = 1 в 64-битных чистых функциях. , (Указатели на статический код / ​​данные являются 32-разрядными в исполняемых файлах x86-64 без PIE в Linux и всегда в Linux x32 ABI, поэтому версия x86-64, использующая 32-разрядные указатели, может использоваться в некоторых случаях.) В любом случае, это взаимодействие делает интересным взглянуть на различные комбинации требований.

  • IA32 с DF = 0 при соглашении о вызове на вход / выход: 17B ( nostring) .
  • IA32: 16B (с условным обозначением DF = 1: stosb_edx_argили skew) ; или с входящим DF = dontcare, оставляя его установленным: 16 + 1Bstosb_decode_overlap или 17Bstosb_edx_arg
  • x86-64 с 64-разрядными указателями и DF = 0 при соглашении о вызове входа / выхода: 17 + 1 байт ( stosb_decode_overlap) , 18B ( stosb_edx_argили skew)
  • x86-64 с 64-битными указателями, другая обработка DF: 16B (DF = 1 skew) , 17B ( nostringс DF = 1, используя scasbвместо dec). 18B ( stosb_edx_argсохранение DF = 1 с 3 байтами inc rdi).

    Или если мы разрешаем возвращать указатель на 1 байт перед строкой, 15B ( stosb_edx_argбез incконца в конце). Все готово к повторному вызову и расширению еще одной строки в буфере с другой базой / таблицей ... Но это имело бы больше смысла, если бы мы не хранили и завершение 0, и вы могли бы поместить тело функции в цикл, так что это действительно отдельная проблема.

  • x86-64 с 32-разрядным выходным указателем, соглашение о вызовах DF = 0: улучшения по сравнению с 64-разрядным выходным указателем нет, но nostringтеперь 18B ( ) связывается.

  • x86-64 с 32-разрядным выходным указателем: без улучшений по сравнению с лучшими версиями 64-разрядного указателя, поэтому 16B (DF = 1 skew). Или установить DF = 1 и оставить его, 17B для skewс, stdно нет cld. Или 17 + 1B для stosb_decode_overlapс inc ediв конце вместо cld/ scasb.

С соглашением о вызовах DF = 1: 16 байтов (IA32 или x86-64)

Требует DF = 1 на входе, оставляет его установленным. Едва ли правдоподобно , по крайней мере, для каждой функции. Делает то же самое, что и вышеупомянутая версия, но с xchg для получения остатка в / из AL до / после XLATB (поиск таблицы с R / EBX в качестве базы) и STOSB ( *output-- = al).

При нормальном DF = 0 на входной / выходной конвенции, / / версия 18 байт для 32 и 64-битного кода, и является 64-битным (работает с выходным указателем 64-битной).stdcldscasb

Обратите внимание, что входные аргументы находятся в разных регистрах, включая RBX для таблицы (для xlatb). Также обратите внимание, что этот цикл начинается с сохранения AL и заканчивается последним еще не сохраненным символом (следовательно, movв конце). Таким образом, петля "перекошена" относительно других, отсюда и название.

                            ;DF=1 version.  Uncomment std/cld for DF=0
                            ;32-bit and 64-bit: 16B
157                         DEF(ascii_compress_skew)
158                         ;;; inputs
159                             ;; O in RDI = end of output buffer
160                             ;; I in RBX = lookup table  for xlatb
161                             ;; n in EDX = number to decode
162                             ;; B in ECX = length of table = modulus
163                         ;;; returns: pointer in RDI to the start of a 0-terminated string
164                         ;;; clobbers:; EDX=0, EAX=last char
165                         .start:
166                         ;    std
167 00000060 31C0               xor    eax,eax
168                         .loop:                    ; do{
169 00000062 AA                 stosb
170 00000063 92                 xchg    eax, edx
171                         
172 00000064 99                 cdq                    ; 1 byte shorter than   xor edx,edx / div
173 00000065 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
174                         
175 00000067 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
176 00000068 D7                 xlatb                  ; al = byte [rbx + al]
177                         
178 00000069 85D2               test    edx,edx
179 0000006B 75F5               jnz     .loop         ; }while(n = n/B);
180                         
181 0000006D 8807               mov     [rdi], al     ; stosb would move RDI away
182                         ;    cld
183 0000006F C3                 ret

184 00000070 10             .size: db $ - .start

Подобная нескошенная версия выходит за рамки EDI / RDI, а затем исправляет ее.

                            ; 32-bit DF=1: 16B    64-bit: 17B (or 18B for DF=0)
70                         DEF(ascii_compress_stosb_edx_arg)  ; x86-64 SysV arg passing, but returns in RDI
71                             ;; O in RDI = end of output buffer
72                             ;; I in RBX = lookup table  for xlatb
73                             ;; n in EDX = number to decode
74                             ;; B in ECX = length of table
75                         ;;; clobbers EAX,EDX, preserves DF
76                             ; 32-bit mode: a DF=1 convention would save 2B (use inc edi instead of cld/scasb)
77                             ; 32-bit mode: call-clobbered DF would save 1B (still need STD, but INC EDI saves 1)
79                         .start:
80 00000040 31C0               xor     eax,eax
81                         ;    std
82 00000042 AA                 stosb
83                         .loop:
84 00000043 92                 xchg    eax, edx
85 00000044 99                 cdq
86 00000045 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
87                         
88 00000047 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
89 00000048 D7                 xlatb                  ; al = byte [rbx + al]
90 00000049 AA                 stosb                  ; *output-- = al
91                         
92 0000004A 85D2               test    edx,edx
93 0000004C 75F5               jnz     .loop
94                         
95 0000004E 47                 inc    edi
96                             ;; cld
97                             ;; scasb          ; rdi++
98 0000004F C3                 ret
99 00000050 10             .size: db $ - .start
    16 bytes for the 32-bit DF=1 version

Я попробовал альтернативную версию этого с lea esi, [rbx+rdx]/ movsbв качестве тела внутреннего цикла. (RSI сбрасывается при каждой итерации, но RDI уменьшается). Но он не может использовать xor-zero / stos для терминатора, поэтому он на 1 байт больше. (И это не 64-битная чистота для таблицы поиска без префикса REX на LEA.)


LUT с явной длиной и разделителем 0: 16 + 1 байт (32-разрядный)

Эта версия устанавливает DF = 1 и оставляет это так. Я считаю дополнительный байт LUT, необходимый как часть общего количества байтов.

Крутой трюк здесь состоит в том, чтобы одни и те же байты декодировали двумя разными способами . Мы попадаем в середину цикла с остаток = основание и частное = входное число, и копировать терминатор 0 на место.

В первый раз через функцию первые 3 байта цикла потребляются как старшие байты disp32 для LEA. Этот LEA копирует базу (модуль) в EDX, idivпроизводит остаток для последующих итераций.

2-й байт idiv ebp- FDэто код операции для stdинструкции, необходимой для работы этой функции. (Это было счастливое открытие. Я смотрел на это divранее, что отличается от idivиспользования /rбитов в ModRM. 2-й байт div epbдекодирования как cmc, что безвредно, но не полезно. Но с idiv ebpпомощью мы можем на самом деле удалить stdсверху функции.)

Обратите внимание, что входные регистры снова отличаются: EBP для базы.

103                         DEF(ascii_compress_stosb_decode_overlap)
104                         ;;; inputs
105                             ;; n in EAX = number to decode
106                             ;; O in RDI = end of output buffer
107                             ;; I in RBX = lookup table, 0-terminated.  (first iter copies LUT[base] as output terminator)
108                             ;; B in EBP = base = length of table
109                         ;;; returns: pointer in RDI to the start of a 0-terminated string
110                         ;;; clobbers: EDX (=0), EAX,  DF
111                             ;; Or a DF=1 convention allows idiv ecx (STC).  Or we could put xchg after stos and not run IDIV's modRM
112                         .start:
117                             ;2nd byte of div ebx = repz.  edx=repnz.
118                             ;            div ebp = cmc.   ecx=int1 = icebp (hardware-debug trap)
119                             ;2nd byte of idiv ebp = std = 0xfd.  ecx=stc
125                         
126                             ;lea    edx, [dword 0 + ebp]
127 00000040 8D9500             db  0x8d, 0x95, 0   ; opcode, modrm, 0 for lea edx, [rbp+disp32].  low byte = 0 so DL = BPL+0 = base
128                             ; skips xchg, cdq, and idiv.
129                             ; decode starts with the 2nd byte of idiv ebp, which decodes as the STD we need
130                         .loop:
131 00000043 92                 xchg    eax, edx
132 00000044 99                 cdq
133 00000045 F7FD               idiv    ebp            ; edx=n%B   eax=n/B;
134                             ;; on loop entry, 2nd byte of idiv ebp runs as STD.  n in EAX, like after idiv.  base in edx (fake remainder)
135                         
136 00000047 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
137 00000048 D7                 xlatb                  ; al = byte [rbx + al]
138                         .do_stos:
139 00000049 AA                 stosb                  ; *output-- = al
140                         
141 0000004A 85D2               test    edx,edx
142 0000004C 75F5               jnz     .loop
143                         
144                         %ifidn __OUTPUT_FORMAT__, elf32
145 0000004E 47                 inc     edi         ; saves a byte in 32-bit.  Makes DF call-clobbered instead of normal DF=0
146                         %else
147                             cld
148                             scasb          ; rdi++
149                         %endif
150                         
151 0000004F C3                 ret
152 00000050 10             .size: db $ - .start
153 00000051 01                     db 1   ; +1 because we require an extra LUT byte
       # 16+1 bytes for a 32-bit version.
       # 17+1 bytes for a 64-bit version that ends with DF=0

Этот трюк с перекрывающимся декодированием также можно использовать с cmp eax, imm32: для эффективного перехода вперед на 4 байта требуется всего 1 байт, только флаги засорения. (Это ужасно для производительности на процессорах, которые отмечают границы команд в кеше L1i, кстати).

Но здесь мы используем 3 байта, чтобы скопировать регистр и перейти в цикл. Обычно это занимает 2 + 2 (mov + jmp) и позволяет нам перейти в цикл прямо перед STOS, а не перед XLATB. Но тогда нам понадобится отдельная ЗППП, и это будет не очень интересно.

Попробуйте онлайн! (с _startвызывающим абонентом, который использует sys_writeрезультат)

Лучше всего для отладки запускать его straceили выводить в шестнадцатеричном формате, чтобы вы могли убедиться, что \0в нужном месте есть терминатор и так далее. Но вы можете видеть, что это на самом деле работает, и производить AAAAAACHOOдля ввода

num  equ 698911
table:  db "CHAO"
%endif
    tablen equ $ - table
    db 0  ; "terminator" needed by ascii_compress_stosb_decode_overlap

(На самом деле xxAAAAAACHOO\0x\0\0..., потому что мы выгружаем из буфера на 2 байта ранее до фиксированной длины. Таким образом, мы можем видеть, что функция записала байты, которые она должна, и не наступила ни на один байт, которого она не должна иметь. указатель начала, переданный функции, был вторым последним xсимволом, за которым следовали нули.)


3

Желе , 4 байта

ṙ1ṃ@

Попробуйте онлайн!

буквально встроенный для этого. Остальные три байта составляют индексирование Jelly на основе одного.


Из любопытства, почему Jelly даже имеет встроенную « декомпрессию базы; преобразовать x в базовую длину (y), а затем индексировать в y. »? Это для очень исключительных случаев, когда база, которую вы хотите преобразовать, и длина строки / целого числа / списка равны? Когда я ищу его, я могу найти только три ответа, используя его: 1 ; 2 ; 3 . Что-то странное, встроенное в каждый день. : S
Кевин Круйссен

3
@KevinCruijssen очень полезно, например, когда вы хотите преобразовать N в шестнадцатеричное число, используя шестнадцатеричные буквы вместо списка чисел.
г-н Xcoder

@KevinCruijssen Это метод сжатия строк. В первом примере желаемая строка есть “sspspdspdspfdspfdsp”, но “çƥ÷£ḟ’ṃ“spdf”¤вы сохраните шесть байтов. Это особенно полезно с базовыми 250 номерами
Желе


3

Древесный уголь , 3 1 байта

θη

Попробуйте онлайн! Ссылка на подробную версию кода. Редактировать: Сохранено 2 байта благодаря @ ASCII-only. Предыдущая версия до добавления встроенной функции, 8 байт:

⭆↨θLη§ηι

Попробуйте онлайн! Ссылка на подробную версию кода. Объяснение:

    η       Second input
   L        Length
  θ         First input
 ↨          Base convert to array
⭆           Map over values and join
      η     Second input
       ι    Current value
     §      Index into list
            Implicitly print result

На самом деле он должен уже работать, но, видимо, я снова все испортил> _>
Только для ASCII

Кроме того, фактически это будет 1 байт : P (хотя в настоящее время он не работает, поэтому я не использую число и строковый массив в качестве аргументов) (также мне интересно, как (не) полезен неявный ввод)
ASCII-only

@ ASCII-only Разве вы не имеете в виду «1 байт» (смотрите вывод -vl ;-) Кроме того, неявный ввод в Charcoal кажется почти бесполезным, за исключением подобных задач.
Нил

1
@ ASCII-только Нейтральный байт вместо единственного байта - это то, что имеет в виду Нейл. ;) Что касается вашего 1-байтового ответа, почему вычеркнуты θη? Выглядит немного запутанно. Почему бы просто не удалить его полностью и не уйти ?
Кевин Круйссен

1
@Nit Я дважды проверил, и встроенное было добавлено до того, как был задан вопрос, но я не понял, потому что в нем была ошибка.
Нил

3

D 112 байт

import std.conv;C u(C,I)(I n,C b){C t;for(I l=b.length;n;n/=l)t=to!C(n%l)~t;foreach(ref c;t)c=b[c-48];return t;}

Попробуйте онлайн!

Это порт ответа C ++ от HatsuPointerKun

Стиль вызова: u(ulong(n), to!(char[])(b))где nи где bлевый и правый аргументы

D конкретные вещи

К сожалению, нам нужно импортировать, std.convчтобы делать любые преобразования типов сверх очень простых преобразований типов.

Используя golfy системы шаблонов, и давая функцию необходимых типов (поэтому называть это не просто u(n,b)), мы можем сократить вхождения char[]и ulongв 1байтах каждого, когда внутри й функций.

D инициализирует наши типы для нас, поэтому C t;сокращенно дляC t=cast(char[])([])

to!Cпреобразует целое число n%lв массив символов (используя кодовые точки) и ~выполняет конкатенацию

foreach(ref c;t)похоже на for(... : ...)цикл C ++ , но немного дольше. refпохоже &, он обрабатывается cкак скопированный по ссылке (т. е. мы можем изменить t). К счастью, D выводит тип cбез какого-либо ключевого слова, обозначающего тип.



3

C ++, 150 144 байта, uint64ввод

-6 байт благодаря Захари

#include<string>
using s=std::string;s u(uint64_t n,s b){s t;for(;n;n/=b.size())t=std::to_string(n%b.size())+t;for(auto&a:t)a=b[a-48];return t;}

Использование переменной для хранения размера увеличит количество пользователей на 1

Для вызова функции:

u(2740, "|_")

Сначала число, второе - строка (массив символов)

Тестовые случаи:

std::cout << u(2740, "|_") << '\n' << u(698911, "chao") << '\n';
return 0;

1
3 байта, чтобы сбрить: вам не нужно пространство после #include, вы можете изменить ;;на просто ;, и '0'может быть просто48
Zacharý

1
Кроме того, цикл while может быть forциклом:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
Zacharý

@ceilingcat, я забыл, что b.size()в этом цикле ничего не меняется.
Захари

@ceilingcat Это увеличило бы байтовый счет на 1, вместо того, чтобы
уменьшать

2

Веточка, 66 байт

Создан, macroкоторый должен быть importвставлен в шаблон.

{%macro d(n,c)%}{%for N in n|split%}{{c[N]}}{%endfor%}{%endmacro%}

Ожидаемые значения:

Для первых аргументов ( n):

  • количество
  • строка

Для второго аргумента (c ):

  • Массив чисел
  • Массив строк

Как использовать:

  • Создать .twig файл
  • Добавлять {% import 'file.twig' as uncompress %}
  • Вызовите макрос uncompress.d()

Ungolfed (нефункциональный):

{% macro d(numbers, chars) %}
    {% for number in numbers|split %}
        {{ chars[number] }}
    {% endfor %}
{% endmacro %}


Вы можете проверить этот код на: https://twigfiddle.com/54a0i9


2

Pyth, 9 8 7 байт

s@LQjEl

Сохраненный байт благодаря hakr14 и еще одно спасибо Mr. Xcoder.
Попробуй здесь

объяснение

s@LQjEl
    jElQ      Convert the second input (the number) to the appropriate base.
 @LQ          Look up each digit in the list of strings.
s             Add them all together.

Сохраните байт, заменив его m@Qdна@LQ
hakr14

Сохраните байт, заменив vzна E.
г-н Xcoder

2

C89, ограниченный диапазон со знаком int n, 64 53 байта

  • список изменений: возьмите char **outи измените его, вместо того, чтобы брать и возвращатьchar *

Принимает число как int, таблица поиска как массив + длина.
Выход записывается в char *outbuf. Вызывающая сторона передает (по ссылке) указатель на конец буфера. Функция изменяет этот указатель так, чтобы он указывал на первый байт строки при возврате.

g(n,I,B,O)char*I,**O;{for(**O=0;n;n/=B)*--*O=I[n%B];}

Это действительно C89 и работает правильно даже при включенной оптимизации. то есть не зависит от -O0поведения gcc при падении с конца непустой функции или любого другого UB.

Передача указателя в конец буфера является нормальной для оптимизированной функции int-> string, такой как встроенная_itoa функция glibc . Смотрите этот ответ для подробного объяснения разбиения целого числа на цифры с помощью цикла div / mod, как мы делаем здесь, в C, а также в x86-64 asm. Если основание является степенью 2, вы можете сдвинуть / замаскировать, чтобы сначала извлечь цифры MSD, но в противном случае единственный хороший вариант - сначала младшая цифра (с модулем).

Попробуйте онлайн! , Безголовая версия:

/* int n = the number
 * int B = size of I = base
 * char I[] = input table
 * char **O = input/output arg passed by ref:
 *    on entry: pointer to the last byte of output buffer.
 *    on exit:  pointer to the first byte of the 0-terminated string in output buffer
 */
void ungolfed_g(n,I,B,O)char*I,**O;
{
    char *outpos = *O;     /* Golfed version uses *O everywhere we use outpos */
    *outpos = 0;           /* terminate the output string */
    for(;n;n/=B)
        *--outpos = I[n%B]; /* produce 1 char at a time, decrementing the output pointer */
    *O = outpos;
}

В этой версии с явной длиной входными данными является a, char table[]который не нуждается в завершающем 0 байте, потому что мы никогда не рассматриваем его как строку. Это может быть int table[]для всех нас волнует. В C нет контейнеров, которые знают свою собственную длину, поэтому указатель + длина - это обычный способ передать массив с размером. Поэтому мы выбираем это вместо необходимости strlen.

Максимальный размер буфера приблизительно sizeof(int)*CHAR_BIT + 1, так что он маленький и постоянный во время компиляции. (Мы используем это много места с base = 2 и всеми битами, установленными на 1.) Например, 33 байта для 32-битных целых чисел, включая 0терминатор.


C89, со знаком, intтаблица как строка C неявной длины, 65 байт

B;f(n,I,O)char*I,**O;{B=strlen(I);for(**O=0;n;n/=B)*--*O=I[n%B];}

Это то же самое, но входные данные являются строкой неявной длины, поэтому мы должны найти длину сами.


2

Bash + основные утилиты , 49 байт

dc -e`echo -en $2|wc -c`o$1p|tr -dc 0-9|tr 0-9 $2

Попробуйте онлайн!

Комментарии / объяснение

Он принимает аргументы командной строки в качестве входных данных (число в базе 10, затем одну строку со списком символов) и выводит в стандартный вывод. Специальные символы , такие как пространство, символ новой строки, и т.д. , могут быть введены в восьмеричной записи (например, \040для пространства), или \nдля перевода строки, \tна вкладке или любой другой управляющей последовательности , что echo -eи trинтерпретировать одинаково.

Многие байты здесь предназначены для обработки специальных символов и больших тестовых случаев. Если мне нужно обрабатывать только не страшные символы, а цифры маленькие (например, первый тестовый пример), это сделают следующие 24 байта:

dc -e${#2}o$1p|tr 0-9 $2

При этом используется расширение параметра ${#2}для получения количества символов в строке, создается программа постоянного тока для выполнения базового преобразования, а затем отправляется преобразованное число через tr.

Это не будет обрабатывать символы новой строки, пробелы или табуляции, поэтому, чтобы иметь дело с escape-последовательностями, не затрагивая основание, я делаю подсчет символов wc -cпосле интерпретации escape -кодов echo -en. Это расширяет программу до 38 байт:

dc -e`echo -en $2|wc -c`o$1p|tr 0-9 $2

К сожалению, у dc есть досадная «особенность», при которой, если он выводит большое число, он будет обтекать его последовательностью слеш + новая строка, поэтому в больших тестовых примерах этот дополнительный вывод получен. Чтобы удалить его, я передаю вывод dc, tr -dc 0-9чтобы удалить нечисловые символы. И вот мы здесь.


Я собирался предложить dc -e${#2}o$1p|tr 0-9 "$2"воспринимать ввод буквально, а не в \ escaped-форме, чтобы он мог обрабатывать пробелы, но trне имеет возможности, например, не рассматривать его -как символ диапазона. Если на входе -нет конца строки, он прерывается. Возможно, вы можете использовать sed "y/0123456789/$2/". Нет, я думаю, нет, GNU sedтребует , чтобы оба аргумента yбыли одинаковой длины, и кажется, что они задыхаются от перевода строки.
Питер Кордес

2

APL (Dyalog Unicode) , 14 13 12 байт

⊢⌷⍨∘⊂⊥⍣¯1⍨∘≢

Попробуйте онлайн!

Инфиксная молчаливая функция; не может обработать самый большой тестовый пример из-за представления с плавающей запятой.

Благодаря @ Adám сэкономлено 1 2 байта!

Для заголовков добавлено 13 байтов ⎕IO←0:: I ndex O rigin = 0 и ⎕FR←1287: F loat R epresentation = 128 бит. (Я забыл, что это не относится. )

Как?

⊢⌷⍨∘⊂⊥⍣¯1⍨∘≢    Tacit function, infix.
               Tally (number of elements in) the right argument.
         ⍨∘     Then swap the arguments of
     ⊥⍣¯1       Base conversion (to base ≢<r_arg>)
               Enclose (convert to an array)
  ⍨∘            Then swap the arguments of
               Index
               (Into) the right argument.


1

Холст , 7 байтов

L┬{╵⁸@p

Попробуй это здесь!

Прямая реализация:

L┬{╵⁸@p
L      get the length of the input (popping the item)
 ┬     base decode the other input
  {    for each number there
   ╵     increment
    ⁸@   in the 1st input get that numbered item
      p  and output that

Входной набор символов также может быть строкой, если он не содержит новой строки, потому что Canvas не имеет символа новой строки и автоматически преобразует его в 2D-объект.



1

SOGL V0.12 , 10 байтов

l;A─{IaWp}

Попробуй здесь!

Довольно долго, учитывая, что идея в значительной степени реализована на языке: здесь , ввод

¶    __   __    ¶   |  |_|  |   ¶___|       |___¶-   -   -   -  ¶ - - - - - - - ¶- - - - - - - -¶_______________¶

выдает сжатую строку, используя этот метод.



1

Stax , 2 байта

:B

Запустите и отладьте его

:Bэто инструкция в Stax, которая делает это. Обычно он работает с «строкой» * вместо массива «строк». В конце концов, это означает, что вывод представляет собой массив из односимвольных массивов. Но выход неявно выравнивается в любом случае.

* У Stax нет строкового типа. Текст представлен целочисленными массивами кодовых точек.


Да, я никогда не замечал эту команду ...
wastl

Много. Однажды я добавил инструкцию к Stax, которая уже существовала, и я просто забыл о ней. (массив не нисходящий?)
рекурсивный



1

C (gcc) , 110 байтов

char s[99],S[99];i;f(x,_)char*_;{i=strlen(_);*s=*S=0;while(x)sprintf(S,"%c%s",_[x%i],s),strcpy(s,S),x/=i;x=s;}

Попробуйте онлайн!

Описание:

char s[99],S[99];           // Two strings, s and S (capacity 99)
i;                          // A variable to store the length of the string
f(x,_)char*_;{              // f takes x and string _
    i=strlen(_);            // set i to the length of _
    *s=*S=0;                // empty s and S
    while(x)                // loop until x is zero
        sprintf(S,"%c%s",   // print into S a character, then a string
                _[x%i],s),  // character is the x%i'th character of _, the string is s
        strcpy(s,S),        // copy S into s
        x/=i;               // divide x by the length of the string (and loop)
    x=s;}                   // return the string in s

1
Если вы начинаете с конца буфера и работаете в обратном направлении, вы можете избежать этого sprintf. Моя версия C составляет 53 байта с выходным буфером, предоставленным вызывающей стороной. Вы можете сделать это strcpyв конце, если хотите скопировать байты в начало буфера.
Питер Кордес

Это великолепно. Мне все равно, если это неуклюжий формат ввода / вывода. Неудобный ввод-вывод - это C-претензия на известность! Отлично, я бы порекомендовал поместить это в пост с советами.
LambdaBeta

Опубликовал ответ на Советы по игре в гольф на С, объясняющий и обосновывающий технику.
Питер Кордес

1

CJam , 11 байт

liq_,@\b\f=

Попробуйте онлайн! Принимает ввод как число, затем перевод строки, затем символы в ASCII-арт.

объяснение

li           e# Read the first line and convert it to an integer
  q_,        e# Read the rest of the input and push its length n
     @\b     e# Convert the number to its base-n equivalent, as an array of numbers
        \f=  e# Map over the array, taking each element's index from the string

Так как «IO is Flexible», я думаю, вы можете избавиться от него liqв начале, и это сэкономит вам 3 байта!
Хром

1

JavaScript, 39 байт

Решение Python для Port of Rod .

s=>g=n=>n?g(n/(l=s.length)|0)+s[n%l]:""

Попробуйте онлайн


Работает только nдо 64 бит, верно? (В Python встроены целые числа произвольной точности, но числа JS, естественно, являются doubleточными числами с плавающей точкой, которые можно преобразовать в целое число). Кажется, не работает для более крупных тестовых случаев в вопросе, например 1928149325670647244912100789213626616560861130859431492905908574660758972167966. Да, но вопрос позволяет получить ответы, подобные этому. И все же следует отметить.
Питер Кордес

1

SimpleTemplate , 86 байт

Вау, это был огромный вызов!

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

{@setA argv.1}{@eachargv.0}{@setC C,"{@echoA.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}

Ожидаемые значения:

Первый аргумент ( argv.0) может быть:

  • Целое число
  • Строка с числами
  • Массив целых

Второй аргумент ( argv.1) может быть:

  • Строка
  • Массив

Как это работает?

Это работает так:

  • Перебирает число / строку, переданную в качестве первого аргумента
  • Устанавливает переменную Cкак массив, содержащий:
    • Предыдущее значение C
    • Струна "{@echoA."
    • Значение цикла
    • Струна "}"
  • Присоединяется все вместе ( с помощью РНР joinфункции)
    Это приводит, например, Cсодержащий"{@echoA.0}{@echoA.1}..."
  • Оценивает результат C

Ungolfed:

{@set args argv.1}
{@each argv.0 as number}
    {@set code code, "{@echo args.", number , "}"}
    {@call join into code "", code}
{@/}
{@eval code}

Вы можете попробовать этот код на: https://ideone.com/NEKl2q


Оптимальный результат

Если бы не было ошибок, это был бы лучший результат, учитывая ограничения (77 байт):

{@eachargv.0}{@setC C,"{@echoargv.1.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.