Descompresión de arte ASCII a partir de un número base-n


24

Esto está inspirado en una respuesta 05AB1E de Magic Octupus Urn .

Dados dos argumentos, un entero positivo y una cadena / lista de caracteres:

  1. Traduzca el número a base-n, donde n es la longitud de la cadena.
  2. Para cada carácter, reemplace cada aparición del índice de ese carácter en el número base-n con ese carácter.
  3. Imprime o devuelve la nueva cadena.

Ejemplos:

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

Reglas:

  • IO es flexible .
    • Puede tomar el número en cualquier base, siempre que sea coherente entre las entradas
    • Sin embargo, la lista de caracteres debe estar indexada en 0, donde 0 es el primer carácter y n-1 es el último
  • Los caracteres posibles pueden ser cualquier ASCII imprimible, junto con espacios en blanco como pestañas y líneas nuevas
  • La lista de caracteres dada tendrá una longitud en el rango 2-10inclusive. Es decir, la base más pequeña es binaria y la más grande es decimal ( no hay letras molestas aquí )
  • Las lagunas estándar están prohibidas
  • No dude en responder incluso si su idioma no puede manejar los casos de prueba más grandes.

Como se trata de , gana el código más corto para cada idioma. ( Sé que todos los idiomas de golf tienen incorporados un byte listo para usar ;)


Sandbox (eliminado)
Jo King

3
D'awwh, me siento honrado. 05AB1E ascii-art fue mi favorito hace un tiempo.
Magic Octopus Urn

puedes crear un nuevo desafío: encuentra la permutación de los personajes en la matriz para minimizar el número :)
mazzy

Respuestas:


8

05AB1E , 7 6 bytes

gв¹sèJ

Como se inspiró en una respuesta 05AB1E, una respuesta dada en 05AB1E parece adecuada. :)

-1 byte gracias a @Enigma al eliminar el foreach y hacer esto implícitamente.

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

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èJpara guardar un byte
Emigna

@ Emmigna Gracias. No puedo creer que no hubiera pensado en ¹sèmí ahora ... (sabía que cambiarlo ?a a Jdaría la misma salida en este caso)
Kevin Cruijssen

6

Java 8, 72 50 bytes

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

-22 bytes gracias a @ OlivierGrégoire devolviendo un en IntStreamlugar de imprimir directamente.

Pruébalo en línea .

Explicación:

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 bytes) desde "IO es flexible"
Olivier Grégoire

String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69 bytes) uno recursivo, por diversión.
Olivier Grégoire

6

Python 3 , 49 bytes

No puedo comentar todavía, así que publico la respuesta de Python 2 adaptada a Python 3.5.

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

2
Bienvenido a PPCG! Siéntase libre de incluir un enlace TIO para ayudar a mostrar su solución.
Jo King

5

Japt, 2 bytes

Puede tomar la segunda entrada como una matriz o una cadena. Falla los últimos 2 casos de prueba ya que los números exceden el entero máximo de JavaScript Reemplace scon ìpara generar una matriz de caracteres en su lugar.

sV

Intentalo


5

Haskell , 40 39 bytes

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

Pruébalo en línea!

Como el Inttipo de Haskell se limita a 9223372036854775807, esto falla para números más grandes.

-1 byte gracias a Laikoni .

Sin golf

(!) :: 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)

Pruébalo en línea!


Buena idea para usar en cyclelugar de mod! div n(length l)guarda un byte.
Laikoni

4

MATL , 2 bytes

YA

Pruébalo en línea!

Las entradas son un número y una cadena.

Falla para los números que exceden 2^53, debido a la precisión de punto flotante.

Explicación

Lo que sí YAsé, un incorporado (conversión de base con símbolos de destino especificados).


4

JavaScript (ES6), 48 bytes

Toma entrada en la sintaxis de curry (c)(n), donde c es una lista de caracteres yn es un número entero.

Seguro solo para n <2 53 .

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

Pruébalo en línea!


JavaScript (ES6), 99 bytes

Con soporte para enteros grandes

Toma entrada en la sintaxis de curry (c)(a), donde c es una lista de caracteres y a es una lista de dígitos decimales (como enteros).

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

Pruébalo en línea!


4

Código de máquina x86 de 32 bits (enteros de 32 bits): 17 bytes.

(vea también otras versiones a continuación, incluidos 16 bytes para 32 bits o 64 bits, con una convención de llamada DF = 1).

La persona que llama pasa argumentos en los registros, incluido un puntero al final de un búfer de salida (como mi respuesta C ; míralo para justificar y explicar el algoritmo). El interno de glibc _itoahace esto , por lo que no solo está diseñado para el golf de código. Los registros de paso de argumentos están cerca de x86-64 System V, excepto que tenemos un argumento en EAX en lugar de EDX.

Al regresar, EDI apunta al primer byte de una cadena C terminada en 0 en el búfer de salida. El registro de valor de retorno habitual es EAX / RAX, pero en lenguaje ensamblador puede usar cualquier convención de llamada que sea conveniente para una función. ( xchg eax,edial final agregaría 1 byte).

La persona que llama puede calcular una longitud explícita si lo desea, desde buffer_end - edi. Pero no creo que podamos justificar la omisión del terminador a menos que la función realmente devuelva punteros de inicio + fin o puntero + longitud. Eso ahorraría 3 bytes en esta versión, pero no creo que sea justificable.

  • EAX = n = número para decodificar. (Para idiv. Los otros argumentos no son operandos implícitos).
  • EDI = fin del búfer de salida (la versión de 64 bits todavía se usa dec edi, por lo que debe estar en los 4GiB bajos)
  • ESI / RSI = tabla de búsqueda, también conocida como LUT. No golpeó.
  • ECX = longitud de la tabla = base. No golpeó.

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (Editado a mano para reducir los comentarios, la numeración de líneas es extraña).

   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

Es sorprendente que la versión más simple, básicamente sin compensaciones de velocidad / tamaño, sea la más pequeña, pero std/ cldcostó 2 bytes para usar stosben orden descendente y seguir la convención de llamadas DF = 0 común. (Y STOS disminuye después del almacenamiento, dejando el puntero apuntando un byte demasiado bajo en la salida del bucle, lo que nos cuesta bytes adicionales para evitar).

Versiones

Se me ocurrieron 4 trucos de implementación significativamente diferentes (usando simple movload / store (arriba), usando lea/ movsb(ordenado pero no óptimo), usando xchg/ xlatb/ stosb/ xchg, y uno que ingresa al ciclo con un hack de instrucciones superpuestas. Ver código a continuación) . El último necesita un seguimiento 0en la tabla de búsqueda para copiar como terminador de cadena de salida, por lo que lo cuento como +1 byte. Dependiendo de 32/64 bits (1 byte inco no), y si podemos asumir que la persona que llama establece DF = 1 ( stosbdescendente) o lo que sea, las diferentes versiones son (empatadas) más cortas.

DF = 1 para almacenar en orden descendente lo convierte en una victoria para xchg / stosb / xchg, pero la persona que llama a menudo no querrá eso; Se siente como descargar el trabajo a la persona que llama de una manera difícil de justificar. (A diferencia de los registros personalizados de paso de argumento y valor de retorno, que generalmente no cuestan a un llamador de asm ningún trabajo adicional). Pero en el código de 64 bits, cld/ scasbfunciona como inc rdi, evitando truncar el puntero de salida a 32 bits, por lo que a veces es inconveniente para preservar DF ​​= 1 en funciones de limpieza de 64 bits. . (Los punteros a código / datos estáticos son de 32 bits en x86-64 ejecutables no PIE en Linux, y siempre en Linux x32 ABI, por lo que en algunos casos se puede usar una versión x86-64 que usa punteros de 32 bits). Esta interacción hace que sea interesante observar diferentes combinaciones de requisitos.

  • IA32 con un DF = 0 en la convención de llamada de entrada / salida: 17B ( nostring) .
  • IA32: 16B (con una convención DF = 1: stosb_edx_argo skew) ; o con DF entrante = no importa, dejándolo configurado: 16 + 1Bstosb_decode_overlap o 17Bstosb_edx_arg
  • x86-64 con punteros de 64 bits y un DF = 0 en la convención de llamada de entrada / salida: 17 + 1 bytes ( stosb_decode_overlap) , 18B ( stosb_edx_argo skew)
  • x86-64 con punteros de 64 bits, otro manejo de DF: 16B (DF = 1 skew) , 17B ( nostringcon DF = 1, usando en scasblugar de dec). 18B ( stosb_edx_argpreservando DF = 1 con 3 bytes inc rdi).

    O si permitimos devolver un puntero a 1 byte antes de la cadena, 15B ( stosb_edx_argsin incel final). Todo listo para llamar de nuevo y expandir otra cadena en el búfer con una base / tabla diferente ... Pero eso tendría más sentido si tampoco almacenamos una terminación 0, y podría poner el cuerpo de la función dentro de un bucle, así que eso es realmente un problema separado

  • x86-64 con puntero de salida de 32 bits, convención de llamada DF = 0: no hay mejora con respecto al puntero de salida de 64 bits, pero nostringahora se vincula 18B ( ).

  • x86-64 con puntero de salida de 32 bits: no hay mejora con respecto a las mejores versiones de puntero de 64 bits, por lo que 16B (DF = 1 skew). O para establecer DF = 1 y dejarlo, 17B para skewcon stdpero no cld. O 17 + 1B para stosb_decode_overlapcon inc edial final en lugar de cld/ scasb.

Con una convención de llamada DF = 1: 16 bytes (IA32 o x86-64)

Requiere DF = 1 en la entrada, lo deja configurado. Apenas plausible , al menos en función de cada función. Hace lo mismo que la versión anterior, pero con xchg para obtener el resto de entrada / salida de AL antes / después de XLATB (búsqueda de tabla con R / EBX como base) y STOSB ( *output-- = al).

Con un DF = 0 normal en la convención de entrada / salida, la versión std/ cld/ scasbtiene 18 bytes para el código de 32 y 64 bits, y está limpia en 64 bits (funciona con un puntero de salida de 64 bits).

Tenga en cuenta que los argumentos de entrada están en diferentes registros, incluido RBX para la tabla (para xlatb). También tenga en cuenta que este ciclo comienza almacenando AL y termina con el último carácter que aún no está almacenado (de ahí movel final). Entonces el bucle está "sesgado" en relación con los demás, de ahí el nombre.

                            ;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

Una versión similar no sesgada supera el EDI / RDI y luego lo arregla.

                            ; 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

Intenté una versión alternativa de esto con lea esi, [rbx+rdx]/ movsbcomo el cuerpo del bucle interno. (RSI se restablece cada iteración, pero RDI disminuye). Pero no puede usar xor-zero / stos para el terminador, por lo que es 1 byte más grande. (Y no está limpio para 64 bits para la tabla de búsqueda sin un prefijo REX en la LEA).


LUT con longitud explícita y un terminador 0: 16 + 1 bytes (32 bits)

Esta versión establece DF = 1 y lo deja así. Estoy contando el byte LUT adicional requerido como parte del recuento total de bytes.

El truco genial aquí es tener los mismos bytes decodificar de dos maneras diferentes . Caemos en el medio del bucle con resto = base y cociente = número de entrada, y copiamos el terminador 0 en su lugar.

En la primera vez a través de la función, los primeros 3 bytes del bucle se consumen como los bytes altos de un disp32 para un LEA. Esa LEA copia la base (módulo) a EDX, idivproduce el resto para iteraciones posteriores.

El segundo byte de idiv ebpes FD, que es el código de operación para la stdinstrucción que esta función necesita para funcionar. (Este fue un descubrimiento afortunado. Había estado mirando esto divantes, que se distingue del idivuso de los /rbits en ModRM. El segundo byte de div epbdecodifica como cmc, que es inofensivo pero no útil. Pero con idiv ebpeso podemos eliminarlo stdde la parte superior de la función.)

Tenga en cuenta que los registros de entrada son una vez más diferencia: EBP para la 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

Este truco de decodificación superpuesta también se puede usar con cmp eax, imm32 : solo se necesita 1 byte para avanzar de manera efectiva 4 bytes, solo banderas de clobbering. (Esto es terrible para el rendimiento en las CPU que marcan los límites de las instrucciones en la caché L1i, por cierto).

Pero aquí, estamos usando 3 bytes para copiar un registro y saltar al bucle. Eso normalmente tomaría 2 + 2 (mov + jmp), y nos permitiría saltar al bucle justo antes del STOS en lugar de antes del XLATB. Pero entonces necesitaríamos una ETS por separado, y no sería muy interesante.

Pruébalo en línea! (con una _startpersona que llama que usa sys_writeen el resultado)

Es mejor para la depuración ejecutarlo straceo reducir la salida de forma hexadecimal, para que pueda verificar que haya un \0terminador en el lugar correcto y así sucesivamente. Pero puede ver que esto realmente funciona y producir AAAAAACHOOpara una entrada de

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

(En realidad xxAAAAAACHOO\0x\0\0..., porque estamos volcando desde 2 bytes antes en el búfer a una longitud fija. Entonces podemos ver que la función escribió los bytes que se suponía que debía y no pisó ningún byte que no debería tener. El puntero de inicio que se pasó a la función fue el segundo y último xcarácter, seguido de ceros).


3

Jalea , 4 bytes

ṙ1ṃ@

Pruébalo en línea!

está literalmente incorporado para esto. Los otros tres bytes representan la indexación basada en uno de Jelly.


Por curiosidad, ¿por qué Jelly incluso tiene la " Descompresión de base incorporada ; convierte x a la longitud de base (y) y luego indexa a y "? ¿Es para los casos muy excepcionales en los que la base que desea convertir y la longitud de una cadena / entero / lista son iguales? Cuando lo busco, solo puedo encontrar tres respuestas al usarlo: 1 ; 2 ; 3 . Un poco raro en todos los días, el golf de código desafía a la OMI. : S
Kevin Cruijssen

3
@KevinCruijssen es muy útil cuando desea, por ejemplo, convertir N a hexadecimal usando letras hexadecimales en lugar de una lista de números.
Sr. Xcoder

@KevinCruijssen Es un método de compresión para cadenas. En el primer ejemplo, la cadena deseada es “sspspdspdspfdspfdsp”, pero “çƥ÷£ḟ’ṃ“spdf”¤ahorra seis bytes. Es especialmente útil con los números de base 250 de Jelly
dylnan


3

Carbón , 3 1 bytes

θη

Pruébalo en línea! El enlace es a la versión detallada del código. Editar: Guardado 2 bytes gracias a @ ASCII-only. Versión anterior antes de que se agregara el incorporado, 8 bytes:

⭆↨θLη§ηι

Pruébalo en línea! El enlace es a la versión detallada del código. Explicación:

    η       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

En realidad se supone que ya funciona, pero evidentemente me he equivocado una vez más> _>
solo ASCII

Además, en realidad sería 1 byte : P (actualmente está roto, así que no estoy usando el número y la matriz de cadena como argumentos) (también, me pregunto qué tan (in) útil es la entrada implícita)
ASCII-only

@ Solo ASCII No quiere decir "1 bytes" (vea su salida -vl ;-) Además, la entrada implícita parecería ser casi inútil en el carbón, excepto para desafíos como este.
Neil

1
@ Solo ASCII "Neur" en plural en lugar de "byte" singular es lo que significa Neil. ;) En cuanto a su respuesta de 1 byte, ¿por qué la tachada θη? Parece un poco confuso tbh. ¿Por qué no simplemente eliminarlo por completo y dejarlo ?
Kevin Cruijssen

1
@Nit Lo verifiqué dos veces y el incorporado se había agregado antes de que se hiciera la pregunta, pero no me había dado cuenta porque tenía un error.
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;}

Pruébalo en línea!

Este es un puerto de la respuesta C ++ de HatsuPointerKun

El estilo de llamada es u(ulong(n), to!(char[])(b)), donde ny bson los argumentos izquierdo y derecho

D cosas específicas

Lamentablemente, necesitamos importar std.convpara realizar conversiones de cualquier tipo por encima de una conversión de tipo muy básica.

Utilizando el sistema de plantillas golfy, y dando la función de los tipos requeridos (por eso llamándolo no es sólo u(n,b)), podemos acortar las apariciones de char[]y ulonga 1byte cada uno, cuando dentro de la función f.

D inicializa nuestros tipos para nosotros, por lo que C t;es la abreviatura deC t=cast(char[])([])

to!Cconvierte el entero n%len una matriz de caracteres (usando puntos de código) y ~es una concatenación

foreach(ref c;t)es como el for(... : ...)bucle de C ++ , pero un poco más largo. refes como si &se tratara ccomo copiado por referencia (es decir, podemos modificarlo t). Por suerte, infiere D del tipo de csin ningún tipo de palabras clave que denota.



3

C ++, 150 144 bytes, uint64de entrada

-6 bytes gracias 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;}

El uso de una variable para almacenar el tamaño aumentaría el bytecount en 1

Para llamar a la función:

u(2740, "|_")

Primero el número, segundo es la cadena (matriz de caracteres)

Casos de prueba :

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

1
3 bytes para recortar: no necesita el espacio después #include, puede cambiar ;;a solo ;y '0'puede ser simplemente48
Zacharý

1
Además, el ciclo while podría ser un forciclo:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
Zacharý

@ceilingcat, olvidé que eso b.size()no cambia en ese ciclo.
Zacharý

@ceilingcat Eso aumentaría el bytecount en 1, en lugar de
reducirlo

2

Ramita, 66 bytes

Creado un macroque debe ser imported en una plantilla.

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

Valores esperados:

Para los primeros argumentos ( n):

  • número
  • cuerda

Para el segundo argumento ( c):

  • Matriz de números
  • Matriz de cuerdas

Cómo utilizar:

  • Crear un .twigarchivo
  • Añadir {% import 'file.twig' as uncompress %}
  • Llamar a la macro uncompress.d()

Sin golf (no funcional):

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


Puede probar este código en: https://twigfiddle.com/54a0i9


2

Pyth, 9 8 7 bytes

s@LQjEl

Ahorré un byte gracias a hakr14 y otro gracias al Sr. Xcoder.
Pruébalo aquí

Explicación

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.

Ahorre un byte reemplazándolo m@Qdcon@LQ
hakr14

Guarde un byte reemplazándolo vzcon E.
Sr. Xcoder

2

C89, rango limitado firmado int n, 64 53 bytes

  • registro de cambios: tome un char **outy modifíquelo, en lugar de tomar y devolver unchar *

Toma el número como una int, la tabla de búsqueda como una matriz + longitud.
La salida se escribe en a char *outbuf. La persona que llama pasa (por referencia) un puntero al final del búfer. La función modifica ese puntero para que apunte al primer byte de la cadena al regresar.

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

Este es un C89 válido y funciona correctamente incluso con la optimización habilitada. es decir, no depende del -O0comportamiento de gcc cuando se cae al final de una función no nula o tiene cualquier otra UB.

Pasar un puntero al final de un búfer es normal para una función int-> string optimizada, como la interna de glibc_itoa . Consulte esta respuesta para obtener una explicación detallada de cómo dividir un número entero en dígitos con un bucle div / mod como lo estamos haciendo aquí, en C y en x86-64 asm. Si la base es una potencia de 2, puede cambiar / enmascarar para extraer dígitos MSD primero, pero de lo contrario, la única buena opción es el primer dígito menos significativo (con módulo).

Pruébalo en línea! . Versión sin golf:

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

En esta versión de longitud explícita, la entrada es una char table[]que no necesita un byte de terminación 0, porque nunca la tratamos como una cadena. Podría ser un int table[]para todo lo que nos importa. C no tiene contenedores que conozcan su propia longitud, por lo que puntero + longitud es la forma normal de pasar una matriz con un tamaño. Así que elegimos eso en lugar de necesitarlo strlen.

El tamaño máximo del búfer es aproximadamente sizeof(int)*CHAR_BIT + 1, por lo que es pequeño y constante en tiempo de compilación. (Utilizamos este espacio con base = 2 y todos los bits establecidos en 1.) por ejemplo, 33 bytes para enteros de 32 bits, incluido el 0terminador.


C89, firmada int, tabla como una cadena C de longitud implícita, 65 bytes

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

Esto es lo mismo, pero la entrada es una cadena de longitud implícita, por lo que tenemos que encontrar la longitud nosotros mismos.


2

Bash + utilidades principales , 49 bytes

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

Pruébalo en línea!

Comentarios / explicación

Esto toma los argumentos de la línea de comandos como entrada (el número en la base 10, luego una sola cadena con la lista de caracteres) y sale a stdout. Los caracteres especiales como el espacio, salto de línea, etc se pueden introducir en notación octal (por ejemplo, \040por un espacio), o \nde una nueva línea, \tpara la lengüeta, o cualquier otra secuencia de escape que echo -ee trinterpretar de forma idéntica.

Muchos de los bytes aquí son para manejar caracteres especiales y casos de prueba más grandes. Si solo tengo que manejar caracteres no terribles y los números son pequeños (por ejemplo, el primer caso de prueba), los siguientes 24 bytes lo harán:

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

Esto usa la expansión de parámetros ${#2}para obtener el número de caracteres en la cadena, crea un programa de CC para realizar la conversión base y luego envía el número convertido tr.

Sin embargo, esto no manejará nuevas líneas o espacios o pestañas, por lo que para tratar las secuencias de escape sin afectar la base, hago un recuento de caracteres wc -cdespués de interpretar los escapes echo -en. Esto expande el programa a 38 bytes:

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

Desafortunadamente, DC tiene una "característica" molesta en la que si está generando un gran número, lo envolverá en línea con una secuencia de barra + nueva línea, por lo que los casos de prueba más grandes tienen esta salida adicional. Para eliminarlo, canalizo la salida de CC tr -dc 0-9para eliminar caracteres no numéricos. Y ahí estamos.


Iba a sugerir dc -e${#2}o$1p|tr 0-9 "$2"tomar la entrada literalmente en lugar de en forma \ escape para que pueda manejar espacios, pero trno tiene una opción para no tratar -como un carácter de rango, por ejemplo. Si la entrada -no tiene un extremo de la cadena, se rompe. Quizás puedas usar sed "y/0123456789/$2/". No, supongo que no, GNU sedrequiere que ambos argumentos ytengan la misma longitud, y parece que se ahoga en la nueva línea.
Peter Cordes

2

APL (Dyalog Unicode) , 14 13 12 bytes

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

Pruébalo en línea!

Función infija tácita; no puede manejar el caso de prueba más grande debido a la representación de punto flotante.

Guardado 1 2 bytes gracias a @ Adám!

13 bytes añadidos para los encabezados: ⎕IO←0: I ndex O rigin = 0 y ⎕FR←1287: F loat R ePresentation = 128 bits. (Había olvidado que esto no se aplica ) .

¿Cómo?

⊢⌷⍨∘⊂⊥⍣¯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.

2

Adjunto , 17 bytes

{_[_2&ToBase!#_]}

Pruébalo en línea!

Explicación

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

1

Lienzo , 7 bytes.

L┬{╵⁸@p

Pruébalo aquí!

Implementación directa:

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

El conjunto de caracteres de entrada también puede ser una cadena siempre que no contenga una nueva línea, ya que Canvas no tiene un carácter de nueva línea y lo convierte automáticamente en un objeto 2D.


1

Stax , 6 5 bytes

n%|E@

Ejecutar y depurarlo

Explicación:

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

1

SOGL V0.12 , 10 bytes

l;A─{IaWp}

Pruébalo aquí!

Bastante largo, considerando que la idea está más o menos implementada en el lenguaje: aquí , ingresando

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

emite una cadena comprimida usando este método.



1

Stax , 2 bytes

:B

Ejecutar y depurarlo

:Bes una instrucción en stax que hace esto. Normalmente funcionaría en una "cadena" * en lugar de una matriz de "cadenas". Al final, esto significa que la salida es una matriz de matrices de un solo carácter. Pero la salida implícitamente se aplana de todos modos.

* Stax en realidad no tiene un tipo de cadena. El texto está representado por conjuntos enteros de puntos de código.


Eh, nunca me di cuenta de este comando ...
Wastl

Hay muchos Una vez agregué una instrucción a stax que ya existía, y me había olvidado. (¿la matriz no es descendente?)
recursiva el

1

J , 12 bytes

]{~#@]#.inv[

¿Cómo?

      #.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        

Pruébalo en línea!



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

Pruébalo en línea!

Descripción:

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
Si comienza al final de un búfer y trabaja hacia atrás, puede evitarlo sprintf. Mi versión C es de 53 bytes , con el búfer de salida proporcionado por la persona que llama. Puede hacer uno strcpyal final si desea copiar los bytes al inicio de un búfer.
Peter Cordes

Eso es genial No me importa si es un formato de E / S incómodo. ¡E / S incómoda es C reclamo de fama! Bien hecho, recomendaría poner eso en la publicación de consejos C.
LambdaBeta

Publicó una respuesta en Consejos para jugar golf en C explicando y justificando la técnica.
Peter Cordes

1

CJam , 11 bytes

liq_,@\b\f=

Pruébalo en línea! Toma la entrada como el número, luego una nueva línea, luego los caracteres en el arte ASCII.

Explicación

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

Como "IO es flexible", creo que puedes deshacerte de él liqal principio, ¡y eso te ahorra 3 bytes!
Cromo

1

JavaScript, 39 bytes

Solución Python del puerto de Rod .

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

Pruébalo en línea


Solo funciona nhasta 64 bits, ¿verdad? (Python tiene enteros de precisión arbitraria incorporados, pero los números JS son doubleflotantes de precisión natural que se pueden convertir a enteros). No parece funcionar para los casos de prueba más grandes en la pregunta, como 1928149325670647244912100789213626616560861130859431492905908574660758972167966. Oh, pero la pregunta permite respuestas como esa. Aún así, debe tenerse en cuenta.
Peter Cordes

1

SimpleTemplate , 86 bytes

¡Guau, este fue un gran desafío!

Esto se hizo difícil debido a la falta de acceso directo a índices específicos cuando el índice es una variable.
Un error también lo hizo más largo, requiriendo almacenar los valores dentro de una variable.

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

Valores esperados:

El primer argumento ( argv.0) puede ser:

  • Un entero
  • Una cadena con números
  • Un conjunto de enteros

El segundo argumento ( argv.1) puede ser:

  • Una cuerda
  • Una matriz

¿Cómo funciona esto?

Funciona de esta manera:

  • Recorre el número / cadena pasado como primer argumento
  • Establece la variable Ccomo una matriz que contiene:
    • El valor anterior C
    • La cuerda "{@echoA."
    • El valor del bucle.
    • La cuerda "}"
  • Une todo junto (usando la joinfunción de PHP )
    Esto resulta, por ejemplo, en Ccontener"{@echoA.0}{@echoA.1}..."
  • Evalúa el resultado de C

Sin golf:

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

Puede probar este código en: https://ideone.com/NEKl2q


Resultado óptimo

Si no hubiera errores, este sería el mejor resultado, teniendo en cuenta las limitaciones (77 bytes):

{@eachargv.0}{@setC C,"{@echoargv.1.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.