골프 스크립트-12 자
{,1\{)*}/}:f
Golfscript 시작하기-단계별 계승
골프 스크립트를 배우려는 사람들을위한 것입니다. 전제 조건은 골프 스크립트에 대한 기본 지식과 골프 스크립트 문서를 읽는 기능입니다.
그래서 우리는 새로운 도구 golfscript 를 시도하고 싶습니다 . 항상 간단한 것으로 시작하는 것이 좋으므로 계승으로 시작합니다. 간단한 명령형 의사 코드를 기반으로 한 초기 시도는 다음과 같습니다.
# pseudocode: f(n){c=1;while(n>1){c*=n;n--};return c}
{:n;1:c;{n 1>}{n c*:c;n 1-:n;}while c}:f
공백은 골프 스크립트에서 거의 사용되지 않습니다. 공백을 제거하는 가장 쉬운 방법은 다른 변수 이름을 사용하는 것입니다. 모든 토큰을 변수로 사용할 수 있습니다 ( 구문 페이지 참조). 변수로 사용하기에 유용한 토큰은 |
, 와 같은 특수 문자 &
이며 ?
일반적으로 코드의 다른 곳에서는 사용되지 않습니다. 이들은 항상 단일 문자 토큰으로 구문 분석됩니다. 반대로, 같은 변수 n
는 스택에 숫자를 넣을 공간이 필요합니다. 숫자는 본질적으로 사전 초기화 된 변수입니다.
항상 그렇듯이, 최종 결과에 영향을 미치지 않으면 서 우리가 바꿀 수있는 진술이있을 것입니다. golfscript에서 모든 제외 true로 평가 0
, []
, ""
,과 {}
(참조 이 ). 여기서 루프 종료 조건을 간단히 변경할 수 있습니다 {n}
(추가 시간을 반복하고 n = 0 일 때 종료).
다른 언어로 골프를 타는 것과 마찬가지로 사용 가능한 기능을 아는 데 도움이됩니다. 운 좋게도 목록은 golfscript에 대해 매우 짧습니다. 다른 캐릭터를 구하기 1-
위해 (
로 변경할 수 있습니다 . 현재 코드는 다음과 같습니다. ( 원하는 경우 여기 1
대신 사용할 수 있으므로 |
초기화가 중단됩니다.)
{:n;1:|;{n}{n|*:|;n(:n;}while|}:f
가장 짧은 솔루션을 얻으려면 스택을 잘 사용하는 것이 중요합니다 (연습 실습). 일반적으로 값이 작은 코드 세그먼트에만 사용되는 경우 변수에 값을 저장하지 않아도됩니다. 실행중인 제품 변수를 제거하고 단순히 스택을 사용함으로써 많은 문자를 절약 할 수 있습니다.
{:n;1{n}{n*n(:n;}while}:f
여기에 다른 생각이 있습니다. n
루프 바디 끝의 스택에서 변수 를 제거하고 바로 다음에 밀어 넣습니다. 실제로 루프가 시작되기 전에 스택에서 루프를 제거합니다. 대신 스택에 그대로 두어야하며 루프 조건을 비워 둘 수 있습니다.
{1\:n{}{n*n(:n}while}:f
변수를 완전히 제거 할 수도 있습니다. 이렇게하려면 항상 변수를 스택에 유지해야합니다. 이는 상태 확인이 끝날 때 스택에 변수의 사본 두 개가 필요하므로 확인 후에도 손실되지 않습니다. 즉 0
, 루프가 끝난 후 스택에 중복 이 생기지 만 쉽게 해결할 수 있습니다.
이것은 우리를 최적의 while
루프 솔루션으로 안내합니다!
{1\{.}{.@*\(}while;}:f
이제 우리는 여전히 이것을 더 짧게 만들고 싶습니다. 명백한 목표는 단어 여야합니다 while
. 문서를 살펴보면 전개 와 수행 이라는 두 가지 대안 이 있습니다. 다른 노선을 선택할 수있는 경우 두 가지 혜택을 모두 시도해보십시오. 펼치기는 '거의 while 루프'이므로 5 문자 while
를 4로 줄 /
입니다. 에 관해서는 3자를 do
삭감 while
하고 두 블록을 합치면 다른 문자를 저장할 수 있습니다.
실제로 do
루프 를 사용하면 큰 단점이 있습니다. 본문이 한 번 실행 된 후 조건 확인이 수행되므로 값 0
이 잘못되므로 if 문이 필요할 수 있습니다. 펼치기가 더 짧다는 것을 알려 드리겠습니다 (일부 솔루션 do
은 마지막에 제공됨). 우리가 이미 가지고있는 코드는 최소한의 변경이 필요합니다.
{1\{}{.@*\(}/;}:f
큰! 우리의 솔루션은 이제 매우 짧으며 여기서 끝났습니다. 아니. 이것은 17 자이며 J는 12 자입니다. 패배를 인정하지 마십시오!
지금 당신은 생각하고 있습니다 ... 재귀
재귀를 사용한다는 것은 분기 구조를 사용해야 한다는 것을 의미 합니다 . 불행히도, 간결하게 재귀 적으로 계승을 표현할 수 있기 때문에 반복에 대한 대안으로 보일 수 있습니다.
# pseudocode: f(n){return n==0?n*f(n-1):1}
{:n{n.(f*}1if}:f # taking advantage of the tokeniser
재귀를 일찍 시도했다면 while
루프 를 사용하지 않았을 수도 있습니다 ! 여전히 우리는 16 자에 불과합니다.
배열
배열은 일반적으로 [
and ]
문자를 사용하거나 ,
함수를 사용하여 두 가지 방식으로 생성됩니다 . 스택 맨 위에서 정수로 실행하면 ,
arr [i] = i를 가진 해당 길이의 배열을 반환합니다.
배열을 반복하기 위해 다음 세 가지 옵션이 있습니다.
{block}/
: 밀기, 막기, 밀기, 막기 ...
{block}%
: [push, block, push, block, ...] (이것은 약간의 뉘앙스가 있습니다. 예를 들어 각 푸시 전에 스택에서 중간 값이 제거됩니다)
{block}*
: 밀기, 밀기, 막기, 밀기, 막기 ...
골프 스크립트 문서에는 {+}*
배열의 내용을 합하는 데 사용하는 예제가 있습니다. 이것은 {*}*
배열의 곱을 얻는 데 사용할 수 있음 을 나타냅니다.
{,{*}*}:f
불행히도, 그렇게 간단하지 않습니다. 모든 요소가 1 개씩 꺼져 있습니다 ( [0 1 2]
대신 [1 2 3]
). {)}%
이 문제를 해결 하는 데 사용할 수 있습니다 .
{,{)}%{*}*}:f
글쎄요 이것은 0을 올바르게 처리하지 않습니다. 비용이 너무 많이 들지만 (n + 1)! / (n + 1)을 계산하여이를 수정할 수 있습니다.
{).,{)}%{*}*\/}:f
n = 1과 동일한 버킷에서 n = 0을 처리 할 수도 있습니다. 이 작업은 실제로 수행 할 수있는 시간이 매우 짧습니다.
7 자에서 정렬하는 것이 좋지 않습니다 : [1\]$1=
. 이 분류 기술은 숫자에 경계를 두는 것과 같은 유용한 목적을 가지고
있습니다.
같은 블록에서 증분과 곱셈을하려면 배열의 모든 요소를 반복해야합니다. 우리는 배열을 만들지 않기 때문에,를 사용해야한다는 것을 의미합니다 {)*}/
. 이것은 factorial의 가장 짧은 golfscript 구현을 가능하게합니다! 12 자 길이로 J와 연결됩니다!
{,1\{)*}/}:f
보너스 솔루션
루프에 if
대한 간단한 솔루션으로 시작 do
:
{.{1\{.@*\(.}do;}{)}if}:f
이 중 몇 가지를 더 짜낼 수 있습니다. 조금 복잡하기 때문에 이러한 것들이 작동하도록 설득해야합니다. 이 모든 것을 이해했는지 확인하십시오.
{1\.!!{{.@*\(.}do}*+}:f
{.!{1\{.@*\(.}do}or+}:f
{.{1\{.@*\(.}do}1if+}:f
더 좋은 대안은 (n + 1)! / (n + 1)을 계산하는 것이므로 if
구조 가 필요하지 않습니다 .
{).1\{.@*\(.}do;\/}:f
그러나 do
여기서 가장 짧은 솔루션은 0에서 1까지의 모든 문자와 그 자체로 모든 문자를 매핑하는 데 몇 문자가 필요하므로 분기가 필요하지 않습니다. 이런 종류의 최적화는 놓치기 매우 쉽습니다.
{.!+1\{.@*\(.}do;}:f
관심있는 사람은 위와 동일한 길이의 대체 재귀 솔루션을 몇 가지 제공합니다.
{.!{.)f*0}or+}:f
{.{.)f*0}1if+}:f
{.{.(f*}{)}if}:f
* 참고 :이 게시물에서 실제로 많은 코드 조각을 테스트하지 않았으므로 오류가 있는지 알려주십시오.