사용할 수없는 것으로 보이는 프로그래밍 언어 만들기


85

강도의 챌린지 스레드가 여기 있습니다 .

경찰의 과제 : 프로그래밍에는 사용할 수없는 것으로 보이지만, 명백하지 않은 메커니즘을 통해 계산 (또는 최소한 작업 완료)을 허용하는 프로그래밍 언어를 설계하십시오.

입력 파일에서 코드를 읽은 다음 무언가를 수행하는 간단한 프로그래밍 언어를 설계해야합니다. 통역사에서 실행될 때 입력에서 세 번째로 큰 숫자를 찾는 솔루션 프로그램 을 준비해야합니다 . 강도가 솔루션 프로그램을 찾으려면 최대한 어렵게 만들어야합니다. 강도는 생각한 것만이 아니라 작업을 수행하는 모든 솔루션을 게시 수 있습니다 .

이것은 인기 콘테스트입니다. 경찰의 목표는 통역사를 파견하지 않고 8 일 동안 생존하면서 최대한 많은 표를 얻는 것입니다. 이를 위해 다음 관행이 도움이 될 것입니다.

  • 언어의 의미를 정확하게 설명
  • 읽을 수있는 코드 작성

다음과 같은 전술은 권장하지 않습니다.

  • 암호화, 해시 또는 기타 암호화 방법 사용 RSA 암호화를 사용하는 언어가 표시되거나 SHA-3 해시가 0x1936206392306이 아닌 경우 프로그램 실행을 거부하는 경우 주저하지 말고 하향 조정하십시오.

강도의 도전 : 경찰의 통역사에서 실행될 때 입력에서 세 번째로 큰 정수를 찾는 프로그램을 작성하십시오.

이것은 비교적 간단합니다. 경찰 응답을 해독하려면 인터프리터에서 실행될 때 작업을 완료하는 프로그램을 만들어야합니다. 답변을 해독 할 때 게시물에 연결된 경찰의 답변에 "충돌 됨"이라는 메모를 게시하십시오. 경찰을 가장 많이 파는 사람은 강도의 실에서 이깁니다.

I / O 규칙

  • 통역사는 프로그램의 명령 행에서 파일 이름을 가져 와서 실행할 때 표준 입력 및 출력을 사용해야합니다.
  • 입력은 단항으로 제공되며 문자 01ASCII (48 및 49) 로만 구성됩니다 . 숫자 N은 로 인코딩 N은 1s a로 하였다 0. 0파일 끝 전에 추가 가 있습니다. 예 : 시퀀스 (3, 3, 1, 14)의 경우 입력은 11101110101111111111111100입니다.
  • 입력 값은 3 자리 이상이어야합니다. 모든 숫자는 양의 정수입니다.
  • 출력은 1프로그램이 정지되기 전에 인쇄 된 수에 의해 판단됩니다 . 다른 문자는 무시됩니다.

다음 예에서 첫 번째 행은 10 진수 형식의 입력입니다. 두 번째는 실제 프로그램 입력입니다. 세 번째는 샘플 출력입니다.

1, 1, 3
101011100
1

15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u

247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>

경찰 답변에 대한 지루한 규칙 :

  • 모호함을 통한 보안을 방지하려면 인터프리터를이 TIOBE 인덱스 의 상위 100 개 언어로 작성 해야하며 자유롭게 사용할 수있는 컴파일러 / 인터프리터가 있어야합니다.
  • 통역사는이 도전 전에 출판 된 언어를 해석해서는 안됩니다.
  • 통역사는 게시물에 적합해야하며 외부에서 호스팅해서는 안됩니다.
  • 통역사는 결정 론적이어야한다
  • 통역사는 이식성이 있어야하며 모국어의 표준을 따라야합니다. 정의되지 않은 동작이나 버그를 사용하지 마십시오
  • 솔루션 프로그램이 너무 길어서 답에 맞지 않으면이를 생성하는 프로그램을 게시해야합니다.
  • 솔루션 프로그램은 인쇄 가능한 ASCII 및 줄 바꿈으로 만 구성되어야합니다.
  • 위의 각 예제 입력에 대해 자신의 컴퓨터에서 1 시간 이내에 솔루션 프로그램을 실행해야합니다.
  • 프로그램은 임의의 정수 10 미만 작동한다 (6) , 및 10 미만의 정수의 어느 번호 6 (반드시의 시간 미만), 입력 길이의 합계가 10 미만이 제공 9 .
  • 안전을 유지하기 위해 경찰은 8 일이 지난 후에 솔루션 프로그램을 답변으로 편집해야합니다.

채점

가장 높은 점수와 긍정적 인 점수로 안전 해지는 경찰이이 질문에서 승리합니다.


당신은 이것을 명시 적으로 언급하지는 않지만 경찰이 실제로 통역사를 작성하여 답변에 게시해야한다고 가정 할 때 맞습니까?
Blue

@muddyfish 예, 통역사는 경찰의 답변 내용이어야합니다.
feersum

1
@ kirbyfan64sos 출력은 프로그램이 중지되기 전에 인쇄 된 1의 수로 판단됩니다. 다른 문자는 무시됩니다.
mbomb007


20
나는이 도전에 자신을 저격했다. 나는 프로그래밍 언어를 만든 후 언어도 실제로 것을 찾아에만 작동 할 수 있는지 확인하기 위해 작업을 프로그래밍 시간을 보냈다 이었다 사용할 수 없게.
Sanchises

답변:


24

교환 (안전)

ShapeScript

ShapeScript는 자연스럽게 발생하는 프로그래밍 언어입니다. 셰이프 쉬프터 (또는 Changelings , 호출하기를 선호 함)는 데이터를 처리 할 수있는 일련의 명령어로 변환 할 수 있습니다.

ShapeScript는 비교적 간단한 구문을 가진 스택 기반 언어입니다. 당연히 대부분의 내장 기능은 줄 모양 변경을 처리합니다. 다음과 같이 문자별로 해석됩니다.

  • '"문자열 리터럴을 시작합니다.

    소스 코드에서 일치하는 따옴표를 찾을 때까지 이러한 일치하는 따옴표 사이의 모든 문자가 문자열로 수집 된 다음 스택에서 푸시됩니다.

  • 0스택 9에서 정수 0 ~ 9 를 푸시합니다 . 정수 를 10푸시 합니다.

  • ! 스택에서 문자열을 팝하고 ShapeScript로 평가하려고 시도합니다.

  • ? 스택에서 정수를 팝하고 해당 인덱스에서 스택 항목의 복사본을 푸시합니다.

    인덱스 0은 맨 위 스택 항목 (LIFO)에 해당하고 인덱스 -1은 맨 아래 스택 항목에 해당합니다.

  • _ 스택에서 iterable을 팝하고 길이를 푸시합니다.

  • @ 스택에서 두 항목을 팝하고 반대 순서로 푸시합니다.

  • $스택에서 두 개의 문자열을 팝하고 최상위 문자열이 발생할 때 맨 아래 문자열을 분할합니다. 결과 목록이 반환됩니다.

  • &스택에서 문자열 (최상위)과 iterable을 팝하고 문자열을 구분 기호로 사용하여 iterable을 조인합니다. 결과 문자열이 반환됩니다.

  • 비단뱀은 지구상에서 Changelings 가장 가까운 친척이기 때문에 ShapeScript는, 우리의 행성에 사용하는 경우, 다른 모든 문자 c는 두 항목의 팝업 X를 하고 Y (맨 위) 스택에서, 그리고 파이썬 코드를 평가하려고 시도 x c y.

    예를 들어, 문자 순서 23+는 평가 2+3되고 문자 순서 "one"3*는 평가 'one'*3되며 문자 순서 1''A는 평가 1A''됩니다.

    마지막 경우, 결과는 유효한 Python이 아니기 때문에 Changeling은 현재 Shape가 유효하지 않기 때문에 (구문 오류) 불평 할 것입니다. ShapeScript가 유효하지 않기 때문입니다.

코드를 실행하기 전에 인터프리터는 전체 사용자 입력을 문자열 형태로 스택에 배치합니다. 소스 코드를 실행 한 후 인터프리터는 스택의 모든 항목을 인쇄합니다. 그 사이에 부품이 고장 나면 Changeling은 현재 모양이 적절하지 않다고 불평합니다 (런타임 오류).

모양 이동

자연 상태에서 Changelings는 ShapeScript의 모양을 취하지 않습니다. 그러나 이들 중 일부는 하나의 잠재적 인 소스 코드로 변환 할 수 있습니다 (필수적으로 유용하거나 구문 적으로 유효한 것은 아님).

모든 적격 변경점은 다음과 같은 자연 형태를 갖습니다.

  • 모든 줄의 문자 수는 같아야합니다.

  • 모든 줄은 인쇄 가능한 ASCII 문자로 구성되고 한 번의 줄 바꿈이 뒤 따릅니다.

  • 줄 수는 줄당 인쇄 가능한 문자 수와 일치해야합니다.

예를 들어, 바이트 시퀀스 ab\ncd\n는 적합한 Changeling입니다.

ShapeScript 로의 전환을 위해 Changeling은 다음과 같이 변환됩니다.

  • 처음에는 소스 코드가 없습니다.

  • 각 줄에 대해 다음이 발생합니다.

    • Changeling의 누산기가 0으로 설정되어 있습니다.

    • 행의 각 문자 c (후행 줄 바꿈 포함)에 대해 c 의 코드 포인트 는 누산기를 2로 나눈 XOR되며 결과 코드 포인트에 해당하는 유니 코드 문자가 소스 코드에 추가됩니다.

      그 후, c 의 코드 포인트와 공백의 코드 포인트 (32) 사이의 차이 가 누산기에 추가된다.

위의 일부가 실패하면 Changeling은 현재 모양이 불쾌하다고 불평합니다.

모든 라인이 처리 된 후에 Changeling의 (유망하게 유효한) ShapeScript 로의 변환이 완료되고 결과 코드가 실행됩니다.

솔루션 (ShapeScript)

"0"@"0"$"0"2*&"0"@+0?_'@1?"0"$_8>"1"*+@1?"0"+$""&'*!#

ShapeScript는 실제로 매우 유용한 것으로 판명되었습니다. 또한 원시 테스트 ( proof )를 수행 할 수 있으므로 프로그래밍 언어에 대한 정의를 충족합니다.

약간 수정 된 구문과 더 나은 I / O로 GitHub에 ShapeScript를 다시 게시 했습니다 .

코드는 다음을 수행합니다.

"0"@    Push "0" (A) and swap it with the input string (S).
"0"$    Split S at 0's.
"0"2*   Push "00".
&       Join the split S, using "00" as separator.
"0"@+   Prepend "0" to S.
        The input has been transformed into
        "0<run of 1's>000<run of 1's>0...0<run of 1's>0000".
0?_     Push a copy and compute its length (L).
'       Push a string that, when evaluated, does the following:
  @1?     Swap A on top of S, and push a copy of S.
  "0"$    Split the copy of S at 0's.
  _8>     Get the length of the resulting array and compare it with 8.
          If this returns True, there are more than eight chunks, so there are
          more then seven 0's. With two 0's surrounding each run of 1's and
          three extra 0's at the end, this means that there still are three or
          more runs of 1's in the string.
  "1"*    Push "1" if '>' returned True and "" if it returned False.
  +       Append "1" or "" to A.
  @1?     Swap S on top of A, and push a copy of A.
  "0"+    Append "0" to the copy of A.
  $       Split S at occurrences of A+"0".
  ""&     Flatten the resulting array of strings.
'       This removes all occurrences of "010" in the first iteration, all
        occurrences of "0110" in the second, etc., until there are less than
        three runs of 1's left in S. At this point, A is no longer updated,
        and the code inside the string becomes a noop.
*!      Repeat the code string L times and evaluate.
#       Drop S, leaving only A on the stack.

솔루션 (변경)

"1+-.......................
""B1.......................
"" 2)+7....................
"" 2)=<....................
""( $86=...................
""B8=......................
""247......................
""]`b......................
""B1.......................
""%D1=.....................
""%500=....................
""%&74?....................
""%&#.2....................
""%[bdG....................
""%D1=.....................
""%<5?.....................
""%:6>.....................
""%&65?....................
""%&-%7>...................
""%D1=.....................
""%500=....................
""%&74?....................
""%&,)5>...................
""%&%,79...................
"" )$?/=...................
""),-9=....................
""# !......................

모든 Changeling 프로그램과 마찬가지로이 코드에는 후행 줄 바꿈이 있습니다.

모든 문자가 이해되지 않으면 ShapeScript가 즉시 오류가 발생하지만 임의의 문자열을 필러로 푸시하고 나중에 팝업 할 수 있습니다. 이를 통해 각 줄에 작은 양의 코드 만 넣을 수 있습니다 (처음에는 누산기가 작은 곳) ". 로 다음 줄을 시작 "#하면 실제 코드에 영향을주지 않고 문자열을 닫고 팝합니다.

또한 세 가지 사소한 장애물을 극복해야합니다.

  • ShapeScript 코드의 긴 문자열은 단일 토큰이므로 한 줄에 맞출 수 없습니다.

    우리는 덩어리 (이 문자열 밀어 것입니다 '@', '1?'우리는 나중에 연결할 것 등).

  • 코드 포인트 _가 다소 높으므로 푸시 '_'가 문제가됩니다.

    그러나 우리는 스왑을 취소 하기 위해 '_@'쉽게 밀고 나올 수 있습니다 '@'.

ShapeScript 코드는 우리의 변신이 같은 외모 생성 1 :

"0""
"#@"
"#"0"$"
"#"0"2"
"#*&"0""
"#@+"
"#0?"
"#_@"
"#@"
"#'@'"
"#'1?'"
"#'"0'"
"#'"$'"
"#'_@'"
"#'@'"
"#'8'"
"#'>'"
"#'"1'"
"#'"*+'"
"#'@'"
"#'1?'"
"#'"0'"
"#'"+$'"
"#'""&'"
"#"+"77"
"#+*!*"
"#!#"

이 변환기를 통해 위의 ShapeScript 코드를 실행하여 Changeling 코드를 찾았 습니다 . 2

통역사 (Python 3)

#!/usr/bin/env python3

import fileinput

def error(code):
  print("This shape is " + ["unpleasant", "unpurposed", "inadequate"][code - 1] + ".")
  exit(code)

def interpret(code):
  global stack
  stringing = 0
  for char in code:
    quote = (char == "'") + 2 * (char == '"')
    if quote or stringing:
      if not stringing:
        string = ""
        stringing = quote
      elif stringing == quote:
        stack.append(string)
        stringing = 0
      else:
        string += char
    elif char in "0123456789":
      stack.append(int(char))
    else:
      x = stack.pop()
      if char == '!':
        interpret(x)
      else:
        if char == '?':
          y = stack[~x]
        elif char == "_":
          y = len(x)
        else:
          y = stack.pop()
          if char == '@':
            stack.append(x)
          elif char == '$':
            y = y.split(x)
          elif char == '&':
            y = x.join(map(str, y))
          else:
            try:
              y = eval(repr(y) + char + repr(x))
            except SyntaxError:
              error(2)
        stack.append(y)

source = ""
lengths = []

for line in fileinput.input():
  if not line or sorted(line)[:2][-1] < " " or max(line) > "~":
    error(1)
  lengths.append(len(line))
  accumulator = 0
  for char in line:
    value = ord(char)
    try:
      source += chr(value ^ (accumulator >> 1))
    except:
      error(1)
    accumulator += value - 32

lengths.append(len(lengths) + 1)

if min(lengths) != max(lengths):
  error(1)

stack = ""

for line in fileinput.input("-"):
  stack += line

stack = [stack]

try:
  interpret(source)
except:
  error(3)

print("".join(map(str, stack)))

1 각 줄에는 임의의 쓰레기가 줄 수만큼 채워져 있으며 실제로 줄 바꿈이 없습니다.
2 하단의 숫자는 Changeling 코드에서 가장 낮은 코드 포인트와 가장 높은 코드 포인트를 나타내며 32와 126 사이 여야합니다.


1
xor / transformations를 사용하는 경우 -1입니다. ShapeScript 변환으로의 전환은 암호화와 비슷하게 보입니다.
MegaTom

10
@MegaTom 당신이 적합하다고 생각하는대로 투표 할 수 있지만 , 강도는 강도에게 중요한 단점을 가져 오는 경찰에게만 알려진 키를 필요로하기 때문에 암호화에 대해 눈살을 찌푸립니다 . 변환은 없는 변환입니다.
Dennis

1
ShapeScript, 67 바이트 : 0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#. 그래도 Changeling을 찾는 것을 포기했습니다. 대부분 쓸모없는 문장으로 산재되어 있어도 20 바이트 이상을 얻을 수 없었습니다.
primo

2
@MegaTom 주어진 솔루션에 실제로 실망했습니다. 나는 쓸모없는 코드 92.9 %보다 훨씬 더 영리한 것을 기대하고있었습니다.
primo

2
@primo 좀 더 어려워졌지만 Python 2에서도 작동하는 Changeling 을 발견 했습니다 . 나는 내 대답이 얼마나 영리 한지 알지 못하지만, 허점을 발견 한 경찰을 게시하려는 계획은 효과가 있었던 것으로 보인다.
Dennis

30

셔플 (C ++로 작성), 금! 마틴

편집 마틴은 금이 갔다. 그의 솔루션을 보려면 링크를 클릭하십시오. 내 솔루션도 추가되었습니다.

레지스터와 스택을 모두 처리 할 수 ​​있도록 고정 명령 편집 이것은 솔루션에서 허용되지 않는 디버깅 명령이므로 이전 버전의 인터프리터를 사용하는 사람에게는 영향을 미치지 않아야합니다.print-d

나는 아직도 이것에 익숙하지 않기 때문에 내 대답이나 통역에 문제가 있으면 알려주십시오. 명확하지 않은 경우 설명을 요청하십시오.

나는 이것이 너무 어려울 것이라고는 생각하지 않지만 희망적으로는 일종의 도전을 제공 할 것입니다. 셔플을 상당히 사용할 수 없게 만드는 것은 물건이 적절한 곳에있을 때만 인쇄된다는 것입니다.

-> 기본 :

24 개의 스택이 있습니다 stack1, ... stack24. 이 스택은 목록에 있습니다. 모든 프로그램의 시작 부분에서,이 스택들은 제로로 밀렸으며 그것들은 적절한 위치에서 시작합니다. 즉 ,리스트에서 i 번째 위치에 스택 i 가 있습니다 (C ++과는 달리 1부터 시작 함). 프로그램이 진행되는 동안 목록 내 스택 순서가 바뀝니다. 이것은 명령에 대해 설명 할 때 설명 할 이유로 중요합니다.

사용 가능한 5 개의 레지스터가 있습니다. 그들은의 이름은 Alberto, Gertrude, Hans, Leopold, ShabbySam. 이들 각각은 프로그램 시작시 0으로 설정됩니다.

따라서 모든 프로그램이 시작되면 24 개의 스택이 있으며 각 스택은 스택 목록의 색인과 일치하는 번호를 갖습니다. 모든 스택에는 정확히 하나의 0이 있습니다. 5 개의 레지스터 각각은 0으로 초기화됩니다.

-> 명령 및 구문 :

Shuffle에는 13 개의 명령 (+1 디버깅 명령)이 있습니다. 그들은 다음과 같습니다

  • cinpush이 명령에는 인수가 없습니다. 질문에 설명 된 방식으로 명령 행 입력을 기다립니다 (다른 입력은 지정되지 않은 / 정의되지 않은 결과로 이어짐). 그런 다음 입력 문자열을 정수로 나눕니다 ( 예 : 101011100->) 1,1,3. 수신 된 각 입력에 대해 다음을 수행합니다. (1) 값을 기준으로 스택 목록을 변경합니다. 해당 정수 값을이라고 합니다 . 경우 A는 10 미만이다가 순열을 수행 U를 . 경우 a가 9 및 30 (noninclusive) 사이는 치환하지 D를 . 그렇지 않으면 순열 r을 수행 합니다. (2) 그런 다음 푸시목록에서 첫 번째 스택에. 의미하지는 않습니다 stack1( stack1목록에서 첫 번째 경우 일 수 있음 ). 순열은 아래에 정의되어 있습니다. cinpush사용자 입력을 얻는 유일한 방법 이므로 모든 솔루션에 나타나야합니다.
  • mov value registermov명령은 기본적으로 변수 할당입니다. 에 할당 value합니다 register. value여러 가지 형태를 취할 수있다 : 그것은 일 수 (1) 의 정수, 예를 들어 47 (2) 는 다른 레지스터의 이름, 예를 들면 Hans (3) 의 '예 다음에 스택의 인덱스 4s. 이것은 스택의 번호가 아니라 목록의 색인입니다. 따라서이 수는 24를 초과하지 않아야합니다.

    몇 가지 mov예 :

    mov 4s Hans 
    mov Hans ShabbySam
    mov 9999 Gertrude
    
  • movfs index register이것은 '스택에서 이동'을 나타냅니다. mov명령 과 비슷합니다 . 레지스터에 의해 인덱스 된 스택에 액세스 할 수 있도록 존재합니다. 예를 들어, 이전에 Hans를 4 ( mov 4 Hans) movfs Hans Gertrude로 설정 한 경우 Gertrude를 스택 4의 상단과 동일하게 설정 하는 데 사용할 수 있습니다 . 이러한 유형의 동작은을 사용하여 간단히 액세스 할 수 없습니다 mov.

  • inc register 레지스터 값을 1 씩 증가시킵니다.
  • dec register 레지스터 값을 1 씩 줄입니다.
  • compg value value register이것은 '더 큰 비교'를 의미합니다. 레지스터를 두 값 중 더 큰 값으로 설정합니다. value위와 같이 정수, 레지스터 또는 스택 인덱스와 's'가 될 수 있습니다.
  • compl value value register 더 작은 값을 취하는 것을 제외하고는 위와 동일하게 '더 적게 비교하십시오'.
  • gte value1 value2 registervalue1 >= value2그런 다음 부울 값 (1 또는 0)을에 넣는 지 여부 를 확인합니다 register.
  • POP!! indexindex스택 목록에서 색인을 생성 한 스택의 상단에서 튀어 나옵니다 .
  • jmp label무조건 레이블로 이동합니다 label. 레이블에 대해 이야기하기에 좋은시기입니다. 레이블은 단어 다음에 ':'이옵니다. 인터프리터는 레이블을 미리 분석하므로 레이블뿐만 아니라 뒤로 이동할 수 있습니다.
  • jz value label0 label이면 점프 value합니다.
  • jnz value label0이 아닌 label경우 value로 이동합니다 .

    라벨 및 점프의 예 :

    this_is_my_label:
         jmp this_is_my_label
    
    mov 10 Hans
    jnz Hans infinite_loop
    
    infinite_loop:
         jmp infinite_loop
    
  • "shuffle" permutation다음은 셔플 명령입니다. 이를 통해 스택 목록을 치환 할 수 있습니다. 인수로 사용할 수있는 세 가지 유효한 순열이있다 l, f그리고는 b.

  • print register모든 스택이 초기 위치에 있는지 확인합니다. 즉, 스택 i 가 스택 목록의 인덱스 i 에 있는지 확인 합니다. 이 경우 값 register은 단항으로 인쇄 됩니다. 그렇지 않으면 심한 오류가 인쇄됩니다. 보시다시피, 무엇이든 출력하려면 스택이 모두 올바른 위치에 있어야합니다.
  • done!이것은 프로그램이 오류없이 종료되도록 지시합니다. 프로그램이없이 종료 done!되면 콘솔에 각 스택 상단의 번호와 스택 번호가 인쇄됩니다. 스택이 인쇄되는 순서는 스택 목록에 나타나는 순서입니다. 스택이 비어 있으면 생략됩니다. 이 동작은 디버깅 목적으로 사용되며 솔루션에서 사용되지 않을 수 있습니다.
  • print-d value이 (액세스 스택 주어진 스택의 값을 등록 또는 정수 인쇄 통과 is전술 한 바와 같이, 인수하면서). 이것은 디버깅 도구이며 언어의 일부가 아니므로 솔루션에서 허용되지 않습니다.

-> 인터프리터 코드는 다음과 같습니다

모든 구문 분석은 기본 기능에서 발생합니다. 여기에서 특정 명령에 대한 구문 분석을 찾을 수 있습니다.

#include<fstream>
#include<iostream>
#include<string>
#include<stack>
#include<cmath>

using namespace std;

class superStack: public stack<long> {
    private:
        int m_place;
    public:
        static int s_index;


        superStack() {
            m_place = s_index;
            s_index++;
        }

        int place() {
            return m_place;
        }
};
int superStack::s_index=1;

superStack  stack1,stack2,stack3,stack4,stack5,stack6,stack7,stack8,stack9,stack10,stack11, \
            stack12,stack13,stack14,stack15,stack16,stack17,stack18,stack19,stack20,stack21,stack22,stack23,stack24;


superStack* stackptrs[]=    { \
                        &stack1,&stack2,&stack3,&stack4,&stack5,&stack6,&stack7,&stack8,&stack9,&stack10,&stack11, \
                        &stack12,&stack13,&stack14,&stack15,&stack16,&stack17,&stack18,&stack19,&stack20,&stack21,&stack22,&stack23,&stack24 \
                        };


long Gertrude=0;
long Hans=0;
long Alberto=0;
long ShabbySam=0;
long Leopold=0;


void SWAP( int i, int j) {    // 0 < i,j < 25

    i--;
    j--;


    superStack* tempptr = stackptrs[i];
    stackptrs[i]=stackptrs[j];
    stackptrs[j] = tempptr;



}

void u() {
    int list[3][4] = {
                        {1,9,6,13},
                        {2,10,5,14},
                        {17,19,20,18},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void d() {
    int list[3][4] = {
                        {3,11,8,15},
                        {4,12,7,16},
                        {22,24,23,21},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void r() {
    int list[3][4] = {
                        {2,17,8,24},
                        {4,18,6,23},
                        {9,10,12,11},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void l() {
    int list[3][4] = {
                        {1,19,7,22},
                        {3,20,5,21},
                        {14,13,15,16},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void f() {
    int list[3][4] = {
                        {20,9,24,16},
                        {18,11,22,14},
                        {1,2,4,3},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void b() {
    int list[3][4] = {
                        {19,10,23,15},
                        {17,12,21,13},
                        {5,6,8,7},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}

void splitpush(string input) {
    long value=0;

    for(long i=0;i<input.size();i++) {

        if(input[i]=='1'){
            value++;
        }
        else if(input[i]=='0' && value!=0 ) {
            if(value<10) {
                u();
            }
            else if (value<30) {
                d();

            }
            else {
                r();
            }
            (*stackptrs[0]).push(value);
            value=0;

        }
        else {
            break;
        }

    }

}

long strToInt(string str) { // IF STRING HAS NON DIGITS, YOU WILL GET GARBAGE, BUT NO ERROR
    long j=str.size()-1;
    long value = 0;
    for(long i=0;i<str.size();i++) {
        long x = str[i]-48;

        value+=x*floor( pow(10,j) );
        j--;
    }
    return value;
}

bool isEmpty(superStack stk) {
    if( stk.size()>0){return false; }
    else {return true;}

}    

long getValue(string str) {
    if(str=="ShabbySam") {
        return ShabbySam;
    }
    else if(str=="Hans") {
        return Hans;
    }
    else if(str=="Gertrude") {
        return Gertrude;
    }
    else if(str=="Alberto") {
        return Alberto;
    }   
    else if(str=="Leopold") {
        return Leopold;
    }
    else if(str[ str.size()-1 ]=='s'){
        str.pop_back();

        long index = strToInt(str)-1;

        if( !isEmpty( (*stackptrs[index]) ) ) {
            return (*stackptrs[index]).top();
        }
        else {
            cerr<<"Bad Expression or Empty Stack";


        }   
    }
    else {
        return strToInt(str);
    }

}

void printUnary(long i) {
    while(i>0) {
        cout<<1;
        i--;
    }
}

int main(int argc, char**argv) {

    if(argc<2){std::cerr<<"No input file given"; return 1;}
    ifstream inf(argv[1]);
    if(!inf){std::cerr<<"File open failed";return 1;}

    for(int i=0;i<24;i++) { 
        (*stackptrs[i]).push(0);         // Pre push a zero on every stack
    }

    string labels[20];
    unsigned labelPoints[20];
    int index=0;



    string str;
    while(inf) { //  parse for labels
        inf>>str;
        //cout<<inf.tellg()<<" ";
        if(inf) {
            if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }

        }

    }
    inf.clear();
    inf.seekg(0,inf.beg);

    while(inf) { // parse for other commands 
        inf>>str;

        if(inf) {


            if(str=="cinpush") {
                string input;
                cin>>input;
                splitpush(input);
            }

            else if(str=="mov") {
                inf>>str;
                long value = getValue(str);

                inf>>str;
                if(str=="Gertrude"){Gertrude=value;}
                else if(str=="Hans"){Hans=value;}
                else if(str=="ShabbySam"){ShabbySam=value;}
                else if(str=="Alberto"){Alberto=value;}
                else if(str=="Leopold"){Leopold=value;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="movfs") {
                inf>>str;
                long index = getValue(str);
                if(!isEmpty( *stackptrs[index-1] )) {
                    inf>>str;
                    long value = (*stackptrs[index-1]).top();
                    if(str=="Gertrude"){Gertrude=value;}
                    else if(str=="Hans"){Hans=value;}
                    else if(str=="ShabbySam"){ShabbySam=value;}
                    else if(str=="Alberto"){Alberto=value;}
                    else if(str=="Leopold"){Leopold=value;}
                    else {cerr<<"Bad register name.";}
                }
                else {
                    cerr<<"Empty Stack";
                }



            }

            else if(str=="inc") {
                inf>>str;
                if(str=="Gertrude"){Gertrude++;}
                else if(str=="Hans"){Hans++;}
                else if(str=="ShabbySam"){ShabbySam++;}
                else if(str=="Alberto"){Alberto++;}
                else if(str=="Leopold"){Leopold++;}
                else {cerr<<"Bad register name. ";}
            }
            else if(str=="dec") {
                inf>>str;
                if(str=="Gertrude"){Gertrude--;}
                else if(str=="Hans"){Hans--;}
                else if(str=="ShabbySam"){ShabbySam--;}
                else if(str=="Alberto"){Alberto--;}
                else if(str=="Leopold"){Leopold--;}
                else {cerr<<"Bad register name. ";}
            }


            else if(str=="compg") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger;
                if(value1>value2){larger = value1;}
                else {larger = value2;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }
            else if(str=="compl") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger; //LARGER IS REALLY SMALLER HERE
                if(value1>value2){larger = value2;}
                else {larger = value1;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="gte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 >= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="lte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 <= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="POP!!") {
                inf>>str;
                long index = getValue(str);
                index--; //because we (C++ and this interpreter) index differently
                if(!isEmpty( *stackptrs[index] )) {
                    (*stackptrs[index]).pop();
                }
                else {cerr<<"Can't POP!! from empty stack";}

            }

            else if(str=="push"){cerr<<" You can't. ";}

            /*
            else if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }*/

            else if(str=="jmp") {
                inf>>str;
                for(int i=0;i<index;i++) {
                    if( labels[i]==str) {
                        inf.seekg( labelPoints[i], ios::beg);
                    }
                }
            }
            else if(str=="jz") {
                inf>>str;
                long value = getValue(str);

                if(value==0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str=="jnz") {
                inf>>str;
                long value = getValue(str);

                if(value!=0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str== "\"shuffle\"") {
                inf>>str;
                if(str=="l"){ l(); }
                else if(str=="f"){ f(); }
                else if(str=="b"){ b(); }
                else {cerr<<"Bad shuffle parameter";}

            }

            else if(str=="print") {

                for(int i=0;i<24;i++) {

                    if( (i+1) != (*stackptrs[i]).place() ) {
                        cerr<< "Sorry, your stacks are in the wrong place! You can't print unless you put them back! Exiting. ";
                        return 1;
                    }

                }
                inf>>str;
                if(str=="Gertrude"){printUnary(Gertrude);}
                else if(str=="Hans"){printUnary(Hans);}
                else if(str=="ShabbySam"){printUnary(ShabbySam);}
                else if(str=="Alberto"){printUnary(Alberto);}
                else if(str=="Leopold"){printUnary(Leopold);}
                else {cerr<<"Bad register name. ";}


            }

            else if(str=="done!") {return 0;}

            else if(str=="print-d" ){
                inf>>str;
                long value = getValue(str);
                cout<<str;
              }
        }

    }







    /*for(int i=1;i<25;i++) {
        (*(stackptrs[i-1])).push(i);
    }

    u();d();r();l();f();b();
    */

    cout<<"\n";
    for(int i=1;i<25;i++) {
        if( (*(stackptrs[i-1])).size()>0 ) {
            cout<<(*(stackptrs[i-1])).top()<<" "<<(*(stackptrs[i-1])).place()<<"\n";
            (*(stackptrs[i-1])).pop();
        }
    }
    /*
    for (int i=0;i<index;i++) {
        cout<<labels[i]<<": "<<labelPoints[i]<<"\n";
    }*/

    return 1;
}

-> 순열 순열 은 스택 목록의 요소를 다음과 같은 방식으로 순열합니다.

어디 것을 의미한다

(이것은 인터프리터 코드에도 나타납니다. 불일치가 있으면 인터프리터가 올바른 것입니다.)

-> 간단한 예

이 두 간단한 프로그램은 공백없이 24에서 1까지 (단항으로) 숫자를 인쇄합니다.

mov 24 Hans
start:
    print Hans
    dec Hans
    jnz Hans start
done!

또는

mov 24 Hans start: print Hans dec Hans jnz Hans start done!

그들은 같은 프로그램입니다.

설명 및 해결책 :

마틴은 그의 대답 에 대해서도 잘 설명했다 .

Martin이 알아 낸 것처럼이 언어는 포켓 큐브 (일명 2x2 Rubik 큐브)에서 영감을 얻었습니다. 24 개의 스택은 큐브의 24 개의 개별 사각형과 같습니다. 순열은 허용되는 기본 동작입니다 (위, 아래, 오른쪽, 왼쪽, 앞, 뒤).

여기서 가장 큰 어려움은 가치가 밀릴 때 위, 아래, 오른쪽의 세 가지 움직임 만 사용된다는 것입니다. 그러나 스택을 "셔플 링"할 때는 이러한 이동에 액세스 할 수 없습니다. 다른 세 가지 동작 만 있습니다.

결과적으로, 세 가지 동작 모두 두 그룹 전체가 실제로 그룹 전체에 걸쳐 있으므로 문제를 해결할 수 있습니다. 이것은 실제로 3 개의 움직임 만 사용하여 2x2 Rubik의 큐브를 실제로 풀 수 있음을 의미합니다.

남은 것은 다른 세 가지를 사용하여 위, 아래 및 오른쪽 이동을 취소하는 방법을 알아내는 것입니다. 이를 위해 GAP 라는 컴퓨터 대수 시스템을 사용했습니다 .

순열을 취소 한 후 세 번째로 큰 숫자를 찾는 것은 매우 간단합니다.

cinpush
main:
    mov 1s ShabbySam
    POP!! 1
    jmp compare
    continue:
        gte 0 ShabbySam Leopold
        jnz Leopold end
        gte ShabbySam 9 Leopold
        jz Leopold uinverse
        gte ShabbySam 29 Leopold
        jz Leopold dinverse
        jnz Leopold rinverse
compare:
    gte ShabbySam Alberto Leopold
    jz Leopold skip
    mov Gertrude Hans
    mov Alberto Gertrude
    mov ShabbySam Alberto
    jmp continue
    skip:
        gte ShabbySam Gertrude Leopold
        jz Leopold skip_2
        mov Gertrude Hans
        mov ShabbySam Gertrude
        jmp continue
    skip_2:
        gte ShabbySam Hans Leopold
        jz Leopold continue
        mov ShabbySam Hans
        jmp continue
uinverse: 
    "shuffle" f
    "shuffle" f
    "shuffle" f
    "shuffle" l
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" f
    jmp main
dinverse:
    "shuffle" f
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" f
    "shuffle" f
    "shuffle" f
    jmp main
rinverse: 
    "shuffle" b "shuffle" l "shuffle" f "shuffle" l "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f "shuffle" b
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" b "shuffle" b "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" l "shuffle" l "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    jmp main
end:
    print Hans
    done!

2
깨진. :) 나는 언어에 정말로 감동한다!
Martin Ender

와우 그것은 내가 예상했던 것보다 빠르다. 고마워요. 글을 쓰는 것만 큼 재미있어서 다행입니다.
Liam

궁금합니다. 순열의 이름을 Rubik의 큐브에 대해 덜 분명한 것으로 변경했다면 상당히 어려울 것입니까?
Liam

그들은 확실히 단서했다,하지만 난 그것을 촬영하지 않았을 생각 더 이상 서로 다른 이름을 있었다면.
Martin Ender

그는 GAP가 세 가지 입력 순열을 뒤집는 데 특히 영리하지 않은 것처럼 보입니다. ;)
Martin Ender

22

Brian_Chuck , cardboard_box에 의해 금이

나는 두 프로그램이 서로 상호 작용하는 프로그래밍 언어 ( ROCB에서 영감을 얻었을 ) 에 대한 아이디어로 얼마 동안 흥미를 느꼈다 . 이 도전은 언어를 가능한 최소한으로 유지하려고 노력하면서 마침내이 개념을 다루는 좋은 동기가되었습니다. 디자인 목표는 언어 Turing-complete를 만드는 반면 각 부분은 개별적으로 Turing-complete가 아닙니다. 또한 소스 코드 조작을 사용하지 않고 둘 다 튜링이 완료되어서는 안됩니다. 나는 그것으로 성공 했다고 생각 하지만, 공식적으로 아직 그런 것들을 입증하지 못했습니다. 그래서 더 이상 고민하지 않고 내가 당신에게 선물합니다 ...

주인공

브라이언과 척은 두 가지 Brainfuck 같은 프로그램입니다. Brian을 시작으로 주어진 시간에 그들 중 하나만 실행됩니다. 캐치의 메모리 테이프는 척의 소스 코드이기도하다. 척의 메모리 테이프도 브라이언의 소스 코드입니다. 또한 Brian의 테이프 헤드는 Chuck의 명령 포인터이기도하며 그 반대도 마찬가지입니다. 테이프는 반 무한대 (즉, 오른쪽에 무한대)이며 부호가있는 임의 정밀도 정수를 보유 할 수 있으며 0으로 초기화됩니다 (소스 코드에서 다르게 지정하지 않는 한).

소스 코드도 메모리 테이프이므로 명령은 기술적으로 정수 값으로 정의되지만 합리적인 문자에 해당합니다. 다음과 같은 명령이 있습니다.

  • ,( 44) : STDIN에서 현재 메모리 셀로 바이트를 읽습니다. 오직 브라이언 만이 이것을 할 수 있습니다. 이 명령은 척에게는 아무런 문제가 없습니다.
  • .( 46) : 현재 메모리 셀 모듈로 256을 바이트로 STDOUT에 씁니다. 척만이이 작업을 수행 할 수 있습니다. 이 명령은 Brian에게 적합하지 않습니다.
  • +( 43) : 현재 메모리 셀을 증가시킵니다.
  • -( 45) : 현재 메모리 셀을 줄입니다.
  • ?( 63) : 현재 메모리 셀이 0이면 이는 작동하지 않습니다. 그렇지 않으면 다른 프로그램으로 직접 제어하십시오. 사용하는 프로그램의 테이프 헤드 ?는에 유지됩니다 ?. 다른 프로그램의 테이프 헤드는 첫 번째 명령을 실행하기 전에 한 셀을 오른쪽으로 이동합니다 (따라서 테스트로 사용되는 셀은 자체적으로 실행되지 않습니다).
  • <( 60) : 테이프 헤드를 한 셀 왼쪽으로 이동합니다. 테이프 헤드가 이미 테이프의 왼쪽 끝에 있으면 이것은 작동하지 않습니다.
  • >( 62) : 테이프 헤드를 한 셀 오른쪽으로 이동합니다.
  • {( 123) : 현재 셀이 0이거나 테이프의 왼쪽 끝에 도달 할 때까지 테이프 헤드를 왼쪽으로 반복해서 움직입니다.
  • }( 125) : 현재 셀이 0이 될 때까지 테이프 헤드를 오른쪽으로 반복해서 움직입니다.

활성 프로그램의 명령 포인터가 오른쪽에 더 이상 명령이없는 지점에 도달하면 프로그램이 종료됩니다.

소스 코드

소스 파일은 다음과 같이 처리됩니다.

  • 파일에 string이 포함되어 있으면 파일은 해당 문자열 ```의 첫 항목 주위에서 두 부분으로 분할됩니다. 모든 선행 및 후행 공백이 제거되고 첫 번째 부분은 Brian의 소스 코드로 사용되고 두 번째 부분은 Chuck의 경우에 사용됩니다.
  • 파일에이 문자열이 포함되어 있지 않으면 파일의 첫 번째 줄이 Brian의 소스로 사용되고 두 번째 부분은 Chuck의 줄 바꿈으로 구분됩니다 (공백을 구분하지 않음).
  • _두 프로그램 모두에서 발생하는 모든 항목은 NULL 바이트로 대체됩니다.
  • 두 개의 메모리 테이프는 결과 문자열에 해당하는 문자 코드로 초기화됩니다.

예를 들어, 다음 소스 파일

  abc
```
0_1
23

다음과 같은 초기 테이프를 산출합니다.

Brian: [97 98 99 0 0 0 0 ...]
Chuck: [48 0 49 10 50 51 0 0 0 0 ...]

통역사

통역사는 루비로 작성되었습니다. 실제 언어 사양의 일부가 아니므로 솔루션에서 사용 해서는 안되는 두 개의 명령 행 플래그가 필요합니다 .

  • -d:이 플래그를 사용하면 Brian과 Chuck이 더 많은 명령을 이해합니다. !두 메모리 테이프의 문자열 표현을 인쇄하며 활성 프로그램이 먼저 나열됩니다 (a ^는 현재 테이프 헤드를 표시합니다). @또한이 작업을 수행하지만 즉시 프로그램을 종료하십시오. 나는 게으 르기 때문에 프로그램의 마지막 명령이면 작동하지 않으므로 거기서 사용하려면 반복하거나 no-op를 쓰십시오.
  • -D: 자세한 디버그 모드입니다. !매 틱마다 동일한 디버그 정보를 인쇄합니다 . @이 모드에서도 작동합니다.

코드는 다음과 같습니다.

# coding: utf-8

class Instance
    attr_accessor :tape, :code, :ip

    OPERATORS = {
        '+'.ord  => :inc,
        '-'.ord  => :dec,
        '>'.ord  => :right,
        '<'.ord  => :left,
        '}'.ord  => :scan_right,
        '{'.ord  => :scan_left,
        '?'.ord  => :toggle,
        ','.ord  => :input,
        '.'.ord  => :output,
        '!'.ord  => :debug,
        '@'.ord  => :debug_terminate
    }

    OPERATORS.default = :nop

    def initialize(src)
        @code = src.chars.map(&:ord)
        @code = [0] if code.empty?

        @ip = 0
    end

    def tick
        result = :continue
        case OPERATORS[@code[@ip]]
        when :inc
            @tape.set(@tape.get + 1)
        when :dec
            @tape.set(@tape.get - 1)
        when :right
            @tape.move_right
        when :left
            @tape.move_left
        when :scan_right
            @tape.move_right while @tape.get != 0
        when :scan_left
            @tape.move_left while @tape.ip > 0 && @tape.get != 0
        when :toggle
            if @tape.get != 0
                @tape.move_right
                result = :toggle
            end
        when :input
            input
        when :output
            output
        when :debug
            result = :debug
        when :debug_terminate
            result = :debug_terminate
        end

        return :terminate if result != :toggle && @ip == @code.size - 1

        move_right if result != :toggle

        return result
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_left
        @ip -= 1 if @ip > 0
    end

    def get
        @code[@ip]
    end

    def set value
        @code[@ip] = value
    end

    def input() end
    def output() end

    def to_s
        str = self.class.name + ": \n"
        ip = @ip
        @code.map{|i|(i%256).chr}.join.lines.map do |l|
            str << l.chomp << $/
            str << ' '*ip << "^\n" if 0 <= ip && ip < l.size
            ip -= l.size
        end
        str
    end
end

class Brian < Instance
    def input
        byte = STDIN.read(1)
        @tape.set(byte ? byte.ord : -1)
    end
end

class Chuck < Instance
    def output
        $> << (@tape.get % 256).chr
    end
end

class BrianChuck

    class ProgramError < Exception; end

    def self.run(src, debug_level=0)
        new(src, debug_level).run
    end

    def initialize(src, debug_level=false)
        @debug_level = debug_level

        src.gsub!('_',"\0")

        if src[/```/]
            brian, chuck = src.split('```', 2).map(&:strip)
        else
            brian, chuck = src.lines.map(&:chomp)
        end

        chuck ||= ""

        brian = Brian.new(brian)
        chuck = Chuck.new(chuck)

        brian.tape = chuck
        chuck.tape = brian

        @instances = [brian, chuck]
    end

    def run
        (puts @instances; puts) if @debug_level > 1

        loop do
            result = current.tick

            toggle if result == :toggle

            (puts @instances; puts) if @debug_level > 1 || @debug_level > 0 && (result == :debug || result == :debug_terminate)

            break if result == :terminate || @debug_level > 0 && result == :debug_terminate
        end
    end

    private

    def current
        @instances[0]
    end

    def toggle
        @instances.reverse!
    end
end

case ARGV[0]
when "-d"
    debug_level = 1
when "-D"
    debug_level = 2
else
    debug_level = 0
end

if debug_level > 0
    ARGV.shift
end

BrianChuck.run(ARGF.read, debug_level)

다음은 문제에 대한 내 (필기) 솔루션입니다.

>}>}>
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>} Append a bunch of 1s as a dummy list element:
+>+>+>+>+>+>+>+>+>+
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
{<<<<<<<<<{<{    Move back to the start
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}<<<<<<- Subtract 1 from the result to account for initial 1
?   If integer was positive switch to Chuck
@todo: process end
_
This code is run when reading 1:
}>}>>>>>>>>>}<<<<<<+ Move to the end of Chuck; skip one null cell; move to the end of the list
{<<<<<<<<<{<?   Move back to the code that resets this loop.
_
This code is run after finalising an integer:
change the code after the integer first
<<--<--<--}
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: +
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<<<+<<{<{    Move back to the start; incrementing the list length
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}
Leave the resetting code, but remove the rest of the last list element:
<<<--<--<--
1: <-
question mk: <---------------------------------------------------------------
arrow left: <------------------------------------------------------------
brace right: <-----------------------------------------------------------------------------------------------------------------------------
1: <-
<{< Move back to the cell we reserved for the counter
<<<<<<-- decrement list size by two so we don't process the two largest elements
_

<{<<<<<<{<{<{<{<{>}>}>>>>>>> This is the beginning of the loop which decrements all list elements by 1
+ Add 1 to the running total
>>- Set marker of dummy list element to zero
_ Beginning of loop that is run for each list element
<{<<<<<<{<{<{<{<{>}>}>}>}+ set last marker back to 1
>>>>>>>>>> move to next marker
? Skip the next bit if we're not at the end of the list
<? Move back to the beginning of the loop
@ we should never get here
_
This is run when we're not at the end of the list
<<<- Set marker to 0 to remember current position
>>>>- Move to the current value and decrement it
? Move back to loop beginning if value is not zero yet
- Make element negative so it's skipped in the future
{<{<{>- Move to remaining list length and decrement it
? If it's nonzero switch to Chuck
>>>>>>>>->->->->->->->->->- Remove the dummy list to make some space for new code:
>}+ Fill in the marker in the list
{<<<<<<<<< Add some loop resetting code after the result:
brace left: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
This loop adds a print command to Chuck's code while decrementing the result
>>>>>>>>}>>>>>}>>>>>} Move to the very end of Chuck's code and leave some space to seek the 1
print: ++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<{<<<<<{<<<<<<<{<
- decrement the result
? if nonzero run loop again
At this point we just need to make Chuck seek for the 1 at the end of this code print it often enough
>>}>>>>>>>}>>>>>}
arrow right: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<?1 Switch to Chuck which moves Brian's tape head onto the 1 and then prints it N times


```

_   Dummy cell to hold input
This code is run when reading a 1:
{<{<{<{ ensure we're at the start
}>}<? Skip 0 handling code and switch to Brian
_ This code is run after a 1 has been processed:
{<{<?

이 코드는 모든 주석이 어떤 작전을 사용하지 의해 생략되어 있기 때문에, 그대로 실행 가능하다 {}.

기본 아이디어는 다음과 같습니다.

  1. 척 테이프의 끝에있는 목록에 새로운 0 요소를 추가하고 목록 길이를 1 씩 늘리십시오.
  2. 1s를 읽는 동안 해당 요소를 늘리십시오.
  3. 를 읽을 때 0정리를 수행하십시오. 결과 정수가 0보다 큰 경우 1로 돌아갑니다.

    이제 Chuck의 테이프 끝에 입력 번호 목록이 있고 목록의 길이를 알고 있습니다.

  4. 리스트의 길이에서 2를 빼면 (다음 단계는 두 개의 가장 큰 요소를 무시합니다) 이것을 this라고 부릅니다 N.

  5. 동안 N > 0누적 합계를 늘리고 모든 목록 요소를 줄입니다. 목록 요소가 0에 도달 할 때마다 감소 N합니다.

    이것의 끝에 누적 합계는 입력에서 세 번째로 큰 숫자를 포함합니다 M.

  6. 척 테이프 끝에 M사본을 씁니다 ..

  7. Chuck 1에서 Brian의 테이프를 검색 한 다음 .끝에 생성 된 테이프를 실행 하십시오.

이 작업을 마친 후 일부 장소에서 상당히 단순화 할 수 있음을 깨달았습니다. 예를 들어, 카운터를 추적 .하고 척의 테이프에 기록하는 대신 1모든 목록 요소를 줄이기 전에 매번 바로 인쇄 할 수 있습니다. 그러나이 코드를 변경하면 다른 변경 사항이 모든 곳에서 전파되므로 변경하지 않아도됩니다.

흥미로운 점은 목록을 추적하는 방법과 목록을 반복하는 방법입니다. 척의 테이프에 숫자를 연속해서 저장할 수는 없습니다.리스트 요소 중 하나에서 조건을 확인하려면 유효한 코드를 포함 할 수있는 나머지리스트를 실행할 위험이 있기 때문입니다. 또한 목록의 길이를 모르므로 척의 코드 앞에 약간의 공간을 예약 할 수 없습니다.

다음 문제는 목록을 N처리하는 동안 감소시키기 위해 목록을 남겨 두어야하고 이전과 같은 위치로 돌아 가야한다는 것입니다. 그러나 {}단지 전체 목록 건너 뛸 것입니다.

따라서 Chuck에 코드를 동적으로 작성해야합니다. 실제로 각 목록 요소 i의 형식은 다음과 같습니다.

[1 <Code A> i <Code B>]

1목록 처리를 중단 한 위치를 나타 내기 위해 0으로 설정할 수있는 마커입니다. 그 목적은 잡을 것입니다 {또는 }어느 단지 코드와를 통해 전달합니다 i. 또한이 값을 사용하여 처리 중에 목록의 끝에 있는지 확인하므로 그렇지 않은 동안에는이 값이 적용 1되고 조건부 ?로 제어가 척으로 전환됩니다. Code A이러한 상황을 처리하고 그에 따라 Brian의 IP를 이동시키는 데 사용됩니다.

이제 감소 i할 때 i이미 0 인지 확인해야 합니다. 그렇지 않으면 ?제어를 다시 전환하므로 Code B처리해야합니다.



@cardboard_box 니스!
mbomb007

15

PythonR로 작성된 HPR ( TheNumberOne에 의해 크랙 됨 )

HPR (이름은 무의미 함)은 정수 목록을 처리하기위한 언어입니다. 수 있도록 설계되어 최소한의 , 극히 제한 하고, "인공"제한 무료 . HPR 프로그래밍은 통역사가 소리 지르지 않도록 퍼즐을 풀어야하기 때문에가 아니라 프로그램이 유용한 작업을 수행하기 어렵 기 때문에 고통 스럽습니다. HPR이 목록의 세 번째로 큰 요소를 계산하는 것보다 실질적으로 더 흥미로운 것을 할 수 있는지 여부는 알 수 없습니다.

언어 사양

HPR 프로그램은 환경 에서 실행되며 순서가없는 중복되지 않은 음이 아닌 정수 세트와 음이 아닌 정수 목록입니다. 처음에는 환경에 입력 목록 만 포함되어 있습니다 (인터프리터가 입력 목록을 구문 분석합니다). 환경을 수정하는 세 가지 명령과 두 개의 "제어 흐름"연산자가 있습니다.

  • *비어 있지 않은 모든 목록의 첫 번째 요소를 환경에서 제거하고 환경에 배치합니다. 빈 목록은 영향을받지 않습니다. 예를 들어

    {4,1,[0,2],[1,3],[]} -> {4,1,0,[2],[3],[]}
    
  • -환경의 모든 숫자를 줄인 다음 음수 요소를 제거합니다. 예를 들어

    {4,2,0,[0,2],[4,4,4]} -> {3,1,[0,2],[4,4,4]}
    
  • $환경의 모든 목록을 한 단계 왼쪽으로 회전합니다. 예를 들어

    {4,1,[0,2],[3,4,1]} -> {4,1,[2,0],[4,1,3]}
    
  • !(A)(B), where ABare 프로그램은 기본적으로 while루프입니다. A"test" B가 빈 환경이 될 때까지 "action"을 수행 합니다. 무한 루프가 발생할 수 있습니다.
  • #(A)(B), 프로그램이 있는 곳 A, 현재 환경에 B적용 A되며 B결과의 대칭 적 차이를 취합니다.

명령은 왼쪽에서 오른쪽으로 실행됩니다. 결국 환경의 크기는 단항으로 인쇄됩니다.

통역

이 인터프리터에는 ?환경을 수정하지 않고 인쇄 하는 debug 명령이 있습니다. 작업에 대한 솔루션에는 나타나지 않아야합니다. 이외의 모든 문자 *-$!#()?는 무시되므로 코드에 직접 주석을 작성할 수 있습니다. 마지막으로, 인터프리터는 관용구 !(A)(#(A)())가 " A결과가 더 이상 변하지 않을 때까지 수행"으로 인식하고 추가 속도를 위해 최적화합니다 (마지막 테스트 케이스에서 1 시간 이내에 솔루션을 완료해야했습니다).

import sys

def parse(prog):
    "Parse a prefix of a string into an AST. Return it and the remaining input."
    ret = []
    while prog:
        if prog[0] in "#!":
            sub1, prog1 = parse(prog[2:])
            sub2, prog2 = parse(prog1[1:])
            ret += [prog[0],sub1,sub2]
            prog = prog2
        elif prog[0] == ')':
            prog = prog[1:]
            break
        else:
            ret += [prog[0]]
            prog = prog[1:]
    return ret, prog

def intp(ast, L_env, N_env):
    "Interpret the AST on an environment, return the resulting environment."
    ptr = 0
    while ptr < len(ast):
        cmd = ast[ptr]
        if cmd == '*':
            N_env = N_env | set(L[0] for L in L_env if L)
            L_env = set(L[1:] for L in L_env)
            ptr += 1
        elif cmd == '-':
            N_env = set(N-1 for N in N_env if N>0)
            ptr += 1
        elif cmd == '$':
            L_env = set(L[1:]+L[:1] for L in L_env)
            ptr += 1
        elif cmd == '!':
            # Speed optimization
            cond = ast[ptr+2]
            if cond == ['#', ast[ptr+1], []]:
                L_next, N_next = intp(ast[ptr+1], L_env, N_env)
                while L_next != L_env or N_next != N_env:
                    L_env, N_env = L_next, N_next
                    L_next, N_next = intp(ast[ptr+1], L_env, N_env)
            else:
                while True:
                    L_test, N_test = intp(cond, L_env, N_env)
                    if not L_test and not N_test:
                        break
                    L_env, N_env = intp(ast[ptr+1], L_env, N_env)
            ptr += 3
        elif cmd == '#':
            L_env1, N_env1 = intp(ast[ptr+1], L_env, N_env)
            L_env2, N_env2 = intp(ast[ptr+2], L_env, N_env)
            L_env = L_env1 ^ L_env2
            N_env = N_env1 ^ N_env2
            ptr += 3
        elif cmd == '?':
            print(L_env | N_env)
            ptr += 1
        else:
            ptr += 1
    return L_env, N_env

def main(p, L):
    "Run the program on the input, return the output."
    # Parse the input list
    L = ''.join(c for c in L if c in "01")
    while "00" in L:
        L = L.replace("00","0")
    L = [-2] + [i for i in range(len(L)-1) if L[i:i+2] == "10"]
    L = tuple(b-a-1 for (a,b) in zip(L, L[1:]))
    # Parse the program
    ast = parse(p)[0]
    L_env, N_env = intp(ast, set([L]), set())
    return '1'*(len(L_env) + len(N_env))

if __name__ == "__main__":
    filename = sys.argv[1]
    f = open(filename, 'r')
    prog = f.read()
    f.close()
    L = input()
    print(main(prog, L))

내 솔루션

내 참조 솔루션은 484 바이트 길이이므로 TheNumberOne의 3271 바이트 프로그램과 비교할 때 상당히 짧습니다. HPR 프로그래밍을 위해 개발 된 정교하고 멋진 매크로 시스템 TheNumberOne 때문일 것입니다. 두 프로그램의 주요 아이디어는 비슷합니다.

  1. 목록의 최대 요소를 생성하는 방법을 알아보십시오.
  2. 최대 요소를 제거하려면 첫 번째 요소가 최대 요소와 같아 질 때까지 목록을 회전 한 다음 팝업하십시오.
  3. 최대 값을 두 번 제거한 다음 새 최대 값 요소를 인쇄하십시오.

그러나 내가 알 수있는 한 정확한 구현 세부 사항은 상당히 다릅니다. 내 해결책은 다음과 같습니다.

!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())-#(!(-)(#(-)()))()

그리고 여기에 주석이 달린 파이썬 프로그램이 있습니다 (여기에는 멋진 것이 없으며 모든 반복을 제거하기위한 기본 문자열 조작 만 있습니다).

# No numbers in the environment
no_nums = "#(-)()"
# No non-empty lists in the environment
no_lists = "#(*)()"
# Remove all numbers from the environment
del_nums = "!(-)(" + no_nums + ")"
# Remove all lists from the environment
del_lists = "#(" + del_nums + ")()"
# Splat the list to the environment:
#  pop the list until it's empty and delete the empty list,
#  then take symmetric difference with all numbers removed
splat = "#(!(*)(" + no_lists + ")" + del_lists + ")(" + del_nums + ")"
# Put into the environment all numbers up to list maximum:
#  decrement and splat until a fixed point is reached.
#  Without the speed optimization, this is very slow if the list elements are large.
splat_upto = "!(-" + splat + ")(#(-" + splat + ")())"
# Copy maximum element to environment:
#  take all elements up to maximum,
#  then take symmetric difference of decrement and list deletion
copy_max = splat_upto + "#(-)(" + del_lists + ")"
# Delete maximum element from list:
#  rotate until first element is maximal, then pop and delete it
del_max = "!($)(" + del_nums + "#(" + copy_max + ")(*)" + del_lists + ")*" + del_nums
# Full program:
#  remove the maximum twice, then produce all numbers up to maximum,
#  then decrement and remove lists. The environment will contain exactly
#  the integers from 0 to third largest - 1, and their number is printed.
main = del_max + del_max + splat_upto + "-" + del_lists
print(main)


@TheNumberOne 솔루션을 추가했습니다.
Zgarb

12

TKDYNS (용을 죽이려면 검이 필요)-Martin Büttner에 의해 금이

편집 : 나는 주요 게시물 아래에 솔루션과 설명을 추가했습니다.

배경

이 언어로, 당신은 끔찍한 용을 죽이는 용감한 전사를 통제합니다. 용은 위험과 위험으로 가득한 지하 미로에 살고 있으며, 지금까지 아무도 그것을 찾아 내서 생존 할 수 없었습니다. 이것은 당신을 안내하기 위해 직관과 용기만으로, 암흑의 어둠 속에서 용으로가는 길을 찾아야 함을 의미합니다.

...

글쎄요 일회용 미니언을 거의 무제한으로 가져 왔으며 안전한 길을 찾기 위해 기꺼이 도와 줄 것입니다. 불행히도, 그들은 두 개의 짧은 널빤지만큼 두껍고, 당신이 지시 한대로 만 할 것입니다. 미니언이 올바른 길을 찾도록하는 영리한 방법을 생각해내는 것은 당신에게 달려 있습니다.

더 자세한 내용

용의 은신처는 10x10 격자의 형태를 취합니다. 그리드의 특정 인접 지점 사이에는 좁은 통로가 있습니다. 다른 사람들 사이에는 깊은 틈과 죽음이 있습니다. 4x4 그리드의 레이아웃 예는 다음과 같습니다.

 0---1   2---3
     |   |   |
 4---5---6   7
 |           |
 8   9--10  11
     |       |
12--13--14--15

당신은 한 지점에서 다른 지점으로 갈 수있는 방법이 항상 있다는 것을 알고 있지만 그 이상은 당신에게 공개되지 않았습니다.

드래곤을 성공적으로 물 리치려면 먼저 함께 결합하여 마법의 드래곤 사냥 블레이드를 만들 수있는 아이템을 모아야합니다. 편리하게도,이 무기의 모든 조각들은 용의 은신처에 흩어져 있습니다. 당신은 단순히 그들을 수집해야합니다.

트위스트는 각 무기가 부비 트랩 된 것입니다. 하나를 수집 할 때마다 산책로의 레이아웃이 변경됩니다. 이전의 안전한 길은 이제 특정 사망으로 이어질 수 있으며 그 반대도 마찬가지입니다.

명령

유효한 명령은 5 개뿐입니다.

  • < -왼쪽으로 이동

  • > -오른쪽으로 이동

  • ^ -위로 올라 가세요

  • v -아래로 한 걸음

  • c-현재 위치에 누워있는 물건을 모으십시오. 아이템이 있으면, 레어의 레이아웃이 변경됩니다. 위와 같이 행에 번호가 매겨진 위치로, 위치 모듈로 10을 가져 오십시오. 10 개의 레이아웃이 인터프리터에 하드 코딩되고 레이아웃이 해당 위치로 변경됩니다. 예를 들어 13 번 위치에 있으면 레이아웃이layouts[3]

interpeter에 나타나는 레이아웃은 다음과 같은 방식으로 정수로 인코딩되었습니다.

  • 빈 레이아웃은 0으로 인코딩됩니다.

  • 레이아웃의 각 모서리에 대해 x결합하는 두 위치 중 작은 크기로 설정하십시오.

    • 단계가 수평이면 2^(2*x)인코딩에 추가 하십시오 (XOR이 아닌 power-of 임).

    • 단계가 수직이면 2^(2*x + 1)인코딩에 추가 하십시오.

실행 흐름

인터프리터는 소스 파일 이름을 명령 줄 인수로 사용하여 실행됩니다.

통역사가 실행되면 사용자에게 퀘스트를 제공하라는 메시지가 표시됩니다. 이 입력은 질문에 설명 된 형식이어야하며 무기 구성 요소의 은신처 위치를 결정합니다. 구체적으로, 각각의 입력 정수는 모듈로 (100)로 취해지고, 레어의 대응하는 위치에 배치된다.

각 소스 프로그램은 여러 줄로 구성되며 각 줄은 위의 5 개의 유효한 문자 시퀀스로 구성됩니다. 이 줄은 미니언을 나타냅니다. 전사는 안전하다고 알려진 일련의 동작을 추적합니다. 처음에, 당신은 은신처에 대해 아무것도 모르므 로이 순서는 비어 있습니다. 각 미니언을 차례로 가져 가면 위치 0에서 시작하여 다음이 수행됩니다.

  • 미니언은 알려진 모든 안전 조치를 수행 한 후 자체 코드 행의 조치를 수행하도록 지시받습니다.

    • 미니언이 어느 시점에서 죽으면, 당신은 이것을 통보받으며, 레어는 초기 구성으로 재설정됩니다. 모든 품목이 교체되고 통로가 시작 위치로 돌아갑니다.

    • 대신, 미니언이 살아남 으면 어쨌든 기화합니다. 결국 미니언입니다. 이전과 마찬가지로, 이것은 Lair의 초기 상태로의 재설정을 트리거하지만 이번에는 미니언 코드 라인에서 알려진 동작 순서로 동작을 추가합니다.

모든 미니언이 소진되면 전사는 안전하다고 알려진 모든 행동을 다시 0 번 위치에서 시작하여 수행합니다. 두 가지 가능한 결과가 있습니다.

  • 무기의 모든 조각을 모으십시오.이 경우 드래곤을 성공적으로 죽이고 흥미로운 승리 메시지가 출력됩니다. 이 승리의 메시지는 다른 문자, 중, 포함 n것들, n입력으로 제공되는 가장 높은 세 번째 숫자입니다.

  • 당신은 무기의 일부를 모으지 못했습니다-이 경우, 용은 살아 있으며, 당신은 퀘스트에 실패했습니다.

통역사 코드 (Python 2)

import collections
import copy
import sys

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

class Interpreter(object):

    def __init__(self, source_file):
        self.source_filename = source_file
        self.layout = layouts[0]
        self.position = 0
        self.ingredients = []
        self.quest_items = {}
        self.attempts = collections.deque()

        self.safe_position = 0
        self.safe_ingredients = []
        self.safe_quest_items = {}
        self.safe_layout = layouts[0]

    def get_input(self):
        s = raw_input("Which quest would you like to embark on today?")
        ind = s.find('00')
        s = s[:ind]
        items = map(len, s.split('0'))
        for item in items:
            if item not in self.safe_quest_items:
                self.safe_quest_items[item] = 1
            else:
                self.safe_quest_items[item] += 1

    def parse_attempts(self):
        with open(self.source_filename, 'r') as source:
            for line in source:
                self.attempts.append(line.strip())

    def enc(self, x, y):
        x, y = min(x, y), max(x, y)
        if x < 0:
            return 0
        if y == x + 1:
            return 1 << (2*x)
        elif y == x + size:
            return 1 << (2*x + 1)
        else:
            return 0

    def exec_command(self, char):
        if char == '<':
            if self.enc(self.position, self.position-1) & self.layout:
                self.position -= 1
            else:
                return False
        elif char == '>':
            if self.enc(self.position, self.position+1) & self.layout:
                self.position += 1
            else:
                return False
        elif char == '^':
            if self.enc(self.position, self.position-size) & self.layout:
                self.position -= size
            else:
                return False
        elif char == 'v':
            if self.enc(self.position, self.position+size) & self.layout:
                self.position += size
            else:
                return False
        elif char == 'c':
            for item in xrange(self.position, 10**6, size*size):
                if item in self.quest_items:
                    self.ingredients += ([item] * self.quest_items.pop(item))
                    self.ingredients.sort()
                    self.layout = layouts[self.position % 10]
        else:
            raise ValueError

        return True

    def run_minion(self):
        minion = self.attempts.popleft()
        self.position = self.safe_position
        self.ingredients = copy.copy(self.safe_ingredients)
        self.quest_items = copy.copy(self.safe_quest_items)
        self.layout = self.safe_layout
        dead = False

        for cmd in minion:
            if not self.exec_command(cmd):
                dead = True

        if not dead:
            self.safe_position = self.position
            self.safe_ingredients = copy.copy(self.ingredients)
            self.safe_quest_items = copy.copy(self.quest_items)
            self.safe_layout = self.layout

    def process_minions(self):
        while self.attempts:
            self.run_minion()

    def final_run(self):
        if len(self.safe_quest_items) == 0:
            print "You killed the dragon" + "!!1" * self.safe_ingredients[-3]
        else:
            print "The dragon lives on. Better luck next time..."

    def interpret(self):
        self.get_input()
        self.parse_attempts()
        self.process_minions()
        self.final_run()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Wrong number of arguments"
    else:
        test = Interpreter(sys.argv[1])
        test.interpret()

행운을 빈다, 용감한 전사.

내 해결책과 설명

다음은 문제를 해결하기 위해 소스 코드를 생성하는 Python 스크립트입니다. 흥미롭게도 Martin의 최종 소스 코드는 필자가 작성한 스크립트보다 약 5 배 작습니다. 반면에, 코드를 생성하는 스크립트는 Martin의 Mathematica 프로그램보다 약 15 배 작습니다.

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

def enc(edge):
    x,y = min(edge), max(edge)
    if x < 0:
        return 0
    if y == x + 1:
        return 1 << (2*x)
    elif y == x + size:
        return 1 << (2*x + 1)

def path(x, y, tree):
    stack = [(x,'')]
    while stack[-1][0] != y:
        vertex, path = stack.pop()
        if (enc((vertex, vertex+1))&tree) and ((not path) or path[-1] != '<'):
            stack.append((vertex+1, path+'>'))
        if (enc((vertex, vertex-1))&tree) and ((not path) or path[-1] != '>'):
            stack.append((vertex-1, path+'<'))
        if (enc((vertex, vertex+size))&tree) and ((not path) or path[-1] != '^'):
            stack.append((vertex+size, path+'v'))
        if (enc((vertex, vertex-size))&tree) and ((not path) or path[-1] != 'v'):
            stack.append((vertex-size, path+'^'))
    return stack[-1][1]

def reverse(path):
    rev = ''
    for i in xrange(len(path)-1, -1 ,-1):
        if path[i] == '<':
            rev += '>'
        if path[i] == '>':
            rev += '<'
        if path[i] == 'v':
            rev += '^'
        if path[i] == '^':
            rev += 'v'
    return rev

def assert_at(x, tree):
    path_ul = path(x, 0, tree)
    path_dr = path(x, size*size - 1, tree)
    return path_ul + reverse(path_ul) + path_dr + reverse(path_dr)

def safe_path(x, y, tree):
    return assert_at(x, tree) + path(x, y, tree)

with open('source.txt', 'w') as f:
    for x in xrange(size*size - 1):
        for tree in layouts:
            f.write(safe_path(x, x+1, tree) + 'c\n')

기본 구조

이것은 990 라인의 소스 코드를 생성하는데, 그룹은 10 개 그룹으로 나옵니다. 처음 10 개 라인에는 미니언을 위치에서 위치 0로 이동시키고 1가능한 각 레이아웃마다 한 세트 씩 항목을 수집하는 명령이 들어 있습니다 . 다음 10 줄은 모두 미니언을 위치에서 위치 1로 이동시킨 2다음 아이템을 수집하는 명령을 포함합니다 . 그리고 등등 ...이 경로는 path스크립트 의 함수로 계산됩니다 -그것은 단지 간단한 깊이 우선 검색을 수행합니다.

각 그룹 10 명당 정확히 하나의 미니언이 성공할 수 있다면 문제를 해결할 것입니다.

접근 방식의 문제

예를 들어, 한 위치에서 다른 위치 01이동 하도록 설계된 미니언 은 실수 1로 위치 에서 다른 위치 로 이동 2하는 경우 (레이아웃의 유사성으로 인해) 성공할 수있는 경우가 항상 아닐 수도 있습니다. 잘못 계산하면 전파되어 잠재적으로 오류가 발생할 수 있습니다.

고치는 방법

내가 사용한 수정은 다음과 같습니다.

위치에서 얻으려고 각 미니언의 경우 nn+1첫째, 그 위치에서 도보로 만들 n위치로 0위치에서 다음, 다시 (왼쪽 상단)와 n위치로 99다시 (오른쪽 하단)합니다. 이 지시 사항은 위치에서 안전하게 수행 할 수 있습니다. n다른 시작 위치와 미니언은 가장자리 에서 나옵니다 .

따라서 이러한 추가 지시 사항은 미니언이 의도하지 않은 곳으로 우연히 이동하는 것을 방지하며, 이는 각 그룹 10 명 중 정확히 하나의 미니언이 성공하도록 보장합니다. 반드시 예상되는 미니언은 아닙니다. 레이아웃 0에 있다고 생각하는 미니언은 실제로 레이아웃 7에있을 때에도 성공합니다. 그러나 어쨌든 우리가 가진 사실은 이제 위치가 바뀌 었다는 것은 그룹의 다른 모든 하수인이 반드시 죽을 것이라는 의미입니다. 이 추가 단계는 assert_at함수에 의해 계산되며이 safe_path함수는 추가 단계를 일반 경로와 연결 한 경로를 반환합니다.


1
깨진. 이것은 재미 있었지만 퍼즐을 크래킹하는 것은 실제로 프로그래밍 작업을 해결하는 것과 아무런 관련이 없기 때문에 "프로그래밍 언어는이 한 가지 작업 만 해결하면됩니다"규칙에 문제가 있다고 생각합니다. ;)
Martin Ender

나는이 문제가 존재한다는 것을 알았 기 때문에이 대답을 주로 만들었습니다. 그리고 누군가가 그 대신에 정말로 어려운 계산 문제를 사용하는 것을 막는 것이없는 것 같습니다. '암호화 없음'에 대한 금지는 임의로 좁아 보입니다 ...
Sam Cappleman-Lynes

참된. 이것이 인기 콘테스트 인 이유입니다. 문제가 계산상의 성격이 많고 실제로 사용하기가 어려운 적절한 (잠재적으로 튜링 완료) 언어로 대답하는 것만 큼 많은 투표를하지 않은 경우.
Martin Ender

관심있는 솔루션을 추가했습니다. 또한 관심을 끌기 위해 원래 1000x1000 격자를 사용하여 퍼즐을 디자인했지만 ~ 600000 자릿수로 인코딩 된 레이아웃을 사용하지 않기 위해 작은 크기를 선택했습니다.
Sam Cappleman-Lynes

8

파이어 타입, 마틴 부트

BF와 CJam의 정말 이상한 혼합. 그리고 누가 또 무엇을 알고 있는지! 이것이 쉬운 일이라고 확신하지만 어쨌든 재미있었습니다. 참고로,이 이름은 Final Fantasy Type-0의 Vermillion Fire를 지칭합니다 .

참고 :이 설명의 모호한 점을 용서해주십시오. 난 최고의 작가가 아니야 ... : O

마틴은 이것을 정말 빨리 깨뜨 렸습니다! 이것은 문제를 해결하기위한 원래의 프로그램이었습니다.

_
,
^
~
+
|
|
-
%
+
_
+
=











`
~
+
|
%

_
=

\
@
-
-
!
<
>
>
>

_
+
.
<
-
`
~
~
+
|
|
-
#
%

통사론

Firetype 스크립트는 기본적으로 줄 목록입니다. 각 줄의 첫 번째 문자는 실행할 명령입니다. 빈 줄은 기본적으로 NOP입니다.

의미론

정수 배열과 포인터가 있습니다 (BF를 생각하십시오). 왼쪽 및 오른쪽 또는 "푸시"요소를 배열로 이동할 수 있습니다.

미는

요소를 "푸시"하고 배열의 끝에 있으면 추가 요소가 끝에 추가됩니다. 마지막에 없으면 다음 요소가 무시됩니다. 어쨌든 포인터는 항상 증가합니다.

명령

_

배열에 0을 넣습니다.

+

현재 포인터에서 요소를 증가시킵니다.

-

현재 포인터에서 요소를 줄입니다.

*

현재 포인터에서 요소를 두 배로 만듭니다.

/

현재 포인터에서 요소를 절반으로 줄입니다.

%

현재 포인터에서 요소를 가져 와서 그 많은 행을 앞으로 이동하고 포인터를 왼쪽으로 이동하십시오. 값이 음수이면 대신 뒤로 이동하십시오.

=

현재 포인터에서 요소를 가져와 해당 라인 + 1로 이동합니다. 예를 들어, 현재 요소가 0이면 line으로 이동 1합니다. 포인터를 왼쪽으로 이동합니다.

,

표준 입력에서 문자를 읽고 ASCII 값을 입력하십시오.

^

현재 포인터에서 요소를 가져 와서 문자의 ASCII 값으로 해석하여 정수로 변환하십시오. 예를 들어, 현재 값이 49 (ASCII 값 1) 인 경우 현재 포인터의 요소는 integer로 설정됩니다 1.

.

현재 번호를 화면에 씁니다.

!

현재 포인터에서 요소를 가져 와서 다음 줄을 여러 번 반복하십시오. 포인터를 왼쪽으로 이동합니다.

<

포인터를 왼쪽으로 이동하십시오. 이미 시작한 경우 오류가 발생합니다.

>

포인터를 오른쪽으로 움직입니다. 이미 끝났 으면 오류가 발생합니다.

~

현재 요소가 0이 아니면 0; 그렇지 않으면로 교체하십시오 1.

|

현재 요소를 제곱합니다.

@

현재 요소를 배열의 길이로 설정하십시오.

`

현재 요소를 복제하십시오.

\

포인터 앞뒤에 요소를 정렬하십시오.

#

현재 요소를 무효화하십시오.

통역

Github 에서도 사용 가능 합니다.

#!/usr/bin/env python

# The FireType interpreter.
# Runs under Python 2 and 3.
import sys

class Array(object):
    def __init__(self):
        self.array = []
        self.ptr = 0

    def push_zero(self):
        if self.ptr == len(self.array):
            self.array.append(0)
        else:
            self.array[self.ptr] = 0
        self.ptr += 1

    def left(self):
        self.ptr -= 1
        assert self.ptr >= 0 and self.array, 'pointer underflow (at %d)' % i

    def right(self):
        self.ptr += 1
        assert self.ptr <= len(self.array), 'pointer overflow (at %d)' % i

    def sort(self):
        lhs = self.array[:self.ptr-1]
        rhs = self.array[self.ptr-1:]
        lhs.sort()
        lhs.reverse()
        self.array = lhs + rhs

    def __call__(self, *args):
        args = list(args)
        assert self.array, 'out-of-bounds (at %d)' % i
        if not args:
            return self.array[self.ptr-1]
        self.array[self.ptr-1] = args.pop()
        assert not args

    def __len__(self):
        return len(self.array)

    def __str__(self):
        return 'Array(array=%s, ptr=%s)' % (self.array, self.ptr)

    def __repr__(self):
        return 'Array(array=%r, ptr=%r)' % (self.array, self.ptr)

def execute(lines):
    global i, array
    i = 0
    array = Array()
    rep = 0
    while i < len(lines):
        line = lines[i]
        if not line:
            i += 1
            continue
        line = line[0]
        if line == '_':
            array.push_zero()
        elif line == '+':
            array(array() + 1)
        elif line == '-':
            array(array() - 1)
        elif line == '*':
            array(array() * 2)
        elif line == '/':
            array(int(array() / 2))
        elif line == '%':
            i += array()
            array.left()
        elif line == '=':
            i = array()-1
            array.left()
        elif line == ',':
            array.push_zero()
            array(ord(sys.stdin.read(1)))
        elif line == '.':
            sys.stdout.write(str(array()))
        elif line == '!':
            rep = array()
            array.left()
            i += 1
        elif line == '<':
            array.left()
        elif line == '>':
            array.right()
        elif line == '^':
            array(int(chr(array())))
        elif line == '~':
            array(int(not array()))
        elif line == '|':
            array(array() ** 2)
        elif line == '@':
            array(len(array))
        elif line == '`':
            top = array()
            array.push_zero()
            array(top)
        elif line == '\\':
            array.sort()
        elif line == '#':
            array(-array())

        if rep:
            rep -= 1
        else:
            i += 1

def main(args):
    try:
        _, path = args
    except ValueError:
        sys.exit('usage: %s <file to run, - for stdin>')

    if path == '-':
        data = sys.stdin.read()
    else:
        with open(path) as f:
            data = f.read()

    try:
        execute(data.split('\n'))
    except:
        print('ERROR!')
        print('Array was %r' % array)
        print('Re-raising error...')
        raise

if __name__ == '__main__':
    main(sys.argv)

배열의 하한에 대한 주장은 버그가 있다고 생각합니다. self.ptr-1액세스에 사용 하고 있으므로 확인 self.ptr>0하지 않아야 >=0합니다. (이것은 유효한 프로그램을 무효화하지 말아야하지만 일부 프로그램이 실수로 작동하지 않게 만들 수 있습니다.)
Martin Ender

한가지 더 : 코드는 =값을로 설정 array() - 1하고 문서는 +1?
Martin Ender

깨진. (통역사가 설명이 아니라 규범 적이라고 가정).
Martin Ender

@ MartinBüttner Dang, 생각보다 빠릅니다! : OI는 언급 한 문서 문제를 해결했습니다.
kirbyfan64sos

7

Acc !! (안전한)

빵이야 ...

여기에 이미지 설명을 입력하십시오

... 그리고 잘하면 확실히 더 허점 방지.

나는 이미 Acc! 투기. Acc 는 어떻습니까 ! 다른?

에서 도 Acc! 루프가 종료되면 루프 변수가 범위를 벗어납니다. 루프 내에서만 사용할 수 있습니다. 외부에서는 "이름이 정의되지 않았습니다"라는 오류가 발생합니다. 이 변경 이외에 언어는 동일합니다.

진술

명령은 한 줄씩 구문 분석됩니다. 세 가지 유형의 명령이 있습니다.

  1. Count <var> while <cond>

<var>0 <cond>이 아닌 한 C ++에 해당 하는 한 0부터 계산 합니다 for(int <var>=0; <cond>; <var>++). 루프 카운터는 하나의 소문자 일 수 있습니다. 조건은 루프 변수를 반드시 포함 할 필요는없는 표현식 일 수 있습니다. 조건 값이 0이되면 루프가 정지됩니다.

루프에는 K & R 스타일 중괄호 (특히 Stroustrup 변형 )가 필요합니다.

Count i while i-5 {
 ...
}

위에서 언급했듯이 루프 변수는 루프 내부에서만 사용할 수 있습니다 . 나중에 참조하려고하면 오류가 발생합니다.

  1. Write <charcode>

주어진 ASCII / 유니 코드 값을 가진 단일 문자를 stdout으로 출력합니다. 문자 코드는 모든 표현식이 될 수 있습니다.

  1. 표현

자체적으로 표현 된 표현식은 평가되어 누산기에 다시 할당됩니다 (로 액세스 가능 _). 따라서 예를 들어 3누산기를 3으로 설정하는 설명이 있습니다. _ + 1누산기를 증가시킵니다. 및 _ * N문자를 판독하고, 그 charCode 값으로 어큐뮬레이터를 곱한다.

참고 : 어큐뮬레이터는 직접 할당 할 수있는 유일한 변수입니다. 루프 변수이며 N계산에는 사용할 수 있지만 수정할 수는 없습니다.

누산기는 처음에는 0입니다.

표현

식에는 정수 리터럴, 누산기의 루프 변수 ( a-z) _및 특수 값을 포함 할 수 있습니다.이 값 N은 문자를 읽고 사용할 때마다 문자 코드로 평가합니다. 참고 : 이것은 각 문자를 읽을 수있는 샷을 한 번만 얻는다는 것을 의미합니다. 다음에을 (를) 사용 N하면 다음 내용을 읽게됩니다.

운영자는 다음과 같습니다.

  • +, 추가
  • -뺄셈; 단항 부정
  • *곱셈
  • /정수 나누기
  • %, 모듈로
  • ^, 지수

괄호를 사용하여 작업 우선 순위를 적용 할 수 있습니다. 식의 다른 문자는 구문 오류입니다.

공백과 주석

선행 및 후행 공백과 빈 줄은 무시됩니다. 루프 헤더의 공백은 표시된 것과 정확히 일치해야하며 루프 헤더와 여는 중괄호 사이에 단일 공백이 있어야합니다. 표현식 내부의 공백은 선택 사항입니다.

# 한 줄 주석을 시작합니다.

입출력

Acc !! 한 줄의 문자를 입력으로 예상합니다. 각 입력 문자를 순서대로 검색하고을 사용하여 해당 문자 코드를 처리 할 수 ​​있습니다 N. 줄의 마지막 문자를 지나서 읽으려고하면 오류가 발생합니다. 문자를 Write문 에 전달하여 문자를 출력 할 수 있습니다 .

통역사

인터프리터 (Python 3로 작성)는 Acc !! 파이썬으로 코드하고 execs.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
                pyCode.append(" "*indent + "del " + loopVar)
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()

해결책

원래 Acc 의 몰락 ! 루프 외부에서 계속 액세스 할 수있는 루프 변수였습니다. 이를 통해 어큐뮬레이터의 사본을 저장할 수있어 솔루션이 훨씬 쉬워졌습니다.

이 구멍 이 없어서 (죄송합니다) 물건을 보관할 수있는 어큐뮬레이터 만 있습니다. 그러나이 과제를 해결하려면 임의로 큰 값 4 개를 저장해야합니다. 1 해결책 : 비트를 인터리브하고 결과 조합 번호를 누산기에 저장합니다. 예를 들어, 누산기 값 6437은 다음 데이터를 저장합니다 (최하위 비트를 단일 비트 플래그로 사용).

1100100100101  Binary representation of accumulator
321032103210F  Key

The flag is 1 and the four numbers are
Number 0: 010 = 2
Number 1: 001 = 1
Number 2: 100 = 4
Number 3: 110 = 6

어큐뮬레이터를 2, mod 2의 적절한 거듭 제곱으로 나누어 임의의 수의 비트에 액세스 할 수 있습니다. 또한 개별 비트를 설정하거나 뒤집을 수 있습니다.

매크로 수준에서 알고리즘은 입력의 단수를 반복합니다. 숫자 0으로 값을 읽은 다음 거품 정렬 알고리즘을 통과하여 다른 세 숫자와 비교하여 적절한 위치에 배치합니다. 마지막으로, 숫자 4에 남은 값은 4에서 가장 작고 절대로 3 번째로 클 수 없으므로 버립니다. 루프가 끝나면 1 번이 세 번째로 큰 것이므로 다른 것을 버리고 출력합니다.

가장 어려운 부분 (그리고 첫 번째 화신에 전역 루프 변수가있는 이유)은 두 숫자를 비교하여 스왑 여부를 알고 있기 때문입니다. 두 비트를 비교하기 위해 진리표를 수학적 표현으로 바꿀 수 있습니다. Acc에 대한 나의 돌파구 !! 전역 변수가 없으면 왼쪽에서 오른쪽으로 숫자 비트를 반복 할 수있는 방법이 없기 때문에 하위 비트에서 상위 비트로 진행되는 비교 알고리즘을 찾고있었습니다. 누산기의 최하위 비트는 현재 고려중인 두 숫자를 교환할지 여부를 나타내는 플래그를 저장합니다.

나는 그 Acc! Turing-complete이지만, 그것을 증명하는 데 어려움을 겪고 싶지는 않습니다.

의견이있는 내 솔루션은 다음과 같습니다.

# Read and process numbers until the double 0

Count y while N-48 {
    # Read unary number and store it (as binary) in number 0
    # The above loop header consumed the first 1, so we need to add 1 to number 0

    _ + 2

    # Increment number 0 for each 1 in input until next 0

    Count z while N-48 {
        # In this context, the flag indicates a need to carry; set it to 1
        _ - _%2 + 1

        # While carry flag is set, increment the next bit in line
        Count i while _%2 {
            # Set carry flag to 1 if i'th bit is 1, 0 if it's 0
            # Set i'th bit to 1 if it was 0, 0 if it was 1
            _ - _%2 + _/2^(i*4+1)%2 + (-1)^(_/2^(i*4+1)%2)*2^(i*4+1)
        }
    }

    # Bubble number 0 upwards

    Count n while n-3 {
        # The flag (rightmost bit of accumulator) needs to become 1 if we want to swap
        # numbers (n) and (n+1) and 0 if we don't
        # Iterate over bit-groups of accumulator, RTL
        Count i while _/2^(i*4+1) {
            # Adjust the flag as follows:
            # _/2^(i*4+n+1)%4 is the current bit of number (n+1) followed by the current
            # bit of number (n), a value between 0 and 3
            # - If this quantity is 1 (01), number (n) is bigger so far; set flag to 1
            # - If this quantity is 2 (10), number (n+1) is bigger so far; set flag to 0
            # - If this quantity is 0 (00) or 3 (11), the two bits are the same; keep
            #   current value of flag
            _ + (_/2^(i*4+n+1)%4%3 + 1)/2*(_/2^(i*4+n+1)%4%3%2 - _%2)
        }

        # Now swap the two if the flag is 1
        Count i while (_%2)*(_/2^(i*4+1)) {
            # _/2^(i*4+n+1)%2 is the current bit of number (n)
            # _/2^(i*4+n+2)%2 is the current bit of number (n+1)
            _ - (_/2^(i*4+n+1)%2)*2^(i*4+n+1) - (_/2^(i*4+n+2)%2)*2^(i*4+n+2) + (_/2^(i*4+n+2)%2)*2^(i*4+n+1) + (_/2^(i*4+n+1)%2)*2^(i*4+n+2)
        }
    }

    # Discard number 0, setting it to all zeros for the next iteration
    Count i while _/2^(i*4+1) {
        _ - _/2^(i*4+1)%2*2^(i*4+1)
    }
}

# Once the loop is over, all input has been read and the result is in number 1
# Divide by 2 to get rid of flag bit

_ / 2

# Zero out numbers 2 and 3

Count i while _/2^(i*4) {
    _ - _/2^(i*4+2)%2*2^(i*4+2)
}

Count i while _/2^(i*4) {
    _ - _/2^(i*4+3)%2*2^(i*4+3)
}

# Move bits of number 1 down to their final locations

Count i while _/2^i {
    _ - _/2^(i*4+1)%2*2^(i*4+1) + _/2^(i*4+1)%2*2^i
}

# _ now contains the correct answer in decimal; to output in unary:

Count z while z-_ {
    Write 49
}

1 질문 사양에 따르면 최대 백만 개의 값만 지원하면됩니다. 나는 당신이 비교를 어떻게 할 것인지 완전히 확신하지는 않지만 더 쉬운 해결책을 위해 아무도 그것을 활용하지 않았기 때문에 기쁘다.


LOL @ 빌 고양이 사진
spaghetto

7

Picofuck (안전)

Picofuck과 유사한 Smallfuck . 이진 테이프에서 작동하며 오른쪽에는 바인딩되어 있고 왼쪽에는 바인딩되어 있습니다. 다음과 같은 명령이 있습니다.

  • > 포인터를 오른쪽으로 이동

  • <포인터를 왼쪽으로 이동하십시오. 포인터가 테이프에서 떨어지면 프로그램이 종료됩니다.

  • * 포인터에서 비트를 뒤집다

  • (포인터의 비트가 0인 경우 다음으로 이동)

  • )Picofuck의 괄호는 루프가 if아니라 블록 while입니다.

  • .포인터의 비트를 아스키 0또는 로 stdout에 쓰십시오 1.

  • ,우리가 만날 때까지 표준 입력에서 읽을 0또는 1, 포인터의 비트에이를 저장합니다.

Picofuck 코드 랩-프로그램의 끝에 도달하면 처음부터 계속됩니다.

또한 Picofuck은 중첩 괄호를 허용하지 않습니다. 교대로해야 Picofuck 프로그램에 나오는 괄호 ()함께 시작 (하고 끝나는 ).

통역사

파이썬 2.7로 작성

용법: python picofuck.py <source_file>

import sys

def interpret(code):
    # Ensure parentheses match and are not nested.
    in_if_block = False
    for c in code:
        if c == '(':
            if in_if_block:
                print "NESTED IFS DETECTED!!!!!"
                return
            in_if_block = True
        elif c == ')':
            if not in_if_block:
                print "Unmatched parenthesis"
                return
            in_if_block = False
    if in_if_block:
        print "Unmatched parenthesis"
        return


    code_ptr = 0
    array = [0]
    ptr = 0

    while 1:
        command = code[code_ptr]
        if command == '<':
            if ptr == 0:
                break
            ptr -= 1
        elif command == '>':
            ptr += 1
            if ptr == len(array):
                array.append(0)
        elif command == '*':
            array[ptr] = 1-array[ptr]
        elif command == '(':
            if array[ptr] == 0:
                while code[code_ptr] != ')':
                    code_ptr = (code_ptr + 1) % len(code)
        elif command == ',':
            while True:
                c = sys.stdin.read(1)
                if c in ['0','1']:
                    array[ptr] = int(c)
                    break
        elif command == '.':
            sys.stdout.write(str(array[ptr]))
        code_ptr = (code_ptr+1)%len(code)

if __name__ == "__main__":
    with open(sys.argv[1]) as source_file:
        code = source_file.read()
    interpret(code)

해결책

다음 python 2.7 프로그램은 여기 에서 찾을 수있는 솔루션을 출력 합니다.

이 게시물이 어떻게 작동하는지에 대한 자세한 설명으로 나중에이 게시물을 편집 할 수는 있지만 Picofuck은 Turing-complete입니다.

states = {
    "SETUP":(
        "*>",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "GET_NUMBER":(
        ",",
        "CHANGE_A",
        "PREPARE_PRINT_C"
    ),

    "GET_DIGIT":(
        ",",
        "CHANGE_A",
        "GOT_DIGIT"
    ),

    "GOT_DIGIT":(
        ">>>>",
        "GO_BACK",
        "GO_BACK"
    ),

    "CHANGE_A":(
        ">",
        "CHANGE_B",
        "SET_A"
    ),

    "SET_A":(
        "*>>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_B":(
        ">",
        "CHANGE_C",
        "SET_B"
    ),

    "SET_B":(
        "*>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_C":(
        ">",
        "CONTINUE_GET_NUMBER",
        "SET_C"
    ),

    "SET_C":(
        "*>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CONTINUE_GET_NUMBER":(
        ">>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "GO_BACK":(
        "<<<<<",
        "FINISH_GO_BACK",
        "GO_BACK"
    ),

    "FINISH_GO_BACK":(
        ">",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "PREPARE_PRINT_C":(
        ">>>",
        "PRINT_C",
        "PRINT_C"
    ),

    "PRINT_C":(
        ".>>>>>",
        "PRINT_C",
        "TERMINATE"
    ),

    "TERMINATE":(
        "<",
        "TERMINATE",
        "TERMINATE"
    ),
}

def states_to_nanofuck(states,start_state):
    state_list = list(states)
    state_list.remove(start_state)
    state_list.insert(0,start_state)

    states_by_index = []
    for i,state in enumerate(state_list):
        commands, next1, next0 = states[state]
        states_by_index.append((commands,state_list.index(next1),state_list.index(next0)))


    # setup first state
    fragments = ['*(*>>>>>*<<<<<)>>>>>']

    # reset states that don't match
    for index in range(len(states_by_index)):
        for bool in range(2):
            # at state_0_0
            state_dist = index*3 + bool
            # move state to curstate
            fragments.append('>'*state_dist)
            fragments.append('(*')
            fragments.append(  '<'*state_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*state_dist)
            fragments.append(')')
            fragments.append('<'*state_dist)

            # go to arr
            fragments.append('<<<')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # compute match = arr & curstate
            fragments.append('(>)(>*<)<(<)>')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # reset curstate
            fragments.append('>(*)')

            # move match to matchstate, go back to state_0_0
            matchstate_dist = index*3 + 2
            fragments.append('>(*>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(  '*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append('<)>')

    #fragments.append('|')

    # do the commands of the matching state
    for index,state in enumerate(states_by_index):
        for bool in range(2):
            # at state_0_0
            matchstate_dist = index*3 + 2
            # move matchstate to curstate
            fragments.append('>'*matchstate_dist)
            fragments.append('(*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(')')
            fragments.append('<'*matchstate_dist)

            # if curstate, reset curstate
            fragments.append('<<(*')

            # go to arr
            fragments.append('<')

            # do commands
            commands,next1,next0 = state
            for c in commands:
                if c in '<>':
                    fragments.append(c*(3*len(states_by_index)+5))
                else:
                    fragments.append(c)

            # go to state_0_0
            fragments.append('>>>')

            # set next states
            for dist in [next0*3, next1*3+1]:
                fragments.append('>'*dist)
                fragments.append('*')
                fragments.append('<'*dist)

            # go to curstate
            fragments.append('<<')

            # end if
            fragments.append(')')

            # go to state_0_0
            fragments.append('>>')


    # go back to setup and set it
    fragments.append('<<<<<*')

    code = ''.join(fragments)

    return code



print states_to_nanofuck(states, "SETUP")

2
거의 2 년을 기다립니다. 아직입니까?
CalculatorFeline

참고로, 당신이 제공 한 링크가 이제 죽었습니다. '
Conor O'Brien

링크 다운로드가 필요하고 너무 게으르다. 수정하십시오.
CalculatorFeline

@CalculatorFeline 13KB이므로 다운로드로 처리하기가 훨씬 쉽습니다.
mbomb007

7

PQRS – 안전합니다! / 솔루션 제공

기초

모든 암시 적 명령어에는 4 개의 메모리 주소 피연산자가 있습니다.

P₀ Q₀ R₀ S₀
P₁ Q₁ R₁ S₁
...
Pᵥ₋₁ Qᵥ₋₁ Rᵥ₋₁ Sᵥ₋₁

v4 중 메모리 크기는 어디에 있습니까 ?

Pᵢ, Qᵢ, Rᵢ, Sᵢ컴퓨터의 기본 크기는 정수 서명 (예 : 16, 32 또는 64 비트) 우리가 단어라고 부르는 것입니다.

각 사중 수 i에 대해 암시 적 연산 []은 간접적 의미로 다음과 같습니다.

if (([Pᵢ] ← [Qᵢ] − [Rᵢ]) ≤ 0) go to Sᵢ else go to Pᵢ₊₁

참고 Subleq이 의 하위 집합입니다 PQRS .

Subleq는 완료된 것으로 입증되었으므로 PQRS 도 완료되어야합니다!

프로그램 구조

PQRS 는 다음과 같이 초기 헤더를 정의합니다.

H₀ H₁ H₂ H₃ H₄ H₅ H₆ H₇

H₀ H₁ H₂ H₃항상 첫 번째 명령 P₀ Q₀ R₀ S₀입니다. H₀하는 H₃로드시에 정의 될 필요가있다.

PQRS 에는 기본적인 I / O가 있지만 문제를 해결하기에 충분합니다.

H₄ H₅: 프로그램 시작시 H₅표준 입력에서 최대 ASCII 문자를 읽고 색인에서 단어로 저장 H₄합니다. H₄H₅로드시에 정의 될 필요가있다. 읽은 후에는 읽은 H₅문자 수 및 저장된 단어 수로 설정됩니다.

H₆ H₇: 프로그램 종료시 index에서 시작 H₆하여 H₇단어를 포함하는 모든 바이트 를 표준 출력에 ASCII 문자로 인쇄합니다 . H₆그리고 H₇프로그램이 종료되기 전에 정의 될 필요가있다. '\0'출력의 널 바이트 는 건너 뜁니다.

종료

종료를 설정하여 달성되는 Sᵢ범위를 벗어 i < 0i ≥ v.

트릭

쿼트 Pᵢ Qᵢ Rᵢ Sᵢ는 정렬되거나 순차적 일 필요가 없으며 분기는 서브 쿼트 간격으로 허용됩니다.

PQRS 는 간접 성을 가지므로 Subleq와 달리 서브 루틴을 구현하기에 충분한 유연성이 있습니다.

코드는 스스로 수정 될 수 있습니다!

통역사

통역사는 C로 작성되었습니다.

#include <stdlib.h>
#include <stdio.h>

// The "architecture"
enum {P, Q, R, S, START_OF_INPUT, LENGTH_OF_INPUT, START_OF_OUTPUT, LENGTH_OF_OUTPUT};
const int NEXT = S + 1;

// Recommend optimized!
#define OPTIMIZED

#ifdef PER_SPECS
// This may not work on all OSes and architectures - just too much memory needed!
const int K = 1002000200;
#else // OPTIMIZED
// This provides enough space to run the test cases with challenge-optimized.pqrs
const int K = 5200;
#endif

int main(int argc, char *argv[])
{
    int i, *M;
    char *p;
    FILE *program;

    // Allocate enough memory
    M = calloc(K, sizeof(int));

    // Load the program
    for (i = 0, program = fopen(argv[1], "r"); i < K && !feof(program); i++)
        if (!fscanf(program, "%d", M + i))
            break;
    fclose(program);

    // Read in the input
    for (i = 0; i < M[LENGTH_OF_INPUT] && !feof(stdin); i++)
    {
        int c = fgetc(stdin);
        if (c != EOF)
            M[M[START_OF_INPUT] + i] = c;
        else
            break;
    }
    M[LENGTH_OF_INPUT] = i;

    // Execute until terminated
    for (i = 0; i >= 0 && i < K; )
        i = (M[M[P + i]] = M[M[Q + i]] - M[M[R + i]]) <= 0? M[S + i]: i + NEXT;

    // Write the output
    for (i = 0, p = (char *)(M + M[START_OF_OUTPUT]); i < M[LENGTH_OF_OUTPUT] * sizeof(int); i++)
        // Ignore '\0'
        if (p[i])
            fputc(p[i], stdout);

    // Done
    free(M);

    return 0;
}

사용하려면 위를 pqrs.c로 저장 한 다음 컴파일하십시오.

gcc -o pqrs pqrs.c

샘플 프로그램

에코는 'PQRS-'앞에 40 문자까지 입력됩니다.

8 8 8 -1 14 40 9 45 0 80 81 82 83 45

실행하려면 위와 같이 저장 echo.pqrs한 다음 :

$ ./prqs echo.pqrs
greetings[enter]
[ctrl-D]
PQRS-greetings

테스트 케이스 실행

$ ./pqrs challenge-optimized.pqrs < test-1.txt
1

$ ./pqrs challenge-optimized.pqrs < test-2.txt
11111111111111111

$ ./pqrs challenge-optimized.pqrs < test-3.txt
[lots of ones!]

$ ./pqrs challenge-optimized.pqrs < test-3.txt | wc
0       1     773

모든 테스트 사례는 매우 빠르게 실행됩니다 (예 : 500ms 미만).

도전

PQRS 는 안정적으로 간주 될 수 있으므로 2015-10-31 13:00에 시작하여 2015-11-08 13:00 (UTC)으로 종료됩니다.

행운을 빕니다!

해결책

이 언어는 세계 최초의 저장 프로그램 전자 디지털 기기 인 "Baby" 에서 사용되는 언어와 매우 유사 합니다. 이 페이지에는 32 워드 미만의 (CRT!) 메모리에서 정수의 최고 요소를 찾는 프로그램이 있습니다!

사양에 맞는 솔루션을 작성하는 것이 OS와 호환되지 않는 것으로 나타났습니다. 사용 가능한 것보다 많은 메모리와 코어 덤프를 요청했습니다. 고급 가상 메모리 관리 기능이있는 OS 또는 메모리가 8GB 이상인 시스템에서는 사양에 따라 솔루션을 실행할 수 있습니다. 두 솔루션을 모두 제공했습니다.

PQRS로 직접 코드 를 작성하는 것은 기계 언어 작성, 마이크로 코드 작성과 유사합니다. 대신 일종의 어셈블리 언어로 작성하고 "컴파일"하는 것이 더 쉽습니다. 다음은 테스트 사례를 실행하도록 최적화 된 솔루션에 대한 주석이 달린 어셈블리 언어입니다.

; ANNOTATED PQRS ASSEMBLER CODE
; MINIMAL SIZED BUFFERS TO RUN THE TEST CASES

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       4000        
6         L0:         OUTPUT      1000        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10]

; I/O SPACE
152       INPUT:      [4000]
4152      OUTPUT:     [1000]
5152

그것이하는 일은 입력을 구문 분석하고 단항을 이진수로 변환 한 다음 값이 감소하는 순서로 숫자를 거품 정렬 한 다음 이진수를 단항으로 다시 변환하여 세 번째로 큰 값을 출력하는 것입니다.

참고 INC(증가)이 음수와 DEC(감소)이 긍정적입니다! L#또는 L#+1as P-또는 Q-OPs를 사용 하는 경우 진행중인 것은 포인터를 업데이트하고 있다는 것입니다. 증가, 감소, 교환 등 어셈블러는 레이블을 오프셋으로 대체하여 PQRS 에 수작업으로 컴파일되었습니다 . 다음은 PQRS 최적화 솔루션입니다.

137 132 132 8
152 4000
4152 1000
137 152 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
4152 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

위의 코드 challenge-optimized.pqrs는 테스트 사례를 실행하기 위해 저장할 수 있습니다 .

완전성을 위해 다음은 사양 별 소스입니다.

; ANNOTATED PQRS ASSEMBLER CODE
; FULL SIZED BUFFERS TO RUN ACCORDING TO SPECS

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       10^9        
6         L0:         OUTPUT      10^6        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10^6]

; I/O SPACE
1000142   INPUT:      [10^9]
1001000142 OUTPUT:    [10^6]
1002000142

그리고 해결책 :

137 132 132 8
1000142 1000000000
1001000142 1000000
137 1000142 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
1001000142 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

위를 실행하려면 주석 처리 #define OPTIMIZED하고 추가 #define PER_SPECSpqrs.c후 다시 컴파일해야합니다.

이것은 큰 도전이었다 – 정신 운동을 정말로 즐겼다! 예전 6502 어셈블러 시절로 돌아 왔습니다 ...

PQRS 를“실제”프로그래밍 언어로 구현 한다면 분기에 대한 간접 액세스 옵션과 함께 간접 액세스뿐만 아니라 위치 상대 및 위치 절대뿐만 아니라 직접 및 이중 간접 액세스를위한 추가 모드를 추가 할 것입니다!


3
게시하기 전에 솔루션을 준비해야합니다.
feersum

1
예, 솔루션이 준비되었습니다. 언어가 실제로 작업하기가 매우 어렵 기 때문에 의심의 여지가 있음을 이해합니다. 몰래 미리보기를 원하는 사람들에게는 도전이 끝나기 전에 공개하지 않겠다고 약속하면 보내드릴 수 있습니다!

6

아연, 금이 간! 에 의해 @Zgarb

GitHub 에서도 사용 가능 합니다.

다트 1.12와 펍이 필요합니다. 단지 pub get의존성, 구문 분석 라이브러리를 다운로드하기 위해 실행 하십시오.

여기에 30 분 이상 지속되기를 바라고 있습니다! :영형

언어

아연은 재정의 연산자를 지향합니다. 언어의 모든 연산자를 쉽게 재정의 할 수 있습니다!

전형적인 아연 프로그램의 구조는 다음과 같습니다 :

let
<operator overrides>
in <expression>

정수와 세트의 두 가지 데이터 유형 만 있습니다. 집합 리터럴과 같은 것은 없으며 빈 집합은 허용되지 않습니다.

표현

다음은 아연에서 유효한 표현식입니다.

리터럴

Zinc는 1and 같은 모든 일반 정수 리터럴을 지원합니다 -2.

변수

아연에는 대부분의 언어와 같은 변수가 있습니다. 참조하려면 이름을 사용하십시오. 대부분의 언어를 다시 한 번!

그러나 SPyth 's와 비슷한 종류의 특수 변수 가 Q있습니다. 처음 사용할 때는 표준 입력에서 한 줄로 읽어서 일련의 숫자로 해석합니다. 예를 들어, 입력 라인 1234231이 세트로 바뀝니다 {1, 2, 3, 4, 3, 2, 1}.

중요 사항!!! 경우에 따라 연산자 재정의 끝에있는 리터럴이 잘못 구문 분석되어 괄호로 묶어야합니다.

이진 연산

다음과 같은 이진 연산이 지원됩니다.

  • 를 통한 추가 +: 1+1.
  • 을 통한 빼기 -: 1-1.
  • 를 통한 곱셈 *: 2*2.
  • 를 통해 나누기 /: 4/2.
  • 와 평등 =: 3=3.

또한 다음 단항 작업도 지원됩니다.

  • 길이 #: #x.

우선 순위는 항상 오른쪽 연관입니다. 괄호를 사용하여이를 무시할 수 있습니다.

세트에서 동등성과 길이 만 작동합니다. 정수의 길이를 얻으려고하면 문자열 표현에서 자릿수를 얻습니다.

이해력 설정

세트를 조작하기 위해 아연은 이해력을 설정했습니다. 그들은 다음과 같이 보입니다 :

{<variable>:<set><clause>}

절은 when 절 또는 정렬 절입니다.

때 절 처럼 보인다 ^<expression>. 캐럿 다음의 표현식은 정수 여야합니다. when 절을 사용하면 집합에서 expression0이 아닌 요소 만 가져옵니다 . 표현식 내에서 변수 _는 세트의 현재 색인으로 설정됩니다. 이 Python과 대략 동일합니다.

[<variable> for _, <variable> in enumerate(<set>) when <expression> != 0]

정렬 절 처럼 보이는 $<expression>, 값으로 내림차순 세트를 정렬합니다 <expression>. 이 파이썬과 같습니다 :

sorted(<set>, key=lambda <variable>: <expression>)[::-1]

다음은 몇 가지 이해 예제입니다.

  • s5와 같은 세트의 요소 만 취하십시오 .

    {x:s^x=5}
    
  • s요소가 제곱 인 경우 값을 기준으로 세트 를 정렬하십시오 .

    {x:s$x*x}
    

재정의

연산자 재정의를 사용하면 연산자를 재정의 할 수 있습니다. 그들은 다음과 같이 보입니다 :

<operator>=<operator>

또는:

<variable><operator><variable>=<expression>

첫 번째 경우 다른 연산자와 같도록 연산자를 정의 할 수 있습니다. 예를 들어, +실제로 다음 을 통해 빼도록 정의 할 수 있습니다 .

+=-

이렇게하면 연산자를 마술 연산자 로 재정의 할 수 있습니다 . 두 가지 마법 연산자가 있습니다.

  • join집합과 정수를 가져 와서 집합의 내용을 결합합니다. 예를 들어, 가입 {1, 2, 3}과 함께하는 4정수가 발생합니다 14243.

  • cut또한 세트와 정수를 가져 와서 정수가 발생할 때마다 세트를 분할합니다. 사용 cut{1, 3, 9, 4, 3, 2}3생성합니다 {{1}, {9, 4}, {2}}...하지만 결과가 실제로 할 수 있도록 단일 요소 세트는, 평평하고 있습니다 {1, {9, 4}, 2}.

다음은 +연산자를 의미 하도록 재정의하는 예입니다 join.

+=join

후자의 경우 연산자를 주어진 식으로 재정의 할 수 있습니다. 예를 들어, 더하기 연산을 정의하여 값을 추가 한 다음 1을 추가합니다.

x+y=1+:x+:y

그러나 무엇 +:입니까? :항상 내장 버전을 사용하도록 콜론 을 연산자에 추가 할 수 있습니다 . 이 예제에서는 내장 +비아 +:를 사용하여 숫자를 더한 다음 1을 추가합니다 (모든 것이 오른쪽 연관임을 기억하십시오).

길이 연산자를 재정의하면 다음과 같습니다.

#x=<expression>

거의 모든 내장 연산 (동일성 제외)은이 길이 연산자를 사용하여 세트의 길이를 결정합니다. 정의한 경우 :

#x=1

세트에서 작동하는 아연의 모든 부분 =은 주어진 세트의 첫 번째 요소에서만 작동합니다.

여러 번 재정의

쉼표로 구분하여 여러 연산자를 재정의 할 수 있습니다.

let
+=-,
*=/
in 1+2*3

인쇄

아연에는 어떤 것도 직접 인쇄 할 수 없습니다. 다음 식의 결과 in가 인쇄됩니다. 세트의 값은 구분 기호와 연결됩니다. 예를 들어 다음을 수행하십시오.

let
...
in expr

경우 expr집합입니다 {1, 3, {2, 4}}, 1324프로그램이 완료되면 화면에 인쇄됩니다.

함께 모아서

다음은 간단한 아연 프로그램으로 추가 2+2되었지만 결과는 5입니다.

let
x+y=1+:x+:y
in 1+2

통역

이것은 들어갑니다 bin/zinc.dart:

import 'package:parsers/parsers.dart';
import 'dart:io';

// An error.
class Error implements Exception {
  String cause;
  Error(this.cause);
  String toString() => 'error in Zinc script: $cause';
}


// AST.
class Node {
  Obj interpret(ZincInterpreter interp) => null;
}

// Identifier.
class Id extends Node {
  final String id;
  Id(this.id);
  String toString() => 'Id($id)';
  Obj interpret(ZincInterpreter interp) => interp.getv(id);
}

// Integer literal.
class IntLiteral extends Node {
  final int value;
  IntLiteral(this.value);
  String toString() => 'IntLiteral($value)';
  Obj interpret(ZincInterpreter interp) => new IntObj(value);
}

// Any kind of operator.
class Anyop extends Node {
  void set(ZincInterpreter interp, OpFuncType func) {}
}

// Operator.
class Op extends Anyop {
  final String op;
  final bool orig;
  Op(this.op, [this.orig = false]);
  String toString() => 'Op($op, $orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0[op] : interp.op1[op];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1[op] = func; }
}

// Unary operator (len).
class Lenop extends Anyop {
  final bool orig;
  Lenop([this.orig = false]);
  String toString() => 'Lenop($orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0['#'] : interp.op1['#'];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1['#'] = func; }
}

// Magic operator.
class Magicop extends Anyop {
  final String op;
  Magicop(this.op);
  String toString() => 'Magicop($op)';
  Obj interpret_with(ZincInterpreter interp, Obj x, Obj y) {
    if (op == 'cut') {
      if (y is! IntObj) { throw new Error('cannot cut int with non-int'); }
      if (x is IntObj) {
        return new SetObj(x.value.toString().split(y.value.toString()).map(
          int.parse));
      } else {
        assert(x is SetObj);
        List<List<Obj>> res = [[]];
        for (Obj obj in x.vals(interp)) {
          if (obj == y) { res.add([]); }
          else { res.last.add(obj); }
        }
        return new SetObj(new List.from(res.map((l) =>
          l.length == 1 ? l[0] : new SetObj(l))));
      }
    } else if (op == 'join') {
      if (x is! SetObj) { throw new Error('can only join set'); }
      if (y is! IntObj) { throw new Error('can only join set with int'); }
      String res = '';
      for (Obj obj in x.vals(interp)) {
        if (obj is! IntObj) { throw new Error('joining set must contain ints'); }
        res += obj.value.toString();
      }
      return new IntObj(int.parse(res));
    }
  }
}

// Unary operator (len) expression.
class Len extends Node {
  final Lenop op;
  final Node value;
  Len(this.op, this.value);
  String toString() => 'Len($op, $value)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, value.interpret(interp), null);
}

// Binary operator expression.
class Binop extends Node {
  final Node lhs, rhs;
  final Op op;
  Binop(this.lhs, this.op, this.rhs);
  String toString() => 'Binop($lhs, $op, $rhs)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, lhs.interpret(interp), rhs.interpret(interp));
}

// Clause.
enum ClauseKind { Where, Sort }
class Clause extends Node {
  final ClauseKind kind;
  final Node expr;
  Clause(this.kind, this.expr);
  String toString() => 'Clause($kind, $expr)';
  Obj interpret_with(ZincInterpreter interp, SetObj set, Id id) {
    List<Obj> res = [];
    List<Obj> values = set.vals(interp);
    switch (kind) {
    case ClauseKind.Where:
      for (int i=0; i<values.length; i++) {
        Obj obj = values[i];
        interp.push_scope();
        interp.setv(id.id, obj);
        interp.setv('_', new IntObj(i));
        Obj x = expr.interpret(interp);
        interp.pop_scope();
        if (x is IntObj) {
          if (x.value != 0) { res.add(obj); }
        } else { throw new Error('where clause condition must be an integer'); }
      }
      break;
    case ClauseKind.Sort:
      res = values;
      res.sort((x, y) {
        interp.push_scope();
        interp.setv(id.id, x);
        Obj x_by = expr.interpret(interp);
        interp.setv(id.id, y);
        Obj y_by = expr.interpret(interp);
        interp.pop_scope();
        if (x_by is IntObj && y_by is IntObj) {
          return x_by.value.compareTo(y_by.value);
        } else { throw new Error('sort clause result must be an integer'); }
      });
      break;
    }
    return new SetObj(new List.from(res.reversed));
  }
}

// Set comprehension.
class SetComp extends Node {
  final Id id;
  final Node set;
  final Clause clause;
  SetComp(this.id, this.set, this.clause);
  String toString() => 'SetComp($id, $set, $clause)';
  Obj interpret(ZincInterpreter interp) {
    Obj setobj = set.interpret(interp);
    if (setobj is SetObj) {
      return clause.interpret_with(interp, setobj, id);
    } else { throw new Error('set comprehension rhs must be set type'); }
  }
}

// Operator rewrite.
class OpRewrite extends Node {
  final Anyop op;
  final Node value;
  final Id lid, rid; // Can be null!
  OpRewrite(this.op, this.value, [this.lid, this.rid]);
  String toString() => 'OpRewrite($lid, $op, $rid, $value)';
  Obj interpret(ZincInterpreter interp) {
    if (lid != null) {
      // Not bare.
      op.set(interp, (interp,x,y) {
        interp.push_scope();
        interp.setv(lid.id, x);
        if (rid == null) { assert(y == null); }
        else { interp.setv(rid.id, y); }
        Obj res = value.interpret(interp);
        interp.pop_scope();
        return res;
      });
    } else {
      // Bare.
      if (value is Magicop) {
        op.set(interp, (interp,x,y) => value.interpret_with(interp, x, y));
      } else {
        op.set(interp, (interp,x,y) => (value as Anyop).get(interp)(x, y));
      }
    }
    return null;
  }
}

class Program extends Node {
  final List<OpRewrite> rws;
  final Node expr;
  Program(this.rws, this.expr);
  String toString() => 'Program($rws, $expr)';
  Obj interpret(ZincInterpreter interp) {
    rws.forEach((n) => n.interpret(interp));
    return expr.interpret(interp);
  }
}


// Runtime objects.
typedef Obj OpFuncType(ZincInterpreter interp, Obj x, Obj y);

class Obj {}

class IntObj extends Obj {
  final int value;
  IntObj(this.value);
  String toString() => 'IntObj($value)';
  bool operator==(Obj rhs) => rhs is IntObj && value == rhs.value;
  String dump() => value.toString();
}

class SetObj extends Obj {
  final List<Obj> values;
  SetObj(this.values) {
    if (values.length == 0) { throw new Error('set cannot be empty'); }
  }
  String toString() => 'SetObj($values)';
  bool operator==(Obj rhs) => rhs is SetObj && values == rhs.values;
  String dump() => values.map((x) => x.dump()).reduce((x,y) => x+y);
  List<Obj> vals(ZincInterpreter interp) {
    Obj lenobj = interp.op1['#'](interp, this, null);
    int len;
    if (lenobj is! IntObj) { throw new Error('# operator must return an int'); }
    len = lenobj.value;
    if (len < 0) { throw new Error('result of # operator must be positive'); }
    return new List<Obj>.from(values.getRange(0, len));
  }
}


// Parser.
class ZincParser extends LanguageParsers {
  ZincParser(): super(reservedNames: ['let', 'in', 'join', 'cut']);
  get start => prog().between(spaces, eof);
  get comma => char(',') < spaces;
  get lp => symbol('(');
  get rp => symbol(')');
  get lb => symbol('{');
  get rb => symbol('}');
  get colon => symbol(':');
  get plus => symbol('+');
  get minus => symbol('-');
  get star => symbol('*');
  get slash => symbol('/');
  get eq => symbol('=');
  get len => symbol('#');
  get in_ => char(':');
  get where => char('^');
  get sort => char('\$');

  prog() => reserved['let'] + oprw().sepBy(comma) + reserved['in'] + expr() ^
            (_1,o,_2,x) => new Program(o,x);
  oprw() => oprw1() | oprw2() | oprw3();
  oprw1() => (basicop() | lenop()) + eq + (magicop() | op()) ^
             (o,_,r) => new OpRewrite(o,r);
  oprw2() => (id() + op() + id()).list + eq + expr() ^
             (l,_,x) => new OpRewrite(l[1], x, l[0], l[2]);
  oprw3() => lenop() + id() + eq + expr() ^ (o,a,_,x) => new OpRewrite(o, x, a);
  magicop() => (reserved['join'] | reserved['cut']) ^ (s) => new Magicop(s);
  basicop() => (plus | minus | star | slash | eq) ^ (op) => new Op(op);
  op() => (basicop() + colon ^ (op,_) => new Op(op.op, true)) | basicop();
  lenop() => (len + colon ^ (_1,_2) => new Lenop(true)) |
             len ^ (_) => new Lenop();
  expr() => setcomp() | unop() | binop() | prim();
  setcomp() => lb + id() + in_ + rec(expr) + clause() + rb ^
               (_1,i,_2,x,c,_3) => new SetComp(i,x,c);
  clausekind() => (where ^ (_) => ClauseKind.Where) |
                  (sort  ^ (_) => ClauseKind.Sort);
  clause() => clausekind() + rec(expr) ^ (k,x) => new Clause(k,x);
  unop() => lenop() + rec(expr) ^ (o,x) => new Len(o,x);
  binop() => prim() + op() + rec(expr) ^ (l,o,r) => new Binop(l,o,r);
  prim() => id() | intlit() | parens(rec(expr));
  id() => identifier ^ (i) => new Id(i);
  intlit() => intLiteral ^ (i) => new IntLiteral(i);
}


// Interpreter.
class ZincInterpreter {
  Map<String, OpFuncType> op0, op1;
  List<Map<String, Obj>> scopes;
  ZincInterpreter() {
    var beInt = (v) {
      if (v is IntObj) { return v.value; }
      else { throw new Error('argument to binary operator must be integer'); }
    };
    op0 = {
      '+': (_,x,y) => new IntObj(beInt(x)+beInt(y)),
      '-': (_,x,y) => new IntObj(beInt(x)-beInt(y)),
      '*': (_,x,y) => new IntObj(beInt(x)*beInt(y)),
      '/': (_,x,y) => new IntObj(beInt(x)/beInt(y)),
      '=': (_,x,y) => new IntObj(x == y ? 1 : 0),
      '#': (i,x,_2) =>
        new IntObj(x is IntObj ? x.value.toString().length : x.values.length)
    };
    op1 = new Map<String, OpFuncType>.from(op0);
    scopes = [{}];
  }

  void push_scope() { scopes.add({}); }
  void pop_scope() { scopes.removeLast(); }
  void setv(String name, Obj value) { scopes[scopes.length-1][name] = value; }
  Obj getv(String name) {
    for (var scope in scopes.reversed) {
      if (scope[name] != null) { return scope[name]; }
    }
    if (name == 'S') {
      var input = stdin.readLineSync() ?? '';
      var list = new List.from(input.codeUnits.map((c) =>
        new IntObj(int.parse(new String.fromCharCodes([c])))));
      setv('S', new SetObj(list));
      return getv('S');
    } else throw new Error('undefined variable $name');
  }
}


void main(List<String> args) {
  if (args.length != 1) {
    print('usage: ${Platform.script.toFilePath()} <file to run>');
    return;
  }
  var file = new File(args[0]);
  if (!file.existsSync()) {
    print('cannot open ${args[0]}');
    return;
  }
  Program root = new ZincParser().start.parse(file.readAsStringSync());
  ZincInterpreter interp = new ZincInterpreter();
  var res = root.interpret(interp);
  print(res.dump());
}

그리고 이것은 들어갑니다 pubspec.yaml:

name: zinc
dependencies:
  parsers: any

의도 된 솔루션

let
#x=((x=S)*(-2))+#:x,
/=cut
in {y:{x:S/0$#:x}^_=2}

1
세트가 주문되고 복제본을 가질 수 있으므로 기본적으로 목록이라는 것을 올바르게 알고 있습니까? 또한와 join같은 혼합 세트를 사용 {1,{3,2}}하면 오류가 발생합니까? 현재 Dart를 설치할 수 없으므로 직접 확인할 수 없습니다.
Zgarb

@Zgarb 예,이 경우 기본적으로 세트가 목록입니다. 혼합 세트에 참가하는 것은 해야 오류,하지만 인터프리터가 실제로 ATM 충돌 ...
kirbyfan64sos

통역사를 어떻게 운영합니까? 방금 시도 dart bin/zinc.dart test.znc하면 구문 오류가 발생합니다. 'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'...var input = stdin.readLineSync() ?? '';
Martin Ender


1
@Zgarb 스펙에서 등식을 제외한 모든 내장 연산이 길이 연산자를 사용한다고 말한 것을 기억하십니까? -2+#:S주어진 경우 반환하도록 오버로딩 S하여 두 개의 후행 0을 차단합니다. 그것이 내가 해결되기를 바랐던 방법이었습니다. 그리고 ^그 세트를 뒤집어서는 안됩니다 ... 버그였습니다 ...
kirbyfan64sos

5

나침반 스프 ( cardboard_box에 의해 금 )

통역사 : C ++

Compass Soup은 무한 2 차원 테이프를 가진 Turing 기계와 비슷합니다. 주요 캐치는 명령 메모리와 데이터 메모리가 동일한 공간에 있고 프로그램의 출력이 해당 공간의 전체 내용이라는 것입니다.

여기에 이미지 설명을 입력하십시오

작동 원리

프로그램은 2 차원 텍스트 블록입니다. 프로그램 공간은 (0,0)에 첫 문자가있는 전체 소스 코드로 시작합니다. 나머지 프로그램 공간은 무한하며 널 문자 (ASCII 0)로 초기화됩니다.

프로그램 공간을 이동할 수있는 두 가지 포인터가 있습니다.

  • 실행 포인터에는 위치와 방향 (북쪽, 남쪽, 동쪽 또는 서쪽)이 있습니다. 각 틱, 실행 포인터 아래의 명령이 실행 된 다음 실행 포인터가 현재 방향으로 이동합니다. 실행 포인터는 !문자 의 위치 또는 존재하지 않는 경우 (0,0)에서 동쪽 (양수 x)으로 이동하기 시작 합니다.
  • 데이터 포인터에는 위치 만 있습니다. 그것은 지시로 이동 x, X, y,와 Y. @문자 의 위치에서 시작 하거나 존재하지 않는 경우 (0,0)에서 시작 합니다.

입력

stdin의 내용은 >문자 의 위치에서 시작 하거나 존재하지 않는 경우 (0,0)에서 프로그램 공간에 인쇄됩니다 .

산출

실행 포인터가 범위를 벗어나서 실행될 때 프로그램이 종료됩니다. 출력은 그 당시 프로그램 공간의 전체 내용입니다. stdout 및 'result.txt'로 전송됩니다.

명령

  • n -실행 포인터를 북쪽으로 리디렉션합니다 (음수 y).
  • e -실행 포인터를 동쪽으로 리디렉션합니다 (양수 x).
  • s -실행 포인터를 남쪽으로 리디렉션합니다 (양수 y).
  • w -실행 포인터를 서쪽으로 리디렉션합니다 (음수 x).
  • y -데이터 포인터를 북쪽으로 이동합니다 (음수 y).
  • X -데이터 포인터를 동쪽으로 이동 (양수 x)
  • Y -데이터 포인터를 남쪽으로 이동합니다 (양수 y).
  • x -데이터 포인터를 서쪽으로 이동합니다 (음수 x).
  • p-실행 포인터가 발견 한 다음 문자를 데이터 포인터에 씁니다. 그 캐릭터는 명령으로 실행되지 않습니다.
  • j-데이터 포인터 아래의 문자와 실행 포인터가 만나는 다음 문자를 확인합니다. 그 캐릭터는 명령으로 실행되지 않습니다. 동일하면 실행 포인터가 다음 문자 위로 이동합니다.
  • c -데이터 포인터에 널 문자를 씁니다.
  • * -중단 점-인터프리터가 중단됩니다.

다른 모든 문자는 실행 포인터에 의해 무시됩니다.

통역사

인터프리터는 소스 파일을 stdin의 인수 및 입력으로 사용합니다. 스테핑 가능한 디버거가 있으며 코드 ( *) 에서 중단 점 명령어로 호출 할 수 있습니다 . 중단되면 실행 포인터는 ASCII 178 (어두운 음영 블록)로 표시되고 데이터 포인터는 ASCII 177 (밝은 음영 블록)으로 표시됩니다.

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>

// Compass Soup programming language interpreter
// created by Brian MacIntosh (BMacZero)
// for https://codegolf.stackexchange.com/questions/61804/create-a-programming-language-that-only-appears-to-be-unusable
//
// 31 October 2015

struct Point
{
    int x, y;
    Point(int ix, int iy) { x = ix; y = iy; };
    bool operator==(const Point &other) const
    {
        return other.x == x && other.y == y;
    }
    bool operator!=(const Point &other) const
    {
        return other.x != x || other.y != y;
    }
};

struct Bounds
{
    int xMin, xMax, yMin, yMax;
    Bounds(int xmin, int ymin, int xmax, int ymax)
    {
        xMin = xmin; yMin = ymin; xMax = xmax; yMax = ymax;
    }
    bool contains(Point pt)
    {
        return pt.x >= xMin && pt.x <= xMax && pt.y >= yMin && pt.y <= yMax;
    }
    int getWidth() { return xMax - xMin + 1; }
    int getHeight() { return yMax - yMin + 1; }
    bool operator==(const Bounds &other) const
    {
        return other.xMin == xMin && other.xMax == xMax && other.yMin == yMin && other.yMax == yMax;
    }
    bool operator!=(const Bounds &other) const
    {
        return other.xMin != xMin || other.xMax != xMax || other.yMin != yMin || other.yMax != yMax;
    }
};

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

Bounds hull(Point a, Bounds b)
{
    return Bounds(min(a.x, b.xMin), min(a.y, b.yMin), max(a.x, b.xMax), max(a.y, b.yMax));
}

Bounds hull(Bounds a, Bounds b)
{
    return Bounds(min(a.xMin, b.xMin), min(a.yMin, b.yMin), max(a.xMax, b.xMax), max(a.yMax, b.yMax));
}

Bounds programBounds(0,0,0,0);
char** programSpace;

Point execPtr(0,0);
Point execPtrDir(1,0);
Point dataPtr(0,0);
Point stdInPos(0,0);

bool breakpointHit = false;
char breakOn = 0;

/// reads the character from the specified position
char read(Point pt)
{
    if (programBounds.contains(pt))
        return programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin];
    else
        return 0;
}

/// read the character at the data pointer
char readData()
{
    return read(dataPtr);
}

/// read the character at the execution pointer
char readProgram()
{
    return read(execPtr);
}

/// gets the bounds of the actual content of the program space
Bounds getTightBounds(bool debug)
{
    Bounds tight(0,0,0,0);
    for (int x = programBounds.xMin; x <= programBounds.xMax; x++)
    {
        for (int y = programBounds.yMin; y <= programBounds.yMax; y++)
        {
            if (read(Point(x, y)) != 0)
            {
                tight = hull(Point(x, y), tight);
            }
        }
    }
    if (debug)
    {
        tight = hull(dataPtr, tight);
        tight = hull(execPtr, tight);
    }
    return tight;
}

/// ensure that the program space encompasses the specified rectangle
void fitProgramSpace(Bounds bounds)
{
    Bounds newBounds = hull(bounds, programBounds);

    if (newBounds == programBounds) return;

    // allocate new space
    char** newSpace = new char*[newBounds.getWidth()];

    // copy content
    for (int x = 0; x < newBounds.getWidth(); x++)
    {
        newSpace[x] = new char[newBounds.getHeight()];
        for (int y = 0; y < newBounds.getHeight(); y++)
        {
            Point newWorldPos(x + newBounds.xMin, y + newBounds.yMin);
            newSpace[x][y] = read(newWorldPos);
        }
    }

    // destroy old space
    for (int x = 0; x < programBounds.getWidth(); x++)
    {
        delete[] programSpace[x];
    }
    delete[] programSpace;

    programSpace = newSpace;
    programBounds = newBounds;
}

/// outputs the current program space to a file
void outputToStream(std::ostream &stream, bool debug)
{
    Bounds tight = getTightBounds(debug);
    for (int y = tight.yMin; y <= tight.yMax; y++)
    {
        for (int x = tight.xMin; x <= tight.xMax; x++)
        {
            char at = read(Point(x, y));
            if (debug && x == execPtr.x && y == execPtr.y)
                stream << (char)178;
            else if (debug && x == dataPtr.x && y == dataPtr.y)
                stream << (char)177;
            else if (at == 0)
                stream << ' ';
            else
                stream << at;
        }
        stream << std::endl;
    }
}

/// writes a character at the specified position
void write(Point pt, char ch)
{
    fitProgramSpace(hull(pt, programBounds));
    programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin] = ch;
}

/// writes a character at the data pointer
void write(char ch)
{
    write(dataPtr, ch);
}

/// writes a line of text horizontally, starting at the specified position
void writeLine(Point loc, std::string str, bool isSource)
{
    fitProgramSpace(Bounds(loc.x, loc.y, loc.x + str.size(), loc.y));
    for (unsigned int x = 0; x < str.size(); x++)
    {
        programSpace[x + loc.x][loc.y] = str[x];

        // record locations of things
        if (isSource)
        {
            switch (str[x])
            {
            case '>':
                stdInPos = Point(loc.x + x, loc.y);
                break;
            case '!':
                execPtr = Point(loc.x + x, loc.y);
                break;
            case '@':
                dataPtr = Point(loc.x + x, loc.y);
                break;
            }
        }
    }
}

void advanceExecPtr()
{
    execPtr.x += execPtrDir.x;
    execPtr.y += execPtrDir.y;
}

void breakpoint()
{
    breakpointHit = true;
    outputToStream(std::cout, true);
    std::cout << "[Return]: step | [Space+Return]: continue | [<char>+Return]: continue to <char>" << std::endl;
    while (true)
    {
        std::string input;
        std::getline(std::cin, input);
        if (input.size() == 0)
        {
            break;
        }
        else if (input.size() == 1)
        {
            if (input[0] == ' ')
            {
                breakpointHit = false;
                break;
            }
            else
            {
                breakOn = input[0];
                breakpointHit = false;
                break;
            }
        }
    }
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("Usage: CompassSoup <source-file>");
        return 1;
    }

    // open source file
    std::ifstream sourceIn(argv[1]);

    if (!sourceIn.is_open())
    {
        printf("Error reading source file.");
        return 1;
    }

    programSpace = new char*[1];
    programSpace[0] = new char[1];
    programSpace[0][0] = 0;

    // read starting configuration
    std::string line;
    int currentLine = 0;
    while (std::getline(sourceIn, line))
    {
        writeLine(Point(0, currentLine), line, true);
        currentLine++;
    }

    sourceIn.close();

    // take stdin
    std::string input;
    std::cout << ">";
    std::cin >> input;
    std::cin.ignore();
    writeLine(stdInPos, input, false);

    // execute
    while (programBounds.contains(execPtr))
    {
        if (execPtrDir.x == 0 && execPtrDir.y == 0)
        {
            printf("Implementation error: execPtr is stuck.");
            break;
        }

        advanceExecPtr();

        char command = readProgram();

        // breakpoint control code
        if (breakpointHit || (breakOn != 0 && command == breakOn))
        {
            breakOn = 0;
            breakpoint();
        }

        switch (command)
        {
        case 'n':
            execPtrDir = Point(0,-1);
            break;
        case 'e':
            execPtrDir = Point(1,0);
            break;
        case 's':
            execPtrDir = Point(0,1);
            break;
        case 'w':
            execPtrDir = Point(-1,0);
            break;
        case 'x':
            dataPtr.x--;
            break;
        case 'X':
            dataPtr.x++;
            break;
        case 'y':
            dataPtr.y--;
            break;
        case 'Y':
            dataPtr.y++;
            break;
        case 'p':
            advanceExecPtr();
            write(readProgram());
            break;
        case 'j':
            advanceExecPtr();
            if (readData() == readProgram())
            {
                advanceExecPtr();
            }
            break;
        case 'c':
            write(0);
            break;
        case '*':
            breakpoint();
            break;
        }
    }

    std::ofstream outputFile("result.txt");
    outputToStream(outputFile, false);
    outputToStream(std::cout, false);
    outputFile.close();
}

안녕하세요 월드

Hello, World!

고양이

>

패리티 : 0으로 끝나는 문자열을받습니다 ( '0'). 출력 yes출력의 첫 번째 줄에 입력 내의 1의 개수는 별도로 출력을 홀수 인 경우 |.

|>
!--eXj1s-c-eXj0s-c-exj|s-pyXpeXps
   c   |   c   |   |   |
  cn0j-w---n1j-w   n---w

좋은 텍스트 편집기를 사용하고 '삽입'키의 기능을 신중하게 사용하고 'Alt-Drag'를 사용하여 여러 행의 텍스트를 한 번에 추가하거나 삭제해야합니다.

해결책

여기 내 해결책이 있습니다. 소스 코드를 삭제해야했기 때문에 cardboard_box만큼 좋지 않습니다. 또한 모든 코드를 삭제하고 답변 만 남기는 방법을 찾을 수 있기를 바랍니다.

내 접근 방식은 서로 다른 시퀀스 1를 서로 다른 라인 으로 분할 한 다음 다른 라인에 1도달 할 때까지 모든 "떨어짐" 을 갖도록 정렬하고 1입력 후 세 번째 라인을 제외한 모든 항목을 삭제합니다.

  • 오른쪽 하단의 큰 블록 #A#1s 를 읽고 a 0를 읽을 때까지 분할의 마지막 행에 복사합니다 .
  • #B#1 초를 확인 0하고 북쪽으로 #D#1 개가 있습니다. 그렇지 않으면, 마지막 #C#분할 선 |뒤에 넣어 새로운 분할 선을 시작 하고로 돌아갑니다 #A#.
  • 위의 블록 #F#은 중력 코드입니다. 1첫 번째 행 의 마지막 행으로 이동하여 1또는에 도달 할 때까지 위로 이동합니다 -. 그렇게 할 수 없다면 행 +앞에 놓아 행이 완료된 것으로 표시 합니다.
  • #G#불필요한 분할을 모두 #H#지우고 괄호 사이의 stdin과 모든 코드를 지우고 있습니다.

암호:

 s-----------------------w
 s-c-w  s-c-w  s---w    e+-
 eXj)nc-eXj)nc-exj(ncyj(nn
(n-----------------------------------------w                      ))
(  #H#                             s---w   |                      ))
(                                  exj+ncyxn                      ))
(                                  |                              ))
(                      s---w   s-c-+w                             ))
(                      exj+ncy-eXj1nn                             ))
(                      |                                          ))
(         s---w    s-c-+w    s+pxw                                ))
(         eyj-n-YY-eXj1nn    |  sn1jX--w           e----s         ))
(         |                  Y  x     e+---s e---s ns1jyw         ))
(      ej+n------s           j  |     nn+jYw-n+jxw-Yw   |         ))
(      Y   ec----s      e---s|  |                       1         ))
(      c   ns1jX-wYcYYY-n-jyww  |                       p         ))
(      ns+jxw      #G#       e--s                       Y         ))
(       e---n                   |               s------w|         ))
(                               |               |   ej-nn         ))
(             s--w              e----s   exc----eyj1n---n         ))
(#A#          p e+---s   s---w       |#F#|                        ))
(e----se---s  1 ||   |   exj|n----p+YeXj1ns                       ))
(ns-jXwn-jyw--w-nn1jXw   c #D#       n----w                       ))
( |        |         |   |                                        ))
( |        n---------+---+-------------|pw            s---w s---w ))
( |                  |   |     exp)XYs   |            eyj-nYeXj0ns)
( |         s---ws---+w  n-----+-----+---+------------+----------w))
( |         |   ||   ||  e--yp)n     e---+--s         |           )
( |     e-c-exj|neYj|nn  |     #C#       |  |         p           ))
( |     |                |     s---w s---+w s---w s---+w          ))
( |     |          #B#  e+s    |   | |   || |   | |   ||          ))
(!ep-Yj0n-c----------Xj0nne----exj|n-eYj|nn exj|n-eYj|nn          ))
(-@
 |>


젠장, 너무 가까이! 오늘 밤 집에 도착하면 솔루션을 공유하겠습니다.
BMac

패리티 프로그램이 작동하지 않습니다. 처음에 디버그 명령이 있어야합니까? 내가 그것을 통해 무한 루프에 갇히게되면, 내가 뭘 잘못하고 있는지 전혀 모른다?
feersum

c처음에는 거기에 있어서는 안될 여분의 것이있는 것 같습니다 . 나는 그것을 고쳤다. 또한 문제에 대한 해결책을 추가했습니다.
BMac

4

Acc! , Cracc'd ppperry에 의해

이 언어는 하나의 루핑 구조, 기본 정수 수학, 문자 I / O 및 누산기 (따라서 이름)를 갖습니다. 하나의 축 압기. 따라서 이름입니다.

진술

명령은 한 줄씩 구문 분석됩니다. 세 가지 유형의 명령이 있습니다.

  1. Count <var> while <cond>

<var>0 <cond>이 아닌 한 C 에서 시작하는 한 0부터 계산 합니다 for(<var>=0; <cond>; <var>++). 루프 카운터는 하나의 소문자 일 수 있습니다. 조건은 루프 변수를 반드시 포함 할 필요는없는 표현식 일 수 있습니다. 조건 값이 0이되면 루프가 정지됩니다.

루프에는 K & R 스타일 중괄호 (특히 Stroustrup 변형 )가 필요합니다.

Count i while i-5 {
 ...
}
  1. Write <charcode>

주어진 ASCII / 유니 코드 값을 가진 단일 문자를 stdout으로 출력합니다. 문자 코드는 모든 표현식이 될 수 있습니다.

  1. 표현

자체적으로 표현 된 표현식은 평가되어 누산기에 다시 할당됩니다 (로 액세스 가능 _). 따라서 예를 들어 3누산기를 3으로 설정하는 설명이 있습니다. _ + 1누산기를 증가시킵니다. 및 _ * N문자를 판독하고, 그 charCode 값으로 어큐뮬레이터를 곱한다.

참고 : 어큐뮬레이터는 직접 할당 할 수있는 유일한 변수입니다. 루프 변수이며 N계산에는 사용할 수 있지만 수정할 수는 없습니다.

누산기는 처음에는 0입니다.

표현

식에는 정수 리터럴, 누산기의 루프 변수 ( a-z) _및 특수 값을 포함 할 수 있습니다.이 값 N은 문자를 읽고 사용할 때마다 문자 코드로 평가합니다. 참고 : 이것은 각 문자를 읽을 수있는 샷을 한 번만 얻는다는 것을 의미합니다. 다음에을 (를) 사용 N하면 다음 내용을 읽게됩니다.

운영자는 다음과 같습니다.

  • +, 추가
  • -뺄셈; 단항 부정
  • *곱셈
  • /정수 나누기
  • %, 모듈로
  • ^, 지수

괄호를 사용하여 작업 우선 순위를 적용 할 수 있습니다. 식의 다른 문자는 구문 오류입니다.

공백과 주석

선행 및 후행 공백과 빈 줄은 무시됩니다. 루프 헤더의 공백은 표시된 것과 정확히 일치해야하며 루프 헤더와 여는 중괄호 사이에 단일 공백이 있어야합니다. 표현식 내부의 공백은 선택 사항입니다.

# 한 줄 주석을 시작합니다.

입출력

Acc! 한 줄의 문자를 입력으로 예상합니다. 각 입력 문자를 순서대로 검색하고을 사용하여 해당 문자 코드를 처리 할 수 ​​있습니다 N. 줄의 마지막 문자를 지나서 읽으려고하면 오류가 발생합니다. 문자를 Write문 에 전달하여 문자를 출력 할 수 있습니다 .

통역사

인터프리터 (Python 3으로 작성)는 Acc! 파이썬으로 코드하고 execs.

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                if loopVar is not None:
                    pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()


3

GoToTape (안전)

(이전 명칭은 Simp-plex입니다.)

이 언어는 간단합니다. 주요 흐름 제어는 가장 자연스럽고 유용한 제어 형식 인 goto입니다.

언어 사양

데이터는 테이프와 누산기에 저장됩니다. 서명되지 않은 통합과 전적으로 작동합니다. 각 문자는 명령입니다. 다음은 모든 명령입니다.

  • 편지는 : a- z에가는 고토 문이다 A- Z각각.
  • :: 입력에서 누산기를 ASCII 값으로 char로 설정합니다.
  • ~: 누산기에서 ASCII 값의 문자를 출력합니다.
  • &: 누산기에서 1 이상인 경우 누산기에서 빼고, 그렇지 않으면 1을 더합니다.
  • |: 누산기에 하나를 추가합니다.
  • <: 데이터 포인터를 0으로 설정합니다.
  • +: 데이터 포인터에서 데이터 셀을 증가시킨다; 포인터 +1을 이동하십시오.
  • -: 긍정적 인 경우 데이터 포인터에서 데이터 셀에서 하나를 빼십시오. 포인터 +1을 이동하십시오.
  • [...]: 코드를 n 번 실행합니다. 여기서 n은 데이터 포인터의 테이프 번호입니다 (중첩 할 수 없음).
  • /: 누산기가 0이면 다음 명령을 건너 뜁니다.

통역사 (C ++)

#include <iostream>
#include <memory.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int serch(char* str,char ch){
    for(int i = 0;str[i];i++){
        if(str[i]==ch)
            return i;
    }
    return -1;
}

void runCode(char* code){
    int i = 0;
    char c;
    unsigned int* tape;
    tape = new unsigned int[1000003];
    memset(tape,0,1000003*sizeof(int));
    unsigned int p=0;
    unsigned int a=0;
    unsigned int n;
    unsigned int s;

    while(c=code[i]){
        if('A'<=c && c<='Z');
        if('a'<=c && c<='z')i=serch(code, c+'A'-'a');
        if(':'==c)a=cin.get();
        if('+'==c)tape[p++]++;
        if('-'==c)tape[p++] += tape[p]?-1:0;
        if('|'==c)a++;
        if('&'==c)a=a?a-1:1;
        if('<'==c)p=0;
        if('['==c){if(tape[p]){n=tape[p];s=i;}else i+=serch(code+i,']');};
        if(']'==c)i=--n?i:s;
        if('~'==c)cout<<(char)a;
        if('/'==c)i+=a?0:1;
        if('$'==c)p=a;
        i++;
    }
    delete[](tape);
}

int main(int argc, char* argv[]) {
    if(argc == 2){

        ifstream sorceFile (argv[1]);
        string code(static_cast<stringstream const&>(stringstream() << sorceFile.rdbuf()).str());
        runCode((char*)code.c_str());
    }else
        cout << "Code file must be included as a command-line argument \n";
    return 0;
}

즐기세요!

해결책

A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e


2
C ++ 코딩이 나를 죽이고 있습니다! calloc대신에 new charC 스타일 while 루프를 작성하고 C 스타일 메모리 관리를 사용하고, 코드를 변경할 때마다 C ++ 파일을 다시 컴파일하고, 대신 20 ifs 를 사용하는 이유 가 switch있습니까? 나는 불평 아니지만, 내 눈은 지금 출혈 ... : O
kirbyfan64sos

3
나는 통역사에게 고기를 고치기 위해 얼룩을 고쳤다.
MegaTom

@ kirbyfan64sos 코드가 잘못되었습니다. 나는 이것을 빨리 합쳐서 내가하지 않았을 수도 있습니다. 코드를 입력으로 사용하도록 기본 기능을 변경할 수 있습니다. 사실 나는 지금 그렇게 할 것이라고 생각합니다 ...
MegaTom

1
문제는 인터프리터가 프로그램의 명령 행에서 파일 이름가져와야한다고 말합니다 .
Dennis

다음은 파일을 문자열로 읽는 간단한 방법입니다 . 그런 다음 전화 str.c_str()를 받으십시오 char*.
feersum

0

거의 모든 난해한 언어는 읽을 수없는 것처럼 보이기 때문에 나쁜 생각이었습니다 (젤리보기).
그러나 여기에 간다 :

pylongolf2 베타 6

스택으로 밀기

스택으로 푸시하는 것은 다른 언어와 다르게 작동합니다.
코드는 78밀어 78스택으로, 그러나 Pylongolf에서 그것을 밀어 78.
Pylongolf2에서는로 전환 할 수 Ü있습니다.

명령

) Print the stack.
Ü Toggle the method Pylongolf2 uses for pushing to stack.
a The useless command, removes and adds the selected item in the same place.
c Ask for input.
n Convert string to a number.
" Toggle string mode for pushing text to the stack.
s Convert a number to a string. ╨ Encode the selected item (it must be a string).
_ Duplicate the selected item next to itself.
b Swap places between the selected item and the one before.
d Set the selected item to the last one.
m Move the selected item to the end of the stack.
@ Select an item. (Number required after this command as an argument).
w Wait a specified amount of time (the time is taken from the stack).
= Compare the selected item to the one before. (WARNING. THIS DELETES THE 2 ITEMS AND PLACES A true OR A false) (V2 beta)
~ Print the stack nicely. (V2 beta)
² Square a number. (V3 beta)
| Split a string to an array by the character after |. (V4 beta)
♀ Pop the array. (the contents are left in the stack) (V4 beta)
> Begin a while statement. (V5 beta)
< Loop back to the beginning of the while statement. (V5 beta)
! Break out of the while statements. (V5 beta)
? An if statement, does nothing if the selected item is a `true` boolean. (V6 beta)
¿ If an if statement is `false`, the interpreter skips everything to this character. (V6 beta)

문자열 연결 및 문자열에서 정규식 패턴 제거

+ 기호는 문자열을 연결합니다.
-기호를 사용하여 문자열에서 정규식 패턴 다음에 나오는 문자를 제거 할 수 있습니다.

c╨2"[^a-zA-Z]"-~

이 코드는 입력을 받아 일치하는 모든 패턴을 제거하여 알파벳이 아닌 모든 문자를 제거합니다 [^a-zA-Z].
선택한 항목은 정규식이어야하고 이전 항목은 편집 할 문자열이어야합니다.

if 문

if 문을 수행하려면 a =를 선택하여 선택한 항목과 그 다음 항목을 비교하십시오.
이것은 장소에 a true또는 a false를 배치합니다.
명령은 ?이 부울을 확인합니다.
그렇다면 true아무것도하지 않고 통역사가 계속됩니다.
그렇다면 false통역사가 가장 가까운 ¿문자로 건너 뜁니다 .

Github 페이지에서 가져 왔습니다.

Pylongolf2에 대한 통역사 (Java) :

package org.midnightas.pylongolf2;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Pylongolf {

    public static final void main(String[] args) throws Exception {
        String content = new String(Files.readAllBytes(Paths.get(new File(args[0]).toURI()))) + " ";
        boolean fullreadMode = true;
        List<Object> stack = new ArrayList<Object>();
        List<Integer> whileStatements = new ArrayList<Integer>();
        HashMap<String, Object> vars = new HashMap<String, Object>();
        int ifStatements = 0;
        Scanner scanner = new Scanner(new UnclosableDecorator(System.in));
        int selectedIndex = 0;
        for (int cl = 0; cl < content.length(); cl++) {
            char c = content.charAt(cl);
            if (isNumber(c)) {
                if (!fullreadMode) {
                    stack.add(Double.parseDouble(c + ""));
                } else {
                    String number = "";
                    for (int cl0 = cl; cl0 < content.length(); cl0++) {
                        if (isNumber(content.charAt(cl0))) {
                            number += content.charAt(cl0);
                        } else {
                            cl = cl0 - 1;
                            stack.add(Double.parseDouble(number));
                            break;
                        }
                    }
                }
            } else if (c == ')') {
                System.out.println(Arrays.toString(stack.toArray()));
            } else if (c == 'Ü') {
                fullreadMode = !fullreadMode;
            } else if (c == '+') {
                if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Double dbl = new Double(0d);
                    for (Object o : obj) {
                        dbl += (Double) o;
                    }
                    stack.add(selectedIndex, dbl);
                } else {
                    Object obj0 = stack.remove(selectedIndex);
                    Object obj1 = stack.remove(selectedIndex);
                    if (obj0 instanceof Number && obj1 instanceof Number)
                        stack.add(((Number) obj0).doubleValue() + ((Number) obj1).doubleValue());
                    else if (obj0 instanceof String) {
                        stack.add(obj0.toString() + obj1.toString());
                    }
                }
            } else if (c == '-') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() - ((Number) obj1).doubleValue());
                else if (obj0 instanceof String && obj1 instanceof String) {
                    stack.add(obj0.toString().replaceAll(obj1.toString(), ""));
                }
            } else if (c == '*') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() * ((Number) obj1).doubleValue());
            } else if (c == '/') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() / ((Number) obj1).doubleValue());
            } else if (c == 'a') {
                stack.add(selectedIndex, stack.remove(selectedIndex));
            } else if (c == 'c') {
                stack.add(scanner.nextLine());
            } else if (c == 'n') {
                if (stack.get(selectedIndex) instanceof String) {
                    stack.add(selectedIndex, Double.parseDouble(stack.remove(selectedIndex).toString()));
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] oldArray = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[oldArray.length];
                    for (int i = 0; i < oldArray.length; i++) {
                        newArray[i] = Double.parseDouble(oldArray[i].toString());
                    }
                    stack.add(selectedIndex, newArray);
                }
            } else if (c == '"') {
                String string = "\"";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    string = string + content.charAt(cl0);
                    if (content.charAt(cl0) == '"') {
                        stack.add(string.substring(1, string.length() - 1));
                        cl = cl0;
                        break;
                    }
                }
            } else if (c == 's') {
                Object obj = stack.remove(selectedIndex);
                if (obj instanceof Double) {
                    Double dbl = (Double) obj;
                    if (dbl.doubleValue() == Math.floor(dbl)) {
                        stack.add(selectedIndex, "" + dbl.intValue() + "");
                    } else {
                        stack.add(selectedIndex, "" + dbl + "");
                    }
                }
            } else if (c == '╨') {
                cl++;
                char editmode = content.charAt(cl);
                if (editmode == '0') {
                    stack.add(selectedIndex, rot13(stack.remove(selectedIndex).toString()));
                } else if (editmode == '1') {
                    stack.add(selectedIndex,
                            new StringBuilder(stack.remove(selectedIndex).toString()).reverse().toString());
                } else if (editmode == '2') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toLowerCase());
                } else if (editmode == '3') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toUpperCase());
                }
            } else if (c == '_') {
                stack.add(selectedIndex, stack.get(selectedIndex));
            } else if (c == 'b') {
                stack.add(selectedIndex + 1, stack.remove(selectedIndex));
            } else if (c == 'd') {
                selectedIndex = stack.size() == 0 ? 0 : stack.size() - 1;
            } else if (c == 'm') {
                stack.add(stack.remove(selectedIndex));
            } else if (c == '@') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        selectedIndex = Integer.parseInt(number);
                        break;
                    }
                }
            } else if (c == 'w') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        Thread.sleep(Long.parseLong(number));
                        break;
                    }
                }
            } else if (c == '=') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                stack.add(new Boolean(obj0.equals(obj1)));
            } else if (c == '~') {
                for (Object o : stack)
                    System.out.print(o);
                System.out.println();
            } else if (c == '²') {
                if (stack.get(selectedIndex) instanceof Double) {
                    Double dbl = (Double) stack.remove(selectedIndex);
                    stack.add(selectedIndex, dbl * dbl);
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[obj.length];
                    for (int i = 0; i < obj.length; i++) {
                        newArray[i] = Math.pow((Double) obj[i], 2);
                    }
                    stack.add((Object[]) newArray);
                }
            } else if (c == '|') {
                String string = (String) stack.remove(selectedIndex);
                cl++;
                char splitChar = content.charAt(cl);
                stack.add((Object[]) string.split(splitChar + ""));
            } else if (c == '♀') {
                for (Object obj : (Object[]) stack.remove(selectedIndex)) {
                    stack.add(selectedIndex, obj);
                }
            } else if (c == '>') {
                whileStatements.add(new Integer(cl));
            } else if (c == '<') {
                cl = whileStatements.get(whileStatements.size() - 1);
            } else if (c == '!') {
                whileStatements.remove(whileStatements.size() - 1);
            } else if (c == '?') {
                if (stack.get(selectedIndex) instanceof Boolean) {
                    Boolean bool = (Boolean) stack.remove(selectedIndex);
                    if (bool == false) {
                        ifStatements++;
                        for (int cl0 = cl; cl0 < content.length(); cl0++) {
                            if (content.charAt(cl0) == '¿') {
                                ifStatements--;
                                cl = cl0;
                            }
                        }
                    }
                }
            } else if (c == 't') {
                break;
            } else if (c == '(') {
                stack.remove(selectedIndex);
            } else if (c == ':') {
                cl++;
                char charToVar = content.charAt(cl);
                vars.put(charToVar + "", stack.remove(selectedIndex));
            } else if (c >= 'A' && c <= 'Z') {
                stack.add(vars.get(c + ""));
            } else if (c == 'r') {
                stack.add(selectedIndex,
                        (double) new Random().nextInt(((Double) stack.remove(selectedIndex)).intValue() + 1));
            }
        }
        scanner.close();
    }

    public static String rot13(String input) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if (c >= 'a' && c <= 'm')
                c += 13;
            else if (c >= 'A' && c <= 'M')
                c += 13;
            else if (c >= 'n' && c <= 'z')
                c -= 13;
            else if (c >= 'N' && c <= 'Z')
                c -= 13;
            sb.append(c);
        }
        return sb.toString();
    }

    public static boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

}

사용하기 어려운가요? : /
CalculatorFeline

0

레인보우 (참고 : 곧 통역사 제공)

이 도전이 만료되었음을 알고 있습니다.

무지개는 많은 것들이 섞여 있습니다.

Rainbow는 2 개의 스택 (Like Brain-Flak)과 8 개의 방향 ( N NE E SE S SW W NW) 이있는 2D 스택 기반 언어입니다 . 8 가지 명령이 있습니다 :

  • 1, +, *, "정확히 그들이 1+에해야 할 일.
  • ! 활성 스택을 토글합니다.
  • > IP를 시계 방향으로 돌립니다.
  • , 문자를 입력하고 밀어 넣으십시오.
  • . 팝하고 문자를 출력합니다.

그러나 소스 코드의 문자는 즉시 실행되지 않습니다. 대신 [The Character in the source code]^[Top Of Stack]Collatz Conjecture에 입력되어 1에 도달하는 단계 수가 ASCII 테이블에 의해 문자로 변환됩니다. 그런 다음이 문자가 실행됩니다.

  • 1에 도달하는 데 127 단계 이상이 걸리면 총 단계 수를 127로 나누고 미리 알림을 가져온 다음 몫에 미리 알림을 추가하십시오.

프로그램 시작시 소스 코드 (마지막 문자 제외)가 스택에 푸시됩니다.

IP가 소스 코드의 가장자리에 도달하면 IP가 종료됩니다.

묵시

n과 m은 두 레지스터입니다. >명령이 실행될 때 m이 증가합니다. 묵시록은 m이 n을 초과하는 경우에만 트리거됩니다. 묵시록이 발생하면 다음과 같이됩니다.

  • 시계 방향이 아닌 시계 반대 방향으로 돌리십시오.
  • m은 0이됩니다.
  • n은 스택의 상단이됩니다. 그런 다음 스택이 튀어 나옵니다.

m은 처음에 0이고 n은 처음에 소스 코드의 마지막 문자입니다.

암호화

실행을 실행 한 후 소스 코드가 암호화됩니다. 첫 번째 문자의 ASCII는 1 씩 증가하고, 두 번째는 1 씩 감소하고, 세 번째는 2 씩 증가하고, 4 번째는 2 씩 감소합니다.


1
이 질문에 대한 답을
얻으

@ ConorO'Brien이 도전이 이미 만료되었으므로 이것은 단지 재미를위한 것입니다. 그래도 통역을 제공 할 것입니다.
HighRadioactive

@HighlyRadioactive ... 당신은 거의 한 달 전에 말했다.
pppery
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.