BrainF ** k, 396 391 바이트
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
나는 이것에 대한 유혹에 저항 할 수 없었다. 최소한 삼각형이 뾰족한 쪽을 향합니다.
입력은 하나의 줄 바꿈 뒤에 숫자 문자열로 제공됩니다.
출력은 모든 줄에 단일 후행 공백을 포함합니다.
예 :
$ bf sd.bf
010
0 1 0
1 1
2
$ bf sd.bf
123456
1 2 3 4 5 6
3 5 7 9 1
8 2 6 0
0 8 6
8 4
2
$ bf sd.bf
9245322
9 2 4 5 3 2 2
1 6 9 8 5 4
7 5 7 3 9
2 2 0 2
4 2 2
6 4
0
설명
기능적인 관점에서 코드를 설명하기는 어렵 기 때문에 대신 테이프 상태의 관점에서 코드를 여러 번 볼 수 있습니다. 여기서 핵심 아이디어는 우리가 출력하는 삼각형이 루프가 반복 될 때마다 크기가 1 씩 줄어드는 꽉 채워진 (BF, 어쨌든) 배열로 초기화된다는 것입니다. 또 다른 중요한 생각은 255
테이프에서 검색 할 수있는 "자리 표시 자"를 나타내는 데 사용 한다는 것입니다.
초기화
가장 쉬운 단계입니다. 프로그램 시작시 다음을 실행합니다.
>+>>++++[-<++++++++>]->
이렇게하면 테이프가 다음 상태가됩니다 ( >N<
테이프에서 포인터의 위치를 나타냄).
[ 0 1 32 255 >0< 0 0 ...]
여기서 첫 번째 숫자는 "버퍼"위치입니다. 우리는 장기간 사용하지는 않지만 적은 작업을 단순화하고 데이터를 복사하는 데 유용합니다.
두 번째 숫자는 우리가 시작, 각 라인의 시작에서 출력 될 거라고 공간의 개수 후 첫 줄. 첫 번째 줄에는 선행 공백이 없습니다.
세 번째 숫자는 우리가 출력하는 공백 문자입니다.
네 번째 숫자는 자리 표시 자 255이므로 상대적으로 쉽게이 위치로 돌아갈 수 있습니다.
입력
이 위치에서 모든 문자를 읽습니다. 이 단계가 끝나면 다음과 같은 상황에 처하기를 바랍니다.
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
여기서 a b c d e f ...
, 줄 바꿈이 아닌 입력 된 숫자 문자열을 나타냅니다.
우리는 이것을 다음과 같이 달성합니다.
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
이것에는 약간의 뉘앙스가 있습니다. 우선, 각 문자를 가져올 때 각 문자를 출력 한 다음 그 뒤에 공백을 출력합니다. 둘째, ASCII 값을 테이프에 복사하지 않고 실제 숫자를 복사하려고합니다. 셋째, 우리는 개행을 멈출 때 멈추고 그 당시 좋은 곳으로 떠나고 싶습니다.
우리의 입력을 받았다고 6723
. 그런 다음 첫 번째를 읽으면 6
테이프가 다음과 같이 보입니다.
[ 0 1 32 255 >54< 0 0 ...]
이 값이 10
(ASCII 줄 바꿈)과 같지 않은지 확인합니다 ,----------[++++++++++
. 그런 다음 값을 인쇄하고 입력 값에서 48을 빼고 그 옆 값에 32를 더하여 ( >>++++++++[-<++++<------>>]<
) 계속해서 여기에 남겨 둡니다.
[ 0 1 32 255 6 >32< 0 ...]
공지 사항이 과정에서 우리가 생각하는 방법을 우리의 입력의 오른쪽에있는 모든 숫자가 0임을 - 우리가 계산에 대한 권리에 값을 사용하는 경우 우리가 이전 상태를 망치고의 위험하지 않은 것으로이 의미 6 * 8
하고 4 * 8
.
이제 방금 생성 한 공백 문자를 출력하고 새로운 입력을 받아 계산 된 공백을 삭제합니다. 결국 입력은 255
줄 바꾸기 로 끝나고 루프는 종료 되어 줄 바꿈 위치는 ( ,----------]-
)로 남습니다 . 테이프를 탐색하는 데 사용할 두 번째 자리 표시 자 문자입니다. 시나리오의 현재 시점에서 테이프는 정확히 다음과 같습니다.
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
계산
이것이 작동하는 방식은 자리 255
표시 자 사이의 숫자 목록 이 루프가 반복 될 때마다 하나씩 줄어드는 것입니다. 여기에 1 자리 만 남았 으면 완료되었으며 즉시 중지해야합니다 (이 시점에서 해당 목록의 모든 숫자가 이미 출력되었으므로 다시 출력 할까 걱정할 필요가 없습니다).
이제이 트릭을 사용하여 첫 번째 255
자리 표시 자로 이동합니다 <+[-<+]-
. 이렇게하면 왼쪽에서 테이프를 효과적으로 검색하여 255
사이에 아무것도 변경되지 않습니다. 포인터를 움직 였으므로 종료 조건을 확인할 수 있습니다. 목록에 한 자리 만 있으면 오른쪽에있는 두 칸의 셀이 유지 255
됩니다. 따라서 우리는 그것을 확인하고 루프를 시작합니다.>>+[-<<
루프의 첫 번째 단계는 개행을 출력하는 것입니다. 그래서 우리는 첫 번째 셀 (버퍼 셀)로 이동하여 10을 더하고 출력합니다. 다음 단계는 모든 선행 공백 문자를 출력하는 것입니다. 그것들을 출력 한 후, 우리는 선행 공간 수에 대한 카운트를 증가시킵니다. 이 단계는 다음에 의해 수행됩니다.
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
이 상태에서 우리를 떠난다 :
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
다음 단계는 두 번째 자리 표시자를지나 목록의 첫 번째 값을 복사하는 것입니다 255
.
[[->+]->>+<<<+[-<+]->]
우리는 본질적으로 자리 표시 자 사이를 앞뒤로 움직여서 255
여기에 남겨 둡니다.
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
우리는 이제 루프를 시작하고 나머지리스트를 반복하면서 우리가 쳤을 때 멈 춥니 다 255
.>+[-<
이 시점에서 가장 왼쪽에있는 숫자는 항상 0입니다. 그래서 우리는 그것들을 사랑하기 때문에 자리 표시자를 열어서 255
목록에서 우리 자리로 돌아올 수 있습니다. 다음 단계는 목록에서 두 번째 자리를 두 번째 자리 표시자를 지나서 첫 번째 자리를 이동 한 주변 위치로 이동하는 것 255
입니다. 이 단계는 다음에 의해 수행됩니다.
->
[[->+]->+>>+<<<<+[-<+]->]
우리를 여기로 남겨주세요 : [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
이제 6
와와 둘 다 7
계산이 일어날 수있는 위치로 옮겨졌습니다. 7
목록의 다음 번호에서도 필요하므로 두 개의 사본 이 필요합니다. 7
바로 후에 255
나머지가있는 반면,이 목적을 제공 7
계산에 의해 소비 될 것이다.
먼저 두 자리를 추가합니다 :
<+>->+[->+]->>
[->+<]>
여기 우리를 떠나 :
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
다음 단계 조합은 가장 복잡합니다. 우리가 가리키는 숫자가 10보다 큰지 확인해야하며, 그렇다면 숫자를 뺍니다 10
. 실제로, 우리가하는 일은 10을 빼서 빼기의 0
어느 시점에서나 치르는 지 확인하는 것 입니다. 그렇다면 10
나중에 다시 추가 합니다. 이것의 끝에 합계 모듈로 10이 있어야합니다.
Prepare a 10 to the right
+>++++++++++
Leave yet another 255 for a loop condition later
>>-<<
If the number is greater than 10 end up one space to the left
else one space to the right
[-<-[>>]<]<->
Check if the previous 255 is two spaces to the right and if it is
add 10 back to our sum--we've subtracted too much
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
이 시점에서 목표를 달성했습니다. 우리는 합 모듈로 10을 가지고 있습니다! 또한 숫자가 10보다 큰지 여부는 다음과 같습니다.
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
다음 목표는이 새로운 합계를 출력하고 공백으로 따라 가서 목록에 다시 주입하는 것입니다. 우리는이 모든 것을 이전에 255
도약하고 48
합계에 추가 하는 기술로 수행 하므로 자세히 다루지 않습니다.
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
그리고 우리는 여기에 있습니다 : 새로 주입 한 후에 [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
추가 255
자리 표시자를 추가 3
하여 목록에서 자리를 잃지 않도록하십시오. 이 시점에서 합계와 그 공간을 출력 했으므로 다음 루프 반복이 작동 할 상태로 정리하고 되돌려 야합니다. 다시 시작하려면 셀 51
과 32
셀 을 지우고 7
한 번 오른쪽으로 이동 한 다음 목록 자리 표시 자로 이동해야합니다.
[-]<[-]<<<[->+<]<<+[-<+]
이제 우리는 여기 있습니다 : [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
다음 반복을 위해 정확히 원하는 곳입니다. 255를 확인하고 계속 진행하십시오! ( >+]
)
루프에서 빠져 나오면 이전 목록의 합계로 구성된 완전히 새로운 목록이 생깁니다. 처음에는 다음과 같습니다.
[ 0 2 32 255 3 9 5 0 >0< ]
이제 우리는 새로운 목록에서 전체 프로세스를 반복하고 싶기 때문에 255
왼쪽 으로 내려 가서 다시 시작합니다! 로 약간의 정리를 수행 한 >>[-]<<
다음 자리 표시자를로 삭제해야 <-
합니다. 그 후, 우리는 입력 후와 정확히 같은 위치에 있으므로 동일한 검사를 수행하지 않아도됩니다 <+[-<+]->>+
. 우리는 우리의 전체 루프를 가지고있다! 필요한 것은 닫는 괄호이며, 끝날 때 이미 모든 것을 출력 했으므로 완료되었습니다 ]
.