Décompression d'art ASCII à partir d'un nombre en base n

24

Ceci est inspiré d'une réponse 05AB1E de Magic Octupus Urn .

Étant donné deux arguments, un entier positif et une chaîne / liste de caractères:

  1. Traduisez le nombre en base-n, où n est la longueur de la chaîne.
  2. Pour chaque caractère, remplacez chaque apparence de l'index de ce caractère dans le nombre base-n par ce caractère.
  3. Imprimez ou renvoyez la nouvelle chaîne.

Exemples:

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

Règles:

  • IO est flexible .
    • Vous pouvez prendre le nombre dans n'importe quelle base, tant qu'il est cohérent entre les entrées
    • La liste des caractères doit cependant être indexée 0, où 0 est le premier caractère et n-1 est le dernier
  • Les caractères possibles peuvent être n'importe quel ASCII imprimable, ainsi que des espaces tels que des tabulations et des retours à la ligne
  • La liste de caractères donnée aura une longueur dans la plage 2-10incluse. Autrement dit, la plus petite base est binaire et la plus grande est décimale ( pas de lettres embêtantes ici )
  • Les failles standard sont interdites
  • N'hésitez pas à répondre même si votre langue ne peut pas gérer les plus grands cas de test.

Comme il s'agit de , le code le plus court pour chaque langue l'emporte. ( Je sais que toutes les langues de golf ont des octets intégrés prêts à l'emploi ;)

Jo King
la source
Sandbox (supprimé)
Jo King
3
D'awwh, je me sens honoré. 05AB1E ascii-art était mon préféré depuis un moment.
Magic Octopus Urn
vous pouvez créer un nouveau défi: trouver la permutation des caractères dans le tableau pour minimiser le nombre :)
mazzy

Réponses:

8

05AB1E , 7 6 octets

gв¹sèJ

Puisqu'elle a été inspirée par une réponse 05AB1E, une réponse donnée dans 05AB1E semble appropriée. :)

-1 octet grâce à @Enigma en supprimant foreach et en le faisant implicitement.

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

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
la source
1
gв¹sèJpour enregistrer un octet.
Emigna
@Emigna Merci. Je ne peux pas croire que je n'avais pas pensé à ¹sèmoi maintenant. (Je savais que changer le ?en Jdonnerait la même sortie dans ce cas.)
Kevin Cruijssen
6

Java 8, 72 50 octets

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

-22 octets grâce à @ OlivierGrégoire en retournant un IntStreamau lieu d'imprimer directement.

Essayez-le en ligne .

Explication:

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
la source
2
a->n->n.toString(a.length).chars().map(c->a[c-48])(50 octets) depuis "IO is flexible"
Olivier Grégoire
String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69 octets) récursif, pour le plaisir.
Olivier Grégoire
6

Python 3 , 49 octets

Je ne peux pas encore commenter, donc je poste la réponse Python 2 adaptée à Python 3.5.

f=lambda n,s:n and f(n//len(s),s)+s[n%len(s)]or''
Romzie
la source
2
Bienvenue chez PPCG! N'hésitez pas à inclure un lien TIO pour présenter votre solution.
Jo King
5

Japt, 2 octets

Peut prendre la deuxième entrée sous forme de tableau ou de chaîne. Échoue les 2 derniers cas de test car les nombres dépassent l'entier maximum de JavaScript. Remplacez spar ìpour afficher un tableau de caractères à la place.

sV

Essayez-le

Hirsute
la source
5

Haskell , 40 39 octets

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

Essayez-le en ligne!

Comme le Inttype de Haskell est limité à 9223372036854775807, cela échoue pour les plus grands nombres.

-1 octet merci à Laikoni .

Non 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)

Essayez-le en ligne!

ovs
la source
Belle idée à utiliser cycleau lieu de mod! div n(length l)enregistre un octet.
Laikoni
4

MATL , 2 octets

YA

Essayez-le en ligne!

Les entrées sont un nombre et une chaîne.

Échoue pour les nombres dépassant 2^53, en raison de la précision en virgule flottante.

Explication

Que YAsavez-vous, une fonction intégrée (conversion de base avec des symboles cibles spécifiés).

Luis Mendo
la source
4

JavaScript (ES6), 48 octets

Prend une entrée dans la syntaxe de curry (c)(n), où c est une liste de caractères et n est un entier.

Sûr uniquement pour n <2 53 .

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

Essayez-le en ligne!


JavaScript (ES6), 99 octets

Avec prise en charge des grands nombres entiers

Prend la saisie dans la syntaxe de curry (c)(a), où c est une liste de caractères et a est une liste de chiffres décimaux (sous forme d'entiers).

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

Essayez-le en ligne!

Arnauld
la source
4

Code machine x86 32 bits (entiers 32 bits): 17 octets.

(voir également les autres versions ci-dessous, y compris 16 octets pour 32 bits ou 64 bits, avec une convention d'appel DF = 1.)

L' appelant passe args dans les registres, y compris un pointeur vers la fin d'un tampon de sortie (comme ma C réponse , voir pour la justification et l' explication de l'algorithme.) Interne de glibc _itoafait cela , il est donc pas seulement arrangea pour le code-golf. Les registres de passage d'argument sont proches du système V x86-64, sauf que nous avons un arg dans EAX au lieu d'EDX.

En retour, EDI pointe vers le premier octet d'une chaîne C terminée par 0 dans le tampon de sortie. Le registre de valeur de retour habituel est EAX / RAX, mais en langage assembleur, vous pouvez utiliser n'importe quelle convention d'appel convenant à une fonction. ( xchg eax,edià la fin ajouterait 1 octet).

L'appelant peut calculer une longueur explicite s'il le souhaite, à partir de buffer_end - edi. Mais je ne pense pas que nous puissions justifier l'omission du terminateur à moins que la fonction ne retourne réellement les deux pointeurs de début + fin ou le pointeur + la longueur. Cela économiserait 3 octets dans cette version, mais je ne pense pas que ce soit justifiable.

  • EAX = n = nombre à décoder. (Pour idiv. Les autres arguments ne sont pas des opérandes implicites.)
  • EDI = fin du tampon de sortie (la version 64 bits utilise toujours dec edi, donc doit être dans le bas 4GiB)
  • ESI / RSI = table de recherche, également appelée LUT. pas clobber.
  • ECX = longueur de la table = base. pas clobber.

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (Modifié à la main pour réduire les commentaires, la numérotation des lignes est bizarre.)

   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

Il est surprenant que la version la plus simple sans compromis de vitesse / taille soit la plus petite, mais std/ cldcoûte 2 octets à utiliser stosbpour aller dans l'ordre décroissant et toujours suivre la convention d'appel DF = 0 commune. (Et STOS diminue après le stockage, laissant le pointeur pointant un octet trop bas à la sortie de la boucle, ce qui nous coûte des octets supplémentaires pour contourner.)

Versions:

J'ai trouvé 4 astuces d'implémentation significativement différentes (en utilisant un movchargement / stockage simple (ci-dessus), en utilisant lea/ movsb(soigné mais pas optimal), en utilisant xchg/ xlatb/ stosb/ xchget un qui entre dans la boucle avec un hack d'instruction à chevauchement. Voir le code ci-dessous) . Le dernier a besoin d'une fin 0dans la table de recherche pour copier en tant que terminateur de chaîne de sortie, donc je compte cela comme +1 octet. Selon 32/64 bits (1 octet incou non), et si nous pouvons supposer que l'appelant définit DF = 1 ( stosbdécroissant) ou autre, différentes versions sont (à égalité) les plus courtes.

DF = 1 à stocker dans l'ordre décroissant en fait une victoire pour xchg / stosb / xchg, mais souvent, l'appelant n'en voudra pas; C'est comme décharger le travail de l'appelant d'une manière difficile à justifier. (Contrairement aux registres de passage d'argument et de valeur de retour personnalisés, qui ne coûtent généralement pas de travail supplémentaire à un appelant asm.) Mais dans le code 64 bits, cld/ scasbfonctionne comme inc rdi, évitant de tronquer le pointeur de sortie sur 32 bits, il est donc parfois gênant de conserver DF = 1 dans les fonctions de nettoyage 64 bits. . (Les pointeurs vers du code / des données statiques sont 32 bits dans les exécutables non PIE x86-64 sous Linux, et toujours dans l'ABI Linux x32, donc une version x86-64 utilisant des pointeurs 32 bits est utilisable dans certains cas.) Quoi qu'il en soit, cette interaction rend intéressant d'examiner différentes combinaisons d'exigences.

  • IA32 avec un DF = 0 à la convention d'appel d'entrée / sortie: 17B ( nostring) .
  • IA32: 16B (avec une convention DF = 1: stosb_edx_argou skew) ; ou avec DF entrant = dontcare, en le laissant réglé: 16 + 1Bstosb_decode_overlap ou 17Bstosb_edx_arg
  • x86-64 avec pointeurs 64 bits, et un DF = 0 sur la convention d'appel d'entrée / sortie: 17 + 1 octets ( stosb_decode_overlap) , 18B ( stosb_edx_argou skew)
  • x86-64 avec pointeurs 64 bits, autre gestion DF: 16B (DF = 1 skew) , 17B ( nostringavec DF = 1, en utilisant à la scasbplace de dec). 18B ( stosb_edx_argpréservant DF = 1 avec 3 octets inc rdi).

    Ou si nous permettons de renvoyer un pointeur à 1 octet avant la chaîne, 15B ( stosb_edx_argsans le incà la fin). Tous ensemble pour appeler à nouveau et développer une autre chaîne dans le tampon avec une base / table différente ... Mais cela aurait plus de sens si nous ne stockions pas de terminaison 0non plus, et vous pourriez mettre le corps de la fonction dans une boucle, donc c'est vraiment un problème distinct.

  • x86-64 avec pointeur de sortie 32 bits, convention d'appel DF = 0: aucune amélioration par rapport au pointeur de sortie 64 bits, mais 18B ( nostring) est maintenant lié.

  • x86-64 avec pointeur de sortie 32 bits: aucune amélioration par rapport aux meilleures versions de pointeur 64 bits, donc 16B (DF = 1 skew). Ou pour définir DF = 1 et le laisser, 17B pour skewavec stdmais pas cld. Ou 17 + 1B pour stosb_decode_overlapavec inc edià la fin au lieu de cld/ scasb.

Avec une convention d'appel DF = 1: 16 octets (IA32 ou x86-64)

Nécessite DF = 1 en entrée, laisse-le défini. À peine plausible , au moins sur une base par fonction. Fait la même chose que la version ci-dessus, mais avec xchg pour obtenir le reste dans / hors de AL avant / après XLATB (recherche de table avec R / EBX comme base) et STOSB ( *output-- = al).

Avec un DF = 0 normal sur la convention d'entrée / sortie, la version std/ cld/ scasbest de 18 octets pour le code 32 et 64 bits, et est propre 64 bits (fonctionne avec un pointeur de sortie 64 bits).

Notez que les arguments d'entrée sont dans différents registres, y compris RBX pour la table (pour xlatb). Notez également que cette boucle commence par stocker AL et se termine par le dernier caractère non encore enregistré (d'où le movà la fin). La boucle est donc "biaisée" par rapport aux autres, d'où le nom.

                            ;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

Une version similaire non biaisée dépasse EDI / RDI, puis la 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

J'ai essayé une autre version de ceci avec lea esi, [rbx+rdx]/ movsbcomme corps de boucle interne. (RSI est réinitialisé à chaque itération, mais RDI diminue). Mais il ne peut pas utiliser xor-zero / stos pour le terminateur, c'est donc 1 octet de plus. (Et ce n'est pas propre en 64 bits pour la table de recherche sans préfixe REX sur le LEA.)


LUT avec longueur explicite et terminateur 0: 16 + 1 octets (32 bits)

Cette version définit DF = 1 et le laisse de cette façon. Je compte l'octet LUT supplémentaire requis dans le cadre du nombre total d'octets.

L'astuce ici consiste à décoder les mêmes octets de deux manières différentes . Nous tombons au milieu de la boucle avec reste = base et quotient = numéro d'entrée, et copions le terminateur 0 en place.

Lors de la première utilisation de la fonction, les 3 premiers octets de la boucle sont consommés en tant qu'octets élevés d'un disp32 pour un LEA. Que LEA copie la base (module) sur EDX, idivproduit le reste pour les itérations ultérieures.

Le 2ème octet de idiv ebpis FD, qui est l'opcode de l' stdinstruction dont cette fonction a besoin pour fonctionner. (Ce fut une découverte chanceuse. J'avais déjà regardé cela avec divplus tôt, qui se distingue de l' idivutilisation des /rbits dans ModRM. Le 2ème octet de div epbdécodage as cmc, ce qui est inoffensif mais pas utile. Mais avec idiv ebppeut-on réellement supprimer le stddu haut de la fonction.)

Notez que les registres d'entrée sont à nouveau différents: EBP pour 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

Cette astuce de décodage qui se chevauchent peut également être utilisée avec cmp eax, imm32: il ne faut que 1 octet pour avancer efficacement de 4 octets, seulement les drapeaux qui tapent. (C'est terrible pour les performances sur les processeurs qui marquent les limites des instructions dans le cache L1i, BTW.)

Mais ici, nous utilisons 3 octets pour copier un registre et sauter dans la boucle. Cela prendrait normalement 2 + 2 (mov + jmp), et nous permettrait de sauter dans la boucle juste avant le STOS au lieu d'avant le XLATB. Mais nous aurions alors besoin d'une MST distincte, et ce ne serait pas très intéressant.

Essayez-le en ligne! (avec un _startappelant qui utilise sys_writele résultat)

Il est préférable pour le débogage de l'exécuter sous straceou hexdump la sortie, afin que vous puissiez voir qu'il y a un \0terminateur au bon endroit et ainsi de suite. Mais vous pouvez voir que cela fonctionne réellement et produire AAAAAACHOOpour une entrée de

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

(En fait xxAAAAAACHOO\0x\0\0..., parce que nous vidons de 2 octets plus tôt dans le tampon vers une longueur fixe. Nous pouvons donc voir que la fonction a écrit les octets qu'elle était censée faire et n'a pas marché sur les octets qu'elle ne devrait pas avoir. le pointeur de début transmis à la fonction était l'avant-dernier xcaractère, suivi de zéros.)

Peter Cordes
la source
3

Gelée , 4 octets

ṙ1ṃ@

Essayez-le en ligne!

est littéralement intégré pour cela. Les trois autres octets représentent l'indexation à base unique de Jelly.

M. Xcoder
la source
Par curiosité, pourquoi Jelly a-t-il même la " décompression de base; convertir x en longueur de base (y) puis indexer en y. "? Est-ce pour les cas très exceptionnels où la base à convertir et la longueur d'une chaîne / d'un entier / d'une liste sont égales? Lorsque je le recherche, je ne peux trouver que trois réponses en l'utilisant: 1 ; 2 ; 3 . Un peu bizarre intégré dans tous les jours de défis de golf de code imo. : S
Kevin Cruijssen
3
@KevinCruijssen c'est très utile lorsque vous voulez, par exemple, convertir N en hexadécimal en utilisant des lettres hexadécimales au lieu d'une liste de nombres.
M. Xcoder
@KevinCruijssen C'est une méthode de compression pour les chaînes. Dans le premier exemple, la chaîne souhaitée est “sspspdspdspfdspfdsp”, mais “çƥ÷£ḟ’ṃ“spdf”¤vous économisez six octets. C'est particulièrement utile avec les nombres de base 250 de Jelly
dylnan
3

Python 2 , 49 48 octets

-1 octet grâce à Jo King

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

Essayez-le en ligne!

Version alternative (ne se termine pas pour les grands nombres), 45 43 octets

-2 octets grâce à Jo King

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

Essayez-le en ligne!

Barre
la source
3

Fusain , 3 1 octets

θη

Essayez-le en ligne! Le lien est vers la version détaillée du code. Edit: sauvé 2 octets grâce à @ ASCII uniquement. Version précédente avant l'ajout de la fonction intégrée, 8 octets:

⭆↨θLη§ηι

Essayez-le en ligne! Le lien est vers la version détaillée du code. Explication:

    η       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
la source
En fait, il est censé déjà fonctionner, mais j'ai évidemment encore foiré> _>
ASCII uniquement
De plus, ce serait en fait 1 octet : P (il est actuellement cassé, donc je n'utilise pas de tableau de nombres et de chaînes comme arguments) (aussi, je me demande comment l'entrée implicite (in) utile est)
ASCII uniquement le
@ ASCII uniquement Ne voulez-vous pas dire "1 octet" (voir votre sortie -vl ;-) De plus, les entrées implicites semblent presque inutiles dans Charcoal, sauf pour des défis comme celui-ci.
Neil
1
@ ASCII uniquement "Octets" au pluriel au lieu de "octet" au singulier, c'est ce que Neil veut dire. ;) Quant à votre réponse de 1 octet, pourquoi le barré θη? Ça a l'air un peu déroutant. Pourquoi ne pas simplement l'enlever complètement et partir ?
Kevin Cruijssen
1
@Nit J'ai revérifié et la fonction intégrée avait été ajoutée avant que la question ne soit posée, mais je ne m'en étais pas rendu compte car il y avait un bug.
Neil
3

D , 112 octets

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

Essayez-le en ligne!

Ceci est un portage de la réponse C ++ de HatsuPointerKun

Le style d'appel est u(ulong(n), to!(char[])(b)), où net bsont les arguments gauche et droit

D trucs spécifiques

Malheureusement, nous devons importer std.convpour effectuer des conversions de type supérieures à une conversion de type très basique.

En utilisant le système de modèles golfy, et en donnant à la fonction les types requis (c'est pourquoi l'appeler n'est pas seulement u(n,b)), nous pouvons raccourcir les occurrences de char[]et ulongpour les 1octet chacune, à l'intérieur de f la fonction.

D initialise nos types pour nous, C t;est donc court pourC t=cast(char[])([])

to!Cconvertit l'entier n%len un tableau de caractères (en utilisant des points de code), et ~est une concaténation

foreach(ref c;t)est comme la for(... : ...)boucle de C ++ , mais un peu plus longue. refest comme &, il traite ccomme copié par référence (c'est-à-dire, nous pouvons modifier t). Heureusement, D infère le type de csans tout type de mot - clé dénoter.

Zacharý
la source
3

C ++, 150 144 octets, uint64entrée

-6 octets grâce à 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'utilisation d'une variable pour stocker la taille augmenterait le nombre d'octets de 1

Pour appeler la fonction:

u(2740, "|_")

D'abord le nombre, le deuxième est la chaîne (tableau de caractères)

Cas de test:

std::cout << u(2740, "|_") << '\n' << u(698911, "chao") << '\n';
return 0;
HatsuPointerKun
la source
1
3 octets à raser: vous n'avez pas besoin d'espace après #include, vous pouvez passer ;;à juste ;, et '0'peut être48
Zacharý
1
De plus, la boucle while pourrait être une forboucle:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
Zacharý
@ceilingcat, j'ai oublié que b.size()cela ne change pas dans cette boucle.
Zacharý
@ceilingcat Cela augmenterait le bytecount de 1, au lieu de le réduire
HatsuPointerKun
2

Brindille, 66 octets

Créé un macroqui doit être importédité dans un modèle.

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

Valeurs attendues:

Pour les premiers arguments ( n):

  • nombre
  • chaîne

Pour le deuxième argument ( c):

  • Tableau de nombres
  • Tableau de chaînes

Comment utiliser:

  • Créer un .twigfichier
  • Ajouter {% import 'file.twig' as uncompress %}
  • Appelez la macro uncompress.d()

Non golfé (non fonctionnel):

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


Vous pouvez tester ce code sur: https://twigfiddle.com/54a0i9

Ismael Miguel
la source
2

Pyth, 9 8 7 octets

s@LQjEl

Enregistré un octet grâce à hakr14 et un autre grâce à M. Xcoder.
Essayez-le ici

Explication

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.

la source
Enregistrer un octet en le remplaçant m@Qdpar@LQ
hakr14
Enregistrez un octet en le remplaçant vzpar E.
M. Xcoder
2

C89, signé à portée limitée int n, 64 53 octets

  • changelog: prenez un char **outet modifiez-le, au lieu de prendre et de retourner unchar *

Prend le nombre sous forme de int, la table de recherche sous forme de tableau + longueur.
La sortie est écrite dans un fichier char *outbuf. L'appelant passe (par référence) un pointeur à la fin du tampon. La fonction modifie ce pointeur pour pointer vers le premier octet de la chaîne au retour.

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

Ceci est C89 valide et fonctionne correctement même avec l'optimisation activée. c'est-à-dire ne dépend pas du -O0comportement de gcc lors de la chute de la fin d'une fonction non vide ou de tout autre UB.

Passer un pointeur à la fin d'un tampon est normal pour une fonction int-> chaîne optimisée, telle que glibc internal_itoa . Voir cette réponse pour une explication détaillée de la décomposition d'un entier en chiffres avec une boucle div / mod comme nous le faisons ici, en C ainsi qu'en asm x86-64. Si la base est une puissance de 2, vous pouvez déplacer / masquer pour extraire d'abord les chiffres MSD, mais sinon la seule bonne option est d'abord le chiffre le moins significatif (avec modulo).

Essayez-le en ligne! . Version non golfée:

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

Dans cette version de longueur explicite, l'entrée est un char table[]qui n'a pas besoin d'un octet de fin 0, car nous ne le traitons jamais comme une chaîne. Ce pourrait être un int table[]pour tout ce dont nous nous soucions. C n'a pas de conteneurs qui connaissent leur propre longueur, donc pointeur + longueur est le moyen normal de passer un tableau avec une taille. Nous choisissons donc cela au lieu d'en avoir besoin strlen.

La taille maximale du tampon est approximativement sizeof(int)*CHAR_BIT + 1, elle est donc petite et constante au moment de la compilation. (Nous utilisons cet espace avec base = 2 et tous les bits mis à 1.) Par exemple 33 octets pour des entiers 32 bits, y compris le 0terminateur.


C89, signé int, table sous forme de chaîne C de longueur implicite, 65 octets

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

C'est la même chose, mais l'entrée est une chaîne de longueur implicite, nous devons donc trouver la longueur nous-mêmes.

Peter Cordes
la source
2

Utilitaires de base Bash + , 49 octets

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

Essayez-le en ligne!

Commentaires / explication

Cela prend les arguments de ligne de commande en entrée (le nombre en base 10, puis une seule chaîne avec la liste des caractères) et les sorties vers stdout. Des caractères spéciaux comme l'espace, la nouvelle ligne, etc. peuvent être entrés en notation octale (par exemple, \040pour un espace), ou \npour une nouvelle ligne, \tpour tabulation, ou toute autre séquence d'échappement qui echo -eet trinterpréter de manière identique.

Une grande partie des octets sert à gérer les caractères spéciaux et les cas de test plus volumineux. Si je dois seulement gérer des caractères non terribles et que les nombres sont petits (par exemple, le premier cas de test), les 24 octets suivants le feront:

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

Cela utilise l'expansion des paramètres ${#2}pour obtenir le nombre de caractères dans la chaîne, crée un programme DC pour effectuer la conversion de base, puis envoie le nombre converti tr.

Cela ne gérera pas les sauts de ligne, les espaces ou les tabulations, donc pour gérer les séquences d'échappement sans affecter la base, je fais un décompte des caractères wc -caprès avoir interprété les échappements avec echo -en. Cela étend le programme à 38 octets:

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

Malheureusement, dc a une "fonctionnalité" ennuyeuse où, s'il émet un grand nombre, il l'enroulera avec une séquence barre oblique + nouvelle ligne, donc les plus grands cas de test ont cette sortie supplémentaire. Pour le supprimer, je redirige la sortie de dc vers tr -dc 0-9pour supprimer les caractères non numériques. Et nous y voilà.

Sophia Lechner
la source
J'allais suggérer dc -e${#2}o$1p|tr 0-9 "$2"de prendre l'entrée littéralement au lieu de la forme in \ escape pour qu'elle puisse gérer les espaces, mais trn'a pas d'option pour ne pas traiter -comme un caractère de plage, par exemple. Si l'entrée n'a -pas à une extrémité de la chaîne, elle se casse. Vous pouvez peut-être utiliser sed "y/0123456789/$2/". Non, je suppose que non, GNU sedexige que les deux arguments ysoient de la même longueur, et il semble s'étouffer sur la nouvelle ligne.
Peter Cordes
2

APL (Dyalog Unicode) , 14 13 12 octets

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

Essayez-le en ligne!

Fonction tacite Infix; ne peut pas gérer le plus grand cas de test en raison de la représentation en virgule flottante.

Enregistré 1 2 octets grâce à @ Adám!

13 octets pour les en- têtes ajoutés: ⎕IO←0: I ndex O rigine = 0 et ⎕FR←1287: F loat R ePresentation = 128 bits. (J'avais oublié que cela ne s'applique pas. )

Comment?

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

Attaché , 17 octets

{_[_2&ToBase!#_]}

Essayez-le en ligne!

Explication

{_[_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
la source
1

Toile , 7 octets

L┬{╵⁸@p

Essayez-le ici!

Mise en œuvre simple:

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

Le jeu de caractères d'entrée peut également être une chaîne tant qu'il ne contient pas de nouvelle ligne, car Canvas n'a pas de caractère de nouvelle ligne et le convertit automatiquement en objet 2D.

dzaima
la source
1

Stax , 6 5 octets

n%|E@

Exécuter et déboguer

Explication:

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
la source
1

SOGL V0.12 , 10 octets

l;A─{IaWp}

Essayez-le ici!

Assez longtemps, étant donné que l'idée est à peu près mise en œuvre dans la langue: ici , entrer

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

donne une chaîne compressée en utilisant cette méthode.

dzaima
la source
1

Stax , 2 octets

:B

Exécuter et déboguer

:Best une instruction dans stax qui fait cela. Il fonctionnerait normalement sur une "chaîne" * au lieu d'un tableau de "chaînes". En fin de compte, cela signifie que la sortie est un tableau de tableaux à caractère unique. Mais la sortie s'aplatit implicitement de toute façon.

* Stax n'a pas de type de chaîne. Le texte est représenté par des tableaux entiers de points de code.

récursif
la source
Huh, je n'ai jamais remarqué cette commande ...
wastl
Il y a beaucoup. Une fois, j'ai ajouté une instruction au stax qui existait déjà, et je venais de l'oublier. (le tableau n'est pas décroissant?)
récursif
1

J , 12 octets

]{~#@]#.inv[

Comment?

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

Essayez-le en ligne!

Galen Ivanov
la source
1

C (gcc) , 110 octets

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

Essayez-le en ligne!

La description:

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
la source
1
Si vous commencez à la fin d'un tampon et travaillez en arrière, vous pouvez éviter sprintf. Ma version C fait 53 octets , avec le tampon de sortie fourni par l'appelant. Vous pouvez en faire un strcpyà la fin si vous souhaitez copier les octets au début d'un tampon.
Peter Cordes
C'est génial. Je me fiche que ce soit un format d'E / S maladroit. Les E / S maladroites sont C à la gloire! Bien joué, je recommanderais de mettre cela dans le post de conseils C.
LambdaBeta
Publié une réponse sur Conseils pour jouer au golf en C expliquant et justifiant la technique.
Peter Cordes
1

CJam , 11 octets

liq_,@\b\f=

Essayez-le en ligne! Prend la saisie comme le nombre, puis une nouvelle ligne, puis les caractères de l'art ASCII.

Explication

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
la source
Puisque "IO is Flexible", je pense que vous pouvez vous débarrasser du liqdébut, et cela vous fait gagner 3 octets!
Chrome
1

JavaScript, 39 octets

Solution Python de Port of Rod .

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

Essayez-le en ligne

Hirsute
la source
Fonctionne uniquement njusqu'à 64 bits, non? (Python a des entiers de précision arbitraire intégrés, mais les nombres JS sont naturellement des doubleflottants de précision qui peuvent être convertis en entier). Ne semble pas fonctionner pour les plus grands cas de test de la question, comme 1928149325670647244912100789213626616560861130859431492905908574660758972167966. Oh, mais la question permet des réponses comme ça. Encore faut-il le noter.
Peter Cordes
1

SimpleTemplate , 86 octets

Wow, c'était un énorme défi!

Cela a été rendu difficile en raison du manque d'accès direct à des index spécifiques lorsque l'index est une variable.
Un bug l'a également allongé, nécessitant de stocker les valeurs dans une variable.

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

Valeurs attendues:

Le premier argument ( argv.0) peut être:

  • Un nombre entier
  • Une chaîne de chiffres
  • Un tableau d'entiers

Le deuxième argument ( argv.1) peut être:

  • Un string
  • Un tableau

Comment ça marche?

Cela fonctionne de cette façon:

  • Parcourt le nombre / la chaîne passée comme premier argument
  • Définit la variable Ccomme un tableau contenant:
    • La valeur précédente C
    • La chaîne "{@echoA."
    • La valeur de la boucle
    • La chaîne "}"
  • Tout ensemble joint ( à l' aide de PHP joinfonction)
    Il en résulte, par exemple, Ccontenant"{@echoA.0}{@echoA.1}..."
  • Évalue le résultat de C

Non golfé:

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

Vous pouvez essayer ce code sur: https://ideone.com/NEKl2q


Résultat optimal

S'il n'y avait pas de bogues, ce serait le meilleur résultat, en tenant compte des limitations (77 octets):

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