Giải nén nghệ thuật ASCII từ số cơ sở n


24

Điều này được lấy cảm hứng từ một câu trả lời 05AB1E của Magic Octupus Urn .

Cho hai đối số, một số nguyên dương và một chuỗi / danh sách các ký tự:

  1. Dịch số sang base-n, trong đó n là độ dài của chuỗi.
  2. Đối với mỗi ký tự, thay thế mọi lần xuất hiện của chỉ mục của ký tự đó trong số cơ sở-n bằng ký tự đó.
  3. In hoặc trả lại chuỗi mới.

Ví dụ:

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

Quy tắc:

  • IO rất linh hoạt .
    • Bạn có thể lấy số ở bất kỳ cơ sở nào, miễn là phù hợp giữa các đầu vào
    • Tuy nhiên, danh sách các ký tự phải được lập chỉ mục 0, trong đó 0 là ký tự đầu tiên và n-1 là ký tự cuối cùng
  • Các ký tự có thể có thể là bất kỳ ASCII có thể in nào, cùng với các khoảng trắng như tab và dòng mới
  • Danh sách các ký tự đã cho sẽ có độ dài trong phạm vi 2-10bao gồm. Đó là, cơ sở nhỏ nhất là nhị phân và lớn nhất là số thập phân ( không có chữ pesky ở đây )
  • Sơ hở tiêu chuẩn bị cấm
  • Hãy trả lời ngay cả khi ngôn ngữ của bạn không thể xử lý các trường hợp kiểm tra lớn hơn.

Vì đây là , mã ngắn nhất cho mỗi ngôn ngữ sẽ thắng. ( Tôi biết tất cả các ngôn ngữ chơi gôn của bạn có sẵn một byte sẵn sàng hoạt động ;)


Sandbox (đã xóa)
Jo King

3
Tôi cảm thấy vinh dự. 05AB1E ascii-art là yêu thích của tôi một thời gian trở lại.
Bạch tuộc ma thuật Urn

bạn có thể tạo một thử thách mới: tìm hoán vị các ký tự trong mảng để giảm thiểu số lượng :)
mazzy

Câu trả lời:


8

05AB1E , 7 6 byte

gв¹sèJ

Vì nó được lấy cảm hứng từ câu trả lời 05AB1E, nên một câu trả lời trong 05AB1E có vẻ phù hợp. :)

-1 byte nhờ @Enigma bằng cách xóa foreach và thực hiện điều này hoàn toàn.

Hãy thử trực tuyến hoặc xác minh tất cả các trường hợp thử nghiệm .

Giải trình:

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

1
gв¹sèJđể lưu một byte.
Emigna

@Emigna Cảm ơn. Không thể tin rằng tôi đã không nghĩ về ¹sèbản thân mình bây giờ .. (Tôi biết việc thay đổi ?thành một Jsẽ cho cùng một đầu ra trong trường hợp này.)
Kevin Cruijssen

6

Java 8, 72 50 byte

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

-22 byte nhờ @ OlivierGrégoire bằng cách trả lại IntStreamthay vì in trực tiếp.

Hãy thử trực tuyến .

Giải trình:

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) vì "IO rất linh hoạt"
Olivier Grégoire

String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69 byte) đệ quy một, cho vui.
Olivier Grégoire

6

Python 3 , 49 byte

Không thể nhận xét nào, vì vậy tôi đăng câu trả lời Python 2 phù hợp với Python 3.5.

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

2
Chào mừng đến với PPCG! Vui lòng bao gồm một liên kết TIO để giúp giới thiệu giải pháp của bạn.
Jo King

5

Japt, 2 byte

Có thể lấy đầu vào thứ hai dưới dạng một mảng hoặc một chuỗi. Thất bại trong 2 trường hợp kiểm tra gần nhất vì các số vượt quá số nguyên tối đa của JavaScript. Thay thế sbằng ìđể xuất ra một mảng các ký tự thay thế.

sV

Thử nó


5

Haskell , 40 39 byte

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

Hãy thử trực tuyến!

Intloại của Haskell bị giới hạn 9223372036854775807, điều này không thành công cho số lượng lớn hơn.

-1 byte nhờ Laikoni .

Bị đánh cắp

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

Hãy thử trực tuyến!


Ý tưởng tốt đẹp để sử dụng cyclethay vì mod! div n(length l)tiết kiệm một byte.
Laikoni

4

MATL , 2 byte

YA

Hãy thử trực tuyến!

Đầu vào là một số và một chuỗi.

Thất bại cho số vượt quá 2^53, vì độ chính xác dấu phẩy động.

Giải trình

Những gì cần YAbiết, một nội trang (chuyển đổi cơ sở với các biểu tượng mục tiêu được chỉ định).


4

JavaScript (ES6), 48 byte

Đưa đầu vào theo cú pháp currying (c)(n), trong đó c là danh sách các ký tự và n là số nguyên.

Chỉ an toàn cho n <2 53 .

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

Hãy thử trực tuyến!


JavaScript (ES6), 99 byte

Với sự hỗ trợ cho số nguyên lớn

Đưa đầu vào theo cú pháp currying (c)(a), trong đó c là danh sách các ký tự và a là danh sách các chữ số thập phân (dưới dạng số nguyên).

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

Hãy thử trực tuyến!


4

mã máy x86 32 bit (số nguyên 32 bit): 17 byte.

(cũng xem các phiên bản khác bên dưới, bao gồm 16 byte cho 32 bit hoặc 64 bit, với quy ước gọi DF = 1.)

Người gọi chuyển các đối số trong các thanh ghi, bao gồm một con trỏ đến cuối bộ đệm đầu ra (như câu trả lời C của tôi ; xem nó để biện minh và giải thích thuật toán.) Nội bộ của glibc _itoathực hiện điều này , vì vậy nó không chỉ được sử dụng cho golf-code. Các thanh ghi chuyển arg gần với x86-64 System V, ngoại trừ chúng ta có một arg trong EAX thay vì EDX.

Khi trả về, EDI trỏ đến byte đầu tiên của chuỗi C kết thúc 0 trong bộ đệm đầu ra. Thanh ghi giá trị trả về thông thường là EAX / RAX, nhưng trong ngôn ngữ lắp ráp, bạn có thể sử dụng bất kỳ quy ước gọi nào thuận tiện cho một chức năng. ( xchg eax,ediở cuối sẽ thêm 1 byte).

Người gọi có thể tính toán độ dài rõ ràng nếu nó muốn, từ buffer_end - edi. Nhưng tôi không nghĩ rằng chúng ta có thể biện minh cho việc bỏ qua bộ kết thúc trừ khi hàm thực sự trả về cả con trỏ bắt đầu + con trỏ kết thúc hoặc con trỏ + chiều dài. Điều đó sẽ tiết kiệm 3 byte trong phiên bản này, nhưng tôi không nghĩ nó hợp lý.

  • EAX = n = số để giải mã. (Dành cho idiv. Các đối số khác không phải là toán hạng ngầm.)
  • EDI = kết thúc bộ đệm đầu ra (phiên bản 64 bit vẫn sử dụng dec edi, do đó phải ở mức 4GiB thấp)
  • ESI / RSI = bảng tra cứu, còn gọi là LUT. không bị tắc nghẽn.
  • ECX = chiều dài của bảng = cơ sở. không bị tắc nghẽn.

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (Chỉnh sửa bằng tay để thu nhỏ bình luận, đánh số dòng là lạ.)

   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

Thật đáng ngạc nhiên khi phiên bản đơn giản nhất về cơ bản không có sự đánh đổi tốc độ / kích thước là nhỏ nhất, nhưng std/ cldtốn 2 byte để sử dụng stosbtheo thứ tự giảm dần và vẫn tuân theo quy ước gọi DF = 0 chung. (Và STOS giảm sau khi lưu trữ, khiến con trỏ chỉ một byte quá thấp khi thoát khỏi vòng lặp, khiến chúng ta phải trả thêm byte để xử lý.)

Phiên bản:

Tôi đã đưa ra 4 thủ thuật thực hiện khác nhau đáng kể (sử dụng movtải / lưu trữ đơn giản (ở trên), sử dụng lea/ movsb(gọn gàng nhưng không tối ưu), sử dụng xchg/ xlatb/ stosb/ xchgvà một thủ thuật xâm nhập vào vòng lặp với một lệnh hack chồng chéo. Xem mã bên dưới) . Cái cuối cùng cần một dấu 0trong bảng tra cứu để sao chép như là bộ kết thúc chuỗi đầu ra, vì vậy tôi đang tính đó là byte 1. Tùy thuộc vào 32/64 bit (1 byte inchay không) và liệu chúng ta có thể giả sử người gọi đặt DF = 1 ( stosbgiảm dần) hay bất cứ điều gì, các phiên bản khác nhau được (gắn cho) ngắn nhất.

DF = 1 để lưu trữ theo thứ tự giảm dần làm cho nó trở thành chiến thắng cho xchg / stosb / xchg, nhưng người gọi thường không muốn điều đó; Nó cảm thấy như giảm tải công việc cho người gọi một cách khó để biện minh. (Không giống như các thanh ghi giá trị chuyển tiếp và trả về giá trị tùy chỉnh, thường không tốn một người gọi asm cho bất kỳ công việc bổ sung nào.) Nhưng trong mã 64 bit, cld/ scasbhoạt động như inc rdi, tránh cắt ngắn con trỏ đầu ra thành 32 bit, vì vậy đôi khi bất tiện trong việc bảo toàn DF = 1 trong các chức năng 64-bit. . (Con trỏ tới mã / dữ liệu tĩnh là 32 bit trong các tệp thực thi không phải PIE x86-64 trên Linux và luôn trong Linux x32 ABI, do đó, một phiên bản x86-64 sử dụng con trỏ 32 bit có thể sử dụng được trong một số trường hợp.) sự tương tác này làm cho nó thú vị để xem xét các kết hợp khác nhau của các yêu cầu.

  • IA32 với DF = 0 trên quy ước gọi vào / ra: 17B ( nostring) .
  • IA32: 16B (với quy ước DF = 1: stosb_edx_arghoặc skew) ; hoặc với DF = dontcare, hãy đặt nó: 16 + 1Bstosb_decode_overlap hoặc 17Bstosb_edx_arg
  • x86-64 với các con trỏ 64 bit và DF = 0 trong quy ước gọi vào / ra: 17 + 1 byte ( stosb_decode_overlap) , 18B ( stosb_edx_arghoặc skew)
  • x86-64 với con trỏ 64 bit, xử lý DF khác: 16B (DF = 1 skew) , 17B ( nostringvới DF = 1, sử dụng scasbthay vì dec). 18B ( stosb_edx_argbảo toàn DF = 1 với 3 byte inc rdi).

    Hoặc nếu chúng tôi cho phép trả về một con trỏ về 1 byte trước chuỗi, 15B ( stosb_edx_argkhông có incở cuối). Tất cả được thiết lập để gọi lại và mở rộng một chuỗi khác vào bộ đệm với cơ sở / bảng khác nhau ... Nhưng điều đó sẽ có ý nghĩa hơn nếu chúng ta không lưu trữ một kết thúc 0, và bạn có thể đặt thân hàm trong một vòng lặp để nó thực sự là một vấn đề riêng biệt.

  • x86-64 với con trỏ đầu ra 32 bit, quy ước gọi DF = 0: không cải thiện con trỏ đầu ra 64 bit, nhưng nostringhiện tại có mối quan hệ 18B ( ).

  • x86-64 với con trỏ đầu ra 32 bit: không cải thiện so với các phiên bản con trỏ 64 bit tốt nhất, vì vậy 16B (DF = 1 skew). Hoặc để thiết lập DF = 1 và rời khỏi nó, 17B cho skewvới stdnhưng không phải cld. Hoặc 17 + 1B cho stosb_decode_overlapvới inc edikhi kết thúc thay vì cld/ scasb.

Với quy ước gọi DF = 1: 16 byte (IA32 hoặc x86-64)

Yêu cầu DF = 1 trên đầu vào, để nó được đặt. Hoàn toàn hợp lý , ít nhất là trên cơ sở từng chức năng. Thực hiện tương tự như phiên bản trên, nhưng với xchg để lấy phần còn lại vào / ra AL trước / sau XLATB (tra cứu bảng với R / EBX làm cơ sở) và STOSB ( *output-- = al).

Với DF bình thường = 0 trên ước nhập / xuất cảnh, các std/ cld/ scasbphiên bản là 18 byte cho mã 32 và 64-bit, và 64-bit sạch (làm việc với một con trỏ đầu ra 64-bit).

Lưu ý rằng các đối số đầu vào nằm trong các thanh ghi khác nhau, bao gồm RBX cho bảng (for xlatb). Cũng lưu ý rằng vòng lặp này bắt đầu bằng cách lưu trữ AL và kết thúc với char cuối cùng chưa được lưu trữ (do đó movở cuối). Vì vậy, vòng lặp là "sai lệch" so với những người khác, do đó tên.

                            ;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

Một phiên bản không bị lệch tương tự làm lu mờ EDI / RDI và sau đó sửa nó.

                            ; 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

Tôi đã thử một phiên bản thay thế của cái này với lea esi, [rbx+rdx]/ movsbnhư thân vòng lặp bên trong. (RSI được đặt lại mỗi lần lặp, nhưng RDI giảm). Nhưng nó không thể sử dụng xor-zero / stos cho bộ kết thúc, vì vậy nó lớn hơn 1 byte. (Và nó không sạch 64 bit cho bảng tra cứu mà không có tiền tố REX trên LEA.)


LUT với độ dài rõ ràng dấu kết thúc 0: 16 + 1 byte (32 bit)

Phiên bản này đặt DF = 1 và để nguyên như vậy. Tôi đang đếm byte LUT bổ sung cần thiết như một phần của tổng số byte.

Thủ thuật hay ở đây là có cùng một byte giải mã hai cách khác nhau . Chúng tôi rơi vào giữa vòng lặp với số dư = cơ sở và thương số = số đầu vào và sao chép số 0 kết thúc vào vị trí.

Lần đầu tiên thông qua chức năng, 3 byte đầu tiên của vòng lặp được tiêu thụ dưới dạng các byte cao của một dist32 cho LEA. LEA đó sao chép cơ sở (mô-đun) sang EDX, idivtạo ra phần còn lại cho các lần lặp lại sau.

Byte thứ 2 idiv ebpFD, là mã opcode cho stdlệnh mà hàm này cần để làm việc. (Đây là một khám phá may mắn. Tôi đã xem xét điều này divtrước đó, nó phân biệt với idivviệc sử dụng các /rbit trong ModRM. Byte thứ hai div epbgiải mã cmclà vô hại nhưng không hữu ích. Nhưng idiv ebpchúng ta thực sự có thể loại bỏ stdtừ trên xuống của hàm.)

Lưu ý các thanh ghi đầu vào là một lần nữa: EBP cho cơ sở.

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

Thủ thuật giải mã chồng chéo này cũng có thể được sử dụng với cmp eax, imm32: chỉ mất 1 byte để chuyển tiếp 4 byte một cách hiệu quả, chỉ có các cờ ghi đè. (Điều này thật tồi tệ đối với hiệu năng trên các CPU đánh dấu ranh giới chỉ dẫn trong bộ đệm L1i, BTW.)

Nhưng ở đây, chúng tôi đang sử dụng 3 byte để sao chép một thanh ghi và nhảy vào vòng lặp. Điều đó thường sẽ mất 2 + 2 (Mov + jmp) và sẽ cho phép chúng tôi nhảy vào vòng lặp ngay trước STOS thay vì trước XLATB. Nhưng sau đó chúng ta cần một STD riêng, và nó sẽ không thú vị lắm.

Hãy thử trực tuyến! (với một _startngười gọi sử dụng sys_writekết quả)

Tốt nhất là gỡ lỗi để chạy nó bên dưới strace, hoặc hexdump đầu ra, vì vậy bạn có thể thấy xác minh rằng có một bộ \0kết thúc ở đúng nơi, v.v. Nhưng bạn có thể thấy điều này thực sự hoạt động và tạo ra AAAAAACHOOđầu vào của

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

(Trên thực tế xxAAAAAACHOO\0x\0\0..., vì chúng ta đã chuyển từ 2 byte trước đó trong bộ đệm ra một độ dài cố định. Vì vậy, chúng ta có thể thấy rằng hàm đã ghi các byte mà nó được cho là và không bước vào bất kỳ byte nào mà nó không nên có. con trỏ bắt đầu được truyền cho hàm là xký tự cuối cùng thứ 2 , được theo sau bởi các số không.)


3

Thạch , 4 byte

ṙ1ṃ@

Hãy thử trực tuyến!

nghĩa đen là tích hợp sẵn cho việc này. Ba byte khác chiếm chỉ mục một dựa trên Jelly.


Vì tò mò, tại sao Jelly thậm chí còn tích hợp sẵn "Giải nén cơ sở; chuyển đổi x thành chiều dài cơ sở (y) sau đó lập chỉ mục thành y. "? Có phải trong các trường hợp rất đặc biệt khi cơ sở bạn ant chuyển đổi và độ dài của chuỗi / số nguyên / danh sách bằng nhau không? Khi tôi tìm kiếm nó, tôi chỉ có thể tìm thấy ba câu trả lời bằng cách sử dụng nó: 1 ; 2 ; 3 . Đây là một nội dung kỳ lạ trong mỗi ngày thử thách chơi gôn. : S
Kevin Cruijssen

3
@KevinCruijssen rất hữu ích khi bạn muốn, ví dụ, để chuyển đổi N thành thập lục phân bằng cách sử dụng các chữ cái hex thay vì danh sách các số.
Ông Xcoder

@KevinCruijssen Đó là một phương pháp nén cho chuỗi. Trong ví dụ đầu tiên, chuỗi mong muốn là “sspspdspdspfdspfdsp”, nhưng với “çƥ÷£ḟ’ṃ“spdf”¤bạn lưu sáu byte. Nó đặc biệt hữu ích với 250 số cơ sở của Jelly
dylnan


3

Than , 3 1 byte

θη

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. Chỉnh sửa: Đã lưu 2 byte chỉ nhờ @ ASCII. Phiên bản trước khi nội dung được thêm vào, 8 byte:

⭆↨θLη§ηι

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. Giải trình:

    η       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

Trên thực tế, nó đáng lẽ đã hoạt động nhưng rõ ràng là tôi đã nhắn tin lại lần nữa> _>
ASCII - chỉ

Ngoài ra, nó thực sự sẽ là 1 byte : P (hiện tại nó đã bị hỏng, vì vậy tôi không sử dụng mảng số và chuỗi chuỗi làm đối số) (ngoài ra, tôi tự hỏi làm thế nào (un) đầu vào ẩn hữu ích)
Chỉ có ASCII vào

@ Chỉ ASCII Đừng có nghĩa là "1 byte" (xem đầu ra -vl của bạn ;-) Ngoài ra, đầu vào ngầm dường như gần như vô dụng trong Char than, ngoại trừ những thách thức như thế này.
Neil

1
@ ByteII "Chỉ số nhiều" thay vì "byte" số ít là ý nghĩa của Neil. ;) Đối với câu trả lời 1 byte của bạn, tại sao lại bỏ qua θη? Trông hơi khó hiểu tbh. Tại sao không chỉ loại bỏ nó hoàn toàn và rời đi ?
Kevin Cruijssen

1
@Nit Tôi đã kiểm tra kỹ và tích hợp sẵn đã được thêm vào trước khi câu hỏi được hỏi, nhưng tôi đã không nhận ra vì nó có lỗi.
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;}

Hãy thử trực tuyến!

Đây là một cổng của câu trả lời C ++ của HatsuPulumKun

Kiểu gọi là u(ulong(n), to!(char[])(b)), ở đâu nblà đối số trái và phải

D cụ thể

Đáng buồn thay, chúng ta cần nhập std.convđể thực hiện bất kỳ chuyển đổi loại nào trên chuyển đổi loại rất cơ bản.

Sử dụng hệ thống mẫu golf và cung cấp cho hàm các loại cần thiết (đó là lý do tại sao gọi nó không chỉ u(n,b)), chúng ta có thể rút ngắn các lần xuất hiện char[]ulongđến 1từng byte, khi bên trong hàm f.

D khởi tạo các loại của chúng tôi cho chúng tôi, vì vậy C t;là viết tắt củaC t=cast(char[])([])

to!Cchuyển đổi số nguyên n%lthành một mảng ký tự (sử dụng mật mã) và ~được ghép

foreach(ref c;t)giống như for(... : ...)vòng lặp của C ++ , nhưng lâu hơn một chút. refgiống như &, nó xử lý cnhư là sao chép theo tham chiếu (nghĩa là chúng ta có thể sửa đổi t). May mắn thay, D xâm nhập vào loại cmà không có bất kỳ loại từ khóa nào .



3

C ++, 150 144 byte, uint64đầu vào

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

Sử dụng một biến để lưu trữ kích thước sẽ tăng số lượng cộng thêm 1

Để gọi hàm:

u(2740, "|_")

Đầu tiên là số, thứ hai là chuỗi (mảng char)

Các trường hợp thử nghiệm:

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

1
3 byte để tắt: Bạn không cần khoảng trống sau #include, bạn có thể thay đổi ;;thành chỉ ;'0'có thể là48
Zacharý

1
Ngoài ra, vòng lặp while có thể là một forvòng lặp:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
Zacharý

@ceilingcat, tôi quên rằng b.size()không thay đổi trong vòng lặp đó.
Zacharý

@ceilingcat Điều đó sẽ tăng số lượng nhân lên 1, thay vì hạ thấp nó
HatsuPulumKun

2

Cành, 66 byte

Tạo một macrocái phải được imported thành một mẫu.

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

Giá trị dự kiến:

Đối với các đối số đầu tiên ( n):

  • con số
  • chuỗi

Đối với đối số thứ hai ( c):

  • Mảng số
  • Mảng dây

Cách sử dụng:

  • Tạo một .twigtập tin
  • Thêm vào {% import 'file.twig' as uncompress %}
  • Gọi macro uncompress.d()

Ungolfed (không chức năng):

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


Bạn có thể kiểm tra mã này trên: https://twigfiddle.com/54a0i9


2

Bình thường, 9 8 7 byte

s@LQjEl

Đã lưu một byte nhờ hakr14 và một byte khác nhờ ông Xcoder.
Hãy thử nó ở đây

Giải trình

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.

Lưu một byte bằng cách thay thế m@Qdbằng@LQ
hakr14

Lưu một byte bằng cách thay thế vzbằng E.
Ông Xcoder

2

C89, phạm vi giới hạn đã ký int n, 64 53 byte

  • changelog: lấy char **outvà sửa đổi nó, thay vì lấy và trả lạichar *

Lấy số là một int, bảng tra cứu dưới dạng một mảng + chiều dài.
Đầu ra được viết thành a char *outbuf. Người gọi chuyển (bằng cách tham chiếu) một con trỏ đến cuối bộ đệm. Hàm sửa đổi con trỏ đó để trỏ đến byte đầu tiên của chuỗi khi trả về.

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

Đây là C89 hợp lệ và hoạt động chính xác ngay cả khi bật tối ưu hóa. tức là không phụ thuộc vào -O0hành vi của gcc khi rơi vào cuối hàm không trống hoặc có bất kỳ UB nào khác.

Việc đưa một con trỏ đến cuối bộ đệm là bình thường đối với hàm int-> chuỗi được tối ưu hóa, chẳng hạn như bên trong của glibc_itoa . Xem câu trả lời này để được giải thích chi tiết về việc chia một số nguyên thành các chữ số với vòng lặp div / mod giống như chúng ta đang làm ở đây, trong C cũng như x86-64 asm. Nếu cơ sở là lũy thừa 2, bạn có thể dịch chuyển / mặt nạ để trích xuất các chữ số MSD trước, nhưng nếu không thì tùy chọn tốt duy nhất là chữ số đầu tiên ít có ý nghĩa nhất (với modulo).

Hãy thử trực tuyến! . Phiên bản bị đánh cắp:

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

Trong phiên bản rõ ràng có độ dài này, đầu vào là một char table[]không cần một byte chấm dứt 0, bởi vì chúng tôi không bao giờ đối xử với nó như là một chuỗi. Nó có thể là một int table[]cho tất cả chúng ta quan tâm. C không có các thùng chứa biết chiều dài của riêng chúng, vì vậy con trỏ + chiều dài là cách thông thường để truyền một mảng có kích thước. Vì vậy, chúng tôi chọn điều đó thay vì cần strlen.

Kích thước bộ đệm tối đa là xấp xỉ sizeof(int)*CHAR_BIT + 1, vì vậy nó nhỏ và hằng số thời gian biên dịch. (Chúng tôi sử dụng nhiều không gian này với base = 2 và tất cả các bit được đặt thành 1.) ví dụ: 33 byte cho số nguyên 32 bit, bao gồm cả bộ 0kết thúc.


C89, đã ký int, bảng dưới dạng chuỗi C có độ dài ẩn, 65 byte

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

Đây là điều tương tự nhưng đầu vào là một chuỗi có độ dài ngầm định vì vậy chúng ta phải tự tìm độ dài.


2

Tiện ích Bash + lõi , 49 byte

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

Hãy thử trực tuyến!

Nhận xét / giải thích

Điều này lấy các đối số dòng lệnh làm đầu vào (số trong cơ sở 10, sau đó là một chuỗi có danh sách các ký tự) và xuất ra đầu ra. Các ký tự đặc biệt như dấu cách, dòng mới, v.v. có thể được nhập vào ký hiệu bát phân (ví dụ: \040đối với khoảng trắng) hoặc \ncho dòng mới, \tcho tab hoặc bất kỳ chuỗi thoát nào khác echo -etrdiễn giải giống hệt.

Rất nhiều byte ở đây là để xử lý các ký tự đặc biệt và các trường hợp thử nghiệm lớn hơn. Nếu tôi chỉ phải xử lý các ký tự không khủng khiếp và các số nhỏ (ví dụ: trường hợp thử nghiệm đầu tiên), 24 byte sau đây sẽ làm điều đó:

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

Điều này sử dụng mở rộng tham số ${#2}để lấy số lượng ký tự trong chuỗi, xây dựng chương trình dc để thực hiện chuyển đổi cơ sở và sau đó gửi số được chuyển đổi qua tr.

Tuy nhiên, điều này sẽ không xử lý các dòng mới hoặc dấu cách hoặc tab, vì vậy, để xử lý các chuỗi thoát mà không ảnh hưởng đến cơ sở, tôi thực hiện đếm số ký tự wc -csau khi giải thích các thoát echo -en. Điều này mở rộng chương trình lên 38 byte:

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

Thật không may, dc có một "tính năng" khó chịu trong đó nếu nó xuất ra một số lượng lớn, nó sẽ bao bọc nó bằng một chuỗi gạch chéo + dòng mới, vì vậy các trường hợp thử nghiệm lớn hơn có đầu ra bổ sung này. Để loại bỏ nó, tôi dẫn đầu ra của dc qua tr -dc 0-9để loại bỏ các ký tự không phải là số. Và chúng tôi ở đó.


Tôi sẽ đề nghị dc -e${#2}o$1p|tr 0-9 "$2"lấy đầu vào theo nghĩa đen thay vì ở dạng \ esc esc để nó có thể xử lý khoảng trắng, nhưng trkhông có tùy chọn để không coi -là một ký tự phạm vi, chẳng hạn. Nếu đầu vào -không ở một đầu của chuỗi, nó sẽ bị hỏng. Có lẽ bạn có thể sử dụng sed "y/0123456789/$2/". Không, tôi đoán là không, GNU sedyêu cầu cả hai đối số yphải có cùng độ dài và dường như nó bị sặc trên dòng mới.
Peter Cordes

2

APL (Dyalog Unicode) , 14 13 12 byte

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

Hãy thử trực tuyến!

Chức năng ngầm Infix; không thể xử lý trường hợp thử nghiệm lớn nhất vì biểu diễn dấu phẩy động.

Đã lưu 1 2 byte nhờ @ Adám!

13 byte gia tăng đối với các tiêu đề: ⎕IO←0: Tôi Ndex O rigin = 0 và ⎕FR←1287: F loat R epresentation = 128 bit. (Tôi đã quên rằng điều này không áp dụng. )

Làm sao?

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

Tùy viên , 17 byte

{_[_2&ToBase!#_]}

Hãy thử trực tuyến!

Giải trình

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

1

Canvas , 7 byte

L┬{╵⁸@p

Hãy thử nó ở đây!

Thực hiện thẳng về phía trước:

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

Bộ ký tự đầu vào có thể là một chuỗi miễn là nó không chứa dòng mới, bởi vì Canvas không có ký tự dòng mới & tự động chuyển đổi nó thành một đối tượng 2D.


1

Stax , 6 5 byte

n%|E@

Chạy và gỡ lỗi nó

Giải trình:

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}

Hãy thử nó ở đây!

Khá lâu, xem xét ý tưởng được thực hiện khá nhiều trong ngôn ngữ: ở đây , nhập

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

đưa ra một chuỗi nén bằng phương pháp này.



1

Stax , 2 byte

:B

Chạy và gỡ lỗi nó

:Blà một hướng dẫn trong stax mà làm điều này. Nó thường hoạt động trên một "chuỗi" * thay vì một mảng "chuỗi". Cuối cùng, điều này có nghĩa là đầu ra là một mảng các mảng ký tự đơn. Nhưng dù sao thì đầu ra cũng phẳng.

* Stax không thực sự có kiểu chuỗi. Văn bản được đại diện bởi các mảng số nguyên.


Huh, tôi chưa bao giờ nhận thấy lệnh này ...
Wastel

Có rất nhiều. Tôi đã từng thêm một hướng dẫn để dỗ dành đã tồn tại, và tôi đã quên mất. (mảng không giảm dần?)
đệ quy

1

J , 12 byte

]{~#@]#.inv[

Làm sao?

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

Hãy thử trực tuyến!



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

Hãy thử trực tuyến!

Sự miêu tả:

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
Nếu bạn bắt đầu ở cuối bộ đệm và làm việc ngược lại, bạn có thể tránh sprintf. Phiên bản C của tôi là 53 byte , với bộ đệm đầu ra được cung cấp bởi người gọi. Bạn có thể làm một cái strcpyở cuối nếu bạn muốn sao chép các byte vào đầu bộ đệm.
Peter Cordes

Đó là tuyệt vời. Tôi không quan tâm nếu nó là một định dạng I / O vụng về. I / O vụng về là C tuyên bố nổi tiếng! Làm tốt lắm, tôi khuyên bạn nên đưa nó vào bài viết mẹo C.
LambdaBeta

Đăng một câu trả lời về Mẹo chơi golf trong C giải thích và chứng minh kỹ thuật.
Peter Cordes

1

CJam , 11 byte

liq_,@\b\f=

Hãy thử trực tuyến! Lấy đầu vào là số, sau đó là một dòng mới, sau đó là các ký tự trong nghệ thuật ASCII.

Giải trình

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

Vì "IO là linh hoạt", tôi nghĩ rằng bạn có thể thoát khỏi liqngay từ đầu và điều đó giúp bạn tiết kiệm 3 byte!
Chromium

1

JavaScript, 39 byte

Giải pháp Python của cảng Rod .

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

Dùng thử trực tuyến


Chỉ hoạt động ntối đa 64 bit, phải không? (Python có các số nguyên có độ chính xác tùy ý được tích hợp sẵn, nhưng số JS là số doublefloat nổi tự nhiên có thể được chuyển đổi thành số nguyên). Dường như không hoạt động cho các trường hợp thử nghiệm lớn hơn trong câu hỏi, như 1928149325670647244912100789213626616560861130859431492905908574660758972167966. Ồ, nhưng câu hỏi cho phép câu trả lời như vậy. Tuy nhiên, cần lưu ý.
Peter Cordes

1

SimpleTemplate , 86 byte

Wow, đây là một thách thức rất lớn!

Điều này đã được thực hiện khó khăn do thiếu quyền truy cập trực tiếp vào các chỉ mục cụ thể khi chỉ mục là một biến.
Một lỗi cũng làm cho nó dài hơn, yêu cầu lưu trữ các giá trị bên trong một biến.

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

Giá trị dự kiến:

Đối số đầu tiên ( argv.0) có thể là:

  • Một số nguyên
  • Một chuỗi có số
  • Mảng số nguyên

Đối số thứ hai ( argv.1) có thể là:

  • Một chuỗi
  • Một mảng

Làm thế nào điều này hoạt động?

Nó hoạt động theo cách này:

  • Chu kỳ thông qua số / chuỗi được truyền làm đối số đầu tiên
  • Đặt biến Clà một mảng chứa:
    • Giá trị trước đó C
    • Chuỗi "{@echoA."
    • Giá trị của vòng lặp
    • Chuỗi "}"
  • Kết hợp mọi thứ lại với nhau (sử dụng joinchức năng của PHP )
    Ví dụ, kết quả này Ccó chứa"{@echoA.0}{@echoA.1}..."
  • Đánh giá kết quả của C

Ung dung:

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

Bạn có thể thử mã này trên: https://ideone.com/NEKl2q


Kết quả tối ưu

Nếu không có lỗi, đây sẽ là kết quả tốt nhất, chiếm các giới hạn (77 byte):

{@eachargv.0}{@setC C,"{@echoargv.1.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.