Descompactação de arte ASCII a partir de um número base-n

24

Isso é inspirado na resposta 05AB1E da Magic Octupus Urn .

Dados dois argumentos, um número inteiro positivo e uma sequência / lista de caracteres:

  1. Traduza o número para base-n, onde n é o comprimento da string.
  2. Para cada caractere, substitua todas as aparências do índice desse caractere no número base-n por esse caractere.
  3. Imprima ou retorne a nova sequência.

Exemplos:

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:
_===_
(.,.)
( : )
( : )

Regras:

  • IO é flexível .
    • Você pode pegar o número em qualquer base, desde que seja consistente entre as entradas
    • A lista de caracteres precisa ser indexada em 0, onde 0 é o primeiro caractere e n-1 é o último
  • Os caracteres possíveis podem ser qualquer ASCII imprimível, além de espaços em branco, como guias e novas linhas
  • A lista de caracteres fornecida terá um comprimento no intervalo, 2-10inclusive. Ou seja, a menor base é binária e a maior é decimal ( sem letras traquinas aqui )
  • As brechas padrão são proibidas
  • Sinta-se à vontade para responder, mesmo que seu idioma não possa lidar com casos de teste maiores.

Como esse é o , o código mais curto para cada idioma vence. ( Eu sei que todos os idiomas de golfe têm um byte embutido ;)

Brincadeira
fonte
Sandbox (excluído)
Jo King
3
D'awwh, me sinto honrado. 05AB1E ascii-art foi a minha favorita há algum tempo.
Magic Octopus Urn
você pode criar um novo desafio: encontrar a permutação de caracteres na matriz para minimizar o número :)
Mazzy

Respostas:

8

05AB1E , 7 6 bytes

gв¹sèJ

Como foi inspirada por uma resposta 05AB1E, uma resposta dada em 05AB1E parece adequada. :)

-1 byte, graças ao @Enigma , removendo o foreach e fazendo isso implicitamente.

Experimente online ou verifique todos os casos de teste .

Explicação:

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)
Kevin Cruijssen
fonte
1
gв¹sèJpara salvar um byte.
Emigna
@ Emigna Thanks. Não posso acreditar que eu não tinha pensado sobre ¹sèmim agora .. (eu sabia que mudando o ?a um Jdaria o mesmo resultado neste caso.)
Kevin Cruijssen
6

Java 8, 72 50 bytes

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

-22 bytes graças a @ OlivierGrégoire retornando um em IntStreamvez de imprimir diretamente.

Experimente online .

Explicação:

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`
Kevin Cruijssen
fonte
2
a->n->n.toString(a.length).chars().map(c->a[c-48])(50 bytes), já que "o IO é flexível"
Olivier Grégoire
String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69 bytes) um recursivo, por diversão.
Olivier Grégoire
6

Python 3 , 49 bytes

Ainda não posso comentar, então eu posto a resposta do Python 2 adaptada ao Python 3.5.

f=lambda n,s:n and f(n//len(s),s)+s[n%len(s)]or''
Romzie
fonte
2
Bem-vindo ao PPCG! Sinta-se à vontade para incluir um link TIO para ajudar a mostrar sua solução.
Jo rei
5

Japonês, 2 bytes

Pode receber a segunda entrada como uma matriz ou uma string. Falha nos dois últimos casos de teste, pois os números excedem o número máximo máximo de JavaScript. Substitua spor ìpara gerar uma matriz de caracteres.

sV

Tente

Shaggy
fonte
5

Haskell , 40 39 bytes

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

Experimente online!

Como o Inttipo de Haskell é limitado 9223372036854775807, isso falha em números maiores.

-1 byte graças a Laikoni .

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)

Experimente online!

ovs
fonte
Boa idéia para usar em cyclevez de mod! div n(length l)salva um byte.
Laikoni 12/06
4

MATL , 2 bytes

YA

Experimente online!

As entradas são um número e uma sequência.

Falha no número excedente 2^53, devido à precisão do ponto flutuante.

Explicação

O que você YAsabe, um builtin (conversão básica com símbolos de destino especificados).

Luis Mendo
fonte
4

JavaScript (ES6), 48 bytes

Toma entrada em currying sintaxe (c)(n), onde c é uma lista de caracteres e n é um número inteiro.

Seguro apenas para n <2 53 .

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

Experimente online!


JavaScript (ES6), 99 bytes

Com suporte para números inteiros grandes

Recebe entrada na sintaxe de curry (c)(a), em que c é uma lista de caracteres e a é uma lista de dígitos decimais (como números inteiros).

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]:''

Experimente online!

Arnauld
fonte
4

código de máquina x86 de 32 bits (números inteiros de 32 bits): 17 bytes.

(veja também outras versões abaixo, incluindo 16 bytes para 32 bits ou 64 bits, com uma convenção de chamada DF = 1.)

Chamador passa args em registos, incluindo um ponteiro para o final de um buffer de saída (como minha resposta C ; vê-lo para a justificação e explicação do algoritmo.) Da glibc interna _itoafaz isso , então não é apenas inventado para o código-golfe. Os registros de passagem de arg estão próximos do x86-64 System V, exceto que temos um arg no EAX, em vez do EDX.

No retorno, o EDI aponta para o primeiro byte de uma cadeia C terminada em 0 no buffer de saída. O registro de valor-retorno usual é EAX / RAX, mas na linguagem assembly você pode usar qualquer convenção de chamada que seja conveniente para uma função. ( xchg eax,edino final adicionaria 1 byte).

O chamador pode calcular um comprimento explícito, se desejar, de buffer_end - edi. Mas acho que não podemos justificar a omissão do terminador, a menos que a função realmente retorne ponteiros de início + fim ou comprimento de ponteiro. Isso economizaria 3 bytes nesta versão, mas não acho que seja justificável.

  • EAX = n = número para decodificar. (Para idiv. Os outros argumentos não são operandos implícitos.)
  • EDI = buffer de final de saída (a versão de 64 bits ainda usa dec edi, portanto deve estar com pouco 4GiB)
  • ESI / RSI = tabela de pesquisa, também conhecida como LUT. não derrotou.
  • ECX = comprimento da tabela = base. não derrotou.

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (Editado manualmente para reduzir os comentários, a numeração das linhas é estranha.)

   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

É surpreendente que a versão mais simples, basicamente sem trocas de velocidade / tamanho, seja a menor, mas std/ cldcusta 2 bytes para usar stosbem ordem decrescente e ainda seguir a convenção de chamada DF = 0 comum. (E o STOS diminui após o armazenamento, deixando o ponteiro apontando um byte muito baixo na saída do loop, nos custando bytes extras para contornar.)

Versões:

Eu criei 4 truques de implementação significativamente diferentes (usando movcarga / armazenamento simples (acima), usando lea/ movsb(puro, mas não ideal), usando xchg/ xlatb/ stosb/ xchg, e um que entra no loop com um hack de instrução sobreposta. Veja o código abaixo) . O último precisa de uma trilha 0na tabela de pesquisa para copiar como o terminador da cadeia de saída, então estou contando isso como +1 byte. Dependendo de 32/64 bits (1 byte incou não), e se podemos assumir que o chamador define DF = 1 ( stosbdescendente) ou o que for, versões diferentes são (ligadas a) mais curtas.

DF = 1 para armazenar em ordem decrescente torna uma vitória para xchg / stosb / xchg, mas o chamador geralmente não deseja isso; Parece transferir o trabalho para o chamador de uma maneira difícil de justificar. (Diferentemente dos registros arg-pass e de valor-retorno personalizados, que normalmente não custam a um chamador asm nenhum trabalho extra.) Mas no código de 64 bits, cld/ scasbfunciona como inc rdi, evitando truncar o ponteiro de saída para 32 bits, então às vezes inconveniente preservar DF ​​= 1 em funções de limpeza de 64 bits. . (Ponteiros para dados / código estático são 32 bits em executáveis ​​não PIE x86-64 no Linux e sempre na ABI do Linux x32, portanto, em alguns casos, uma versão x86-64 usando ponteiros de 32 bits é utilizável.) De qualquer forma, essa interação torna interessante observar diferentes combinações de requisitos.

  • IA32 com um DF = 0 na convenção de chamada de entrada / saída: 17B ( nostring) .
  • IA32: 16B (com uma convenção DF = 1: stosb_edx_argou skew) ; ou com DF de entrada = não cuidar, deixando-o definido: 16 + 1Bstosb_decode_overlap ou 17Bstosb_edx_arg
  • x86-64 com ponteiros de 64 bits e um DF = 0 na convenção de chamada de entrada / saída: 17 + 1 bytes ( stosb_decode_overlap) , 18B ( stosb_edx_argou skew)
  • x86-64 com ponteiros de 64 bits, outro tratamento de DF: 16B (DF = 1 skew) , 17B ( nostringcom DF = 1, usando em scasbvez de dec). 18B ( stosb_edx_argpreservando DF = 1 com 3 bytes inc rdi).

    Ou se permitirmos retornar um ponteiro para 1 byte antes da string, 15B ( stosb_edx_argsem o incno final). Tudo pronto para chamar novamente e expandir outra string no buffer com base / tabela diferente ... Mas isso faria mais sentido se não armazenássemos uma terminação 0também, e você pode colocar o corpo da função dentro de um loop, então isso é realmente um problema separado.

  • x86-64 com ponteiro de saída de 32 bits, DF = 0 convenção de chamada: nenhuma melhoria em relação ao ponteiro de saída de 64 bits, mas 18B ( nostring) está vinculado agora.

  • x86-64 com ponteiro de saída de 32 bits: nenhuma melhoria em relação às melhores versões de ponteiro de 64 bits, então 16B (DF = 1 skew). Ou para definir DF = 1 e deixá-lo, 17B para skewcom stdmas não cld. Ou 17 + 1B para stosb_decode_overlapcom inc edino final em vez de cld/ scasb.

Com uma convenção de chamada DF = 1: 16 bytes (IA32 ou x86-64)

Requer DF = 1 na entrada, deixa-o definido. Quase plausível , pelo menos por função. Faz o mesmo que a versão acima, mas com o xchg para obter o restante da entrada / saída do AL antes / depois do XLATB (pesquisa de tabela com R / EBX como base) e STOSB ( *output-- = al).

Com um DF = 0 normal na convenção de entrada / saída, a versão std/ cld/ scasbé de 18 bytes para códigos de 32 e 64 bits e é limpa de 64 bits (funciona com um ponteiro de saída de 64 bits).

Observe que os argumentos de entrada estão em registradores diferentes, incluindo o RBX para a tabela (para xlatb). Observe também que esse loop começa armazenando AL e termina com o último caractere ainda não armazenado (portanto, movno final). Portanto, o loop é "inclinado" em relação aos outros, daí o nome.

                            ;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

Uma versão semelhante não distorcida ultrapassa o EDI / RDI e depois o corrige.

                            ; 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

Eu tentei uma versão alternativa disso com lea esi, [rbx+rdx]/ movsbcomo o corpo do loop interno. (O RSI é redefinido a cada iteração, mas o RDI diminui). Mas ele não pode usar xor-zero / stos para o terminador, por isso é 1 byte maior. (E não está limpo de 64 bits para a tabela de pesquisa sem um prefixo REX no LEA.)


LUT com comprimento explícito e um terminador 0: 16 + 1 bytes (32 bits)

Esta versão define DF = 1 e deixa assim. Estou contando o byte extra de LUT necessário como parte da contagem total de bytes.

O truque legal aqui é ter os mesmos bytes decodificar de duas maneiras diferentes . Caímos no meio do loop com o restante = base e quociente = número de entrada e copiamos o terminador 0 no lugar.

Na primeira vez através da função, os 3 primeiros bytes do loop são consumidos como os bytes altos de um disp32 para um LEA. Esse LEA copia a base (módulo) para o EDX, idivproduz o restante para iterações posteriores.

O segundo byte de idiv ebpé FD, que é o código de operação para a stdinstrução que esta função precisa para funcionar. (Esta foi uma descoberta de sorte. Eu já estava examinando isso divanteriormente, o que se distingue do idivuso dos /rbits no ModRM. O segundo byte de div epbdecodifica como cmc, o que é inofensivo, mas não é útil. Mas com idiv ebppodemos remover o stdde cima da função.)

Observe que os registros de entrada são diferentes novamente: EBP para a base.

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

Esse truque de decodificação sobreposto também pode ser usado com cmp eax, imm32: são necessários apenas 1 byte para avançar efetivamente 4 bytes, apenas sinalizadores de oscilação. (Isso é terrível para o desempenho em CPUs que marcam os limites de instruções no cache L1i, BTW.)

Mas aqui, estamos usando 3 bytes para copiar um registro e pular para o loop. Isso normalmente levaria 2 + 2 (mov + jmp) e nos permitiria entrar no loop imediatamente antes do STOS em vez de antes do XLATB. Mas então precisaríamos de uma DST separada, e não seria muito interessante.

Experimente online! (com um _startchamador que usa sys_writeno resultado)

É melhor para a depuração executá-lo straceou fazer o hexdump da saída, para que você possa verificar se há um \0terminador no lugar certo e assim por diante. Mas você pode ver isso realmente funcionar e produzir AAAAAACHOOpara uma entrada de

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

(Na verdade xxAAAAAACHOO\0x\0\0..., porque estamos despejando de 2 bytes anteriores no buffer para um comprimento fixo. Assim, podemos ver que a função gravou os bytes que deveria e não pisou em nenhum bytes que não deveria ter. O ponteiro de início passado para a função era o segundo e último xcaractere, seguido por zeros.)

Peter Cordes
fonte
3

Gelatina , 4 bytes

ṙ1ṃ@

Experimente online!

é literalmente um built-in para isso. Os outros três bytes são responsáveis ​​pela indexação baseada em um de Jelly.

Mr. Xcoder
fonte
Por curiosidade, por que Jelly tem a " Descompressão de base incorporada; converte x em comprimento base (y) e depois indexa em y "? É nos casos muito excepcionais em que a base para a qual você deseja converter e o comprimento de uma string / número inteiro / lista são iguais? Quando procuro, só consigo encontrar três respostas: 1 ; 2 ; 3 . Meio que um estranho embutido em todos os dias desafios de código-golfe. : S
Kevin Cruijssen
3
@KevinCruijssen é muito útil quando você deseja, por exemplo, converter N em hexadecimal usando letras hexadecimais em vez de uma lista de números.
Mr. Xcoder
@KevinCruijssen É um método de compressão para strings. No primeiro exemplo, a sequência desejada é “sspspdspdspfdspfdsp”, mas “çƥ÷£ḟ’ṃ“spdf”¤você salva seis bytes. É especialmente útil com os números de base 250 da geléia
dylnan
3

Python 2 , 49 48 bytes

-1 byte graças a Jo King

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

Experimente online!

Versão alternativa (não será finalizada para números grandes), 45 43 bytes

-2 bytes graças a Jo King

f=lambda n,s:s*n and f(n/len(s),s)+(s*n)[n]

Experimente online!

Cajado
fonte
3

Carvão , 3 1 bytes

θη

Experimente online! Link é a versão detalhada do código. Editar: salvou 2 bytes graças a @ ASCII-only. Versão anterior antes da adição do builtin, 8 bytes:

⭆↨θLη§ηι

Experimente online! Link é a versão detalhada do código. Explicação:

    η       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
Neil
fonte
Na verdade, é suposto que já trabalho, mas evidentemente eu errei novamente> _>
ASCII-only
Além disso, seria de fato 1 byte : P (atualmente está quebrado, então não estou usando a matriz de números e seqüências de caracteres como argumentos) (também, pergunto-me como é (não) útil a entrada implícita)
ASCII-only
@ Somente ASCII Você não quer dizer "1 bytes" (veja sua saída -vl ;-) Além disso, a entrada implícita parece quase inútil no carvão, exceto em desafios como esse.
Neil
1
@ "Bytes" plurais somente ASCII, em vez de "byte" singular, é o que Neil significa. ;) Quanto à sua resposta de 1 byte, por que a risca θη? Parece um pouco confuso tbh. Por que não apenas removê-lo completamente e sair ?
Kevin Cruijssen
1
@Nit Verifiquei duas vezes e o built-in foi adicionado antes que a pergunta fosse feita, mas não havia percebido porque havia um erro.
187 Neil
3

D , 112 bytes

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;}

Experimente online!

Esta é uma porta da resposta C ++ de HatsuPointerKun

O estilo de chamada é u(ulong(n), to!(char[])(b)), onde ne bsão os argumentos esquerdo e direito

D coisas específicas

Infelizmente, precisamos importar std.convpara fazer conversões de tipo acima da conversão de tipo muito básica.

Usando o sistema de templates golfy, e dando a função dos tipos necessários (que é porque chamá-lo não é apenas u(n,b)), podemos reduzir as ocorrências de char[]e ulongpara 1byte cada, quando dentro de f a função.

D inicializa nossos tipos para nós, então C t;é a abreviação deC t=cast(char[])([])

to!Cconverte o número inteiro n%lem uma matriz de caracteres (usando pontos de código) e ~é concatenação

foreach(ref c;t)é como o for(... : ...)loop do C ++ , mas um pouco mais. refé como &, trata ccomo copiado por referência (ou seja, podemos modificar t). Felizmente, D deduz o tipo csem qualquer tipo de palavra-chave.

Zacharý
fonte
3

C ++, 150 144 bytes, uint64entrada

-6 bytes graças a Zacharý

#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;}

Usar uma variável para armazenar o tamanho aumentaria o número de bytes em 1

Para chamar a função:

u(2740, "|_")

Primeiro o número, o segundo é a string (array de caracteres)

Casos de teste :

std::cout << u(2740, "|_") << '\n' << u(698911, "chao") << '\n';
return 0;
HatsuPointerKun
fonte
1
3 bytes para raspar: você não precisa do espaço depois #include, pode mudar ;;para apenas ;e '0'pode apenas ser #48
Zacharý
1
Além disso, o loop while pode ser um forloop:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
Zacharý 15/06/19
@ceilingcat, esqueci que b.size()não muda nesse loop.
Zachary
@ceilingcat Isso aumentaria o bytecount por 1, em vez de baixá-lo
HatsuPointerKun
2

Galho, 66 bytes

Criou um macroque deve ser importeditado em um modelo.

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

Valores esperados:

Para os primeiros argumentos ( n):

  • número
  • corda

Para o segundo argumento ( c):

  • Matriz de números
  • Matriz de strings

Como usar:

  • Crie um .twigarquivo
  • Adicionar {% import 'file.twig' as uncompress %}
  • Chame a macro uncompress.d()

Sem Golfe (não funcional):

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


Você pode testar este código em: https://twigfiddle.com/54a0i9

Ismael Miguel
fonte
2

Pitão, 9 8 7 bytes

s@LQjEl

Salvou um byte graças a hakr14 e outro graças ao Sr. Xcoder.
Experimente aqui

Explicação

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.

fonte
Salve um byte, substituindo m@Qdpor@LQ
hakr14
Salve um byte substituindo vzpor E.
Mr. Xcoder
2

C89, intervalo limitado assinado int n, 64 53 bytes

  • changelog: pegue um char **oute modifique-o, em vez de pegar e retornar umchar *

Pega o número como uma int, a tabela de pesquisa como uma matriz + comprimento.
A saída é gravada em a char *outbuf. O chamador passa (por referência) um ponteiro para o final do buffer. A função modifica esse ponteiro para apontar para o primeiro byte da string no retorno.

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

Este é C89 válido e funciona corretamente mesmo com a otimização ativada. isto é, não depende do -O0comportamento do gcc ao cair no final de uma função não nula ou ter qualquer outro UB.

Passar um ponteiro para o final de um buffer é normal para uma função int-> string otimizada, como a interna da glibc_itoa . Veja esta resposta para obter uma explicação detalhada de dividir um número inteiro em dígitos com um loop div / mod como estamos fazendo aqui, em C, bem como em x86-64 asm. Se a base é uma potência de 2, você pode alternar / mascarar para extrair os dígitos MSD primeiro, mas, caso contrário, a única boa opção é o primeiro com o menor número de dígitos (com módulo).

Experimente online! . Versão não destruída:

/* 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;
}

Nesta versão de tamanho explícito, a entrada é uma char table[]que não precisa de um byte final de 0, porque nunca a tratamos como uma string. Poderia ser um int table[]para todos os que nos importamos. C não possui contêineres que possuem seu próprio comprimento; portanto, ponteiro + comprimento é a maneira normal de passar uma matriz com um tamanho. Então escolhemos isso em vez de precisar strlen.

O tamanho máximo do buffer é aproximadamente sizeof(int)*CHAR_BIT + 1, portanto é pequeno e constante em tempo de compilação. (Usamos esse espaço com base = 2 e todos os bits configurados como 1.) por exemplo, 33 bytes para números inteiros de 32 bits, incluindo o 0terminador.


C89, assinado int, tabela como uma cadeia C de comprimento implícito, 65 bytes

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

É a mesma coisa, mas a entrada é uma cadeia de comprimento implícito, portanto, precisamos encontrar o comprimento por nós mesmos.

Peter Cordes
fonte
2

Bash + utilitários principais , 49 bytes

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

Experimente online!

Comentários / explicação

Isso leva os argumentos da linha de comando como entrada (o número na base 10 e, em seguida, uma única sequência com a lista de caracteres) e gera para stdout. Caracteres especiais como espaço, nova linha, etc., podem ser inseridos em notação octal (por exemplo, \040para um espaço), ou \npor uma mudança de linha, \tpara a guia, ou qualquer outra sequência de escape que echo -ee trinterpretar de forma idêntica.

Muitos dos bytes aqui são para lidar com caracteres especiais e casos de teste maiores. Se eu tiver que lidar apenas com caracteres não terríveis e os números forem pequenos (por exemplo, o primeiro caso de teste), os seguintes 24 bytes o farão:

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

Isso usa a expansão de parâmetro ${#2}para obter o número de caracteres na sequência, cria um programa dc para fazer a conversão base e envia o número convertido tr.

Porém, isso não manipula novas linhas, espaços ou tabulações; portanto, para lidar com seqüências de escape sem afetar a base, eu faço uma contagem de caracteres wc -cdepois de interpretar os escapes echo -en. Isso expande o programa para 38 bytes:

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

Infelizmente, o dc tem um "recurso" irritante onde, se estiver produzindo um número grande, o alinhará com uma sequência de barra + nova linha, para que os casos de teste maiores tenham essa saída extra. Para removê-lo, canalizo a saída de dc tr -dc 0-9para remover caracteres não numéricos. E aí estamos nós.

Sophia Lechner
fonte
Eu sugeriria dc -e${#2}o$1p|tr 0-9 "$2"pegar a entrada literalmente em vez da forma \ escaped para que ele possa manipular espaços, mas trnão tem uma opção para não tratar -como um caractere de intervalo, por exemplo. Se a entrada -não tiver uma extremidade da sequência, ela será quebrada. Talvez você possa usar sed "y/0123456789/$2/". Não, acho que não, o GNU sedexige que os dois argumentos ytenham o mesmo tamanho, e parece engasgar com a nova linha.
Peter Cordes
2

APL (Dyalog Unicode) , 14 13 12 bytes

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

Experimente online!

Infix função tácita; não pode lidar com o maior caso de teste devido à representação de ponto flutuante.

Guardado 1 2 bytes graças a @ Adám!

13 bytes adicionados para os cabeçalhos: ⎕IO←0: Eu NDEX O Rigin = 0 e ⎕FR←1287: F loat R ePresentation = 128 bits. (Esqueci que isso não se aplica. )

Quão?

⊢⌷⍨∘⊂⊥⍣¯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.
J. Sallé
fonte
2

Anexo , 17 bytes

{_[_2&ToBase!#_]}

Experimente online!

Explicação

{_[_2&ToBase!#_]}
{               }  ?? anonymous lambda; input: _ = dictionary, _2 = encoded
   _2&ToBase       ?? convert _2 to base
            !#_    ?? ... Size[_]
 _[            ]   ?? and take those members from the dictionary
Conor O'Brien
fonte
1

Tela , 7 bytes

L┬{╵⁸@p

Experimente aqui!

Implementação direta:

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

O conjunto de caracteres de entrada pode ser uma sequência de caracteres desde que não contenha uma nova linha, porque o Canvas não possui um caractere de nova linha e o converte automaticamente em um objeto 2D.

dzaima
fonte
1

Stax , 6 5 bytes

n%|E@

Execute e depure

Explicação:

n%|E@ Full program, implicit input in order list, number
n%    Copy the list to the top and get its length
  |E  Convert the number to that base
    @ Map: index
wastl
fonte
1

SOGL V0.12 , 10 bytes

l;A─{IaWp}

Experimente aqui!

Por muito tempo, considerando que a idéia é praticamente implementada no idioma: aqui , entrando

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

distribui uma string compactada usando esse método.

dzaima
fonte
1

Stax , 2 bytes

:B

Execute e depure

:Bé uma instrução em stax que faz isso. Normalmente, ele operaria em uma "string" * em vez de uma matriz de "strings". No final, isso significa que a saída é uma matriz de matrizes de caracteres únicos. Mas a saída achatada implicitamente de qualquer maneira.

* Stax não tem realmente um tipo de string. O texto é representado por matrizes inteiras de pontos de código.

recursivo
fonte
Huh, eu nunca percebi este comando ...
Wastl
Há um monte. Certa vez, adicionei uma instrução ao stax que já existia e acabara de me esquecer. (a matriz não é decrescente?)
recursiva
1

J , 12 bytes

]{~#@]#.inv[

Quão?

      #.inv    convert
           [   the left argument (the number)      
   #@]         to base the length of the right argument (the list of characters)    
  {~           and use the digits as indices to
]              the list of characters        

Experimente online!

Galen Ivanov
fonte
1

C (gcc) , 110 bytes

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;}

Experimente online!

Descrição:

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
LambdaBeta
fonte
1
Se você iniciar no final de um buffer e trabalhar para trás, poderá evitar sprintf. Minha versão C é de 53 bytes , com o buffer de saída fornecido pelo chamador. Você pode fazer um strcpyno final se quiser copiar os bytes para o início de um buffer.
Peter Cordes
Isso é brilhante. Eu não me importo se é um formato de E / S estranho. E / S inábil é a fama de C! Bem feito, eu recomendo colocar isso no post de dicas C.
LambdaBeta
Postado uma resposta em Dicas para jogar golfe em C explicando e justificando a técnica.
22618 Peter Cordes
1

CJam , 11 bytes

liq_,@\b\f=

Experimente online!Recebe entrada como o número, depois uma nova linha e, em seguida, os caracteres na arte ASCII.

Explicação

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
NinjaBearMonkey
fonte
Como "IO é flexível", acho que você pode se livrar dele liqno início e isso economiza 3 bytes!
Cromo
1

JavaScript, 39 bytes

Solução Python do Port of Rod .

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

Experimente online

Shaggy
fonte
Só funciona para naté 64 bits, certo? (O Python possui inteiros de precisão arbitrária incorporados, mas os números JS são doubleflutuadores de precisão natural que podem ser convertidos em números inteiros). Parece não funcionar para os casos de teste maiores da pergunta, como 1928149325670647244912100789213626616560861130859431492905908574660758972167966. Ah, mas a pergunta permite respostas assim. Ainda assim, deve-se notar.
Peter Cordes
1

SimpleTemplate , 86 bytes

Uau, este foi um grande desafio!

Isso foi dificultado devido à falta de acesso direto a índices específicos quando o índice é uma variável.
Um bug também o tornava mais longo, exigindo armazenar os valores dentro de uma variável.

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

Valores esperados:

O primeiro argumento ( argv.0) pode ser:

  • Um inteiro
  • Uma string com números
  • Uma matriz de números inteiros

O segundo argumento ( argv.1) pode ser:

  • Uma linha
  • Uma matriz

Como isso funciona?

Funciona assim:

  • Percorre o número / sequência passada como o primeiro argumento
  • Define a variável Ccomo uma matriz que contém:
    • O valor anterior C
    • A corda "{@echoA."
    • O valor do loop
    • A corda "}"
  • Une tudo (usando a joinfunção PHP )
    Isso resulta, por exemplo, em Cconter"{@echoA.0}{@echoA.1}..."
  • Avalia o resultado de C

Ungolfed:

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

Você pode tentar este código em: https://ideone.com/NEKl2q


Resultado ideal

Se não houvesse bugs, esse seria o melhor resultado, considerando as limitações (77 bytes):

{@eachargv.0}{@setC C,"{@echoargv.1.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}
Ismael Miguel
fonte