Log Scales dành cho người bỏ cuộc


24

Mọi người đều biết quy mô log là dành cho người bỏ cuộc . Do đó, bạn phải viết một chương trình hoặc chức năng loại bỏ biểu đồ thanh với tỷ lệ nhật ký cho một cơ sở.

Đầu vào biểu đồ thanh được lấy dưới dạng một chuỗi là danh sách các thanh, trong đó mỗi thanh của biểu đồ thanh tỷ lệ nhật ký được phân tách bằng dấu phân cách có thể in (hoặc khoảng trắng) do bạn chọn (vì vậy 0x09-0x0A + 0x20-0x7E) và bao gồm một ký tự điền không phải khoảng trắng có thể in được (vì vậy 0x21-0x7E) mà bạn chọn.

Chương trình hoặc hàm xuất ra một chuỗi là một danh sách các thanh, trong đó mỗi thanh được phân tách bằng cùng một dấu phân cách, đầu vào được phân tách bằng và được tạo thành từ cùng một ký tự điền vào.

Thí dụ

Chúng tôi chọn một dấu phân cách là "\ n" (một dòng mới) và ký tự điền vào "#". Đầu vào được truyền cho chương trình hoặc chức năng của chúng tôi là:

cơ sở = 2 và chuỗi =

####
##
######
###

Mã sẽ thấy rằng độ dài của các thanh là [4,2,6,3]. Nó sẽ tính toán chống nhật ký của từng độ dài với cơ sở 2để có được [2^4,2^2,2^6,2^3]= [16,4,64,8]. Sau đó, độ dài là đầu ra ở định dạng thanh tỷ lệ tuyến tính:

################
####
################################################################
########

Đầu ra đầu vào

Chương trình hoặc chức năng của bạn có thể nhập và xuất ở bất kỳ định dạng hợp lý nào .

Cơ sở đầu vào được đảm bảo là một số nguyên lớn hơn 1. Bạn có thể giả sử cơ sở nhỏ hơn 256. Đầu vào chuỗi được đảm bảo khớp hoàn toàn với regex (f+s)+f+, trong đó fsđược thay thế bằng filler và dấu phân cách tương ứng.

Đầu ra chuỗi phải hoàn toàn khớp với regex (f+s)+f+, ở đâu fsđược thay thế bằng cùng một filler và dấu phân cách tương ứng. Đầu ra có thể tùy chọn có một dòng mới.

Đầu ra và đầu vào cũng có thể là một danh sách các chuỗi thay vì được phân định bởi một chuỗi con, mặc dù phải có thể hiểu thanh nào là thanh nào.

Tủ thử

(giả sử filler là #và dấu phân cách là \n)

base
-
input string
-
output string
-----
2
-
####
##
######
###
-
################
####
################################################################
########
-----
3
-
##
#
###
#
-
#########
###
###########################
###
-----
100
-
#   I am not the delimiter
###  nor the filler
-
Anything (You do not have to handle input which does not match the regex)
-----
1
-
###
#######
###################################################
- 
Anything (You do not have to handle bases less than or equal to 1).
-----
5
-
####
##
###
#
-
#################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################    
#########################
#############################################################################################################################
#####
-----
2
-
#
#
##
##
#
##
#
#
#
#
##
##
#
#
##
#
-
##
##
####
####
##
####
##
##
##
##
####
####
##
##
####
##

Câu trả lời:


6

Chức năng mã máy x86 32 bit, 21 byte

Chức năng mã máy x86-64, 22 byte

Việc tiết kiệm 1B ở chế độ 32 bit yêu cầu sử dụng separator = filler-1, vd fill=0sep=/. Phiên bản 22 byte có thể sử dụng tùy chọn phân tách và phụ tùy ý.


Đây là phiên bản 21 byte, với input-separator = \n(0xa), output-filler = 0, output-separator = /= filler-1. Các hằng số này có thể dễ dàng thay đổi.

; see the source for more comments
; RDI points to the output buffer,  RSI points to the src string
; EDX holds the base
; This is the 32-bit version.
; The 64-bit version is the same, but the DEC is one byte longer (or we can just mov al,output_separator)
08048080 <str_exp>:
 8048080:       6a 01           push   0x1
 8048082:       59              pop    ecx           ; ecx = 1 = base**0
 8048083:       ac                      lods   al,BYTE PTR ds:[esi]  ; skip the first char so we don't do too many multiplies

; read an input row and accumulate base**n as we go.
08048084 <str_exp.read_bar>:
 8048084:       0f af ca        imul   ecx,edx       ; accumulate the exponential
 8048087:       ac              lods   al,BYTE PTR ds:[esi]
 8048088:       3c 0a           cmp    al,0xa        ; input_separator = newline
 804808a:       77 f8           ja     8048084 <str_exp.read_bar>
 ; AL = separator or terminator
 ; flags = below (CF=1) or equal (ZF=1).  Equal also implies CF=0 in this case.

 ; store the output row
 804808c:       b0 30           mov    al,0x30       ; output_filler
 804808e:       f3 aa           rep stos BYTE PTR es:[edi],al  ; ecx bytes of filler
 8048090:       48              dec    eax           ; mov al,output_separator 
 8048091:       aa              stos   BYTE PTR es:[edi],al  ;append delim

 ; CF still set from the inner loop, even after DEC clobbers the other flags
 8048092:       73 ec           jnc    8048080 <str_exp>  ; new row if this is a separator, not terminator

 8048094:       c3              ret    

08048095  <end_of_function>
; 0x95 - 0x80 = 0x15 = 21 bytes

Phiên bản 64 bit dài hơn 1 byte, sử dụng DEC 2 byte hoặc a mov al, output_separator. Ngoài ra, mã máy giống nhau cho cả hai phiên bản, nhưng một số tên đăng ký thay đổi (ví dụ rcxthay vì ecxtrong pop).

Đầu ra mẫu từ khi chạy chương trình thử nghiệm (cơ sở 3):

$ ./string-exponential $'.\n..\n...\n....' $(seq 3);echo 
000/000000000/000000000000000000000000000/000000000000000000000000000000000000000000000000000000000000000000000000000000000/

Thuật toán :

Lặp lại đầu vào, làm exp *= basecho mọi char filler. Trên các dấu phân cách và byte bằng 0 kết thúc, nối các expbyte của bộ đệm và sau đó là dấu phân cách vào chuỗi đầu ra và đặt lại thành exp=1. Thật tiện lợi khi đầu vào được đảm bảo không kết thúc với cả dòng mới bộ kết thúc.

Trên đầu vào, bất kỳ giá trị byte nào phía trên dấu phân cách (so sánh không dấu) được coi là bộ đệm và bất kỳ giá trị byte nào bên dưới dấu phân cách đều được coi là điểm đánh dấu cuối chuỗi. (Việc kiểm tra một cách rõ ràng cho một byte bằng 0 sẽ mất thêm test al,also với phân nhánh trên các cờ được đặt bởi vòng lặp bên trong).


Các quy tắc chỉ cho phép một dấu phân cách kéo dài khi đó là một dòng mới. Việc thực hiện của tôi luôn luôn nối thêm dải phân cách. Để có được mức tiết kiệm 1B ở chế độ 32 bit, quy tắc đó yêu cầu dấu phân cách = 0xa ( '\n'ASCII LF = linefeed), filler = 0xb ( '\v'ASCII VT = tab dọc). Điều đó không thân thiện với con người, nhưng đáp ứng thư pháp luật. (Bạn có thể hexdump hoặc
tr $'\v' xđầu ra để xác minh rằng nó hoạt động hoặc thay đổi hằng số để phân tách đầu ra và filler có thể in được. Tôi cũng nhận thấy rằng các quy tắc dường như yêu cầu nó có thể chấp nhận đầu vào với cùng fill / sep mà nó sử dụng cho đầu ra , nhưng tôi không thấy gì để đạt được từ việc phá vỡ quy tắc đó.).


Nguồn NASM / YASM. Xây dựng dưới dạng mã 32 hoặc 64 bit, sử dụng %ifnội dung đi kèm với chương trình thử nghiệm hoặc chỉ cần thay đổi RCx thành ecx.

input_separator equ 0xa  ; `\n` in NASM syntax, but YASM doesn't do C-style escapes

output_filler equ '0'                 ; For strict rules-compliance, needs to be input_separator+1
output_separator equ output_filler-1  ; saves 1B in 32-bit vs. an arbitrary choice
    ;; Using output_filler+1 is also possible, but isn't compatible with using the same filler and separator for input and output.

global str_exp
str_exp:                        ; void str_exp(char *out /*rdi*/, const char *src /*rsi*/,
                                ;              unsigned base /*edx*/);
.new_row:
    push   1
    pop    rcx                  ; ecx=1 = base**0

    lodsb                       ; Skip the first char, since we multiply for the separator
.read_bar:
    imul   ecx, edx             ; accumulate the exponential
    lodsb
    cmp    al, input_separator
    ja .read_bar                ; anything > separator is treated as filler
    ; AL = separator or terminator
    ; flags = below (CF=1) or equal (ZF=1).  Equal also implies CF=0, since x-x doesn't produce carry.

    mov    al, output_filler
    rep stosb                   ; append ecx bytes of filler to the output string
%if output_separator == output_filler-1
    dec   eax         ; saves 1B in the 32-bit version.  Use dec even in 64-bit for easier testing
%else
    mov    al, output_separator
%endif
    stosb                       ; append the delimiter

    ; CF is still set from the .read_bar loop, even if DEC clobbered the other flags
    ; JNC/JNB here is equivalent to JE on the original flags, because we can only be here if the char was below-or-equal the separator
    jnc .new_row            ; separator means more rows, else it's a terminator
    ; (f+s)+f+ full-match guarantees that the input doesn't end with separator + terminator
    ret

Hàm tuân theo x86-64 SystemV ABI, có chữ ký
void str_exp(char *out /*rdi*/, const char *src /*rsi*/, unsigned base /*edx*/);

Nó chỉ thông báo cho người gọi về độ dài của chuỗi đầu ra bằng cách để con trỏ một đầu quá khứ vào đó rdi, vì vậy bạn có thể coi đây là giá trị trả về - quy ước gọi tiêu chuẩn.

Nó sẽ tốn 1 hoặc 2 byte ( xchg eax,edi) để trả về con trỏ kết thúc bằng eax hoặc rax. (Nếu sử dụng x32 ABI, các con trỏ được đảm bảo chỉ có 32 bit, nếu không chúng ta phải sử dụng xchg rax,rditrong trường hợp người gọi chuyển một con trỏ đến bộ đệm bên ngoài 32 bit thấp.) Tôi đã không đưa nó vào phiên bản đăng bởi vì có cách giải quyết mà người gọi có thể sử dụng mà không nhận được giá trị từ đó rdi, vì vậy bạn có thể gọi nó từ C mà không có trình bao bọc.

Chúng tôi thậm chí không chấm dứt chuỗi đầu ra hoặc bất cứ điều gì, vì vậy nó chỉ kết thúc dòng mới. Sẽ mất 2 byte để sửa lỗi đó: xchg eax,ecx / stosb (RCx bằng 0 rep stosb).

Các cách để tìm ra độ dài chuỗi đầu ra là:

  • rdi trỏ đến một đầu quá khứ của chuỗi khi trả về (để người gọi có thể thực hiện len = end-start)
  • người gọi có thể biết có bao nhiêu hàng trong đầu vào và đếm số dòng mới
  • người gọi có thể sử dụng bộ đệm zeroed lớn và strlen()sau đó.

Chúng không đẹp hoặc hiệu quả (ngoại trừ việc sử dụng giá trị trả về RDI từ người gọi asm), nhưng nếu bạn muốn điều đó thì đừng gọi các hàm asm được đánh gôn từ C .: P


Giới hạn kích thước / phạm vi

Kích thước chuỗi đầu ra tối đa chỉ bị giới hạn bởi các giới hạn không gian địa chỉ bộ nhớ ảo. (Chủ yếu là phần cứng x86-64 hiện tại chỉ hỗ trợ 48 bit đáng kể trong các địa chỉ ảo, bị chia làm đôi vì chúng mở rộng thay vì mở rộng bằng không. Xem sơ đồ trong câu trả lời được liên kết .)

Mỗi hàng chỉ có thể có tối đa 2 ** 32 - 1 byte phụ, vì tôi tích lũy theo cấp số nhân trong một thanh ghi 32 bit.

Hàm hoạt động chính xác cho các cơ sở từ 0 đến 2 ** 32 - 1. (Đúng cho cơ sở 0 là 0 ^ x = 0, tức là chỉ các dòng trống không có byte phụ. Đúng cho cơ sở 1 là 1 ^ x = 1, vì vậy luôn luôn 1 filler trên mỗi dòng.)

Nó cũng cực kỳ nhanh trên Intel IvyBridge và sau đó, đặc biệt là đối với các hàng lớn được ghi vào bộ nhớ căn chỉnh. rep stosblà một triển khai tối ưu memset()cho số lượng lớn với các con trỏ được căn chỉnh trên CPU với tính năng ERMSB . ví dụ: 180 ** 4 là 0,97GB và mất 0,27 giây trên Skylake i7-6700k của tôi (với ~ 256k lỗi trang mềm) để ghi vào / dev / null. (Trên Linux, trình điều khiển thiết bị cho / dev / null không sao chép dữ liệu ở bất cứ đâu, nó chỉ trả về. Vì vậy, tất cả thời gian đều xảy ra rep stosbvà các lỗi trang mềm kích hoạt khi chạm vào bộ nhớ lần đầu tiên. tiếc là không sử dụng các vòng đệm trong suốt cho mảng trong BSS. Có lẽ một madvise()cuộc gọi hệ thống sẽ tăng tốc nó.)

Chương trình kiểm tra :

Xây dựng một nhị phân tĩnh và chạy như ./string-exponential $'#\n##\n###' $(seq 2)cho cơ sở 2. Để tránh thực hiện một atoi, nó sử dụng base = argc-2. (Giới hạn độ dài dòng lệnh ngăn việc kiểm tra các căn cứ lớn một cách lố bịch.)

Trình bao bọc này hoạt động cho các chuỗi đầu ra lên tới 1 GB. (Nó chỉ thực hiện một cuộc gọi hệ thống write () ngay cả đối với các chuỗi khổng lồ, nhưng Linux hỗ trợ điều này ngay cả khi ghi vào đường ống). Để đếm các ký tự, hoặc đặt ống vào wc -choặc sử dụng strace ./foo ... > /dev/nullđể xem arg tới tòa nhà viết.

Điều này tận dụng giá trị trả về RDI để tính toán độ dài chuỗi dưới dạng đối số write().

;;; Test program that calls it
;;; Assembles correctly for either x86-64 or i386, using the following %if stuff.
;;; This block of macro-stuff also lets us build the function itself as 32 or 64-bit with no source changes.

%ifidn __OUTPUT_FORMAT__, elf64
%define CPUMODE 64
%define STACKWIDTH 8    ; push / pop 8 bytes
%define PTRWIDTH 8
%elifidn __OUTPUT_FORMAT__, elfx32
%define CPUMODE 64
%define STACKWIDTH 8    ; push / pop 8 bytes
%define PTRWIDTH 4
%else
%define CPUMODE 32
%define STACKWIDTH 4    ; push / pop 4 bytes
%define PTRWIDTH 4
%define rcx ecx      ; Use the 32-bit names everywhere, even in addressing modes and push/pop, for 32-bit code
%define rsi esi
%define rdi edi
%define rsp esp
%endif


global _start
_start:
    mov  rsi, [rsp+PTRWIDTH + PTRWIDTH*1]  ; rsi = argv[1]
    mov  edx, [rsp]          ; base = argc
    sub  edx, 2              ; base = argc-2  (so it's possible to test base=0 and base=1, and so ./foo $'xxx\nxx\nx' $(seq 2) has the actual base in the arg to seq)
    mov  edi, outbuf         ; output buffer.  static data is in the low 2G of address space, so 32-bit mov is fine.  This part isn't golfed, though

    call str_exp             ; str_exp(outbuf, argv[1], argc-2)
    ;  leaves RDI pointing to one-past-the-end of the string
    mov  esi, outbuf

    mov  edx, edi
    sub  edx, esi               ; length = end - start

%if CPUMODE == 64 ; use the x86-64 ABI
    mov  edi, 1                 ; fd=1 (stdout)
    mov  eax, 1                 ; SYS_write  (Linux x86-64 ABI, from /usr/include/asm/unistd_64.h)
    syscall                     ; write(1, outbuf, length);

    xor edi,edi
    mov eax,231   ; exit_group(0)
    syscall


%else  ; Use the i386 32-bit ABI (with legacy int 0x80 instead of sysenter for convenience)
    mov ebx, 1
    mov eax, 4                  ; SYS_write (Linux i386 ABI, from /usr/include/asm/unistd_32.h)
    mov ecx, esi  ; outbuf
    ; 3rd arg goes in edx for both ABIs, conveniently enough
    int 0x80                    ; write(1, outbuf, length)

    xor ebx,ebx
    mov eax, 1
    int 0x80     ; 32-bit ABI _exit(0)
%endif


section .bss
align 2*1024*1024 ; hugepage alignment (32-bit uses 4M hugepages, but whatever)
outbuf:    resb 1024*1024*1024 * 1
; 2GB of code+data is the limit for the default 64-bit code model.
; But with -m32, a 2GB bss doesn't get mapped, so we segfault.  1GB is plenty anyway.

Đây là một thử thách thú vị mà chính nó đã cho vay rất tốt, đặc biệt là các chuỗi op x86 . Các quy tắc được thiết kế độc đáo để tránh phải xử lý một dòng mới và sau đó là một bộ kết thúc ở cuối chuỗi đầu vào.

Một số mũ với phép nhân lặp đi lặp lại cũng giống như nhân với phép cộng lặp lại và tôi cần phải lặp để đếm số ký tự trong mỗi hàng đầu vào.

Tôi đã cân nhắc sử dụng một toán hạng mulhoặc imulthay vì dài hơn imul r,r, nhưng việc sử dụng EAX ngầm của nó sẽ mâu thuẫn với LODSB.


Tôi cũng đã thử SCASB thay vì tải và so sánh , nhưng tôi cần xchg esi,editrước và sau vòng lặp bên trong, vì cả SCASB và STOSB đều sử dụng EDI. (Vì vậy, phiên bản 64 bit phải sử dụng x32 ABI để tránh cắt ngắn con trỏ 64 bit).

Tránh STOSB không phải là một lựa chọn; không có gì khác là bất cứ nơi nào gần như ngắn. Và một nửa lợi ích của việc sử dụng SCASB là AL = filler sau khi rời khỏi vòng lặp bên trong, vì vậy chúng tôi không cần bất kỳ thiết lập nào cho REP STOSB.

SCASB so sánh theo hướng khác với những gì tôi đã làm, vì vậy tôi cần phải đảo ngược các so sánh.

Nỗ lực tốt nhất của tôi với xchg và scasb. Hoạt động, nhưng không ngắn hơn. (Mã 32 bit, sử dụng inc/ dectrick để thay đổi filler thành dấu phân cách ).

; SCASB version, 24 bytes.  Also experimenting with a different loop structure for the inner loop, but all these ideas are break-even at best
; Using separator = filler+1 instead of filler-1 was necessary to distinguish separator from terminator from just CF.

input_filler equ '.'    ; bytes below this -> terminator.  Bytes above this -> separator
output_filler equ input_filler       ; implicit
output_separator equ input_filler+1  ; ('/') implicit

 8048080:       89 d1                   mov    ecx,edx    ; ecx=base**1
 8048082:       b0 2e                   mov    al,0x2e    ; input_filler= .
 8048084:       87 fe                   xchg   esi,edi
 8048086:       ae                      scas   al,BYTE PTR es:[edi]

08048087 <str_exp.read_bar>:
 8048087:       ae                      scas   al,BYTE PTR es:[edi]
 8048088:       75 05                   jne    804808f <str_exp.bar_end>
 804808a:       0f af ca                imul   ecx,edx           ; exit the loop before multiplying for non-filler
 804808d:       eb f8                   jmp    8048087 <str_exp.read_bar>   ; The other loop structure (ending with the conditional) would work with SCASB, too.  Just showing this for variety.
0804808f <str_exp.bar_end>:

; flags = below if CF=1 (filler<separator),  above if CF=0 (filler<terminator)
; (CF=0 is the AE condition, but we can't be here on equal)
; So CF is enough info to distinguish separator from terminator if we clobber ZF with INC

; AL = input_filler = output_filler
 804808f:       87 fe                   xchg   esi,edi
 8048091:       f3 aa                   rep stos BYTE PTR es:[edi],al
 8048093:       40                      inc    eax         ; output_separator
 8048094:       aa                      stos   BYTE PTR es:[edi],al
 8048095:       72 e9                   jc     8048080 <str_exp>   ; CF is still set from the inner loop
 8048097:       c3                      ret    

Đối với một đầu vào ../.../., sản xuất ..../......../../. Tôi sẽ không bận tâm đến việc hiển thị một hexdump của phiên bản với separator = newline.


4

Toán học 41 38 byte

-3 byte nhờ LLlAMnYP

Điều này nhận đầu vào là một danh sách các chuỗi theo sau là một số nguyên. Đầu ra cũng là một danh sách các chuỗi.

""<>"#"~Table~#&/@(#2^StringLength@#)&

Giải trình:

                   StringLength@# & - find length of each string in first input
                   #2^               & - raise to power of second input
                /@(                 )  - Uses each of these numbers on an inner function of ...
    "#"~Table~#&                       - Create arrys of specific length using character "#"
 ""<>                                  - Join arrays of characters together to make strings

Phiên bản cũ, 41 byte

"#"~StringRepeat~#&/@(#2^StringLength@#)&

"" <> "#"~Table~#ngắn hơn 3 byte "#"~StringRepeat~#, có thể chơi golf tốt hơn nữa.
LLlAMnYP

3

Japt , 7 byte

Lấy biểu đồ dưới dạng một chuỗi các chuỗi với "tư cách là phụ và cơ sở là một số nguyên.

£QpVpXl

Dùng thử trực tuyến

Thêm }Rvào cuối để lấy biểu đồ làm chuỗi phân tách dòng mới thay thế. ( Hãy thử nó )


Giải trình

    :Implicit input of array U.
£   :Map over the array, replacing each element with ...
Q   :the " character ...
p   :repeated ...
V   :integer input ...
p   :to the power of ...
Xl  :the length of the current element times.
    :Implicit output of result.

3

MATL , 14 11 byte

Y'iw^1HL(Y"

Dấu phân cách là không gian. Filler là bất kỳ nhân vật nào khác ngoài không gian.

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

Giải trình

       % Implicit input: string
       %   STACK: '## # ### #'
Y'     % Run-length encoding
       %   STACK: '# # # #', [2 1 1 1 3 1 1]
i      % Input: number
       %   STACK: '# # # #', [2 1 1 1 3 1 1], 3
w      % Swap
       %   STACK: '# # # #', 3, [2 1 1 1 3 1 1]
^      % Power, element-wise
       %   STACK: '# # # #', [9 3 3 3 9 3 3]
1      % Push 1
       %   STACK: '# # # #', [9 3 3 3 27 3 3], 1
HL     % Push [2 2 1j]. When used as an index, this means 2:2:end
       %   STACK: '# # # #', [9 3 3 3 27 3 3], 1, [2 2 1j]
(      % Write specified value at specified entries
       %   STACK: '# # # #', [9 1 3 1 27 1 3]
Y"     % Run-length decoding
       %  STACK: '######### ### ########################### ###'
       % Implicit display

Điều này dường như không hoạt động; độ dài của mỗi dòng trong đầu ra cho trường hợp thử nghiệm mà bạn đưa vào TIO của bạn phải là 9,3,27,9 nhưng thay vào đó là 6,3,9,3.
Xù xì

@Shaggy Bạn hoàn toàn đúng. Cảm ơn đã chú ý. Tôi đã phạm một lỗi trong chỉnh sửa mới nhất của tôi. Tôi đã quay trở lại phiên bản trước, ehich là chính xác
Luis Mendo

Không thể hiểu làm thế nào nó hoạt động từ lời giải thích - sau đó tôi đã nhấp qua TIO! : D
Xù xì

1
@Shaggy Tôi vừa thêm một lời giải thích cho phiên bản này, hy vọng rõ ràng hơn!
Luis Mendo

3

Haskell , 37 33 byte

4 byte bị loại bỏ nhờ sudee

\b->map(\x->'#'<$[1..b^length x])

Sự miêu tả:

\b->                               -- take an integer b as the first input input
    map(\x->                    )  -- apply the following to every element x in the second input
            '#'<$[1..b^length x]   ---- replicate '#' (b^(length x)) times

Thật đáng tiếc , đây là 2 byte ngắn hơn nhiều so với phiên bản pointfree khó đọc hơn:

map.(flip replicate '#'.).(.length).(^)

Đầu vào phải là một chuỗi đơn
bartavelle

@bartavelle, không nhất thiết.
Xù xì

Đó là những gì tôi hiểu bởi đầu vào biểu đồ thanh được lấy dưới dạng một chuỗi ...
bartavelle

1
@bartavelle: Đầu ra và đầu vào cũng có thể là một danh sách các chuỗi thay vì được phân tách bằng một chuỗi con, mặc dù phải có thể hiểu thanh nào là thanh nào.
Julian Wolf

2
Bạn có thể thay thế replicate(b^length x)'#'bằng '#'<$[1..b^length x].
sudee

3

ReRegex , 105 byte

#import math
(\d+)\n((;.*\n)*)(_+)/$1\n$2;$1^d<$4>/^\d+\n((;\d+\n?)+)$/$1/^((_*\n)*);(\d+)/$1u<$3>/#input

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

ReRegex giống như người anh em họ xấu xí của Retina dành tất cả nỗ lực cho Biểu thức chính quy, thay vì có các toán tử ưa thích của riêng nó.

Tất nhiên, nó cũng có #import#inputđể lưu cả đầu vào mã hóa cứng và viết lại các biểu thức tương tự lặp đi lặp lại.

Giải thích.

Đưa đầu vào dưới dạng:

2
____
__
______
___

trên STDIN và cung cấp đầu ra như

________________
____
________________________________________________________________
________

Đầu tiên, chương trình nhập Thư viện toán học , tất nhiên được viết hoàn toàn bằng ReRegex. Phần lớn của điều này sau đó là ba biểu thức chính quy.

(\d+)\n((;.*\n)*)(_+)   ->  $1\n$2;$1^d<$4>
^\d+\n((;\d+\n?)+)$     ->  $1
^((_*\n)*);(\d+)        ->  $1u<$3>

Cái đầu tiên phù hợp với cơ sở đầu vào của chúng tôi và tìm kiếm một dòng unary sau nó. sau đó, thay thế dòng đó bằng ;$1^d<$4>, là cơ sở, cho sức mạnh của Unary (In Decimal). Thư viện toán học xử lý chuyển đổi cơ sở và số mũ. A; được đặt ở đầu để xác định nó sau khi hoàn thành.

Thứ hai, khớp với cơ sở, sau đó nhiều dòng;, trước khi kết thúc. Nếu điều này phù hợp với toàn bộ, nó sẽ cắt khỏi căn cứ. để lại uf chỉ với câu trả lời và ;s.

Cuối cùng, phù hợp với unary lúc bắt đầu, tùy chọn, sau đó một ;câu trả lời. Sau đó, nó biến câu trả lời đó thành unary một lần nữa, mà không có ;.

Bởi vì đầu ra không khớp với regex đầu tiên, nên nó không lặp vô hạn, và vì vậy giải pháp của chúng tôi đã được đưa ra.



2

Röda , 19 byte

f n,s{s|["#"*n^#_]}

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

Lấy một mảng làm đầu vào và trả về một luồng các giá trị là đầu ra.

Giải trình

f n,s{s|["#"*n^#_]}              n is the number and s is the array of strings consisting of #s
      s|                         Push the each value of s to the stream
        [        ]               For each push
         "#"*                     "#" repeated
             n^#_                 n raised to the length of the string

2

Haskell , 32 byte

f b=map$foldr(\_->([1..b]>>))"#"

Hãy thử trực tuyến! Ví dụ sử dụng: f 3 ["##","#","###","#"]trả về ["#########","###","###########################","###"].

Sử dụng mapM putStrLn $ f 3 ["##","#","###","#"]để có được một đầu ra trực quan dễ chịu hơn:

#########
###
###########################
###

Chỉ cần bình luận ở đây vì tôi không thể nhận xét về bài đăng bạn đã xóa ... hãy thử sum[sum[]^sum[],sum[]^sum[]].
Ørjan Johansen

2

05AB1E , 9 byte

Các thanh được phân tách bằng dấu cách, ký tự đầu ra giống như ký tự đầu vào.

¬Š#€gm×ðý

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

¬Š#€gm×ðý   Arguments: n, s
¬           Head, get bar character
 Š          Rearrange stack to get: s, n, bar-character
  #         Split s on spaces
   €g       Map to length
     m      n to that power
      ×     That many bar-characters
       ðý   Join on space
            Implicit output

1

PHP, 69 byte

<?foreach($_GET[1]as$l)echo str_pad("",$_GET[0]**strlen($l),"#")."
";

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


Điều này trả về với một dòng mới hàng đầu, không được regex cho phép. Bạn có thể sử dụng [str_pad]."\n"thay vì "\n".[str_pad]để sửa lỗi này (+1 byte). Ngoài ra, bạn có thể giả sử filler là gì, vì vậy bạn có thể lưu hai byte $l[0]bằng cách thay đổi nó thành "#".
fireflame241

@ fireflame241 Xong Cảm ơn bạn
Jörg Hülsermann

1

Thạch , 7 byte

ṁL*@¥¥€

Một liên kết đơn và lấy danh sách các thanh (bản thân danh sách các ký tự, chuỗi AKA), ký tự phụ là linh hoạt.

Hãy thử trực tuyến!(chân trang sắp xếp danh sách kết quả bằng cách nối các phần tử của nó với dòng mới.)

Làm sao?

ṁL*@¥¥€ - Main link: list of list of characters, bars; number, base
     ¥€ - last two links as a dyad for €ach bar in bars:
    ¥   -   last two links as a dyad:
 L      -     length (of a bar)
  *@    -     exponentiate (swap @rguments) (base ^ length)
ṁ       -   mould like (e.g. moulding "##" like 8 yields "########")

7 -terter thay thế: ṁ"L€*@¥- lấy chiều dài của mỗi thanh ( L€), nâng baselên sức mạnh đó ( *@), sau đó nén ( ") danh sách và áp dụng khuôn dyad ( ) giữa hai thanh.


4 nhanh chóng và 3 liên kết thực tế? Thử thách này khá nặng nề trong việc kiểm soát luồng dữ liệu ...
Sản phẩm ETH

Vâng, có thể có một giải pháp ngắn hơn có sẵn ...
Jonathan Allan

@Jonathan ALLan Tôi sợ là không có.
Erik the Outgolfer

@ETHproductions Đó thực sự là một liên kết. Lời giải thích có thể có khá nhiều chỉ là một dòng.
Erik the Outgolfer

1

Ruby , 29 byte

->x,y{x.map{|z|?#*y**z.size}}

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

Vâng, tôi đã phát hiện ra tuần trước ?#sản xuất một chuỗi ký tự đơn. Tôi không biết tại sao tính năng này tồn tại nhưng tôi chắc chắn rất vui vì nó.


1
Các ?Xnhà điều hành, nơi Xmột số nhân vật, là "có được đại diện mặc định của nhân vật này" điều hành. Trong Ruby <1.9, nó sẽ trả về điểm mã Unicode của ký tự, bởi vì đó là cách xác định các ký tự, nhưng bây giờ nó trả về một chuỗi chứa ký tự. Đó là một phần của sự thay đổi chung hướng tới việc xử lý Unicode phù hợp hơn trong Ruby.
Người hướng dẫn

@Turtman, có bất kỳ raisin cuồng loạn tại sao ?Xđược sử dụng? Rất nhiều quy ước kỳ quặc của Ruby, như rất nhiều $biến thể, tồn tại vì quen thuộc với Perl.
ymbirtt

1

JavaScript (ES8), 39 byte

Lấy cơ sở là một số nguyên và biểu đồ dưới dạng một chuỗi các chuỗi với bất kỳ ký tự nào làm phụ, sử dụng cú pháp currying.

b=>a=>a.map(x=>x.padEnd(b**x.length,x))

Thử nó

f=
b=>a=>a.map(x=>x.padEnd(b**x.length,x))
oninput=_=>o.innerText=f(i.value)(j.value.split`\n`).join`\n`
o.innerText=f(i.value=2)((j.value=`####\n##\n######\n###`).split`\n`).join`\n`
*{box-sizing:border-box}#i,#j{margin:0 0 5px;width:200px}#j{display:block;height:100px
<input id=i type=number><textarea id=j></textarea><pre id=o>


Thay thế, 49 byte

Phiên bản này lấy biểu đồ dưới dạng một chuỗi phân tách dòng mới, một lần nữa với bất kỳ ký tự nào làm phụ.

b=>s=>s.replace(/.+/g,m=>m.padEnd(b**m.length,m))

Đừng nghĩ rằng bạn cần mcờ trên regex, theo mặc định .không khớp với dòng mới.
Sản phẩm ETH

Hmm, không biết nơi đó đến từ đâu - những nguy hiểm khi cố gắng chơi golf từ điện thoại. Cảm ơn bạn đã chỉ ra, @ETHproductions.
Xù xì

0

Toán học, 86 byte

(s=#2^StringLength[StringSplit@#1];StringJoin/@Table[Table["#",s[[i]]],{i,Length@s}])&

đầu vào

["#### \ n ## \ n ###### \ n ###", 2]


ok ... Đã sửa ......
J42161217

0

Octave, 42 byte

@(b,s)[(1:max(k=b.^sum(s'>32)')<=k)+32 '']

* Chuỗi đầu vào / đầu ra không khớp hoàn toàn với biểu thức chính quy nhưng có thể hiểu thanh nào là thanh.

Một hàm lấy làm cơ sở đầu vào bvà một mảng ký tự 2D schứa "!"và đầu ra cũng là một mảng ký tự.

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

Giải trình:

                       s'>32               % logical array of input represents 1 for filler and 0 for spaces
                   sum(     )'             % an array containing length of each string 
              k=b.^                        % exponentiate ( lengths of output)
        1:max(                )            % range form 1 to max of output lengths
                               <=k         % logical array of output represents 1 for filler and 0 for spaces
      [(                          )+32 ''] % convert the logical array to char array.

0

CJam, 20 byte

q~:A;N/{,A\#"#"e*N}%

định dạng đầu vào

Đầu vào là bắt buộc theo định dạng sau:

"##
####
######"2

0

Than , 11 byte

NβWS«PXβLι↓

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. I / O là một danh sách các chuỗi -ký tự (lưu ý rằng bạn cần một dòng trống để chấm dứt danh sách).


0

V , 27 byte

Ý tưởng cơ bản là chúng ta thêm a 'vào mỗi hàng (n ^ 0), và sau đó với mỗi hàng #chúng ta thay thế 's trong dòng bằng [input] * '. Cuối cùng tôi trao đổi tất cả các 'cho #một lần nữa

Àé'ld0ÎA'
ò/#
"_xÓ'/"òÍ'/#

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



0

05AB1E , 10 byte

U|v1Xygm×,

Nhân vật filer là 1và dấu phân cách là một dòng mới.

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

U          # Store the base in X
 |         # Get the rest of input as a list of lines
  v        # For each...
   1       #   Push 1
    X      #   Push the base
     y     #   Push this bar
      g    #   Get the length
       m   #   Push a**b
        ×, #   Print a string of #s with that length

0

Võng mạc , 62 byte

ms`^(?=.*¶(.*))
#;$1$*#;
{`#(?=#*;(#+);#)
$1
}m`#$

;#+;|¶.*$

Hãy thử trực tuyến! Xét cho cùng, một biểu đồ thanh chỉ là một danh sách các số đơn nguyên. Lấy đầu vào dưới dạng biểu đồ (sử dụng #s) theo sau là cơ sở ở dạng thập phân (để tránh nhầm lẫn). Giải thích: Tiền tố thay thế đầu tiên 1 và cơ sở cho từng dòng của biểu đồ. Sự thay thế thứ hai sau đó nhân số thứ nhất trên mỗi dòng với số thứ hai, miễn là số thứ ba là số khác. Sự thay thế thứ ba sau đó giảm số thứ ba trên mỗi dòng. Hai thay thế này được lặp lại cho đến khi số thứ ba trở thành số không. Sự thay thế cuối cùng sẽ xóa cơ sở ở mọi nơi, để lại kết quả mong muốn.



0

Alice , 23 byte

/'/dI
\I!wO&K/h.n$@?~E&

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

Không chỉ tôi không phải là người bỏ cuộc, mà tôi còn rất cam kết đưa ra quan điểm chính xác mà tôi sử dụng !làm phụ. Điều đó chắc chắn sẽ thu hút sự chú ý của độc giả.

Giải trình

Gương được giữ lại trong phần giải thích này để làm cho nó rõ ràng hơn khi chương trình chuyển đổi giữa chế độ hồng y và thứ tự.

/I/!/wI&/h.n$@?~E&\'!dOK

/I                        % input base
  /!/                     % store onto tape as integer
     w                    % push return address
      I                   % input next line
       &/h                % get length (by adding 1 for each character in the string)
          .n$@            % terminate if zero
              ?~E         % get base from tape and raise to power
                 &\'!     % push "!" onto the stack that many times
                     d    % combine into a single string
                      O   % output string with newline
                       K  % return to stored address (without popping it from the return address stack)

0

Perl 6 , 26 byte

{map '#'x$^b** *.comb,@^a}

Danh sách các chuỗi đầu vào nằm trong tham số đầu tiên , @^a. Tham số thứ hai $^blà cơ sở. Một danh sách các chuỗi đầu ra được trả về.

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.