Starry Metagolf


25

Starryเป็นภาษาการเขียนโปรแกรมที่ลึกลับซึ่งประกอบไปด้วยรหัส+*.,`'ที่คำสั่งจริงที่แสดงโดยอักขระแต่ละตัวนั้นถูกกำหนดโดยจำนวนช่องว่างด้านหน้า นั่นทำให้มันยุ่งยากแม้กระทั่งกับความท้าทายของการส่งออกคงที่เนื่องจากคำสั่งที่แตกต่างกันสามารถอธิบายจำนวนไบต์ที่ต่างกันได้อย่างมากมาย โดยเฉพาะอย่างยิ่งตัวอักษรตัวเลขมีการแสดงเอกที่ทำให้มันจำเป็นในการสร้างตัวเลขที่มีขนาดใหญ่ขึ้นโดยการดำเนินการในจำนวนที่น้อยกว่า

ดังนั้นความท้าทายนี้เกี่ยวกับการเขียนโปรแกรมที่สามารถเล่นกอล์ฟโปรแกรม Starry เช่นนั้นได้

Starry ทำงานอย่างไร

(รายละเอียดเล็ก ๆ น้อย ๆ ไม่ได้ระบุไว้ใน esolangs ดังนั้นฉันจะไปกับพฤติกรรมของล่าม Ruby )

Starry เป็นภาษาที่ใช้กองซ้อนโดยมีค่าจำนวนเต็มเดียวที่มีความแม่นยำตามอำเภอใจ (ซึ่งจะว่างเปล่าในตอนแรก)

อักขระที่มีความหมายเพียงอย่างเดียวคือ:

+*.,`'

และช่องว่าง อักขระอื่น ๆ ทั้งหมดจะถูกละเว้น แต่ละลำดับของช่องว่างตามด้วยหนึ่งในอักขระที่ไม่ใช่ช่องว่างหมายถึงคำสั่งเดียว ประเภทของการเรียนการสอนขึ้นอยู่กับตัวละครที่ไม่ใช่ช่องว่างและจำนวนช่องว่าง

คำแนะนำคือ:

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. 

โปรดทราบว่าล่ามจะสแกนซอร์สโค้ดสำหรับฉลากก่อนที่จะเริ่มต้นการดำเนินการดังนั้นจึงเป็นไปได้ที่จะข้ามไปข้างหน้าและข้างหลัง

แน่นอนว่า Starry ยังมีคำสั่งป้อนข้อมูล (ใช้แบบอะนา,ล็อกถึง.) แต่คำสั่งเหล่านั้นไม่เกี่ยวข้องกับความท้าทายนี้

ความท้าทาย

รับสตริงสร้างโปรแกรม Starry ที่ไม่มีอินพุตและพิมพ์สตริงนั้นตรงกับ STDOUT

คุณสามารถเขียนโปรแกรมหรือฟังก์ชั่น, รับอินพุตผ่าน STDIN (หรือทางเลือกที่ใกล้เคียงที่สุด), อาร์กิวเมนต์บรรทัดคำสั่งหรืออาร์กิวเมนต์ของฟังก์ชันและส่งผลลัพธ์ผ่าน STDOUT (หรือทางเลือกที่ใกล้เคียงที่สุด), ค่าส่งคืนของฟังก์ชันหรือพารามิเตอร์

คุณอาจคิดว่าสตริงนั้นมีความยาวไม่เกิน 128 ตัวอักษรและจะประกอบด้วยอักขระ ASCII ที่พิมพ์ได้เท่านั้น (รหัสจุด 0x20 ถึง 0x7E)

วิธีแก้ปัญหาของคุณควรประมวลผลอินพุตดังกล่าวในเวลาน้อยกว่า 5 นาทีบนเครื่องเดสก์ท็อปที่เหมาะสม (มีบางอย่างที่เกินกว่านี้ถ้าใช้เวลาเพิ่มอีกสองสามนาทีบนแล็ปท็อปของฉันฉันไม่รังเกียจ แต่ถ้าใช้เวลา 15) ฉันจะตัดสิทธิ์ มัน).

โซลูชันของคุณจะได้รับการทดสอบตามจำนวนสายอักขระต่าง ๆ ที่ระบุไว้ด้านล่าง คะแนนของคุณคือจำนวนไบต์ทั้งหมดของโปรแกรม Starry ที่เกี่ยวข้อง ในกรณีที่เสมอกันนักพนันสั้นที่สุดจะเป็นผู้ชนะ นั่นคือไม่ต้องตีกอล์ฟรหัสของคุณเองจนกว่าจะมีการผูก (ซึ่งฉันคิดว่าจะเกิดขึ้นเฉพาะในกรณีที่เป็นไปได้ทางออกที่ดีที่สุด)

คุณต้องไม่ปรับรหัสของคุณให้เหมาะสมกับกรณีทดสอบเฉพาะด้านล่าง คุณไม่ควร hardcode โซลูชันที่สร้างขึ้นด้วยมือสำหรับพวกเขา การปรับให้เหมาะสมกับคลาสของสตริงที่มีโครงสร้างคล้ายกับสตริงที่กำหนด หากฉันสงสัยว่าใครก็ตามที่ใช้โซลูชัน hardcoding ฉันขอสงวนสิทธิ์ในการแทนที่กรณีทดสอบบางส่วนหรือทั้งหมด (ด้วยสตริงของโครงสร้างที่เทียบเท่ากัน)

กรณีทดสอบ

แต่ละบรรทัดเป็นกรณีทดสอบแยก:

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

สินเชื่อสำหรับกรณีทดสอบที่สองไปที่เดนนิส เครดิตสำหรับกรณีทดสอบที่สี่ไปที่ Sp3000

โซลูชันอ้างอิง

นี่คือโซลูชันอ้างอิงพื้นฐานจริง ๆ ใน CJam:

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

คุณสามารถเรียกใช้กับชุดทดสอบทั้งหมดได้ที่นี่ คะแนนที่ได้คือ:

1233
5240
4223
11110
7735
10497
11524
11392
Total: 62954

มันเป็นวิธีที่ง่ายที่สุดที่เป็นไปได้: ผลักรหัสจุดของตัวละครแต่ละตัวเป็นตัวอักษรแล้วพิมพ์ออกมา มันไม่ได้ใช้ความแตกต่างเล็กน้อยระหว่างตัวละครที่ต่อเนื่องกันการพิมพ์จำนวนเต็มชิ้นส่วนซ้ำ ๆ ของสตริง ฯลฯ ฉันจะทิ้งสิ่งเหล่านั้นไว้กับคุณ

ฉันเชื่อว่ามีห้องพักมากมายสำหรับการปรับปรุง สำหรับการอ้างอิงhandcrafted ที่สั้นที่สุด "Hello, World!" มีความยาวเพียง 169 ไบต์

คำตอบ:


6

ทับทิม, 13461 1,0997

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

วิธีการstarryตอบคำถามที่กำหนด

ผล:

230
639
682
1974
1024
1897
2115
2436
Total: 10997

มันทำงานอย่างไร

shortestเป็นอัลกอริทึมหลัก ใช้หมายเลขหนึ่งและค้นหาวิธีที่สั้นที่สุดในการวางลงบนสแต็กหรือใช้ตัวเลขสองตัวและส่งคืนรหัสเพื่อวางรหัสที่สองบนสแต็กโดยสมมติว่าหมายเลขแรกเปิดอยู่แล้ว $sเป็นแฮชเพื่อเก็บผลลัพธ์ของการดำเนินการเหล่านี้เพื่อใช้งานเพิ่มเติม

starryใช้สตริงและแยกเป็นอาร์เรย์ของรหัสอักขระ (หรือตัวเลขสำหรับการย่อย) มันเริ่มต้นรหัสด้วยหมายเลขหนึ่งที่ด้านล่างของสแต็ค ถัดไปจะคำนวณวิธีที่สั้นที่สุดที่สามารถสร้างแต่ละหมายเลขที่ต่อเนื่องกันอาจคัดลอกหมายเลขสุดท้ายหรือใช้หมายเลขที่วางอยู่บนสแต็กที่จุดเริ่มต้น


9

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

metagolfฟังก์ชั่นที่เกี่ยวข้องจะเหมาะเจาะกับชื่อ

ผลลัพธ์ที่ได้คือ:

210
676
684
2007
1463
2071
2204
2530
Total: 11845

คุณสามารถค้นหาเอาท์พุทเต็มรูปแบบที่นี่

คำอธิบายสั้น ๆ

ฉันจะอธิบายสั้น ๆ เนื่องจากยังมีหลายสิ่งที่ต้องปรับปรุง

อัลกอริทึมพื้นฐานเพียงแค่ดูที่ตัวอักษรคู่และค้นหาวิธีที่ดีที่สุดในการเปลี่ยนจากตัวอักษรหนึ่งเป็นแบบอื่นผ่านทาง BFS ขณะนี้ตัวเลขจะถูกผลักและพิมพ์ทันทีแม้ว่าจะมีการเปลี่ยนแปลงในภายหลัง

นอกจากนี้ยังมีองค์ประกอบทั่วไปที่ยาวที่สุดที่เกิดขึ้นเล็กน้อยเพื่อทิ้งองค์ประกอบบางส่วนไว้บนสแต็กเพื่อนำมาใช้ใหม่ในภายหลัง มันไม่ดีเท่าการทำซ้ำ แต่ให้การประหยัดที่เหมาะสม


ไชโยใครบางคนที่จะต่อสู้ :-) แน่นอนตอนนี้ฉันเห็นว่าฉันมีทางยาวไป ...
ETHproductions

5

JavaScript, 25158 23778

ตอนนี้รองรับ 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;
}

ผล:

432
949
2465
3996
1805
3551
5205
5375
Total: 23778

การเริ่มต้นที่ดีในความคิดของฉัน แต่เห็นได้ชัดว่ายังไม่เสร็จ แทนที่จะสร้างถ่านแต่ละตัวแยกกันมันจะเพิ่มหรือลบจากรหัสถ่านก่อนหน้านี้ ฉันจะเพิ่มคำอธิบายแบบเต็มเมื่อฉันทำเมตากอล์ฟเสร็จแล้ว


ใช่มันใช้งานได้แล้วใน Firefox แม้ว่า Chrome จะยังบ่นcharCodeAtอยู่
Martin Ender
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.