Golf một Integer Brain-Flak


28

Số nguyên là tẻ nhạt để đại diện trong Brain-Flak . Có 8 nhà khai thác:

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

foocó thể bao gồm nhiều toán tử, trong trường hợp chúng được đánh giá và tổng hợp. Ví dụ (()())đẩy 2vào ngăn xếp (và ước tính 2quá).

Rõ ràng, (()...())cơ chế này không hữu ích trong Code Golf vì số lượng lớn sẽ lấy n*2+2byte để biểu diễn. Do đó, thách thức của bạn là viết một chương trình hoặc hàm sẽ xuất ra càng ít byte càng tốt một chương trình Brain-Flak sẽ đẩy một số nguyên dương đã ncho vào ngăn xếp hoạt động. Chương trình này không được đưa ra bất kỳ giả định nào về nội dung hiện có của ngăn xếp, vì vậy nó không được để các ngăn xếp được trao đổi hoặc thêm hoặc xóa các giá trị bổ sung khỏi ngăn xếp.

Mặc dù chương trình hoặc chức năng của bạn phải có khả năng trả lại chương trình Brain-Flak đang hoạt động cho tất cả các đầu vào từ 1 đến 1.000.000, người chiến thắng sẽ là chương trình hoặc chức năng tạo ra một bộ chương trình Brain-Flak phù hợp nhỏ nhất cho tất cả 1061 số nguyên tố từ 1.000 đến 10.000 . Bạn nên lưu ý tổng kích thước đầu ra của bạn cho 1061 đầu vào đó như là một phần của bài nộp của bạn. Chương trình hoặc hàm của bạn có thể chấp nhận số nguyên và trả về chương trình Brain-Flak (chuỗi) ở bất kỳ định dạng I / O thông thường nào được chấp nhận. Ties sẽ bị phá vỡ bằng cách sử dụng kích thước của chương trình hoặc chức năng của bạn.


4
Cũng như một lưu ý: số lượng chương trình hợp lệ có độ dài 2n4^n catalan(n).
Leaky Nun

2
Hmm, tôi thích thử thách, nhưng tôi nghĩ nó nên được ghi vào các số nguyên chưa biết. Mặt khác, các chương trình số nguyên được tính điểm có thể bị ép buộc và các số nguyên khác chỉ còn lại là (()()()...()). Ngoài ra, nếu bạn chỉ sử dụng số nguyên tố, điều đó có thể bỏ lỡ một số tối ưu hóa có thể có cho vật liệu tổng hợp.
DJMcMayhem

Ngoài ra, tại sao []không xác định cho thử thách này? Tôi thấy lạ khi thực hiện 7 trong số 8 toán tử. Dù bằng cách nào, thử thách thú vị, tôi rất vinh dự ai đó sẽ viết một thử thách lấy cảm hứng từ ngôn ngữ của chính tôi!
DJMcMayhem

2
@DJMcMayhem Tôi muốn mọi người có thể tính điểm của riêng họ. Tất cả các số nguyên tố có liên quan đều nhiều hơn một số tổng hợp, do đó cần có nhiều tối ưu hóa tiềm năng. Ngoài ra, tôi không muốn mọi người dựa vào một giá trị cụ thể []trong câu trả lời của họ.
Neil

1
@YetiCGN Kích thước của tập lệnh chỉ được tính là một bộ ngắt kết nối.
Neil

Câu trả lời:


16

Trăn 2, 59394 59244 58534 58416 58394 58250

Ok đây là giải pháp của tôi.

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

Các chức năng có liên quan là push(n). Để gọi nó chỉ đơn giản là gọi đẩy vào số nguyên bạn muốn đại diện.

Giải trình

Tối ưu hóa chính được thực hiện bởi chương trình là nhân mã hóa cứng. Ý tưởng về mã hóa nhân là khá đơn giản. Bạn đẩy một số và sau đó bật và đẩy nó để tạo ra một giá trị mới. Ví dụ để nhân hai số, bạn có thể sử dụng mã sau ((n){})trong đó mã n tạo ra một số cụ thể. Điều này hoạt động vì cả hai (n){}có giá trị n.

Ý tưởng đơn giản này có thể được thực hiện phức tạp hơn cho số lượng lớn hơn. Lấy ví dụ 5 người ta đã phát hiện ra cách đây một thời gian rằng cách tốt nhất để nhân với năm là (((n)){}){}{}. Mã này làm cho hai bản sao của n nhân một với 4 và cộng hai. Sử dụng cùng một chiến lược tôi thực hiện mọi phép nhân dựa trên biểu diễn nhị phân của một số. Tôi sẽ không đi vào chi tiết về cách thức hoạt động của nó ngay bây giờ nhưng tôi làm điều này bằng cách cắt bỏ phần đầu tiên của biểu diễn nhị phân và thay thế 0 bằng ){}và 1 bằng){}{}. Sau đó, đảm bảo rằng n được đẩy số lần thích hợp và cân bằng tất cả các dấu ngoặc đơn. (Nếu bạn muốn biết làm thế nào được thực hiện, bạn có thể xem mã của tôi). Nếu bạn muốn biết lý do tại sao điều này hoạt động chỉ cần hỏi tôi trong một bình luận. Tôi không nghĩ bất cứ ai thực sự đọc tất cả các cập nhật cho bài viết của tôi vì vậy tôi đã để lại lời giải thích.

Khi thuật toán cố gắng tìm một mã cứng nhân, nó sẽ thử tất cả các thừa số nguyên tố. Nó bỏ qua các yếu tố tổng hợp bởi vì tại một thời điểm, các yếu tố tổng hợp luôn có thể được biểu thị chính xác hơn vì các yếu tố chính của nó không được biết nếu điều này vẫn đúng.

Cơ chế tiết kiệm byte khác là một công cụ tìm giải pháp đa thức. Có một số dạng đa thức nhất định dễ biểu diễn với các vòng lặp giảm dần. Các đa thức này bao gồm, nhưng không giới hạn ở các số đa giác. Tối ưu hóa này tìm các đa thức phù hợp với biểu mẫu và tạo mã tạo ra chúng.

Đầu ra

thùng dán


"Liệu n lớn hơn hay nhỏ hơn n + 1" ??
Sparr

@Sparr cho dù cách giải thích nlớn hơn hay nhỏ hơnn+1
Wheat Wizard

Bạn nên bỏ các dòng từ if n % 3 == 2: đến cuối của hàm đó theo một cấp.
dùng202729

13

Brain-Flak, 64664

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

Đây là mã chú thích của tôi

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

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

Giải trình

Điều này chỉ thực hiện hai quy tắc như bây giờ:

  • Nếu n chia hết cho hai lần trả về (n/2){}

  • Nếu n không chia hết cho hai trả về n-1()

Nó cũng mã hóa tất cả các số nhỏ hơn 6.


Có vẻ như kiểm tra tính phân chia của ba nên giảm số điểm xuống một chút
ASCII - chỉ

@ ASCII - chỉ tôi thực sự triển khai nó và nó đã tăng số byte. Tôi đang nghiên cứu một cách để thực hiện một phiên bản thông minh hơn cho phép chia ba.
Thuật sĩ lúa mì

Ok, sử dụng Brain-Flak để tạo chương trình tạo số Brain-Frak. Tốt đẹp.
Draco18

10

Perl, 592222 59156 58460 ký tự

  • n() (11322660 ký tự)
  • (n){}() (64664 ký tự)
  • ((n)){}{} (63610 ký tự)
  • ((n)()){}{} (63484 ký tự) - đây là một phép tính mới
  • (n){({}[()])}{} (60748 ký tự)
  • n[m] (62800 ký tự)
  • (n){m({}[l])}{} (58460 ký tự) - đây là một tính toán mới

Công thức tính toán cuối cùng đó là n(n/l+1)/2+mn/l. Tôi đã thử một số tính toán khác nhưng chúng không còn hữu ích cho đầu ra đã cho. Chương trình thực sự tạo ra tất cả các giá trị lên tới 9999 nhưng sau đó liệt kê các số nguyên tố đã cho và tổng chiều dài của chúng.

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

Bạn có thể cung cấp một liên kết đến đầu ra?
DJMcMayhem

@DJMcMayhem Rất tiếc, tôi đã vô tình làm hỏng danh sách các số nguyên tố của mình, làm mất hiệu lực số lượng nhân vật của tôi.
Neil

@Linus ((X) ()) {} {} đẩy X, sau đó thêm 1, đẩy kết quả, sau đó bật X + 1 và X. Tổng 3X + 2. Tôi nghĩ rằng tôi đã thử công thức khác trên Dùng thử trực tuyến nhưng tôi có thể kiểm tra lại nếu bạn thích.
Neil

@Neil Sai lầm của tôi ... Những thứ này có vẻ tốt nhưng chính xác thì điều gì làm hỏng số nguyên tố của bạn?
Linus

1
@Neil Tôi nhận được 58158 khi tôi thêm &try($i * $i, "$numbers[$i]{({})({}[()])}{}");, giảm xuống còn 58032 khi tôi cũng thêm &try((3 * $i * $i - $i) / 2, "$numbers[$i]{({})({}[()])({})}{}");(số vuông / ngũ giác) - đó là từ đây
ASCII - chỉ

5

Python, 59136 58676 ký tự

Chức năng chơi gôn số Brainflak:

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

Số nguyên tố lặp:

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)

Đầu ra:

Quá khứ

Giải trình:

Chúng tôi điền trước một danh sách R biểu diễn Brain-flak đánh giá cho các số nguyên riêng lẻ trong phạm vi lớn hơn mức cần thiết [1, m -1] để xác định hàm f của chúng tôi . Các đại diện được hình thành bằng cách lấy đại diện không sử dụng thấp nhất (được lập chỉ mục bởi l ) và hình thành nhiều đại diện mới từ nó, chỉ giữ lại ngắn nhất. Đại diện không sử dụng thấp nhất giả định rằng tất cả các số từ 1 đến l đã được chỉ định một đại diện và các đại diện này đã được sử dụng để tạo ra các số mới. Nếu một giá trị nhỏ hơn l có đại diện ngắn hơn, chúng ta phải quay lại và sao chép số bắt đầu từ điểm đó. Hàm f tạo ra một chương trình lưu số vào ngăn xếp bằng cách thêm dấu ngoặc đơn.

Tôi không biết bất kỳ Brainflak nào khi tôi bắt đầu điều này và đánh giá rất cao câu trả lời của Eamon Olive vì đã chỉ ra công thức cho các số tam giác. Chủ yếu là tôi đã khái quát tổng kết và không ngừng kiểm tra các khoản tiền và sự khác biệt. Thêm nhiều bội số đã có hiệu quả tuyệt vời.

Đối với những người quan tâm, đây là mã cào tôi đã sử dụng để xem công thức nào đáng giá.

Công thức đại diện:

  1. Nhân với số nguyên tố nhỏ:
    (X){}
    ((X)){}{}
    ((((X)))){}{}{}{}
    ((((((X)))))){}{}{}{}{}{}
  2. Bổ sung X + Y :
    XY
  3. Phép trừ X - Y :
    X[Y]
  4. Tổng kết và bao gồm X của gia số Y :
    (X){({}[Y])}{}
  5. Bội số của tổng cộng đến X của Y tăng , cộng với X :
    (X)({({}[Y])}{}){}
    (X)(({({}[Y])}{})){}{}
    (X)(({({}[Y])}{}){}){}
    vv ...

Tôi nghĩ 5 * không hữu ích, nhưng bây giờ tôi thấy nó tiết kiệm được 10 ký tự cho câu trả lời của tôi. Tôi nghĩ tôi đã thử những tổng kết đó, nhưng tôi sẽ kiểm tra lại!
Neil

Tổng các số gia cộng với bội số giúp tôi tiết kiệm thêm 46 byte và thậm chí sau đó tôi phải rửa và lặp lại ba lần để bắt tất cả.
Neil

Hóa ra nếu tôi sử dụng phép trừ thì tôi không sử dụng lại 5 *.
Neil

4

Lua 5.3, 57522

Tôi thực sự bắt đầu làm việc trên lưng này khi câu hỏi được đăng, nhưng quên nó cho đến ngày kỷ niệm Brain-Flak.

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

Ý tưởng tương tự với các câu trả lời khác trong đó các hàm hữu ích đã biết được sử dụng để xây dựng các số lớn hơn từ các biểu diễn tốt của các số đơn giản hơn.

Một điểm khác biệt là thay vì giải các bài toán con về các số nhỏ hơn, tôi đang giải các bài toán con về các số có biểu diễn ngắn hơn. Tôi nghĩ rằng điều này làm cho nó thanh lịch hơn để tận dụng các số âm cũng như xử lý trường hợp các số nhỏ hơn được biểu diễn dưới dạng số lớn hơn.

Ngoài ra, cố gắng tìm tất cả các số có thể được biểu diễn ở một kích thước nhất định thay vì cố gắng đại diện cho một số cụ thể càng sớm càng tốt thực sự đơn giản hóa các tính toán nhất định. Thay vì làm việc một công thức ngược lại để xem liệu nó có thể được áp dụng cho một số hay không, công thức có thể được làm việc chuyển tiếp và áp dụng cho mọi số.

Một sự khác biệt khác là các giải pháp đã biết được lưu trữ thành hai phần - một "tiền tố" (tùy chọn) và "hậu tố" (giống như một phần tử). Việc định giá tiền tố dự kiến ​​sẽ bị bỏ qua khi tính toán số đã cho - tiền tố chỉ chứa mã thiết lập hậu tố để chạy (thường bằng cách đẩy một hoặc nhiều thứ vào ngăn xếp). Vì vậy, với một tiền tố và hậu tố, số tương ứng có thể được đẩy lên ngăn xếp với prefix(suffix).

Sự phân chia này về cơ bản giải quyết vấn đề tương tự như unpackhàm trong câu trả lời của Wheat Wizard. Thay vì gói mã <...>chỉ để hoàn tác điều này sau, mã đó chỉ đơn giản được thêm vào tiền tố.

Trong một vài trường hợp, tiền tố thực sự được đánh giá (chủ yếu cho hoạt động lũy ​​thừa giả), do đó định giá của nó cũng được lưu trữ. Tuy nhiên, điều này không thực sự gây ra vấn đề lớn, vì trình tạo không cố gắng xây dựng các số cụ thể. Về mặt lý thuyết dường như ngụ ý rằng có thể có hai đoạn mã có cùng độ dài và tạo ra cùng một số sẽ không bị thừa trong bộ đệm do có các định giá tiền tố khác nhau. Mặc dù vậy, tôi không bận tâm đến việc này vì nó dường như không quan trọng lắm (ít nhất là trong lĩnh vực này).

Tôi tưởng tượng sẽ dễ dàng giảm số lượng byte chỉ bằng cách thêm nhiều trường hợp, nhưng tôi đã có đủ thời điểm này.

Tôi đã chạy tới 1000000, nhưng chỉ thực hiện kiểm tra độ tỉnh táo lên tới 100000.

Pastebin của đầu ra trên số nguyên tố nhất định.


Làm gì k_limitk_max_lenlàm gì? Tôi không chắc là tôi hiểu tiêu đề.
Thuật sĩ lúa mì

1
Thay vì cố gắng tính các con số cụ thể, tôi đang tính toán tất cả các chương trình hữu ích (tức là đưa ra các số không quá lớn ngắn hơn bất kỳ chương trình tìm thấy nào khác) có độ dài nhất định - k_max_len. Nó có thể dễ dàng kiểm tra xem nó có tìm thấy tất cả các số bạn yêu cầu sau khi xử lý mỗi độ dài không, nhưng thật hữu ích cho tôi khi có thể giới hạn độ dài tối đa trong quá trình thử nghiệm để chương trình chạy nhanh hơn. (Xử lý độ dài lớn hơn có thể rất chậm.) k_limitVề cơ bản là tham số đầu vào - nó sẽ xuất các chương trình cho các số cho đến mức này - giả sử k_max_lenlà đủ lớn để tìm thấy chúng.
tehtmi

4

ruby, 60246 byte

$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

Tôi sử dụng một hàm băm. Tôi tìm thấy golf tốt nhất cho một số nhất định và sử dụng những cái nhỏ hơn để tìm những cái lớn hơn.

Băm đệ quy là rất nhiều niềm vui!


2

Con trăn, 64014 ký tự

Tôi không biết gì về brainflak trước thử thách này và chỉ loay hoay với nó một chút trên tryitonline, vì vậy có thể có những phím tắt rõ ràng mà tôi đã bỏ lỡ. Đây là một giải pháp khá nhàm chán, chỉ cần chia đầu vào thành x=x/2+x%2hoặc x=x/3+x%3, cái nào ngắn hơn.

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)+")"

Gọi nó như vậy: b(42)

đầu ra trên pastebin


1

Lua, 64664 byte

Chương trình in tổng chiều dài của chương trình và chương trình cho số nguyên tố 203 (có một dòng bạn có thể thay đổi để thay đổi dòng nào được in hoặc bỏ dòng để in tất cả các chương trình)

Ngay bây giờ tối ưu hóa duy nhất là x = 2 * n + 1

Hy vọng tôi sẽ có thời gian để thêm một số tối ưu hóa để giảm điểm.

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