Metryolf đầy sao


25

Starry là một ngôn ngữ lập trình bí truyền vui nhộn trong đó mã chỉ bao gồm +*.,`'nơi lệnh thực tế được đại diện bởi mỗi ký tự đó được xác định bởi số lượng khoảng trắng ở phía trước nó. Điều đó làm cho nó trở nên khó khăn ngay cả với những thách thức đầu ra cố định golf, bởi vì các lệnh khác nhau có thể chiếm số lượng byte khác nhau rất lớn. Cụ thể, chữ số có một biểu diễn đơn nhất khiến cho việc xây dựng số lớn hơn bằng cách vận hành trên các số nhỏ hơn là cần thiết.

Do đó, thách thức này là về việc viết một chương trình có thể chơi các chương trình Starry như vậy.

Starry hoạt động như thế nào?

(Một vài chi tiết không được chỉ định trên esolang, vì vậy tôi sẽ xử lý hành vi của trình thông dịch Ruby .)

Starry là một ngôn ngữ dựa trên ngăn xếp, với một chồng các giá trị nguyên chính xác tùy ý (ban đầu là trống).

Các nhân vật có ý nghĩa duy nhất là:

+*.,`'

và không gian. Tất cả các nhân vật khác được bỏ qua. Mỗi chuỗi không gian theo sau bởi một trong những ký tự không phải không gian đó đại diện cho một lệnh. Loại hướng dẫn phụ thuộc vào ký tự không phải không gian và số lượng khoảng trắng.

Các hướng dẫn là:

Spaces  Symbol  Meaning
0         +     Invalid opcode.
1         +     Duplicate top of stack.
2         +     Swap top 2 stack elements.
3         +     Rotate top 3 stack elements. That is, send the top stack element
                two positions down. [... 1 2 3] becomes [... 3 1 2].
4         +     Pop and discard top of stack.
n ≥ 5     +     Push n − 5 to stack.
0 mod 5   *     Pop y, pop x, push x + y.
1 mod 5   *     Pop y, pop x, push x − y.
2 mod 5   *     Pop y, pop x, push x * y.
3 mod 5   *     Pop y, pop x, push x / y, rounded towards -∞.
4 mod 5   *     Pop y, pop x, push x % y. The sign of the result matches the sign of y.
0 mod 2   .     Pop a value and print it as a decimal number.
1 mod 2   .     Pop a value and print it as an ASCII character. This throws an error
                if the value is not in the range [0, 255].
n         `     Mark label n.
n         '     Pop a value; if non-zero, jump to label n. 

Lưu ý rằng trình thông dịch sẽ quét mã nguồn cho các nhãn trước khi bắt đầu thực thi, do đó có thể nhảy về phía trước cũng như lùi lại.

Tất nhiên, Starry cũng có các lệnh đầu vào (sử dụng ,tương tự .), nhưng những lệnh này không liên quan đến thử thách này.

Các thách thức

Đưa ra một chuỗi, tạo một chương trình Starry không có đầu vào và in chính xác chuỗi đó sang STDOUT.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả qua tham số STDOUT (hoặc thay thế gần nhất), tham số trả về hàm hoặc tham số hàm (out).

Bạn có thể giả sử rằng chuỗi không dài hơn 128 ký tự và nó sẽ chỉ bao gồm các ký tự ASCII có thể in được (mã điểm 0x20 đến 0x7E).

Giải pháp của bạn sẽ xử lý bất kỳ đầu vào nào như vậy trong vòng chưa đầy 5 phút trên một máy tính để bàn hợp lý (có một chút chậm trễ trong vấn đề này; nếu mất thêm vài phút trên máy tính xách tay của tôi thì tôi không phiền, nhưng nếu mất 15, tôi sẽ không đủ điều kiện nó).

Giải pháp của bạn sẽ được kiểm tra trên một số chuỗi khác nhau được liệt kê dưới đây. Điểm của bạn là tổng số byte của các chương trình Starry tương ứng. Trong trường hợp hòa, người metagolfer ngắn nhất sẽ thắng. Đó là, đừng bận tâm đến việc chơi mã của riêng bạn trừ khi có một sự ràng buộc (mà tôi nghĩ sẽ chỉ xảy ra trong trường hợp có thể có một giải pháp tối ưu).

Bạn không được tối ưu hóa mã của mình đối với các trường hợp thử nghiệm cụ thể được liệt kê bên dưới. Cụ thể, bạn không nên sử dụng giải pháp thủ công hardcode cho chúng. Tối ưu hóa đối với các lớp của chuỗi có cấu trúc tương tự như các chuỗi đã cho là ổn. Nếu tôi nghi ngờ bất kỳ ai về các giải pháp mã hóa cứng, tôi có quyền thay thế một số hoặc tất cả các trường hợp thử nghiệm (bằng các chuỗi cấu trúc có thể so sánh được).

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

Mỗi dòng là một trường hợp thử nghiệm riêng biệt:

Hello, World!
pneumonoultramicroscopicsilicovolcanoconiosis
.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
Hickory, dickory, dock. The mouse ran up the clock. The clock struck 1. The mouse ran down. Hickory, dickory, dock.
36912059868043514648560046917066768694455682545071266675083273015450033938555319356951628735735013250100789433961153496780296165
bVZ48121347GLtpYnt76CZSxTpMDs6791EJE808077eySXldY162424ddTB90707UupwlWGb63618542VhA252989453TXrWgqGm85899uHOAY2oAKE198GOVUttvW63
7MYxoWBNt180CDHS5xBGvU70HHVB17bh8jYzIIiU6n6g98Rose1nOe8Svcg56nax20q30kT3Ttb2jHl5q2Iuf1vPbjPxm9cyKXwxc0OUK8pr13b2n7U9Y7RwQTc26A1I
n9}unwxVa}[rj+5em6K#-H@= p^X/:DS]b*Jv/_x4.a5vT/So2R`yKy=in7-15B=g _BD`Bw=Z`Br;UwwF[{q]cS|&i;Gn4)q=`!G]8"eFP`Mn:zt-#mfCV2AL2^fL"A

Tín dụng cho trường hợp thử nghiệm thứ hai đi đến Dennis . Tín dụng cho trường hợp thử nghiệm thứ tư đi đến Sp3000.

Giải pháp tham khảo

Đây là một giải pháp tham khảo thực sự cơ bản trong CJam:

q{S5*\iS*'+S'.}%

Bạn có thể chạy nó với toàn bộ bộ thử nghiệm ở đây. Điểm số là:

1233
5240
4223
11110
7735
10497
11524
11392
Total: 62954

Đó là cách tiếp cận đơn giản nhất có thể: đẩy điểm mã của mỗi ký tự thành một chữ và sau đó in nó. Nó không sử dụng các khác biệt nhỏ giữa các ký tự liên tiếp, in số nguyên, các phần lặp lại của chuỗi, v.v. Tôi sẽ để lại những thứ đó cho bạn.

Tôi tin rằng có rất nhiều chỗ để cải thiện. Để tham khảo, thủ công ngắn nhất "Xin chào, thế giới!" chỉ dài 169 byte.

Câu trả lời:


6

Ruby, 13461 10997

$s = {};
def shortest a,b=nil
    return $s[[a,b]] if $s[[a,b]]
    l = []
    if b
        if a == b
            return $s[[a,b]] = ""
        elsif a > b
            l.push shortest(a-b)+" *"
            l.push " +   *"+shortest(1,b) if a > 1
            l.push " + *"+shortest(0,b) if a > 0
            l.push "    +"+shortest(b)
        elsif a < b
            l.push " +  *"+shortest(a*a,b) if a*a>a && a*a<=b
            l.push " +*"+shortest(a+a,b) if a+a<=b && a+a>a
            l.push shortest(b-a)+"*"
            l.push " +"+shortest(a,b/a)+"  *" if a>2 && b%a == 0
            l.push " +"+shortest(a,b-a)+"*" if a>1 && b>a*2
        end
    else
        l.push ' '*(a+5)+'+' #if a < 6
        (1..a/2).each {|n|
            l.push shortest(n)+shortest(n,a)
        }
    end
    return $s[[a,b]] = l.min_by{|x|x.length}
end

def starry(str)
    arr = str.bytes.map{|b|
        if b>47 && b<58
            b-48# change digets to numbers
        else
            b
        end
    }

    startNum = (1..128).min_by{|x|arr.inject{|s,y|s + [shortest(x,y).length+2,shortest(y).length].min}+shortest(x).length}
    #one number to be put on the stack at the start.

    code = shortest(startNum)
    code += [
        shortest(arr[0]),
        " +"+shortest(startNum, arr[0])
    ].min_by{|x|x.length}

    arr.each_cons(2) do |a|
        pr = a[0]<10?'.':' .'
        code += [
            pr+shortest(a[1]),
            " +"+pr+shortest(a[0], a[1]),
            pr+" +"+shortest(startNum, a[1])
        ].min_by{|x|x.length}
    end
    code += arr[-1]<10?'.':' .'
end

a = ["Hello, World!",
"pneumonoultramicroscopicsilicovolcanoconiosis",
".oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.",
"Hickory, dickory, dock. The mouse ran up the clock. The clock struck 1. The mouse ran down. Hickory, dickory, dock.",
"36912059868043514648560046917066768694455682545071266675083273015450033938555319356951628735735013250100789433961153496780296165",
"bVZ48121347GLtpYnt76CZSxTpMDs6791EJE808077eySXldY162424ddTB90707UupwlWGb63618542VhA252989453TXrWgqGm85899uHOAY2oAKE198GOVUttvW63",
"7MYxoWBNt180CDHS5xBGvU70HHVB17bh8jYzIIiU6n6g98Rose1nOe8Svcg56nax20q30kT3Ttb2jHl5q2Iuf1vPbjPxm9cyKXwxc0OUK8pr13b2n7U9Y7RwQTc26A1I",
"n9}unwxVa}[rj+5em6K#-H@= p^X/:DS]b*Jv/_x4.a5vT/So2R`yKy=in7-15B=g _BD`Bw=Z`Br;UwwF[{q]cS|&i;Gn4)q=`!G]8\"eFP`Mn:zt-#mfCV2AL2^fL\"A"]
c = a.map{
    |s|
    starry(s).length
}
p c.inject(0){|a,b|a+b}

Phương pháp starrytrả lời câu hỏi đã cho.

Các kết quả:

230
639
682
1974
1024
1897
2115
2436
Total: 10997

Làm thế nào nó hoạt động

shortestlà thuật toán chính. Nó lấy một số và tìm cách ngắn nhất để đặt nó vào ngăn xếp hoặc mất hai số và trả về mã để đặt số thứ hai vào ngăn xếp giả sử cái đầu tiên đã được bật. $slà một Hash để giữ kết quả của các hoạt động này để sử dụng tiếp.

starrylấy một chuỗi và chia nó thành một chuỗi các ký tự (hoặc số cho các bản tóm tắt). Nó bắt đầu mã với một số ở dưới cùng của ngăn xếp. Tiếp theo, nó tính toán cách ngắn nhất mà nó có thể tạo ra mỗi số liên tiếp, có thể sao chép số cuối hoặc sử dụng số được đặt trên ngăn xếp ở đầu.


9

Trăn 3, 17071 11845

from functools import lru_cache
import heapq
import time

cases = r"""
Hello, World!
pneumonoultramicroscopicsilicovolcanoconiosis
.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
Hickory, dickory, dock. The mouse ran up the clock. The clock struck 1. The mouse ran down. Hickory, dickory, dock.
36912059868043514648560046917066768694455682545071266675083273015450033938555319356951628735735013250100789433961153496780296165
bVZ48121347GLtpYnt76CZSxTpMDs6791EJE808077eySXldY162424ddTB90707UupwlWGb63618542VhA252989453TXrWgqGm85899uHOAY2oAKE198GOVUttvW63
7MYxoWBNt180CDHS5xBGvU70HHVB17bh8jYzIIiU6n6g98Rose1nOe8Svcg56nax20q30kT3Ttb2jHl5q2Iuf1vPbjPxm9cyKXwxc0OUK8pr13b2n7U9Y7RwQTc26A1I
n9}unwxVa}[rj+5em6K#-H@= p^X/:DS]b*Jv/_x4.a5vT/So2R`yKy=in7-15B=g _BD`Bw=Z`Br;UwwF[{q]cS|&i;Gn4)q=`!G]8"eFP`Mn:zt-#mfCV2AL2^fL"A
""".strip().splitlines()

@lru_cache(maxsize=128)
def shortest_m_to_n(m, n):
    if m is None:
        L = []
    else:
        L = [m]

    to_search = [[0, "", L]]
    seen = set()

    while True:
        length, code, stack = heapq.heappop(to_search)

        if len(stack) == 1 and stack[-1] == n:
            return code

        seen.add(tuple(stack))
        options = []

        for i in range(1, 11):
            new_stack = stack[:] + [i]
            new_code = code + ' '*(i+5) + '+'
            options.append([len(new_code), new_code, new_stack])

        if stack:
            new_stack = stack[:] + [stack[-1]]
            new_code = code + " +"
            options.append([len(new_code), new_code, new_stack])

        if len(stack) >= 2:
            x, y = stack[-2:]

            for i, op in enumerate(['+', '-', '*', '//', '%']):
                try:
                    new_elem = eval("{}{}{}".format(x, op, y))
                    new_stack = stack[:-2] + [new_elem]
                    new_code = code + ' '*i + '*'
                    options.append([len(new_code), new_code, new_stack])

                except ZeroDivisionError:
                    pass

        for op in options:
            if tuple(op[2]) in seen or len(op[2]) > 4 or op[2][-1] > 200:
                continue

            heapq.heappush(to_search, op)

def lcs(s1, s2):
    dp_row = [""]*(len(s2)+1)

    for i, c1 in enumerate(s1):
        new_dp_row = [""]

        for j, c2 in enumerate(s2):
            if c1 == c2 and not c1.isdigit():
                new_dp_row.append(dp_row[j] + c1)
            else:
                new_dp_row.append(max(dp_row[j+1], new_dp_row[-1], key=len))

        dp_row = new_dp_row

    return dp_row[-1]

def metagolf(s):
    keep = ""
    split_index = 0

    for i in range(1, len(s)):
        l = lcs(s[:i], s[i:][::-1])
        if len(l) > len(keep):
            keep = l
            split_index = i

    code = []
    stack = []
    keep_ptr = 0
    i = 0

    while i < len(s):
        c = s[i]
        n = ord(c)

        if c in "0123456789":
            code += [" "*(int(c)+5) + "+."]
            i += 1
            continue

        if stack:
            if stack[-1] == n:
                code += [" +", " ."]
            elif len(stack) >= 2 and stack[-2] == n:
                for j in range(len(code)):
                    if code[~j] == " +":
                        code[~j] = ""
                        break

                code += [" +", " ."]
                stack.pop()
            else:
                code += [shortest_m_to_n(stack[-1], n), " +", " ."]
                stack[-1] = n

        else:
            code += [shortest_m_to_n(None, n), " +", " ."]
            stack.append(n)

        while i < split_index and keep[keep_ptr:][:1] == c:
            code += [" +"]
            keep_ptr += 1
            stack.append(n)

        i += 1

    code = "".join(code)

    if code[-4:] == " + .":
        code = code[:-4] + " ."

    return code

total = 0

for case in cases:
    start_time = time.time()

    s = metagolf(case)
    print(len(s), time.time() - start_time)
    total += len(s)
    print(s)
    print('='*50)

print(total)

Các chức năng có liên quan là tên thích hợp metagolf.

Kết quả là:

210
676
684
2007
1463
2071
2204
2530
Total: 11845

Bạn có thể tìm thấy đầu ra đầy đủ ở đây .

Giải thích ngắn gọn

Tôi sẽ tiếp tục giải thích ngắn gọn vì có nhiều điều vẫn cần phải cải thiện.

Thuật toán cơ bản chỉ nhìn vào các cặp ký tự và tìm ra cách tối ưu để chuyển từ char này sang char khác thông qua BFS. Các chữ số hiện đang được đẩy và in ngay lập tức, mặc dù điều này sẽ được thay đổi sau đó.

Ngoài ra còn có một chút phổ biến dài nhất đang diễn ra, để lại một vài yếu tố trên ngăn xếp để sử dụng lại sau này. Nó không tốt như sự lặp lại, nhưng cung cấp tiết kiệm khá.


Hoan hô, ai đó để chiến đấu :-) Tất nhiên, bây giờ tôi thấy rằng tôi có một chặng đường dài để đi ...
ETHproductions

5

JavaScript, 25158 23778

Bây giờ tương thích ES5!

String.prototype.repeat = String.prototype.repeat || function (n) { return Array(n+1).join(this); }

function starrify(x) {
  function c(x){return x.charCodeAt()}
  var char = x[0], result = ' '.repeat(c(char)+5)+'+ + .';
  x=x.slice(1);
  for(var i in x) {
    if (char < x[i]) {
      result += ' '.repeat(c(x[i])-c(char)+5)+'+* + .';
    } else if (char > x[i]) {
      if(c(char)-c(x[i]) < c(x[i])) {
        result += ' '.repeat(c(char)-c(x[i])+5)+'+ * + .';
      } else {
        result += ' '.repeat(c(x[i])+5)+'+ + .';
      }
    } else {
      result += ' + .';
    }
    char = x[i];
  }
  return result;
}

Các kết quả:

432
949
2465
3996
1805
3551
5205
5375
Total: 23778

Một khởi đầu tốt trong quan điểm của tôi, nhưng rõ ràng là không kết thúc. Thay vì tạo từng char riêng biệt, nó thêm hoặc bớt từ mã char trước đó. Tôi sẽ thêm một lời giải thích đầy đủ khi tôi hoàn thành môn đánh gôn.


Đúng, hiện tại nó hoạt động trong Firefox, mặc dù Chrome vẫn phàn nàn charCodeAt.
Martin Ender
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.