Brain-Flak 정수 골프


28

정수는 Brain-Flak 에서 지루합니다 . 8 개의 연산자가 있습니다 :

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

foo여러 연산자로 구성 될 수 있으며이 경우 평가 및 요약됩니다. 예를 들어 스택으로 (()())푸시 2하고 평가합니다 2.

분명히 (()...())코드 매커니즘은 n*2+2바이트 수가 많기 때문에 Code Golf에서 유용하지 않습니다 . 따라서 주어진 양의 정수 n를 활성 스택으로 푸시하는 Brain-Flak 프로그램을 가능한 한 적은 바이트로 출력하는 프로그램이나 함수를 작성 해야합니다. 이 프로그램은 스택의 기존 내용에 대해 어떤 가정도해서는 안되므로 스택을 교환 된 상태로 두거나 스택에서 추가 값을 추가 또는 제거해서는 안됩니다.

귀하의 프로그램이나 기능이 1에서 1,000,000까지의 모든 입력에 대해 작동하는 Brain-Flak 프로그램을 반환 할 수 있어야하지만, 우승자는 1,000에서 1,000 사이의 모든 1061 소수에 대해 적절한 Brain-Flak 프로그램 중 가장 작은 세트를 생성하는 프로그램 또는 기능이됩니다. . 제출의 일부로 1061 입력에 대한 총 출력 크기를 기록해야합니다. 프로그램 또는 함수는 정수를 허용하고 (문자열) Brain-Flak 프로그램을 일반적인 허용되는 I / O 형식으로 반환 할 수 있습니다. 프로그램 또는 기능의 크기를 사용하여 연결이 끊어집니다.


4
참고로 길이 2n가 유효한 프로그램의 수 는 4^n catalan(n)입니다.
Leaky Nun

2
흠, 나는 도전을 좋아하지만 알 수없는 정수로 득점해야한다고 생각합니다. 그렇지 않으면, 프로그램에 점수가 매겨진 정수는 무차별 강제이고 다른 정수는 그대로 남아있을 수 있습니다 (()()()...()). 또한 소수를 사용하면 합성에 가능한 일부 최적화가 누락 될 수 있습니다.
DJMcMayhem

또한 []이 과제에 대해 정의되지 않은 이유는 무엇입니까? 8 명의 연산자 중 7 개를 구현하는 것이 이상하다고 생각합니다. 어느 쪽이든, 멋진 도전, 나는 누군가가 내 모국어에서 영감을 얻은 도전을 쓸 것입니다!
DJMcMayhem

2
@DJMcMayhem 사람들이 자신의 점수를 계산할 수 있기를 바랍니다. 모든 관련 소수는 복합 수보다 하나 이상이므로 잠재적 인 최적화가 많이 있어야합니다. 또한, 나는 사람들이 []그들의 대답에서 특정한 가치에 의존하기를 원하지 않습니다 .
Neil

1
@YetiCGN 스크립트의 크기는 타이 브레이커로만 계산됩니다.
Neil

답변:


16

파이썬 2, 59394 59244 58534 58416 58394 58250

여기 내 해결책이 있습니다.

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

관련 기능은 push(n)입니다. 그것을 호출하려면 단순히 표현하려는 정수를 밀어 넣으십시오.

설명

프로그램이 수행하는 주요 최적화는 곱셈 하드 ​​코딩입니다. 곱셈 하드 ​​코딩의 아이디어는 매우 간단합니다. 숫자를 눌렀다가 밀어서 새 값을 만듭니다. 예를 들어, 2를 곱하기 위해 ((n){})n 코드가 특정 숫자를 생성하는 다음 코드를 사용할 수 있습니다. 이 모두 있기 때문에 작품 (n){}N의 값을 갖는다.

이 간단한 아이디어는 숫자가 클수록 복잡해질 수 있습니다. 예를 들어, 5를 곱하면 5를 곱하는 가장 좋은 방법은 (((n)){}){}{}입니다. 이 코드는 n의 사본 두 개를 하나씩 곱하고 두 개를 더합니다. 같은 전략을 사용하여 숫자의 이진 표현을 기반으로 모든 곱셈을 만듭니다. 나는 이것이 어떻게 작동하는지에 대한 세부 사항을 얻지 않을 것이지만 바이너리 표현 중 첫 번째 표현을 잘라 내고 0을 ){}1과){}{}. 그런 다음 n을 적절한 횟수만큼 푸시하고 모든 괄호의 균형을 맞 춥니 다. (이것이 어떻게 수행되는지 알고 싶다면 내 코드를 볼 수 있습니다). 왜 이것이 작동하는지 알고 싶다면 의견을 보내주십시오. 나는 실제로 내 게시물에 대한 모든 업데이트를 읽는 사람이 없다고 생각하므로 설명을 생략했습니다.

알고리즘이 곱셈 하드 ​​코드를 찾으려고 시도하면 모든 주요 소수 요인을 시도합니다. 한 시점에서 복합 요인은 항상 자신의 주요 요인으로 더 간결하게 표현 될 수 있기 때문에 복합 요인을 무시합니다. 이것이 여전히 사실인지는 알 수 없습니다.

다른 바이트 저장 메커니즘은 다항식 솔루션 파인더입니다. 감소하는 루프로 쉽게 표현할 수있는 특정 형태의 다항식이 있습니다. 이러한 다항식에는 다각형 수가 포함되지만 이에 국한되지는 않습니다. 이 최적화는 양식에 맞는 다항식을 찾고이를 작성하는 코드를 작성합니다.

산출

페이스트 빈


"n이 n + 1보다 크거나 작은 지"??
Sparr

@Sparr의 해석 n이 다음보다 큰지 또는 작은 지n+1
Wheat Wizard

if n % 3 == 2: 해당 기능의 끝에서 끝까지 한 레벨 씩 들여 쓰기하지 않아야 합니다.
user202729

13

브레인 플락, 64664

온라인으로 사용해보십시오!

여기 주석이 달린 코드가 있습니다.

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

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

설명

현재 두 가지 규칙 만 구현합니다.

  • n이 두 개의 리턴으로 나눌 수있는 경우 (n/2){}

  • n을 두 개의 리턴으로 나눌 수없는 경우 n-1()

또한 6보다 작은 모든 숫자를 하드 코딩합니다.


3로 나눌 수있는 검사가 점수를 약간 줄인 것 같습니다
ASCII 전용

@ASCII 전용으로 실제로 구현 했으며 바이트 수를 늘 렸습니다 . 더 똑똑한 버전의 세분화를 구현하는 방법을 연구 중입니다.
밀 마법사

좋아, Brain-Flak을 사용하여 Brain-Frak 숫자를 생성하는 프로그램을 만드십시오. 좋은.
Draco18s

10

펄, 59222 59156 58460 자

  • n() (11322660 자)
  • (n){}() (64664 자)
  • ((n)){}{} (63610 자)
  • ((n)()){}{} (63484 자)-이것은 새로운 계산입니다
  • (n){({}[()])}{} (60748 자)
  • n[m] (62800 자)
  • (n){m({}[l])}{} (58460 자)-이것은 새로운 계산입니다

마지막 계산 공식은 n(n/l+1)/2+mn/l입니다. 다른 계산을 시도했지만 더 이상 주어진 출력에 도움이되지 않습니다. 프로그램은 실제로 최대 9999까지의 모든 값을 생성하지만 주어진 소수와 총 길이를 나열합니다.

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

출력에 대한 링크를 제공 할 수 있습니까?
DJMcMayhem

@DJMcMayhem 죄송합니다. 실수로 소수 목록을 손상시켜 문자 수를 무효화했습니다.
Neil

@Linus ((X) ()) {} {}은 X를 누른 다음 1을 더하고 결과를 누른 다음 X + 1과 X를 팝합니다. 총 3X + 2. Try It Online에서 다른 수식을 사용해 보았지만 원하는 경우 다시 확인할 수 있습니다.
Neil

@ 닐 내 실수 ... 이것들은 좋아 보이지만 정확히 소수를 손상시키는 것은 무엇입니까?
Linus

1
나는 58158을 얻을 @Neil 내가 추가 할 때 &try($i * $i, "$numbers[$i]{({})({}[()])}{}");나는 또한 추가 할 때 58032 아래로 이동하는 &try((3 * $i * $i - $i) / 2, "$numbers[$i]{({})({}[()])({})}{}");(사각형 / 오각형 번호) - 그것은 출신 여기
ASCII 전용

5

Python, 59136 58676 자

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

소수 반복 :

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)

산출:

Pastebin

설명:

함수 f 를 정의하기 위해 필요한 범위 [1, m -1] 보다 큰 개별 정수로 평가되는 Brain-flak 표현 의 목록 R 을 미리 채 웁니다 . 표현은 사용되지 않은 가장 낮은 표현 ( l로 색인화 됨)을 취하고 그로부터 많은 새로운 표현을 형성하여 가장 짧게 유지함으로써 형성됩니다. 사용되지 않은 가장 낮은 표현은 1에서 l 까지의 모든 숫자 에 표현이 할당되었고 이러한 표현이 이미 새로운 수를 생성하는 데 사용되었다고 가정합니다. l 보다 작은 값이 더 짧은 표현을 얻으면 돌아가서 해당 지점에서 시작하는 숫자를 재현해야합니다. 기능 f 괄호를 추가하여 스택에 번호를 저장하는 프로그램을 생성합니다.

나는 이것을 시작했을 때 Brainflak를 몰랐으며, 삼각형 숫자의 공식을 지적한 Eamon Olive의 대답 에 크게 감사드립니다 . 주로 합계를 일반화하고 합계와 차이를 확인하는 데 끊임없이 노력했습니다. 여러 배수의 합을 추가하면 큰 효과가 있습니다.

관심있는 사람들을 위해 여기에 어떤 수식이 가치가 있는지 알기 위해 사용 했던 스크래치 코드 가 있습니다.

표현 공식 :

  1. 작은 소수로 곱하기 :
    (X){}
    ((X)){}{}
    ((((X)))){}{}{}{}
    ((((((X)))))){}{}{}{}{}{}
  2. 추가 X + Y :
    XY
  3. 빼기 X - Y :
    X[Y]
  4. 증분 Y의 X 로의 합산 및 포함 :
    (X){({}[Y])}{}
  5. 증분 Y의 XX 의 합을 더한 X 더하기 : 등 ...
    (X)({({}[Y])}{}){}
    (X)(({({}[Y])}{})){}{}
    (X)(({({}[Y])}{}){}){}

5 *가 도움이되지 않는다고 생각했지만 이제는 답변에 10자를 절약 할 수 있습니다. 나는 그 합계를 시도했다고 생각했지만 다시 확인할 것입니다!
Neil

증분과 배수를 합하면 46 바이트가 더 절약되며, 헹구고 세 번 반복해서 모두 잡아야합니다.
Neil

빼기를 사용하면 5 *를 다시 사용하지 않습니다.
Neil

4

루아 5.3, 57522

질문이 게시되었을 때 실제로이 작업을 시작했지만 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)

알려진 유용한 함수를 사용하여 간단한 숫자를 잘 표현하여 더 큰 숫자를 만드는 다른 답변과 비슷한 아이디어입니다.

한 가지 차이점은 작은 숫자로 하위 문제를 해결하는 대신 표현이 짧은 숫자로 하위 문제를 해결한다는 것입니다. 나는 이것이 더 작은 숫자가 더 큰 숫자로 표현되는 경우를 처리하는 것뿐만 아니라 음수를 이용하는 것이 더 우아하다고 생각합니다.

또한 가능한 한 빨리 특정 숫자를 나타내려고 시도하지 않고 특정 크기로 표현할 수있는 모든 숫자를 찾으려고하면 실제로 특정 계산이 간단 해집니다. 수식을 반대로 적용하여 숫자에 적용 할 수 있는지 확인하는 대신 수식을 앞으로 처리하여 모든 숫자에 적용 할 수 있습니다.

또 다른 차이점은 알려진 솔루션이 (선택적) "접두사"와 "접미사"(접두사와 유사)라는 두 부분으로 저장되어 있다는 것입니다. 접두사의 평가는 주어진 숫자를 계산할 때 무시 될 것으로 예상됩니다. 접두사는 단지 접미사가 실행되도록 설정하는 코드를 포함합니다 (일반적으로 하나 이상의 항목을 스택으로 푸시). 따라서 접두사와 접미사가 주어지면 해당 번호를로 스택에 푸시 할 수 있습니다 prefix(suffix).

이 분할은 기본적으로 unpack밀 마법사의 답변에서 와 동일한 문제를 해결합니다 . <...>나중에이 작업을 취소하기 위해 코드를 래핑하는 대신 이러한 코드가 접두사에 추가됩니다.

경우에 따라 접두사가 실제로 평가 (주로 의사 지수 연산의 경우)되므로 평가도 저장됩니다. 그러나 생성기가 특정 숫자를 생성하려고 시도하지 않기 때문에 이것이 실제로 큰 문제를 일으키지는 않습니다. 이론적으로는 동일한 접두어 평가로 인해 캐시에서 중복되지 않는 동일한 길이와 동일한 수의 코드가 두 개있을 수 있음을 의미합니다. 나는 (적어도이 도메인에서는)별로 중요하지 않은 것처럼 보이기 때문에 이것을 설명하지 않았습니다.

더 많은 사례를 추가하여 바이트 수를 쉽게 줄일 수 있다고 생각하지만 지금은 충분했습니다.

나는 1000000에 달했지만 최대 100000까지 위생 검사 만했습니다.

주어진 소수에 대한 출력의 Pastebin.


무엇을 k_limit하고 k_max_len합니까? 헤더를 이해하지 못했습니다.
위트 마법사

1
특정 숫자를 계산하지 않고 유용한 모든 프로그램 (예 : 다른 프로그램보다 짧지 않은 숫자를 짧은 프로그램)을 특정 길이까지 계산합니다 k_max_len. 각 길이를 처리 한 후 요청한 모든 숫자를 찾았는지 쉽게 확인할 수 있지만 테스트 중에 최대 길이를 바인딩하여 프로그램을 더 빨리 실행할 수 있다는 것이 유용했습니다. (더 큰 길이를 처리하는 것은 매우 느릴 수 있습니다.) k_limit기본적으로 입력 매개 변수입니다. 숫자 k_max_len를 찾을 수있을 정도로 크다고 가정 할 때 최대 숫자까지 프로그램을 출력 합니다.
tehtmi

4

루비, 60246 바이트

$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

해시를 사용합니다. 주어진 숫자에 가장 적합한 골프를 찾고 더 작은 것을 사용하여 더 큰 골프를 찾습니다.

재귀 해시는 너무 재미있다!


2

Python, 64014 자

나는이 도전 이전에 brainflak에 대해 아무것도 몰랐고 tryitonline에서 약간만 놀랐 기 때문에 내가 놓친 지름길이 분명했습니다. 이것은 매우 지루한 해결책이며 입력을 x=x/2+x%2또는 로 나누는 x=x/3+x%3것 중 더 짧은 것입니다.

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

다음과 같이 호출하십시오. b(42)

pastebin에 출력


1

루아, 64664 바이트

프로그램은 프로그램의 전체 길이와 203 번째 프라임에 대한 프로그램을 인쇄합니다 (인쇄 할 행을 변경하도록 변경하거나 모든 프로그램을 인쇄하기 위해 행의 주석을 해제 할 수 있음)

현재 유일한 최적화는 x = 2 * n + 1입니다.

다행히도 점수를 낮추기 위해 더 많은 최적화를 추가 할 시간이있을 것입니다.

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.