Yıldızlı Metagolf


25

Starry , kodun yalnızca +*.,`'bu karakterlerin her biri tarafından temsil edilen asıl komutun önündeki boşlukların sayısı tarafından belirlendiği yerlerden oluştuğu komik bir ezoterik programlama dilidir . Bu, sabit çıktı zorluklarını golf oynamak için bile zorlaştırır, çünkü farklı komutlar çok farklı sayıda bayt için hesap verebilir. Özellikle, sayı hazırlayıcıları, daha küçük sayılar üzerinde çalışarak daha büyük sayılar oluşturmayı gerekli kılan tek bir temsilidir.

Bu nedenle, bu zorluk, bu tür Yıldızlı programları golf edebilecek bir program yazmakla ilgilidir.

Starry nasıl çalışır?

(Bazı detaylar, esolangçlarda belirtilmemiş olarak bırakılıyor, bu yüzden Ruby tercümanının davranışına gidiyorum .)

Starry, tek bir isteğe bağlı tamsayı değerleri (başlangıçta boş olan) içeren bir yığın tabanlı dildir.

Tek anlamlı karakterler:

+*.,`'

ve boşluklar. Diğer tüm karakterler göz ardı edilir. Boşluk olmayan karakterlerden birinin izlediği her boşluk sırası, tek bir talimatı temsil eder. Öğretim tipi boşluk olmayan karaktere ve boşluk sayısına bağlıdır.

Talimatlar:

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. 

Tercümanın, yürütme başlamadan önce etiketlerin kaynak kodunu taradığını unutmayın, bu nedenle geriye ve geriye doğru atlamak mümkündür.

Elbette, Starry'nin de giriş komutları vardır ( ,benzer şekilde kullanılır .), ancak bunlar bu zorluk için anlamsızdır.

Meydan okuma

Bir dize verildiğinde, girdi almayan ve bu dizeyi tam olarak STDOUT'a basan bir Starry programı oluşturun.

STDIN (veya en yakın alternatif), komut satırı argümanı veya işlev argümanı yoluyla giriş alarak ve sonucu STDOUT (veya en yakın alternatif), fonksiyon dönüş değeri veya function (out) parametresi ile çıktı alarak bir program veya işlev yazabilirsiniz.

Dizenin 128 karakterden uzun olmadığını ve yalnızca yazdırılabilir ASCII karakterlerinden oluşacağını varsayabilirsiniz (kod noktaları 0x20 - 0x7E).

Çözümünüz makul bir masaüstü bilgisayarında bu tür girişleri 5 dakikadan daha az bir sürede işlemelidir (buna biraz yer var; dizüstü bilgisayarımda birkaç dakika daha fazla sürerse sorun çıkarmaz, ancak 15 sürerse diskalifiye edeceğim o).

Çözümünüz, aşağıda listelenen bir dizi farklı dizi üzerinde test edilecektir. Puanınız, karşılık gelen Yıldızlı programların toplam bayt sayısıdır. Beraberlik durumunda, en kısa metagolfer kazanır. Diğer bir deyişle, bir beraberlik olmadıkça kendi kodunuzu silmekten çekinmeyin (bence sadece optimal bir çözümün mümkün olması durumunda gerçekleşir).

Kodunuzu aşağıda listelenen belirli test durumlarına göre optimize etmemelisiniz. Özellikle, onlar için el yapımı çözümler kod yazmamalısınız. Yapısı verilen karakter dizisine benzer karakter dizileri sınıfına göre optimizasyon iyidir. Kodlama çözümlerinden herhangi birinin şüphesini alırsam, test durumlarının bazılarını veya tümünü değiştirme hakkını saklı tutarım (karşılaştırılabilir yapıların dizeleriyle).

Test Kılıfları

Her satır ayrı bir test durumudur:

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

İkinci test senaryosu için kredi Dennis'e gidiyor . Dördüncü test vakası için kredi Sp3000'e gitti.

Referans çözümü

İşte CJam'da gerçekten temel bir referans çözümü:

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

Burada tüm test odasına karşı koşabilirsiniz. Puanlar:

1233
5240
4223
11110
7735
10497
11524
11392
Total: 62954

Mümkün olan en basit yaklaşım budur: her karakterin kod noktasını değişmez olarak itin ve yazdırın. Ardışık karakterler, tamsayı baskı, dizenin tekrarlayan kısımları vb. Arasındaki küçük farkları kullanmaz. Bunları size bırakacağım.

Gelişme için çok yer olduğuna inanıyorum. Başvuru için, el yapımı en kısa "Merhaba, Dünya!" sadece 169 byte uzunluğunda.

Yanıtlar:


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}

Yöntem starryverilen soruyu cevaplar.

Sonuçlar:

230
639
682
1974
1024
1897
2115
2436
Total: 10997

Nasıl çalışır

shortestana algoritmadır. Bir sayı alır ve yığına yerleştirmenin en kısa yolunu bulur ya da iki sayı alır ve ikincisinin zaten açık olduğunu varsayarak ikinci sıraya koymak için kodu döndürür. $sdaha fazla kullanım için bu işlemlerin sonuçlarını tutmak için bir Hash.

starrybir dize alır ve onu bir dizi karakter koduna (veya özetler için) böler. Kodu istifin altında bir numara ile başlatır. Daha sonra, art arda gelen her sayıyı üretebilecek en kısa yolu hesaplar, muhtemelen sonuncuyu kopyalar veya başlangıçta yığına yerleştirilen sayıyı kullanır.


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)

İlgili fonksiyon uygun olarak adlandırılmıştır metagolf.

Sonuçlar:

210
676
684
2007
1463
2071
2204
2530
Total: 11845

Çıktının tamamını burada bulabilirsiniz .

Kısa açıklama

Açıklanacak bilgileri kısaca açıklayacağım çünkü hâlâ geliştirilecek çok şey var.

Temel algoritma sadece karakter çiftlerine bakar ve BFS üzerinden bir karakterden diğerine geçiş yapmanın en uygun yolunu bulur. Rakamlar şu anda derhal itilip yazdırılıyor, ancak daha sonra değişecek.

Ayrıca, daha sonra tekrar kullanmak üzere yığında birkaç element bırakması için, en uzun süren ortak ardışıklık devam ediyor. Tekrarlama kadar iyi değildir, ancak iyi tasarruf sağlar.


Yaşasın, Tabii savaş :-) birisi, şimdi benim bir olduğunu görüyoruz uzun ... gitmeye yol
ETHproductions

5

JavaScript, 25158 23778

Şimdi ES5 uyumlu!

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

Sonuçlar:

432
949
2465
3996
1805
3551
5205
5375
Total: 23778

Bence iyi bir başlangıç, ama belli ki bitmedi. Her bir karakteri ayrı ayrı oluşturmak yerine, önceki karakter kodundan ekler veya çıkarır. Meta-golf bittiğinde tam bir açıklama ekleyeceğim.


Evet, Firefox'ta çalışıyor, ancak Chrome hala şikayet ediyor charCodeAt.
Martin Ender
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.