Compressione grafica ASCII da un numero base-n


24

Questo si ispira a una risposta 05AB1E di Magic Octupus Urn .

Dati due argomenti, un numero intero positivo e una stringa / elenco di caratteri:

  1. Traduci il numero in base-n, dove n è la lunghezza della stringa.
  2. Per ogni personaggio, sostituisci ogni aspetto dell'indice di quel personaggio nel numero base-n con quel carattere.
  3. Stampa o restituisce la nuova stringa.

Esempi:

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

Regole:

  • IO è flessibile .
    • Puoi prendere il numero in qualsiasi base, purché sia ​​coerente tra gli input
    • L'elenco dei caratteri deve essere indicizzato con 0, dove 0 è il primo carattere e n-1 è l'ultimo
  • I caratteri possibili possono essere qualsiasi ASCII stampabile, insieme a spazi bianchi come schede e nuove righe
  • L'elenco di caratteri specificato avrà una lunghezza compresa nell'intervallo 2-10. Cioè, la base più piccola è binaria e la più grande è decimale ( non ci sono lettere fastidiose qui )
  • Sono vietate le scappatoie standard
  • Sentiti libero di rispondere anche se la tua lingua non è in grado di gestire i casi di test più grandi.

Poiché si tratta di , vince il codice più breve per ogni lingua. ( So che tutte le lingue del golf hanno un byte integrato pronto per l'uso ;)


Sandbox (cancellato)
Jo King,

3
D'awwh, mi sento onorato. 05AB1E ascii-art era la mia preferita qualche tempo fa.
Magic Octopus Urn,

puoi creare una nuova sfida: trova la permutazione dei personaggi nella matrice per ridurre al minimo il numero :)
mazzy,

Risposte:


8

05AB1E , 7 6 byte

gв¹sèJ

Poiché è stato ispirato da una risposta 05AB1E, una risposta fornita in 05AB1E sembra adatta. :)

-1 byte grazie a @Enigma rimuovendo il foreach e facendolo implicitamente.

Provalo online o verifica tutti i casi di test .

Spiegazione:

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èJper salvare un byte.
Emigna,

@Emigna Grazie. Non riesco a credere di non aver pensato a ¹sème stesso ora .. (Sapevo che cambiare ?in a Javrebbe dato lo stesso risultato in questo caso.)
Kevin Cruijssen,

6

Java 8, 72 50 byte

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

-22 byte grazie a @ OlivierGrégoire restituendo un IntStreaminvece di stampare direttamente.

Provalo online .

Spiegazione:

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 byte) poiché "IO è flessibile"
Olivier Grégoire,

String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69 byte) uno ricorsivo, per divertimento.
Olivier Grégoire,

6

Python 3 , 49 byte

Non posso ancora commentare, quindi inserisco la risposta di Python 2 adattata a Python 3.5.

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

2
Benvenuti in PPCG! Sentiti libero di includere un link TIO per aiutarti a mostrare la tua soluzione.
Jo King,

5

Japt, 2 byte

Può accettare il secondo input come una matrice o una stringa. Non supera gli ultimi 2 casi di test poiché i numeri superano il numero intero massimo di JavaScript. Sostituisci invece scon ìun array di caratteri.

sV

Provalo


5

Haskell , 40 39 byte

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

Provalo online!

Poiché il Inttipo di Haskell è limitato a9223372036854775807 , questo non riesce per numeri più grandi.

-1 byte grazie 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)

Provalo online!


Bella idea da usare al cycleposto di mod! div n(length l)salva un byte.
Laikoni,

4

MATL , 2 byte

YA

Provalo online!

Gli input sono un numero e una stringa.

Non riesce a superare i numeri 2^53 , a causa della precisione in virgola mobile.

Spiegazione

Che ne YAsappiamo, un builtin (conversione di base con simboli target specificati).


4

JavaScript (ES6), 48 byte

Accetta input nella sintassi del curry (c)(n), dove c è un elenco di caratteri e n è un numero intero.

Sicuro solo per n <2 53 .

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

Provalo online!


JavaScript (ES6), 99 byte

Con supporto per grandi numeri interi

Accetta input nella sintassi del curry (c)(a), dove c è un elenco di caratteri e a è un elenco di cifre decimali (come numeri interi).

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

Provalo online!


4

x86 codice macchina a 32 bit (numeri interi a 32 bit): 17 byte.

(vedi anche le altre versioni seguenti, inclusi 16 byte per 32-bit o 64-bit, con una convenzione di chiamata DF = 1).

Il chiamante passa args nei registri, incluso un puntatore alla fine di un buffer di output (come la mia risposta C ; guardalo per giustificazione e spiegazione dell'algoritmo.) Glibc interno _itoafa questo , quindi non è solo concepito per il code-golf. I registri di passaggio arg sono vicini al sistema V x86-64, tranne per il fatto che abbiamo un arg in EAX anziché EDX.

Al ritorno, EDI punta al primo byte di una stringa C con terminazione 0 nel buffer di output. Il normale registro del valore restituito è EAX / RAX, ma nel linguaggio assembly è possibile utilizzare qualunque convenzione di chiamata sia conveniente per una funzione. ( xchg eax,edialla fine aggiungerebbe 1 byte).

Se lo desidera, il chiamante può calcolare una lunghezza esplicita da buffer_end - edi. Ma non credo che possiamo giustificare l'omissione del terminatore a meno che la funzione non restituisca effettivamente entrambi i puntatori inizio + fine o puntatore + lunghezza. Ciò consentirebbe di risparmiare 3 byte in questa versione, ma non credo sia giustificabile.

  • EAX = n = numero da decodificare. (Per idiv. Gli altri argomenti non sono operandi impliciti.)
  • EDI = fine del buffer di output (la versione a 64 bit utilizza ancora dec edi, quindi deve essere in basso 4GiB)
  • ESI / RSI = tabella di ricerca, alias LUT. non ostruito.
  • ECX = lunghezza della tabella = base. non ostruito.

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (Modificato a mano per ridurre i commenti, la numerazione delle righe è strana.)

   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

È sorprendente che la versione più semplice senza praticamente compromessi di velocità / dimensione sia la più piccola, ma std/ cldcostata 2 byte da usare stosbper andare in ordine decrescente e seguire comunque la convenzione di chiamata DF = 0 comune. (E decrementi STOS dopo archiviazione, lasciando il puntatore che punta a un byte troppo basso all'uscita del loop, costandoci byte extra per aggirare.)

versioni:

Ho escogitato 4 trucchi di implementazione significativamente diversi (usando il semplice movcaricamento / archivio (sopra), usando lea/ movsb(pulito ma non ottimale), usando xchg/xlatb / stosb/ xchg, e uno che entra nel ciclo con un hack di istruzioni sovrapposte. Vedi codice sotto) . L'ultimo ha bisogno di un trailing 0nella tabella di ricerca per copiarlo come terminatore della stringa di output, quindi lo conto come +1 byte. A seconda di 32/64 bit (1 byte inco meno) e se possiamo supporre che il chiamante imposta DF = 1 ( stosbdecrescente) o qualsiasi altra cosa, le diverse versioni sono (legate per) più brevi.

DF = 1 da memorizzare in ordine decrescente lo rende una vittoria per xchg / stosb / xchg, ma il chiamante spesso non lo vorrà; Sembra scaricare il lavoro al chiamante in un modo difficile da giustificare. (A differenza dei registri personalizzati di passaggio arg e valore restituito, che in genere non costano ad un chiamante asm alcun lavoro extra.) Ma nel codice a 64 bit,cld / scasbfunziona come inc rdi, evitando di troncare il puntatore di output a 32 bit, quindi a volte scomodo conservare DF = 1 in funzioni pulite a 64 bit. . (I puntatori a codice / dati statici sono 32 bit negli eseguibili x86-64 non PIE su Linux e sempre nell'ABI x32 Linux, quindi in alcuni casi è utilizzabile una versione x86-64 che utilizza puntatori a 32 bit.) Comunque, questa interazione rende interessante esaminare diverse combinazioni di requisiti.

  • IA32 con un DF = 0 sulla convenzione di chiamata in entrata / uscita: 17B ( nostring) .
  • IA32: 16B (con una convenzione DF = 1: stosb_edx_argo skew) ; o con DF = dontcare in entrata, lasciandolo impostato: 16 + 1Bstosb_decode_overlap o 17Bstosb_edx_arg
  • x86-64 con puntatori a 64 bit e un DF = 0 sulla convenzione di chiamata di entrata / uscita: 17 + 1 byte ( stosb_decode_overlap) , 18B ( stosb_edx_argo skew)
  • x86-64 con puntatori a 64 bit, altra gestione DF: 16B (DF = 1 skew) , 17B ( nostringcon DF = 1, usando scasbinvece di dec). 18B ( stosb_edx_argpreservando DF = 1 con 3 byte inc rdi).

    O se consentiamo di restituire un puntatore a 1 byte prima della stringa, 15B ( stosb_edx_argsenza il incalla fine). Tutto pronto per richiamare nuovamente ed espandere un'altra stringa nel buffer con base / tabella diversa ... Ma ciò avrebbe più senso se non memorizzassimo nemmeno una terminazione 0, e potresti mettere il corpo della funzione in un ciclo, quindi è davvero un problema separato.

  • x86-64 con puntatore di output a 32 bit, DF = 0 convenzione di chiamata: nessun miglioramento rispetto al puntatore di output a 64 bit, ma 18B (nostring ) ora si collega.

  • x86-64 con puntatore di output a 32 bit: nessun miglioramento rispetto alle migliori versioni di puntatore a 64 bit, quindi 16B (DF = 1 skew). O per impostare DF = 1 e lasciarlo, 17B per skewcon stdma non cld. O 17 + 1B per stosb_decode_overlapcon inc edialla fine invece di cld/ scasb.

Con una convenzione di chiamata DF = 1: 16 byte (IA32 o x86-64)

Richiede DF = 1 sull'input, lascia impostato. A malapena plausibile , almeno per una funzione. Fa la stessa cosa della versione precedente, ma con xchg per ottenere il resto dentro / fuori di AL prima / dopo XLATB (ricerca tabella con R / EBX come base) e STOSB ( *output-- = al).

Con un normale DF = 0 alla convenzione di entrata / uscita, il std/ cld/scasb versione è di 18 byte per il codice a 32 e 64 bit ed è a 64 bit pulita (funziona con un puntatore di output a 64 bit).

Si noti che gli argomenti di input si trovano in registri diversi, incluso RBX per la tabella (per xlatb). Si noti inoltre che questo ciclo inizia con la memorizzazione di AL e termina con l'ultimo carattere non ancora memorizzato (quindi il movalla fine). Quindi il ciclo è "distorto" rispetto agli altri, da cui il 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

Una versione analoga non inclinata sovrascrive EDI / RDI e quindi lo risolve.

                            ; 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

Ho provato una versione alternativa di questo con lea esi, [rbx+rdx]/ movsbcome il corpo del loop interno. (RSI viene reimpostato ad ogni iterazione, ma decrementi RDI). Ma non può usare xor-zero / stos per il terminatore, quindi è 1 byte più grande. (E non è pulito a 64 bit per la tabella di ricerca senza un prefisso REX sul LEA.)


LUT con lunghezza esplicita e un terminatore 0: 16 + 1 byte (32 bit)

Questa versione imposta DF = 1 e la lascia così. Sto contando il byte LUT extra richiesto come parte del conteggio dei byte totali.

Il trucco interessante qui è che gli stessi byte decodificano in due modi diversi . Cadiamo nel mezzo del ciclo con remainder = base e quotient = input number e copiamo il terminatore 0 in posizione.

Al primo passaggio della funzione, i primi 3 byte del loop vengono consumati come byte alti di un disp32 per un LEA. Che LEA copia la base (modulo) su EDX, idivproduce il resto per successive iterazioni.

Il secondo byte di idiv ebpè FD, che è il codice stdoperativo per l' istruzione che questa funzione deve funzionare. (Questa è stata una scoperta fortunata. Lo avevo già visto in divprecedenza, che si distingue idivdall'uso dei /rbit in ModRM. Il secondo byte di div epbdecodifica come cmc, che è innocuo ma non utile. Ma con idiv ebppossiamo effettivamente rimuovere stddall'alto della funzione.)

Notare che i registri di input sono ancora una volta differenza: EBP per 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

Questo trucco di decodifica sovrapposto può essere utilizzato anche con cmp eax, imm32 : bastano solo 1 byte per saltare in avanti efficacemente di 4 byte, solo bloccando i flag. (Questo è terribile per le prestazioni sulle CPU che segnano i limiti delle istruzioni nella cache L1i, BTW.)

Ma qui, stiamo usando 3 byte per copiare un registro e saltare nel ciclo. Ciò richiederebbe normalmente 2 + 2 (mov + jmp) e ci lascerebbe saltare nel loop proprio prima della STOS invece che prima della XLATB. Ma allora avremmo bisogno di un STD separato, e non sarebbe molto interessante.

Provalo online! (con un _startchiamante che utilizza sys_writeil risultato)

È consigliabile straceeseguirne il debug o eseguirne il dump dell'output, in modo da poter verificare che sia presente un \0terminatore nel posto giusto e così via. Ma puoi vedere che funziona davvero e produrre AAAAAACHOOper un input di

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

(In realtà xxAAAAAACHOO\0x\0\0..., perché stiamo scaricando da 2 byte precedenti nel buffer fino a una lunghezza fissa. Quindi possiamo vedere che la funzione ha scritto i byte che avrebbe dovuto e non ha fatto alcun passo sui byte che non avrebbe dovuto. start-pointer passato alla funzione era il penultimo xcarattere, seguito da zero.)


3

Gelatina , 4 byte

ṙ1ṃ@

Provalo online!

è letteralmente integrato per questo. Gli altri tre byte rappresentano l'indicizzazione basata su uno solo di Jelly.


Per curiosità, perché Jelly ha persino la " decompressione di base incorporata ; converti x in lunghezza di base (y) quindi indicizza in y. "? È per i casi davvero eccezionali in cui la base in cui vuoi convertire e la lunghezza di una stringa / numero intero / elenco sono uguali? Quando lo cerco, riesco a trovare solo tre risposte che lo usano: 1 ; 2 ; 3 . Un po 'strano in ogni giorno sfide golf code imo. : S
Kevin Cruijssen,

3
@KevinCruijssen è molto utile quando si desidera, ad esempio, convertire N in esadecimale utilizzando lettere esadecimali anziché un elenco di numeri.
Mr. Xcoder,

@KevinCruijssen È un metodo di compressione per le stringhe. Nel primo esempio la stringa desiderata è “sspspdspdspfdspfdsp”, ma con “çƥ÷£ḟ’ṃ“spdf”¤te salva sei byte. È particolarmente utile con i 250 numeri di base di Jelly
dylnan,

3

Python 2 , 49 48 byte

-1 byte grazie a Jo King

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

Provalo online!

Versione alternativa (non terminerà per grandi numeri), 45 43 byte

-2 byte grazie a Jo King

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

Provalo online!


3

Carbone , 3 1 byte

θη

Provalo online! Il collegamento è alla versione dettagliata del codice. Modifica: salvato 2 byte grazie solo a @ ASCII. Versione precedente prima dell'aggiunta del builtin, 8 byte:

⭆↨θLη§ηι

Provalo online! Il collegamento è alla versione dettagliata del codice. Spiegazione:

    η       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

In realtà dovrebbe già funzionare, ma evidentemente ho sbagliato ancora una volta> _>
ASCII il

Inoltre, in realtà sarebbe 1 byte : P (al momento è rotto, quindi non sto usando l'array di numeri e stringhe come argomenti) (inoltre, mi chiedo come sia (implicito) un input implicito utile)
ASCII-only

@ ASCII-only Non intendi "1 byte" (vedi il tuo output -vl ;-) Inoltre, l'input implicito sembrerebbe quasi inutile in Charcoal, tranne per sfide come questa.
Neil,

1
@ Solo ASCII "byte" plurale anziché singolare "byte" è ciò che Neil intende. ;) Per quanto riguarda la tua risposta a 1 byte, perché il barrato θη? Sembra un po 'confuso da parte mia. Perché non rimuoverlo completamente e partire ?
Kevin Cruijssen,

1
@No ho ricontrollato e l'integrato era stato aggiunto prima che la domanda fosse posta, ma non mi ero reso conto perché aveva un bug.
Neil,

3

D , 112 byte

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

Provalo online!

Questa è una porta della risposta C ++ di HatsuPointerKun

Lo stile di chiamata è u(ulong(n), to!(char[])(b)), dove ne bsono gli argomenti destro e sinistro

D cose specifiche

Purtroppo, abbiamo bisogno di importare std.convper fare qualsiasi tipo di conversione sopra molto semplice.

Utilizzando il sistema di template Golfy, e dando la funzione dei tipi richiesti (che è il motivo per chiamarla è non solo u(n,b)), si possono ridurre le occorrenze di char[]e ulongper1 byte ciascuno, quando all'interno della funzione f.

D inizializza i nostri tipi per noi, quindi C t; è l'abbreviazione diC t=cast(char[])([])

to!Cconverte il numero intero n%lin una matrice di caratteri (usando i punti di codice) e~ è concatenazione

foreach(ref c;t)è come il for(... : ...)ciclo di C ++ , ma un po 'più a lungo. refè come &, tratta ccome copiato per riferimento (cioè, possiamo modificare t). Per fortuna, D deduce il tipo di c, senza alcun tipo denota parola chiave.



3

C ++, 150 144 byte, uint64input

-6 byte grazie 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;}

L'uso di una variabile per memorizzare le dimensioni aumenterebbe il conteggio dei punti di 1

Per chiamare la funzione:

u(2740, "|_")

Prima il numero, il secondo è la stringa (array di caratteri)

Casi test :

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

1
3 byte per radersi: non hai bisogno di spazio dopo #include, puoi cambiare ;;in solo ;e '0'puoi solo essere48
Zacharý

1
Inoltre, il ciclo while potrebbe essere un forciclo:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
Zacharý

@ceilingcat, ho dimenticato che b.size()non cambia in quel ciclo.
Zacharý,

@ceilingcat Questo aumenterebbe il byte di 1, invece di abbassarlo
HatsuPointerKun

2

Ramoscello, 66 byte

Creato un macroche deve essere importinserito in un modello.

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

Valori previsti:

Per i primi argomenti ( n):

  • numero
  • stringa

Per il secondo argomento ( c):

  • Matrice di numeri
  • Matrice di stringhe

Come usare:

  • Crea un .twigfile
  • Inserisci {% import 'file.twig' as uncompress %}
  • Chiama la macro uncompress.d()

Ungolfed (non funzionale):

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


È possibile testare questo codice su: https://twigfiddle.com/54a0i9


2

Pyth, 9 8 7 byte

s@LQjEl

Salvataggio di un byte grazie a hakr14 e un altro grazie a Mr. Xcoder.
Provalo qui

Spiegazione

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.

Salvare un byte sostituendolo m@Qdcon@LQ
hakr14

Salvare un byte sostituendolo vzcon E.
Mr. Xcoder,

2

C89, firmato a intervallo limitato int n, 64 53 byte

  • log delle modifiche: prendere a char **out modifiche e modificalo, invece di prendere e restituire achar *

Prende il numero come un int, la tabella di ricerca come un array + lunghezza.
L'output è scritto in a char *outbuf. Il chiamante passa (per riferimento) un puntatore alla fine del buffer. La funzione modifica quel puntatore in modo che punti al primo byte della stringa al ritorno.

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

Questo è C89 valido e funziona correttamente anche con l'ottimizzazione abilitata. cioè non dipende da gcc-O0 comportamento di quando si cade al termine di una funzione non nulla o si ha qualsiasi altro UB.

Passare un puntatore alla fine di un buffer è normale per una funzione int-> string ottimizzata, come quella di glibc_itoa . Vedere questa risposta per una spiegazione dettagliata della suddivisione di un numero intero in cifre con un ciclo div / mod come stiamo facendo qui, in C e x86-64 asm. Se la base ha una potenza di 2, è possibile spostare / mascherare per estrarre prima le cifre dell'MSD, ma per il resto l'unica buona opzione è prima la cifra meno significativa (con modulo).

Provalo online! . Versione non golfata:

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

In questa versione di lunghezza esplicita, l'input è un valore char table[]che non richiede uno 0 byte di terminazione, poiché non lo trattiamo mai come una stringa. Potrebbe essere unint table[] che ci interessa. C non ha contenitori che conoscono la propria lunghezza, quindi puntatore + lunghezza è il modo normale di passare un array con una dimensione. Quindi scegliamo questo invece di doverlo fare strlen.

La dimensione massima del buffer è approssimativamente sizeof(int)*CHAR_BIT + 1, quindi è piccola e costante di tempo di compilazione. (Usiamo questo spazio con base = 2 e tutti i bit impostati su 1.) Ad esempio 33 byte per numeri interi a 32 bit, incluso il 0terminatore.


C89, firmato int, tabella come stringa C a lunghezza implicita, 65 byte

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

Questa è la stessa cosa, ma l'input è una stringa di lunghezza implicita, quindi dobbiamo trovare noi stessi la lunghezza.


2

Utilità Bash + core , 49 byte

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

Provalo online!

Commenti / spiegazione

Questo prende gli argomenti della riga di comando come input (il numero in base 10, quindi una singola stringa con l'elenco di caratteri) e l'output su stdout. Caratteri speciali come spazio, newline, ecc. Possono essere inseriti in notazione ottale (ad esempio, \040per uno spazio), o \nper una nuova riga, \tper tab o per qualsiasi altra sequenza di escape che echo -eetr interpretare in modo identico.

Molti byte qui servono per gestire caratteri speciali e casi di test più grandi. Se devo solo gestire caratteri non terribili e i numeri sono piccoli (ad esempio, il primo caso di test), i seguenti 24 byte lo faranno:

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

Questo utilizza l'espansione dei parametri ${#2}per ottenere il numero di caratteri nella stringa, crea un programma cc per eseguire la conversione di base e quindi invia il numero convertito tramitetr .

Questo non gestirà newline o spazi o tab, tuttavia, quindi per gestire le sequenze di escape senza influire sulla base, faccio un conteggio dei caratteri wc -cdopo aver interpretato le escape con echo -en. Questo espande il programma a 38 byte:

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

Sfortunatamente, dc ha una "caratteristica" fastidiosa in cui se sta producendo un numero elevato, lo avvolgerà con una sequenza slash + newline, quindi i casi di test più grandi hanno questo output extra. Per rimuoverlo, installo l'output di DC tr -dc 0-9per rimuovere i caratteri non numerici. Ed eccoci qui.


Stavo per suggerire dc -e${#2}o$1p|tr 0-9 "$2"di prendere l'input letteralmente invece che in forma \ escape in modo che possa gestire gli spazi, ma trnon ha un'opzione da non trattare -come un carattere di intervallo, per esempio. Se l'input -non ha un'estremità della stringa, si interrompe. Forse puoi usare sed "y/0123456789/$2/". No, suppongo di no, GNU sedrichiede che entrambi gli arg ysiano della stessa lunghezza e sembra soffocare su newline.
Peter Cordes,

2

APL (Dyalog Unicode) , 14 13 12 byte

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

Provalo online!

Aggiunta della funzione tacita; impossibile gestire il più grande caso di test a causa della rappresentazione in virgola mobile.

Salvato 1 2 byte grazie a @ Adám!

13 byte aggiunti per le intestazioni ⎕IO←0:: I ndex O rigin = 0 e⎕FR←1287 : F Loat R ePresentation = 128 bit. (Avevo dimenticato che questo non si applica. )

Come?

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

Attache , 17 byte

{_[_2&ToBase!#_]}

Provalo online!

Spiegazione

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

1

Tela , 7 byte

L┬{╵⁸@p

Provalo qui!

Implementazione diretta:

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

Il set di caratteri di input può essere una stringa anche se non contiene una nuova riga, poiché Canvas non ha un carattere di nuova riga e lo converte automaticamente in un oggetto 2D.


1

Stax , 6 5 byte

n%|E@

Esegui ed esegui il debug

Spiegazione:

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 byte

l;A─{IaWp}

Provalo qui!

Abbastanza a lungo, considerando l'idea è praticamente implementata nella lingua: qui , entrando

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

dà una stringa compressa usando questo metodo.



1

Stax , 2 byte

:B

Esegui ed esegui il debug

:Bè un'istruzione in stax che fa questo. Funzionerebbe normalmente su una "stringa" * anziché su una matrice di "stringhe". Alla fine, ciò significa che l'output è un array di array a carattere singolo. Ma l'output si appiattisce implicitamente comunque.

* Stax in realtà non ha un tipo di stringa. Il testo è rappresentato da matrici intere di punti di codice.


Eh, non ho mai notato questo comando ...
wastl,

Ci sono un sacco. Una volta ho aggiunto un'istruzione a Stax che già esisteva e di cui mi ero appena dimenticato. (la matrice non è discendente?)
ricorsiva il

1

J , 12 byte

]{~#@]#.inv[

Come?

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

Provalo online!



1

C (gcc) , 110 byte

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

Provalo online!

Descrizione:

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
Se inizi alla fine di un buffer e lavori all'indietro, puoi evitarlo sprintf. La mia versione C è 53 byte , con il buffer di output fornito dal chiamante. Si potrebbe fare uno strcpyalla fine se si desidera copiare i byte all'inizio di un buffer.
Peter Cordes,

Questo è geniale. Non mi importa se è un formato I / O scomodo. L'I / O imbarazzante è la rivendicazione di C! Ben fatto, consiglierei di inserirlo nel post dei suggerimenti in C.
LambdaBeta,

Ha pubblicato una risposta su Suggerimenti per giocare a golf in C spiegando e giustificando la tecnica.
Peter Cordes,

1

CJam , 11 byte

liq_,@\b\f=

Provalo online!Prende input come numero, quindi una nuova riga, quindi i caratteri nell'arte ASCII.

Spiegazione

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

Poiché "IO è flessibile", penso che tu possa sbarazzartene liqall'inizio, e questo ti fa risparmiare 3 byte!
Chromium,

1

JavaScript, 39 byte

La soluzione Python di Port of Rod .

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

Provalo online


Funziona solo per n fino a 64 bit, giusto? (Python ha numeri interi di precisione arbitraria integrati, ma i numeri JS sono doublefloat di precisione che possono essere convertiti in numeri interi). Non sembra funzionare per i casi di test più grandi nella domanda, come 1928149325670647244912100789213626616560861130859431492905908574660758972167966. Oh, ma la domanda consente risposte del genere. Tuttavia, dovrebbe essere notato.
Peter Cordes,

1

SimpleTemplate , 86 byte

Caspita, questa è stata una grande sfida!

Ciò è stato reso difficile a causa della mancanza di accesso diretto a indici specifici quando l'indice è una variabile.
Un bug lo ha anche allungato, richiedendo di memorizzare i valori all'interno di una variabile.

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

Valori previsti:

Il primo argomento ( argv.0) può essere:

  • Un numero intero
  • Una stringa con numeri
  • Una matrice di numeri interi

Il secondo argomento ( argv.1) può essere:

  • Una stringa
  • Un array

Come funziona?

Funziona in questo modo:

  • Scorre il numero / la stringa passati come primo argomento
  • Imposta la variabile C come matrice contenente:
    • Il valore precedente C
    • La stringa "{@echoA."
    • Il valore del loop
    • La stringa "}"
  • Unisce tutto insieme (usando la joinfunzione di PHP ).
    Ciò si traduce, ad esempio, nel Ccontenimento"{@echoA.0}{@echoA.1}..."
  • Valuta il risultato di C

Ungolfed:

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

Puoi provare questo codice su: https://ideone.com/NEKl2q


Risultato ottimale

Se non ci fossero bug, questo sarebbe il miglior risultato, tenendo conto delle limitazioni (77 byte):

{@eachargv.0}{@setC C,"{@echoargv.1.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.