Brain-Flak Tamsayılı Golf


28

Tamsayılar Brain-Flak'ta temsil etmek için can sıkıcıdır . 8 operatör var:

()      Evaluates to 1, but does not push anything on any stack
[]      Evaluates to an indeterminate value for the purposes of this question
{}      Removes the top of the stack and evaluates to it
<>      Switches to or back from the alternate stack and evaluates to zero
(foo)   Pushes the value of the expression foo to the stack and evaluates to it
[foo]   Evaluates to the negation of foo
{foo}   Evaluates the expression foo until the top of the stack is zero
<foo>   Evaluates to zero but executes foo anyway

foobirden fazla operatörden oluşabilir, bu durumda değerlendirilir ve toplanır. Örneğin yığına (()())iter 2(ve aynı zamanda değerlendirir 2).

Açıkça görülüyor ki, bu (()...())mekanizma Code Golf'te büyük sayıların gösterilmesi n*2+2gereken baytlar için kullanışlı değil . Bu nedenle zorluğunuz, belirli bir pozitif tamsayıyı naktif yığına itecek bir Brain-Flak programını olabildiğince az byte çıkacak bir program veya işlev yazmaktır . Bu program yığınların mevcut içerikleri hakkında herhangi bir varsayımda bulunmamalıdır, bu nedenle yığınları değiş tokuş etmemeli veya yığınlara ekstra değerler eklememeli veya çıkarmamalıdır.

Programınız veya fonksiyonunuz, 1 ila 1,000,000 arasındaki tüm girişler için çalışan bir Brain-Flak programını geri getirebilmelidir, ancak kazanan, 1000 ile 1061 arasındaki tüm 1061 asal sayılar için en küçük uygun Brain-Flak programları setini üreten program veya işlev olacaktır. 10,000 . Gönderinizin bir parçası olarak bu 1061 giriş için çıktılarınızın toplam boyutunu not etmelisiniz. Programınız veya işleviniz tamsayıyı kabul edebilir ve (string) Brain-Flak programını her zamanki kabul edilebilir I / O formatlarından birinde verebilir. Programınızın veya işlevinizin boyutu kullanılarak bağlar kopacak.


4
Sadece bir not olarak: uzunlukta geçerli programların sayısı 2nise 4^n catalan(n).
Sızdıran Rahibe,

2
Hmm, mücadeleyi seviyorum, ama bilinmeyen tamsayılarda skorlanması gerektiğini düşünüyorum. Aksi halde, tamsayı programları puanlanırsa kaba zorlanabilir ve diğer tamsayılar olduğu gibi bırakılabilir (()()()...()). Ayrıca, yalnızca asal sayıları kullanırsanız, bu, kompozitler için olası bazı optimizasyonları kaçırabilir.
DJMcMayhem

Ayrıca, neden []bu zorluk için tanımsız? 8 operatörden 7'sinin uygulanmasını garip buluyorum. Her halükarda, zorlu meydan okuma, birinin kendi diliminden ilham alan bir meydan okuma yazmasından onur duyuyorum!
DJMcMayhem

2
@DJMcMayhem İnsanların kendi puanlarını hesaplayabilmelerini istiyorum. İlgili tüm asal sayılar, birleşik sayılardan bir tanesidir, bu nedenle çok fazla potansiyel optimizasyon yapılmalıdır. Ayrıca, insanların []cevaplarında belirli bir değere güvenmelerini istemiyorum .
Neil

1
@YetiCGN Komut dosyasının boyutu yalnızca bir bağlayıcı olarak sayılır.
Neil

Yanıtlar:


16

Python 2, 59394 59244 58534 58416 58394 58250

Tamam burada benim çözümüm.

import re
import math

cache = {0:"<()>"}

def find(x,i,j):
    return i*((x**2+x)/2)+(j+1)*((x**2-x)/2)

def solve(x, i, j):
    a = (i + j + 1)/2.
    b = (i - j - 1)/2.
    c = -x
    return (-b + math.sqrt(b**2 - 4*a*c))/(2*a)

def size(i,j=0):
    return 4*(i+j)+14

def polynomials(n):
    upperBound = int(4*math.log(n,2))
    i = 0
    answers = []
    while size(i) < upperBound:
        for j in range(i):
            sol = int(solve(n, i-j, j)+.5)
            if find(sol, i-j, j) == n:
                answers.append((sol, i-j, j))
        i += 1
    return answers

def complement(character):
        dict = {"(":")","{":"}","<":">","[":"]",")":"(","}":"{",">":"<","]":"["}
        return dict[character]

def findMatch(snippet, index):
        increment = 1 if snippet[index] in "({<[" else -1
        stack = []
        if snippet[index] in "(){}<>[]":
                stack.append(snippet[index])
        while len(stack) > 0 and index + increment < len(snippet):
                index += increment
                if snippet[index] in "(){}<>[]":
                        if complement(snippet[index]) == stack[-1]:
                                stack = stack[:-1]
                        else:
                                stack.append(snippet[index])
        return index

def isPrime(n):
    return not [0 for x in range(2,int(n**.5)+1) if n%x==0] and n>1

def getPrimeFactors(n):
    return [x for x in range(2,n/2) if n%x==0 and isPrime(x)]

def divHardcode(n,m):
    assert n%m == 0
    assert m != 1
    assert n != 1
    binary = bin(m)[3:]
    return (binary.count("1")+len(binary))*"("+getBF(n/m)+")"*binary.count("1")+binary.replace("1","){}{}").replace("0","){}")

def isTriangular(n):
    #Triangles must be between sqrt(2n) and cbrt(2n)
    if n < 0: return isTriangular(-n)
    for x in range(int((2*n)**(1/3.)),int((2*n)**.5)+1):
        if (x**2+x) == 2*n:
            return True
    return False

def getTriangle(n):
    if n < 0: return -getTriangle(-n)
    #Triangles must be between sqrt(2n) and cbrt(2n)
    for x in range(int((2*n)**(1/3.)),int((2*n)**.5)+1):
        if (x**2+x) == 2*n:
            return x
    #If we don't find one we made a mistake
    assert False

def getSimpleBF(n):
    if n in cache:return cache[n]
    if n < 0:
        # There is room for better solutions here
        return "["+getSimpleBF(-n)+"]"
    elif n == 0:
        return ""
    elif n < 6:
        return "()"*n
    #Non-edge cases
    solutions = []
    factors = getPrimeFactors(n)
    if n >= 78 and isTriangular(n):
        solutions.append(
           min([push(getTriangle(n))+"{({}[()])}{}","<"+push(getTriangle(n)+1)+">{({}[()])}{}"],key=len)
        )
    polynomialSolutions = polynomials(n)
    for polynomial in polynomialSolutions:
        solutions.append("<%s>{%s({}[()])%s}{}"%(push(polynomial[0]),"({})"*polynomial[1],"({})"*polynomial[2]))
        #Mod 3 tricks
    if n % 3 == 2:
       solutions.append(("((%s)()){}{}")%getBF(n/3))
    elif n % 3 == 1:
       solutions.append(("((%s)()()){}{}")%getBF(n/3-1))
    #Basic solutions
    if isPrime(n):
        solutions.append(getSimpleBF(n-1) + "()")
    else:
        #TODO multithread
        solutions += map(lambda m:divHardcode(n,m),factors)
    return min(solutions,key=lambda x:len(unpack(x)))

def getBF(n):
    if n in cache: return cache[n]
    result = getSimpleBF(n)
    index = n - 1
    while index > n-(len(result)/2):
        score = getSimpleBF(index)+getSimpleBF(n-index)
        if len(score) < len(result):result = score
        index -= 1
    index = n + 1
    while index < n+(len(result)/2):
        score = getSimpleBF(index)+getSimpleBF(n-index)
        if len(score) < len(result):result = score
        index += 1
    cache[n] = result
    return result

def unpack(string):
    reMatch = re.match("\(*<",string)
    if reMatch:
        location =reMatch.span()
        return string[location[1]:findMatch(string,location[1]-1)] +string[:location[1]-1] + string[findMatch(string,location[1]-1)+1:]
    return string

def push(n):
    return unpack("("+getBF(n)+")")

def kolmo(string):
    code = push(ord(string[-1]))
    stringVector = map(ord,string)
    for x,y in zip(stringVector[-1:0:-1],stringVector[-2::-1]):
        code = "("+code+getBF(y-x)+")"
    code = code.replace("<()>)",")")
    return code

def kolmo(stringVector):
    code = push(stringVector[-1])
    for x,y in zip(stringVector[-1:0:-1],stringVector[-2::-1]):
        code = "("+code+getBF(y-x)+")"
    code = code.replace("<()>)",")")
    return code


if __name__ == "__main__":
    import primes
    sum = 0
    for prime in primes.nums:
        print push(prime)
        sum += len(push(prime))
    print sum

İlgili fonksiyon push(n). Aramak için basitçe arayın, temsil etmek istediğiniz tamsayıya basın.

açıklama

Program tarafından yapılan temel optimizasyon çarpım sabit kodlamadır. Çarpım kodlaması fikri oldukça basittir. Bir numarayı bastırın ve ardından yeni bir değer oluşturmak için açılır ve bastırın. Örneğin, iki ile çarpmak için, aşağıdaki kodu ((n){}), n kodunun belirli bir sayı ürettiği yerde kullanabilirsiniz . Bu, hem çünkü eserleri (n)ve {}n değerine sahiptir.

Bu basit fikir daha büyük sayılar için daha karmaşık hale getirilebilir. Örnek 5'e bir süre önce, beş ile çarpmanın en iyi yolunun olduğu keşfedildi (((n)){}){}{}. Bu kod, n'lerin iki kopyasını birer birer 4 ile yapar ve ikisini de ekler. Aynı stratejiyi kullanarak her çarpımı bir sayının ikili gösterimini temel alarak yapıyorum. Şu an nasıl çalıştığının ayrıntılarına girmeyeceğim ama bunu ikili gösterimin ilkini keserek ve 0 ile ){}ve 1 ile değiştirerek yapıyorum.){}{}. Daha sonra n'nin uygun sayıda bastırıldığından emin olur ve tüm parantezleri dengeler. (Bunun nasıl yapıldığını bilmek istiyorsanız koduma bakabilirsiniz). Bunun neden işe yaradığını bilmek istiyorsanız sadece bir yorumda bana sorun. Kimsenin gönderideki tüm güncellemeleri okuduğunu sanmıyorum, bu yüzden açıklamayı bıraktım.

Algoritma çarpım hardcode bulmaya çalıştığında, tüm sayılar ana faktörlerini dener. Kompozit faktörleri yok sayar, çünkü bir noktada kompozit faktörler her zaman kendi asal faktörleri olarak daha net bir şekilde ifade edilebilirdi, bunun hala doğru olup olmadığı bilinmiyor.

Diğer bayt tasarruf mekanizması bir polinom çözüm bulucudur. Azalan döngülerle gösterilmesi kolay olan bazı polinom türleri vardır. Bu polinomlar, bunlarla sınırlı olmamak üzere, çokgen sayıları içerir. Bu optimizasyon forma uyan polinomları bulur ve bunları yapan kodu oluşturur.

Çıktı

yapıştırmak-bin


"n, n + 1'den daha büyük veya daha küçük mü"?
Sparr

@Sparr yorumlanmasından ndaha büyük veya küçük olsunn+1
Buğday Sihirbazı

Satırları if n % 3 == 2: bu fonksiyonun sonuna kadar bir seviye açmanız gerekir .
user202729

13

Brain-Flak, 64664

Çevrimiçi Deneyin!

İşte açıklamalı kodum

({}<
 ((((()()()()()){}){}){}()) #41
>)
{
 (({})[()()()()()()])
 ([({}<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){(<{}({}<>)>)}{}({}<>)
 {((< #IF
  {} 
  {({}[()]< #FOR
   ((((()()()()()){}){}){}()) #41
   (({})[()])                 #40
  >)}{}
 >))}{}
 (({}))
 #MOD2
 {(<
  ({}<(())>)({<({}[()]<>)><>(()[{}])<><({}<>)>}{}<({}<>)><>)<>({}<>)
  {((<{}({}< #IF
   {}
   (((()()()()())({})({})({}){})({})({})({}){})  #125
   (({})[()()])                                  #123
   ((((()()()()()){}){}){}())                    #41
   <>
   ((((()()()()()){}){}){})                      #40
   <>
   >)

  >))}{}{}
 >)}{}
 #MOD2 (number 2)
 (({}))
 ({}(())){({}[()]<>)<>(()[{}])<>({}<>)}{}
 (({})<([{}]{})>)
 {
  ({}[()]<<>
    ((((()()()()()){}){}){}) #40
    (({})())                 #41
   <>>)
 }{}
}{}
<>{({}<>)<>}<>((((()()()()()){}){}){})

açıklama

Bu sadece şu an için iki kural uygular:

  • N, iki dönüş ile bölünebilirse (n/2){}

  • Eğer n iki dönüş ile bölünemezse n-1()

Ayrıca 6'dan küçük tüm sayıları kodlar.


Bölünebilirlik kontrolü üçe göre bir kontrol gibi görünüyor, skoru biraz azaltmalı
ASCII-sadece

@ ASCII-sadece ben aslında onu uyguladım ve bayt sayısını arttırdı . Bölünebilirliğin daha akıllı bir versiyonunu üçe kadar uygulamak için çalışıyorum.
Buğday Sihirbazı,

Tamam, Brain-Flak sayılarını üreten bir program yapmak için Brain-Flak'ı kullanmak. Güzel.
Draco18,

10

Perl, 59222 59156 58460 karakter

  • n() (11322660 karakter)
  • (n){}() (64664 karakter)
  • ((n)){}{} (63610 karakter)
  • ((n)()){}{} (63484 karakter) - bu yeni bir hesaplamadır
  • (n){({}[()])}{} (60748 karakter)
  • n[m] (62800 karakter)
  • (n){m({}[l])}{} (58460 karakter) - bu yeni bir hesaplama

Bu son hesaplama için formül n(n/l+1)/2+mn/l. Bazı diğer hesaplamaları da denedim, ancak verilen çıktı için artık yararlı değiller. Program aslında 9999'a kadar tüm değerleri üretiyor, ancak verilen asal sayıları ve toplam uzunluklarını listeler.

@primes = (<list of the 4-digit prime numbers here>);
@numbers = ();
for ($i = 1; $i < 10000; $i++) {
  $numbers[$i] = "()" x $i; # default calculation
}
for ($i = 2; $i < 10000; $i++) {
  for ($j = 1; $j < 8; $j++) {
    &try($i, "$numbers[$i+$j]\[$numbers[$j]]");
  }
  &try($i + 1, "$numbers[$i]()");
  &try($i * 2, "($numbers[$i]){}");
  &try($i * 3, "(($numbers[$i])){}{}");
  &try($i * 3 + 2, "(($numbers[$i])()){}{}");
  for ($l = 1; $l * $l < $i; $l++) { 
    unless ($i % $l) { 
      for ($j = 0; ($k = (($i + $j + $j) * $i / $l + $i) / 2) < 10000; $j++) { 
        &try($k, "($numbers[$i]){$numbers[$j]({}[$numbers[$l]])}{}");
      } 
    } 
  } 
}
$len = 0;
foreach (@primes) {
  print "($numbers[$_])\n";
  $len += 2 + length $numbers[$_];
}
print "$len\n";
sub try {
  ($n, $s) = @_;
  $numbers[$n] = $s if (length($numbers[$n]) > length $s);
}

Çıktıya bir link verebilir misiniz?
DJMcMayhem

@DJMcMayhem Hata! Asal sayılarımı geçersiz kılmak için kazara prime listemi bozdum.
Neil

@Linus ((X) ()) {} {}, X iter, sonra 1 ekler, sonucu iter, sonra X + 1 ve X'i çıkar. Toplam 3X + 2. Sanırım Çevrimiçi Denemeye ilişkin diğer formülü denedim, ancak isterseniz iki kez kontrol edebilirim.
Neil

@ Neil Benim hatam ... Bunlar iyi görünüyor ama asıllarınızı tam olarak ne bozuyor?
Linus

1
@Neil Eklediğimde 58158 alıyorum &try($i * $i, "$numbers[$i]{({})({}[()])}{}");, bu da eklediğimde 58032'ye düşüyor &try((3 * $i * $i - $i) / 2, "$numbers[$i]{({})({}[()])({})}{}");(kare / beşgen sayılar) - buradan
sadece ASCII

5

Python, 59136 58676 karakterler

Brainflak numarası golf işlevi:

m=11111
R=range(0,m)
R[1]="()"
R[2]="()()"
l=2
def a(v,r):
 if v>0 and v<m:
  if isinstance(R[v],int) or len(r)<len(R[v]):
   R[v]=r
   if v<R[0]:
    R[0]=v
def s(v,k):
 S=0
 while v>0:
  S+=v
  v-=k
 return S
p=lambda r:"("+r+")"
w=lambda r:"{({}["+r+"])}{}"
def q(r,v):
 for i in range(1,v):
  r="("+r+")"
 for i in range(1,v):
  r+="{}"
 return r
def e(r,v,k):
 for i in range(0,k):
  r=q(r,v)
 return r
while l<m:
 R[0]=l+1
 a(l*2,q(R[l],2)) 
 a(l*3,q(R[l],3))
 a(l*5,q(R[l],5))
 a(l*7,q(R[l],7))
 for i in range(1,l):
  a(l+i,R[l]+R[i])
  a(l-i,R[l]+"["+R[i]+"]")
  if l%i==0:
   t=s(l-i,i)
   a(s(l,i),p(R[l])+w(R[i]))
   a(l+2*t,p(R[l])+q(w(R[i]),2))
   a(l+4*t,p(R[l])+e(w(R[i]),2,2))
   a(l+8*t,p(R[l])+e(w(R[i]),2,3))
   a(l+16*t,p(R[l])+e(w(R[i]),2,4))
   a(l+32*t,p(R[l])+e(w(R[i]),2,5))
   a(l+64*t,p(R[l])+e(w(R[i]),2,6))
   a(l+128*t,p(R[l])+e(w(R[i]),2,7))
   a(l+3*t,p(R[l])+q(w(R[i]),3))
   a(l+9*t,p(R[l])+e(w(R[i]),3,2))
   a(l+27*t,p(R[l])+e(w(R[i]),3,3))
   a(l+5*t,p(R[l])+q(w(R[i]),5))
   a(l+6*t,p(R[l])+q(q(w(R[i]),3),2))
   a(l+10*t,p(R[l])+q(q(w(R[i]),5),2))
   a(l+15*t,p(R[l])+q(q(w(R[i]),5),3))
   a(l+12*t,p(R[l])+q(q(q(w(R[i]),3),2),2))
   a(l+18*t,p(R[l])+q(q(q(w(R[i]),3),3),2))
   a(l+20*t,p(R[l])+q(q(q(w(R[i]),5),2),2))
   a(l+24*t,p(R[l])+q(q(q(q(w(R[i]),3),2),2),2))
   a(l+36*t,p(R[l])+q(q(q(q(w(R[i]),3),3),2),2))
   a(l+40*t,p(R[l])+q(q(q(q(w(R[i]),5),2),2),2))
 l=R[0]
f=lambda v:p(R[v])

Asal sayı yinelemesi:

def isPrime(v):
 i=2
 while i*i<=v:
  if v%i==0:
   return False
  i+=1
 return True

for i in range(1000,10000):
 if isPrime(i):
  print f(i)

Çıktı:

pastebin

Açıklama:

Bir liste önceden doldurmak R [1, gereken mesafe daha büyük bir fazla bireysel tamsayılar değerlendirilmesi Beyin kurşun geçirmez temsil m -1] Fonksiyonumuzu tanımlamak f . Temsilcilikler en düşük kullanılmayan temsili ( l ile indeksli ) alarak ve ondan en kısa tutarak birçok yeni temsiller oluşturarak oluşturulur. Düşük kullanılmayan temsil tüm sayı 1 varsayar l bir temsilini atanmış ve bu temsillerin zaten yeni numaralar üretmek için kullanılan edildiğini. L' den küçük bir değer daha kısa bir gösterime kavuşursa geri dönüp o noktadan başlayarak sayıları yeniden üretmeliyiz. İşlevi f parantez ekleyerek sayıyı yığına kaydeden bir program üretir.

Buna başladığımda hiçbir Brainflak bilmiyordum ve Eamon Olive'in üçgen sayı formülünü gösterdiği cevabını takdir ediyorum . Çoğunlukla, toplamı genelleştirdim ve toplamları ve farklılıkları kontrol etmekten nefret ediyorum. Çok sayıda toplamın eklenmesi çok etkili oldu.

İlgilenenler için, işte hangi formüllerin buna değdiğini görmek için kullandığım çizik kod .

Temsil Formülleri:

  1. Küçük asal sayılarla çarpma:
    (X){}
    ((X)){}{}
    ((((X)))){}{}{}{}
    ((((((X)))))){}{}{}{}{}{}
  2. Ek X + Y :
    XY
  3. Çıkarma X - Y :
    X[Y]
  4. Y artışının X'ini içeren ve X'in toplamı :
    (X){({}[Y])}{}
  5. İçin toplamları katları X artış arasında Y artı X :
    (X)({({}[Y])}{}){}
    (X)(({({}[Y])}{})){}{}
    (X)(({({}[Y])}{}){}){}
    vs ...

5'in yardımcı olmadığını düşündüm ama şimdi cevabımda 10 karakter kazandırdığını gördüm. Bu toplamları denediğimi sanıyordum ama iki kez kontrol edeceğim!
Neil

Artımların artı katları toplamı, beni bir 46 bayt daha kurtarıyor ve o zaman bile hepsini yakalamak için üç kez durulayıp tekrar etmem gerekiyor.
Neil

Çıkarma kullanırsam tekrar 5 * kullanmayacağımı söyler.
Neil

4

Lua 5.3, 57522

Aslında soru sorulduğunda bu konuda çalışmaya başladım, ancak Brain-Flak yıldönümüne kadar bunu unuttum.

-- 64 gives all results through 10000 (should run in about 1 second)
-- 78 gives all results through 100000 (should run in about 20 seconds)
-- 90 gives all results through 1000000 (should run in about 200 seconds)
-- Note: Timings may not be accurate, as the are not updated every time new cases are added.

local k_max_len = 64
local k_limit = 10000

local pre = os.clock()

local function compute_multiplier_helper(prefix, suffix, m)
  if m == 2 then
    prefix[#prefix + 1] = "("
    suffix[#suffix + 1] = "){}"
  elseif m % 2 == 0 then
    prefix[#prefix + 1] = "("
    compute_multiplier_helper(prefix, suffix, m // 2)
    suffix[#suffix + 1] = "){}"
  else
    suffix[#suffix + 1] = ")"
    compute_multiplier_helper(prefix, suffix, m - 1)
    prefix[#prefix + 1] = "("
    suffix[#suffix + 1] = "{}"
  end
end

local function compute_multiplier(m)
  local prefix = {}
  local suffix = {}
  compute_multiplier_helper(prefix, suffix, m)
  return table.concat(prefix), table.concat(suffix)
end

local multipliers = {}
for m = 2, k_limit do
  -- Including all factors, not just primes.
  -- This did improve a few numbers, although none in the ppcg test set.
  local prefix, suffix = compute_multiplier(m)
  local mult = {prefix = prefix, suffix = suffix, m = m, cost = #prefix + #suffix}
  table.insert(multipliers, mult)
end
table.sort(multipliers, function(a, b) return a.cost < b.cost end)

local poly_multipliers = {}
poly_multipliers[1] = {m = 1, s = "({})", l = 4}
for m = 2, k_limit do
  local prefix, suffix = compute_multiplier(m)
  local s = prefix .. "({})" .. suffix
  assert(#s <= 4 * m)
  poly_multipliers[m] = {m = m, s = s, l = #s}
end
poly_multipliers[k_limit + 1] = {m = 0, s = "", l = 0}

table.sort(poly_multipliers, function(a, b) return a.l < b.l end)

local pcache = {}
local plen_cache = {}

local function register_push(prefix, suffix, value, pvalue)
  if value > 1500000 or value < -1500000 then return end
  local old_res = pcache[value]
  if old_res == nil then
    local res = {prefix = prefix, suffix = suffix, value = value, pvalue = pvalue}
    pcache[value] = res
    local length = #prefix + #suffix
    local lcache = plen_cache[length]
    if lcache == nil then
      lcache = {}
      plen_cache[length] = lcache
    end
    lcache[#lcache + 1] = res
  end
end

local function get_pushes(length)
  return ipairs(plen_cache[length] or {})
end

register_push("", "()", 1, 0)
register_push("", "<()>", 0, 0)

local function triangle(n)
  return (n * (n + 1)) // 2
end

local function process(length)
  -- basic
  for _, res in get_pushes(length - 2) do
    register_push(res.prefix, res.suffix .. "()", res.value + 1, res.pvalue)
    register_push(res.prefix, "[" .. res.suffix .. "]", -res.value, res.pvalue)
  end

  -- multiplication by constant (precomputed)
  for _, mult in ipairs(multipliers) do
    local cost = mult.cost
    if length - cost >= 4 then
      local m, prefix, suffix = mult.m, mult.prefix, mult.suffix
      for _, pus in get_pushes(length - cost) do
        local name = prefix .. pus.suffix .. suffix
        register_push(pus.prefix, name, pus.value * m, pus.pvalue)
      end
    else
      break
    end
  end

  -- residue 2 mod3 trick (Neil)
  -- ((n)()){}{}
  --  (n)        -- push n
  -- (   ())     -- push n + 1
  --        {}{} -- (n + 1) + (n + 1) + n
  if length - 10 >= 2 then
    for _, res in get_pushes(length - 10) do
      local name = "((" .. res.suffix .. ")()){}{}"
      register_push(res.prefix, name, 3 * res.value + 2, res.pvalue)
    end
  end

  -- residue 1 mod3 trick (Wheat Wizard)
  -- ((n)()()){}{}
  --  (n)          -- push n
  -- (   ()())     -- push n + 2
  --          {}{} -- (n + 2) + (n + 2) + n
  -- not useful, but fast...
  if length - 12 >= 2 then
    for _, res in get_pushes(length - 12) do
      local name = "((" .. res.suffix .. ")()()){}{}"
      register_push(res.prefix, name, 3 * res.value + 4, res.pvalue)
    end
  end

  -- residue 2 mod5 trick (tehtmi)
  -- (((n)){}()){}{}
  --   (n)           -- push n
  --  (   )          -- push n
  -- (     {}())     -- push 2n + 1
  --            {}{} -- (2n + 1) + (2n + 1) + n
  -- [[
  if length - 14 >= 2 then
    for _, res in get_pushes(length - 14) do
      local name = "(((" .. res.suffix .. ")){}()){}{}"
      register_push(res.prefix, name, 5 * res.value + 2, res.pvalue)
    end
  end
  -- ]]

  -- residue 4 mod5 trick (tehtmi)
  -- (((n)()){}){}{}
  --   (n)           -- push n
  --  (   ())        -- push n + 1
  -- (       {})     -- push 2n + 2
  --            {}{} -- (2n + 2) + (2n + 2) + n
  -- [[
  if length - 14 >= 2 then
    for _, res in get_pushes(length - 14) do
      local name = "(((" .. res.suffix .. ")()){}){}{}"
      register_push(res.prefix, name, 5 * res.value + 4, res.pvalue)
    end
  end
  -- ]]

  -- residue 6 mod7 trick (tehtmi)
  -- ((((n)())){}{}){}{}
  --    (n)              -- push n
  --   (   ())           -- push n + 1
  --  (       )          -- push n + 1
  -- (         {}{})     -- push 3n + 3
  --                {}{} -- (3n + 3) + (3n + 3) + n
  -- [[
  if length - 18 >= 2 then
    for _, res in get_pushes(length - 18) do
      local name = "((((" .. res.suffix .. ")())){}{}){}{}"
      register_push(res.prefix, name, 7 * res.value + 6, res.pvalue)
    end
  end
  --]]

  -- residue 4 mod7 trick (tehtmi)
  -- ((((n))()){}{}){}{}
  --    (n)              -- push n
  --   (   )             -- push n
  --  (     ())          -- push n + 1
  -- (         {}{})     -- push 3n + 2
  --                {}{} -- (3n + 2) + (3n + 2) + n
  -- [[
  if length - 18 >= 2 then
    for _, res in get_pushes(length - 18) do
      local name = "((((" .. res.suffix .. "))()){}{}){}{}"
      register_push(res.prefix, name, 7 * res.value + 4, res.pvalue)
    end
  end
  --]]

  -- residue 2 mod7 trick (tehtmi)
  -- ((((n))){}{}()){}{}
  --    (n)              -- push n
  --   (   )             -- push n
  --  (     )            -- push n
  -- (       {}{}())     -- push 3n + 1
  --                {}{} -- (3n + 1) + (3n + 1) + n
  -- [[
  if length - 18 >= 2 then
    for _, res in get_pushes(length - 18) do
      local name = "((((" .. res.suffix .. "))){}{}()){}{}"
      register_push(res.prefix, name, 7 * res.value + 2, res.pvalue)
    end
  end
  --]]

  -- triangle numbers (?)
  --(n){({}[()])}{}
  --(n)              -- push n
  --   {        }    -- sum and repeat
  --    (      )     -- push
  --     {}[()]      -- top - 1
  --             {}  -- pop 0
  if length - 14 >= 2 then
    for _, res in get_pushes(length - 14) do
      if res.value > 0 then
        local code = "{({}[()])}{}"
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, triangle(res.value - 1), res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, triangle(res.value), res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, triangle(res.value) + res.pvalue, 0)
      end
    end
  end

  -- negative triangle numbers (tehtmi)
  --(n){({}())}{}
  --(n)            -- push n
  --   {      }    -- sum and repeat
  --    (    )     -- push
  --     {}()      -- top + 1
  --           {}  -- pop 0
  if length - 12 >= 2 then
    for _, res in get_pushes(length - 12) do
      if res.value < 0 then
        local code = "{({}())}{}"
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, -triangle(-res.value - 1), res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, -triangle(-res.value), res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, -triangle(-res.value) + res.pvalue, 0)
      end
    end
  end

  -- cubic (tehtmi)
  -- (n){(({}[()])){({}[()])}{}}{}
  -- (n^3-3*n^2+8*n-6)/6
  -- (-6 + n*(8 + n*(-3 + n)))/6
  --[[ superceded by negative cubic because 
       it is the same cost of -ncubic(-n)
  if length - 28 >= 2 then
    for _, res in get_pushes(length - 28) do
      if res.value > 0 then
        local code = "{(({}[()])){({}[()])}{}}{}"
        local v = res.value + 1
        v = (-6 + v*(8 + v*(-3 + v)))//6
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, v - res.value, res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, v, res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, v + res.pvalue, 0)
      end
    end
  end
  --]]

  -- negative cubic (tehtmi)
  -- (n){(({}())){({}())}{}}{}
  -- (n^3-3*n^2+8*n-6)/6
  -- (-6 + n*(8 + n*(-3 + n)))/6
  -- [[
  if length - 24 >= 2 then
    for _, res in get_pushes(length - 24) do
      if res.value < 0 then
        local code = "{(({}())){({}())}{}}{}"
        local v = -res.value + 1
        v = (-6 + v*(8 + v*(-3 + v)))//6
        v = -v
        register_push(res.prefix .. "(" .. res.suffix .. ")", code, v - res.value, res.pvalue + res.value)
        register_push(res.prefix, "(" .. res.suffix .. ")" .. code, v, res.pvalue)
        register_push("", res.prefix .. "(" .. res.suffix .. ")" .. code, v + res.pvalue, 0)
      end
    end
  end
  --]]

  -- polynomial (Wheat Wizard, modified by tehtmi)
  -- <(n)>{A({}[()])B}{} where A, B are ({})({})({})... repeated a, b times
  -- <(n)>                -- push n (without adding)
  --      {          }    -- repeat until top is zero
  --       A              -- top * a
  --        ({}[()])      -- top = top - 1; += top - 1
  --                B     -- (top - 1) * b
  --                  {}  -- pop 0
  -- triangular numbers are with a = b = 0
  -- from B and base:
  -- (n - 1) * (B + 1) * (n - 2) * (B + 1) * ...
  -- (B + 1) * (1 + ... + n - 1)
  -- (B + 1) * n * (n - 1) / 2
  -- from A:
  -- n * A + (n - 1) * A + ...
  -- A * (1 + ... n)
  -- A * (n + 1) * n / 2
  -- total: (B + 1) * n * (n - 1) / 2 + A * (n + 1) * n / 2
  --        [(A + B + 1) * n^2 + (A - B - 1) * n] / 2
  -- S := 4 * (A + B)
  -- [[
  if length - 18 >= 2 then
    for S = 4, length - 14, 4 do
      for _, res in get_pushes(length - 14 - S) do
        if res.value > 0 then
          for _, A in ipairs(poly_multipliers) do
            if A.l > S then
              break
            end
            for _, B in ipairs(poly_multipliers) do
              if A.l + B.l < S then
                -- continue
              elseif A.l + B.l > S then
                break
              else
                local a = A.m
                local b = B.m

                local logic = "{" .. A.s .. "({}[()])" .. B.s .. "}{}"
                local v = res.value
                v = ((a + b + 1) * v * v + (a - b - 1) * v) // 2
                register_push(res.prefix .. "(" .. res.suffix .. ")", logic, v, res.pvalue + res.value)
                register_push(res.prefix, "(" .. res.suffix .. ")" .. logic, v + res.value, res.pvalue)
                register_push("", res.prefix .. "(" .. res.suffix .. ")" .. logic, v + res.value + res.pvalue, 0)
              end
            end
          end
        end
      end
    end
  end
  --]]

  -- negative polynomial (tehtmi)
  -- <(n)>{A({}())B}{}
  -- [[
  if length - 16 >= 2 then
    for S = 4, length - 12, 4 do
      for _, res in get_pushes(length - 12 - S) do
        if res.value < 0 then
          for _, A in ipairs(poly_multipliers) do
            if A.l > S then
              break
            end
            for _, B in ipairs(poly_multipliers) do
              if A.l + B.l < S then
                -- continue
              elseif A.l + B.l > S then
                break
              else
                local a = A.m
                local b = B.m

                local logic = "{" .. A.s .. "({}())" .. B.s .. "}{}"
                local v = -res.value
                v = ((a + b + 1) * v * v + (a - b - 1) * v) // -2

                register_push(res.prefix .. "(" .. res.suffix .. ")", logic, v, res.pvalue + res.value)
                register_push(res.prefix, "(" .. res.suffix .. ")" .. logic, v + res.value, res.pvalue)
                register_push("", res.prefix .. "(" .. res.suffix .. ")" .. logic, v + res.value + res.pvalue, 0)
              end
            end
          end
        end
      end
    end
  end
  --]]

  -- addition
  -- [[
  if length >= 4 then
    for part1 = 4, length // 2, 2 do
      for _, res1 in get_pushes(part1) do
        for _, res2 in get_pushes(length - part1) do
          register_push(res2.prefix .. res1.prefix, res1.suffix .. res2.suffix, res1.value + res2.value, res1.pvalue + res2.pvalue)
        end
      end
    end
  end
  --]]

  -- pseudo-exponentiation (tehtmi)
  -- (n)<>(m){({}[()])<>(({}){})<>}{}<>{}
  -- (n)<>(m)                             -- push n and m on opposite stacks
  --         {                    }       -- sum and repeat
  --          ({}[()])                    -- top(m) - 1
  --                  <>(({}){})<>        -- n = 2*n; += n
  --                               {}     -- pop 0
  --                                 <>   -- swap to result
  --                                   {} -- pop and add n
  -- [[
  if length - 34 >= 4 then
    local subl = length - 34
    for part1 = 2, subl - 2, 2 do
      for _, res2 in get_pushes(part1) do
        local b = res2.value
        if b > 0 and b < 55 then -- overflow could be a problem, so bound...
          for _, res1 in get_pushes(subl - part1) do
            -- 2n + 4n + 8n + ... + (2^m)*n + 2^m * n
            -- n( 2 + 4 + 8 + .. 2^m + 2^m)
            -- n( 3 * 2^m - 2 )
            local a = res1.value
            local body = "(" .. res1.suffix .. ")<>" .. res2.prefix .. "(" .. res2.suffix .. "){({}[()])<>(({}){})<>}{}<>{}"
            local v = a * (3 * (1 << b) - 2) + b * (b - 1) // 2 + a + b + res2.pvalue
            register_push(res1.prefix, body, v, res1.pvalue)
            register_push("", res1.prefix .. body, v + res1.pvalue, 0)
          end
        end
      end
    end
  end
  --]]
end

--print(os.clock(), "seconds (startup)")

local start = os.clock()
for i = 2, k_max_len - 2, 2 do
  --print(i)
  process(i)
end

plen_cache = nil

local final = {}
for i = 1, k_limit do
  if pcache[i] ~= nil then
    final[i] = pcache[i].prefix .. "(" .. pcache[i].suffix .. ")"
  end
end

pcache = nil

-- hard coded to 10000 for ppcg test
local sieve = {}
for i = 1, 10000 do sieve[i] = true end
for i = 2, 10000 do
  for j = i * i, 10000, i do
    sieve[j] = false
  end
end

--print(os.clock() - start, "seconds (calculation)")

--local bf = require("execute2")

local count = 0
local sum = 0
local sum2 = 0
local maxlen = 0
local pcount = 0
for i = 1, k_limit do
  local res = final[i]
  final[i] = nil
  --print(i, #res, res)
  --local ev = res and bf.eval1(bf.compile(res)) or -1; assert( res == nil or ev == i, string.format("Failed %d %s %d", i, res or "", ev))
  if sieve[i] and i > 1000 then
    sum = #res + sum
    pcount = pcount + 1
  end
  if res then
    sum2 = #res + sum2
    maxlen = math.max(maxlen, #res)
    count = count + 1
  end
end
print("sum", sum)
--print("coverage", count / k_limit, "missing", k_limit - count)
--print("sum2", sum2)
--print("maxlen", maxlen)
assert(pcount == 1061)

Bilinen yararlı işlevlerin daha basit sayıları iyi temsil etmekten daha büyük sayılar oluşturmak için kullanıldığı diğer cevaplara benzer bir fikir.

Bir fark, alt sayıları daha küçük sayılar olarak çözmek yerine, kısa sayıları temsil eden sayılar açısından alt sorunları çözüyorum. Bunun, negatif sayılardan faydalanmanın yanı sıra daha küçük sayılarla daha büyük sayılarla temsil edildiği durumu ele almanın daha zarif olduğunu düşünüyorum.

Ayrıca, belirli bir boyutta temsil edilebilecek tüm sayıları bulmaya çalışmak, belirli bir sayıyı mümkün olan en kısa sürede göstermeye çalışmak, aslında belirli hesaplamaları basitleştirir. Bir sayıya uygulanıp uygulanamayacağını görmek için bir formülü tersine çalışmak yerine, formül ileriye doğru çalışabilir ve her numaraya uygulanabilir.

Diğer bir fark, bilinen çözümlerin iki parça halinde depolanmasıdır - bir (isteğe bağlı) "önek" ve "sonek" (daha fazlası gibi). Verilen sayıyı hesaplarken önek değerinin göz ardı edilmesi beklenir - önek sadece çalıştırılacak son eki ayarlayan kodu içerir (genellikle yığına bir veya daha fazla şey iterek). Böylece, bir önek ve bir sonek verildiğinde, karşılık gelen sayı istifin üzerine itilebilir prefix(suffix).

Bu bölünme temel olarak, unpackBuğday Sihirbazı'nın cevabındaki fonksiyonla aynı problemi çözer . Kodu <...>daha sonra geri almak için yalnızca kodla değiştirmek yerine , bu kod basitçe ön eke eklenir.

Bazı durumlarda, önek aslında değerlendirilir (esas olarak sahte üstelleştirme işlemi için), bu nedenle de değeri kaydedilir. Ancak, jeneratör belirli sayılar oluşturmaya çalışmadığından, bu gerçekten büyük bir soruna neden olmaz. Teorik olarak, farklı önek değerlerine sahip olması nedeniyle önbellekte gereksiz olmayacak aynı uzunlukta iki kod parçası olabileceği ve aynı sayıyı üretebileceği anlaşılmaktadır. Bunun için muhasebe zahmetine girmedim, çünkü pek de önemli değil (en azından bu alanda).

Sadece daha fazla vaka ekleyerek bayt sayımını azaltmanın kolay olacağını hayal ediyorum, ama şu an için yeterli zamanım oldu.

1000000’e koştum, ancak yalnızca 100000’e kadar kontrol sağladı.

Verilen primerlerde pastebin çıktısı.


Ne yap k_limitve k_max_lenyap? Başlığı anladığımdan emin değilim.
Wheat Wizard

1
Belirli sayıları hesaplamaya çalışmak yerine, tüm yararlı programları (yani, bulunan diğer programlardan daha kısa olmayan sayıları vererek) programları belirli bir uzunluğa kadar hesaplıyorum - k_max_len. Her uzunluğu işledikten sonra istediğiniz tüm sayıları bulduğunu kolayca kontrol edebilirdi, ancak test sırasında maksimum uzunluğu sınırlayabilmem faydalı oldu, böylece program daha hızlı çalışabildi. (Daha büyük uzunlukları işlemek çok yavaş olabilir.) k_limitTemelde girdi parametresidir - buna kadar sayılar için programlar çıkarır - varsayımı k_max_lenonları bulabilecek kadar büyük olur.
tehtmi

4

yakut, 60246 bayt

$brain_flak = Hash.new{|h, k|
    a = []
    a.push "()"*k
    if k > 1
        if k > 10
            # Triangle Numbers:
            n = (Math.sqrt(1+8*k).to_i-1)/2
            if (n*n+n)/2 == k
                a.push "("+h[n]+"){({}[()])}{}" 
                a.push  h[n+n]+")({({}[()])}{}"
            end
        end
        (k**0.51).to_i.downto(2){|i|
            # multiplication:
            if k%i==0
                a.push "("*(i-1) + h[k/i] + ")"*(i-1)+"{}"*(i-1)

            end
        }
        (k/2).downto(1){|i|
            # Addition
            a.push h[k-i] + h[i]
        }
    end

    h[k] = a.min_by{|x|x.length}
}
$brain_flak[0] = "<><>"

def get_code_for (i)
  "(#{$brain_flak[i]})"
end

Bir karma kullanırım. Belirli bir sayı için en iyi golfü buluyorum ve daha küçüklerini daha büyüklerini bulmak için kullanıyor.

Özyinelemeli karmaları çok eğlenceli!


2

Python, 64014 karakter

Bu meydan okumadan önce brainflak hakkında hiçbir şey bilmiyordum ve sadece biraz tryitonline ile uğraşıyordum, bu yüzden özlediğim kısa yollar olabilir. Bu oldukça sıkıcı bir çözümdür, girişi x=x/2+x%2ya da x=x/3+x%3hangisine daha kısa olursa oraya yayar.

k=lambda x:"(("+o(x/3)+")){}{}"+(x%3)*"()"if x>3else"()"*x
m=lambda x:"("+o(x/2)+"){}"+(x%2)*"()"if x>6else"()"*x
o=lambda x:min(k(x),m(x),key=len)
b=lambda x:"("+o(x)+")"

Öyle diyoruz: b(42)

pastebin çıktı


1

Lua, 64664 bayt

Program, programların toplam uzunluğunu ve 203.

Şimdilik tek optimizasyon x = 2 * n + 1

Umarım puanı düşürmek için daha fazla optimizasyon eklemek için zamanım olur.

local primeS = [[<INSERT PRIMES HERE>]]

local primes = {}

for num in primeS:gmatch("%d+") do
    table.insert(primes, num+0)
end

local progs = {}
progs[0] = ""
progs[1] = "()"
progs[2] = "()()"

local function half(n)
    if progs[n] then return progs[n] end
    local p = ""
    local div = math.floor(n/2)
    local rem = n%2 == 1 and "()" or ""
    return "("..progs[div].."){}"..rem
end

for i = 3, 10000 do

    local bin = half(i)

    progs[i] = progs[i-1] .. "()"

    if #bin < #progs[i] then
        progs[i] = bin
    end

    if i % 1000 == 0 then
        print(i)
    end

end

local n = 203 -- This is the program it outputs
print(n..", ("..progs[203]..")")

local len = 0
for i,v in ipairs(primes) do
    len = len + #progs[v] + 2
    --print(v.." ("..progs[v]..")\n")
end
print("Total len: "..len)
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.