CJam 은 PPCG 사용자 aditsu가 만든 GolfScript 기반 스택 기반 골프 언어 입니다.
따라서 다른 언어 관련 팁 질문의 맥락에서 :
CJam에서 골프를 할 때 어떤 일반적인 팁이 있습니까? 답변 당 하나의 팁을 게시하십시오 .
CJam 은 PPCG 사용자 aditsu가 만든 GolfScript 기반 스택 기반 골프 언어 입니다.
따라서 다른 언어 관련 팁 질문의 맥락에서 :
CJam에서 골프를 할 때 어떤 일반적인 팁이 있습니까? 답변 당 하나의 팁을 게시하십시오 .
답변:
모듈로 연산의 결과가 첫 번째 피연산자와 동일한 부호를 제공한다는 것은 종종 성가신 일입니다. 예 -5 3%
를 들어 -2
대신에 제공 합니다 1
. 후자를 원하지 않는 경우가 더 많습니다. 순진한 수정은 모듈로를 적용하고, 제수를 한 번 추가 한 후 모듈로를 다시 적용하는 것입니다.
3%3+3%
그러나 그것은 길고 추악합니다. 대신, 우리는 배열 인덱스는 항상 모듈이며, 사실 사용할 수 있습니다 않습니다 부정적인 지표 제대로 일을. 따라서 제수를 범위로 바꾸고 다음에 액세스하십시오.
3,=
에 적용 -5
,이 있습니다 1
예상대로. 그리고 그것은 내장 된 것보다 단지 1 바이트 길다 %
!
모듈러스가 2의 거듭 제곱이면 비트 단위의 산술을 사용하여 다른 바이트를 절약 할 수 있습니다 (이 또한 훨씬 빠름). 비교:
32,=
31&
특수한 경우 65536 == 2^16
다른 문자 유형의 랩핑 동작을 사용하여 다른 바이트를 저장할 수 있습니다.
ci
모든 숫자를 포함하는 문자열 "0123456789"
은 다음과 같이 쓸 수 있습니다
A,s
대문자 ASCII 문자 ( A-Z
)는 다음과 같이 입력 할 수 있습니다.
'[,65>
이는 최대 Z 까지의 모든 문자의 문자열을 생성 한 다음 첫 번째 65 (최대 @ ) 를 버립니다 .
모든 ASCII 문자 ( A-Za-z
)는
'[,65>_el+
위와 같이 작동 한 다음 사본을 만들고 소문자로 변환하고 추가합니다.
그러나 더 짧은 방법이 있습니다!
그런 다음 종종 간과되는 ^
연산자 (목록의 대칭 적 차이)를 통해 3 바이트를 절약하면서 동일한 범위를 만들 수 있습니다.
'[,_el^
'[,
최대 모든 ASCII 문자의 범위 생성 Z를 , _el
소문자 사본을 생성하고 ^
하나가 아니라 둘 다에 나타나는 두 문자열의 문자를 유지합니다.
첫 번째 문자열의 모든 문자는 대문자이므로 두 번째 문자열의 모든 문자는 소문자이고 모든 문자가 아닌 문자는 두 문자열에 모두 있으며 결과는 문자 문자열입니다.
RFC 1642 Base64 알파벳 ( A-Za-z0-9+/
)은 위의 기술을 사용하고 비 문자를 추가하여 푸시 할 수 있습니다.
'[,_el^A,s+"+/"+
이 문자열을 똑같이 짧게 밀면 대칭 차이 만 사용합니다.
"+,/0:[a{A0":,:^
처음에 줄을 어떻게 찾을 수 있습니까?
중고 문자 범위가 ( A-Z
, a-z
, 0-9
, +
, /
) 널 바이트, 즉 시작 범위의 대칭 차이로 푸시 할 수 'A,'[,^
, 'a,'{,^
, '0,':,^
, '+,',,^
및 '/,'0,^
.
따라서 :,:^
on "A[a{):+,/0"
을 실행 하면 원하는 문자가 푸시되지만 올바른 순서는 아닙니다.
올바른 순서를 어떻게 찾습니까? 구조에 대한 무차별 대입! 프로그램
'[,_el^A,s+"+/"+:T;"0:A[a{+,/0"e!{:,:^T=}=
문자열의 가능한 모든 순열을 반복 :,:^
하고 결과를 원하는 출력에 적용 하고 비교합니다 ( permalink ).
예를 들어, crypt ( .-9A-Za-z
)에 의해 사용 된 기수 -64 알파벳 은 위의 방법을 사용하여 생성 될 수 있습니다.
".:A[a{":,:^
이것이 내가 아는 가장 짧은 방법입니다.
원하는 출력의 모든 문자는 ASCII 순서이므로 순열을 반복 할 필요가 없습니다.
를 사용하여 연결된 모든 문자 범위를 원하는 순서대로 푸시 할 수있는 것은 아닙니다 :,:^
.
예를 들어의 순열을 0-9A-Za-z;-?
실행 하여 범위 를 푸시 할 수 없습니다 .:,:^
"0:A[a{;@"
그러나 코드를 사용하여 원하는 문자열의 회전 변형을 찾을 수 있습니다.
A,'[,_el^'@,59>]s2*:T;"0:A[a{;@"e!{:,:^T\#:I)}=Ip
다음을 인쇄합니다 ( permalink ).
10
0:@[a{A;
이것은
"0:@[a{A;":,:^Am>
같은 효과가 있습니다
A,'[,_el^'@,59>]s
을 앞에 추가하지 않고 빈 스택에만 사용할 수 있습니다 [
.
스택에 정수가 있다고 가정하십시오. 홀수이면 3을 곱하고 1을 더합니다. 그렇지 않으면 2로 나누고 싶습니다.
"정상"if / else 문은 다음과 같습니다.
_2%{3*)}{2/}?
그러나 {}{}
이미 4 바이트를 추가하기 때문에 블록을 사용하는 것은 일반적으로 진행되지 않습니다 . ?
스택에서 두 항목 중 하나를 선택하는 데 사용될 수도 있습니다.
_2%1$3*)@2/?
이것은 1 바이트 더 짧습니다.
블록-? 빈 if 문은 항상 no-go입니다. 예를 들어
{}{2/}?
보다 2 바이트 길다
{2/}|
대신에
{2/}{}?
그리고 당신이 확인하는 것은 음이 아닌 정수입니다, 당신은 할 수 있습니다
g)/
새로운 {}&
및 {}|
되어 편리하지만 스택을 어수선 할 수없는 경우 가끔 문제.
그래도
_{…}{;}?
대신 임시 변수를 사용할 수 있습니다.
:T{T…}&
!)/
그리고 g)/
예에서 짧다.
CJam에는 스위치 문이 없습니다. 중첩 된 if 문도 잘 작동하지만 {{}{}?}{}?
이미 12 바이트 길이입니다.
조건을 음이 아닌 작은 정수로 변환 할 수 있으면 모든 case 문을 구분 된 문자열로 변환하고 해당 결과를 평가할 수 있습니다.
예를 들어, 우리는 실행하려면 code0
스택의 정수이면 0 , code1
이 경우 1 , 그리고 code2
이 경우 2 , 우리는 중 하나를 사용 할 수
_{({code2}{code1}?}{;code0}?
또는
[{code0}{code1}{code2}]=~
또는
"code0 code1 code2"S/=~
S/
로 문자열을 분할 ["code0" "code1" "code2"]
, =
해당 덩어리를 추출하고, ~
코드를 평가합니다.
스위치 문장이 실제로 작동하는지 확인 하려면 여기 를 클릭 하십시오 .
마지막으로 @ jimmy23013과 @RetoKoradi에서 제안한대로 스위치를 더 짧게 단축 할 수 있습니다. 말 code0
, code1
그리고 code2
이 길이 L 0 , L 1 과 L 2 를 각각.
만약 L 0 = L 1 ≥ L 2
"code0code1code2"L/=~
대신에 사용될 수 있으며, 여기서 L
이다 L 0 . 구분자에서 /
분리 하는 대신 문자열을 길이가 같은 청크로 나눕니다.
만약 L 0 ≥ L 1 ≥ L 2 ≥ L 0 - 1 ,
"cccooodddeee012">3%~
대신 사용할 수 있습니다. >
문자열의 시작 부분에서 0, 1 또는 2 개의 요소를 제거 3%
하고 첫 번째 요소부터 시작하여 세 번째 요소를 모두 추출합니다.
"code0code1code2"5/=~
있습니까? 나에게 훨씬 더 직관적 인 것 같습니다. 길이는 같습니다.
격자를 초기화하는 등의 짧은 배열이나 문자열이 가끔씩 자릅니다. 순진하게, 이것들은 4 바이트 이상의 비용이들 수 있으므로 동일한 결과를 제공하는 내장 값에 대한 작업을 찾는 것이 좋습니다. 특히 기본 변환이 유용합니다.
[0 1]
로 쓸 수 있습니다 2,
.[1 0]
로 쓸 수 있습니다 YYb
(즉, 이진수로 2).[1 1]
로 쓸 수 있습니다 ZYb
(즉, 이진수로 3).[[0 1] [1 0]]
은로 쓸 수 있습니다 2e!
.[LL]
로 쓸 수 있습니다 SS/
(한 칸씩 공백으로 나누기)."\"\""
로 쓸 수 있습니다 L`
."{}"
로 쓸 수 있습니다 {}s
.후자는 모든 대괄호 유형이 다른 바이트를 저장하려는 경우로 확장 될 수 있습니다.
"[{<()>}]"
로 쓸 수 있습니다 {<()>}a`
."()<>[]{}"
로 쓸 수 있습니다 {<()>}a`$
.특히 기본 변환 트릭은 때때로 나타나는 몇 가지 모호한 경우를 명심하는 데 유용 할 수 있습니다. 예를 들면 [3 2]
다음과 같습니다 E4b
(기본 4의 14).
아주 드문 경우에 인수 분해 연산자가 mf
유용 할 수도 있습니다 . 예를 들면 [2 7]
이다 Emf
.
다른 예를 보시면이 목록을 자유롭게 확장하십시오.
전체 스택을 지우려면 배열로 감싸서 팝하십시오.
];
좀 더 까다로운 점은 많은 계산을 수행했지만 최상위 스택 요소를 유지하고 모든 것을 버리고 싶을 경우입니다. 순진한 접근 방식은 최상위 요소를 변수에 저장하고 스택을 지우고 변수를 푸시하는 것입니다. 그러나 훨씬 짧은 대안이 있습니다 : 스택을 배열로 감싸고 마지막 요소를 추출하십시오.
]W=
(다른 날에 이것을 보여준 Optimizer에게 감사합니다.)
물론 스택에 두 개의 요소 만있는 경우 \;
더 짧습니다.
\;
TOS 아래의 요소 만 표시합니다. 당신은 의미 했습니까 ;;
?
e
그리고 10의 거듭 제곱다른 언어 와 마찬가지로 CJam 1e3
대신 쓸 수 있습니다 1000
.
이것은 정수가 아닌 기초와 정수가 아닌 지수에도 적용됩니다. 예를 들어, 1.23e2
밀어 123.0을 하고 1e.5
밀어 3.1622776601683795 (의 제곱근 10 ).
즉시 명백하지 않은 1e3
것은 실제로 두 개의 토큰이라는 것입니다.
1
스택 에서 정수 1 을 푸시합니다 .
e3
1000을 곱합니다 .
왜 중요한가요?
e<numeric literal>
이미 스택에있는 것을 호출 할 수 있습니다 .
2 3 + e3 e# Pushes 5000.
e<numeric literal>
배열을 통해 매핑 할 수 있습니다 .
5 , :e3 e# Pushes [0 1000 2000 3000 4000].
벡터의 유클리드 표준을 계산하는 간단한 방법, 즉 요소의 제곱의 합의 제곱근은
2f#:+mq
그러나 훨씬 짧은 방법이 있습니다.
mh
빗변 연산자 인 스택에서 두 개의 정수 a 와 b 를 팝 하고 sqrt (a 2 + b 2 )를 푸시 합니다.
스택에 벡터 x : = [x 1 … x n ], n> 1이:mh
있으면 (빗변으로 줄임) 다음을 달성합니다.
스택에 sqrt (x 1 2 + x 2 2 )를 남겨두고 첫 x 1 과 x 2 가 푸시되어 mh
실행 됩니다.
그런 다음 x 3 을 푸시하고 mh
다시 실행하여
sqrt (sqrt (x 1 2 + x 2 2 ) 2 + x 3 2 ) = sqrt (x 1 2 + x 2 2 + x 3 2 ) 를 남겨 둡니다 .
후 X N이 처리 된, 우리는 남아있는 (X SQRT (1) 2 + ... X N 2 ) 의 유클리드 놈 (X)를 .
경우 N = 1 및 X (1) <0 , 상기 코드는 잘못된 결과를 생성 할 것이다. :mhz
무조건 작동합니다. (@ MartinBüttner에게 감사의 말을 전합니다.)
나는 이 대답 에서 처음 으로이 트릭을 사용했습니다 .
CJam은 A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0 (음수가 아닌 n
) 공식을 사용하여 목록을 숫자로 변환합니다 . n
기본이며 l
목록 길이입니다. 이것은 A i 가 임의의 정수일 수 있음을 의미 하며,이 범위는 아니어야합니다 [0,n)
.
몇 가지 예 :
0b
마지막 항목을 추출하여 정수로 캐스트합니다. W=i
정수가 아닌 경우 바이트 처럼 작동 하고 저장합니다. 그러나 목록의 다른 모든 항목도 정수로 캐스트 할 수 있어야합니다.1b
합계를 돌려줍니다. :i:+
정수가 아닌 경우 2 바이트 처럼 작동 하고 저장합니다. 빈 목록으로도 작동하지만 작동 :+
하지 않습니다.[i{_1&9 32?_@\m2/}16*;]W%:c
문자를 줄 끝과 탭의 문자열로 변환하고로 변환 할 수 있습니다 2bc
. 그러나 코드 골프 프로그램에서는 인코딩 기능을 쉽게 사용할 수 없습니다. 그러나 일반적으로 필요하지 않습니다.다음 코드를 사용하여 문자열을 16 비트가 아닌 유니 코드 문자로 변환 할 수 있습니다 2A#b128b:c
. (나중에 설명이 추가 될 수도 있고 나중에 새 버전을 작성할 수도 있습니다.)
128b2A#b " Convert to base 1024. ";
W%2/)W%\:+ " Convert to two base 1024 digit groups. ";
[0X@
{
_54+
@I+_Am>@\-
_Am<@+ 0@-@1^
}fI
]);)
@\+[~+]2A#b_2G#<!{2A#b}*
\W%+:c
가장 중요한 숫자를 제거 할 수있는 방법을 찾을 수 있다면 비슷한 방법 n
이 다른 값을 가진 모든 정수 세트에 대해 작동합니다 n
.
$
삼항으로 사용 하는 경우메모리 누수를 신경 쓰지 않아도됩니다. 즉 나중에 사용하지 않을 스택에 사용되지 않은 요소를 남겨두면 ];
복사 연산자 $
는 삼항 연산자를 대신 할 수 있습니다 ?
.
?
두 항목을 선택하기 전에 조건을 계산할 수 있다면 잘 작동하지만, 그보다 더 자주 조건은 해당 항목에 따라 달라지며 결과를 훨씬 더 자연스럽게 만듭니다.
A B C
스택에 있다면 실행할 수 있습니다
!$
대신에
\@?
진실하고 다른 B
경우 복사 합니다 .C
A
경우 C
(실제 부울입니다 0
또는 1
), 당신은 실행할 수 있습니다
$
대신에
@@?
진실하고 다른 A
경우 복사 합니다 .C
B
행렬과 같은 중첩 목록이 있다고 가정 해보십시오.
[[0 1 2][3 4 5][6 7 8]]
또는 문자열 배열 :
["foo""bar"]
또한 블록을 중첩 레벨에 매핑하려고합니다 (즉, 각 숫자 또는 각 문자에 적용). 순진한 솔루션은 중첩됩니다 %
.
{{...}%}%
그러나 실제로 내부 블록을 스택으로 밀고을 사용할 수 있습니다 f%
. f
"추가 매개 변수가있는 맵"이므로 %
블록을 두 번째 매개 변수로 사용하여 외부 목록에 맵핑 됩니다.
{...}f%
2 바이트를 저장합니다.
같은 것을하는 또 다른 깔끔한 트릭 for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}
은
5,_f{f{...}}
외부 f
는 첫 번째 범위에 매핑되어 두 번째 범위를 추가 매개 변수로 제공합니다. 그러나 이제 f
다시 사용하는 경우 맨 위 스택 요소 만 배열이므로 f
외부 "반복 변수"를 추가 매개 변수로 제공하여 내부 블록을 해당 블록에 맵핑합니다. 이는 내부 블록이 스택 과 함께 i
그리고 j
스택에서 실행됨을 의미합니다 .
이것은 블록을 데카르트 곱으로 매핑하는 것과 동일한 문자 수를 갖습니다 (단, 배열로 쌍이 필요한 경우 후자는 더 짧아 지지만).
5,_m*{~...}%
차이점은이 버전은 모든 쌍에 대해 단일 결과 배열을 생성하는 반면, 이중 배열은 f
중첩 된 목록을 생성하며, 반복자 변수를 좌표로 사용하여 결과를 그리드에 저장하려는 경우 유용 할 수 있습니다.
이 트릭을 보여준 데니스에게 감사합니다.
f
그리고 :
지금 대단히 자신을 포함한 다른 연산자를 복용하여 개선되었습니다. 이것은 이제 더 많은 바이트를 절약 할 수 있음을 의미합니다. 연산자를 중첩 목록에 매핑하는 것이 훨씬 짧아졌습니다.
{:x}%
{x}f%
::x
그래도 중첩 목록에 블록을 매핑하는 데 도움이되지 않습니다.
Cartesian 제품에 블록 또는 연산자를 적용하는 것과 관련하여 이제 블록뿐만 아니라 연산자도 단축되었습니다.
5,_f{f{...}}
5,_ff{...}
5,_f{fx}
5,_ffx
좋은 점은 이제 이것들을 중첩시킬 수 있다는 것입니다. 따라서 목록 아래 3 단계에 쉽게 연산자를 적용 할 수 있습니다.
:::x
또는 속임수가있는 블록 :
{...}ff%
f~
...
많은 ASCII 아트 문제에 대해 나중에 두 가지 패턴을 생성하여 나중에 겹쳐 놓는 것이 유용합니다. 벡터화 된 연산자는 다른 유형의 중첩을 달성하는 데 매우 유용 할 수 있습니다.
연산자 벡터화의 유용한 속성 중 하나는 연산자가 짧은 문자열 / 배열의 각 요소에 대해 한 번만 실행되는 반면 대응 요소가없는 큰 요소의 요소는 그대로 유지됩니다.
.e<
e<
문자열, 문자, 배열 및 정수 쌍에 대한 최소 연산자 작업; 스택에서 두 개의 항목을 팝하고 e를 다시 밀어 넣습니다.
공백은 인쇄 가능한 다른 모든 ASCII 문자보다 코드 포인트가 낮으므로 .e<
생성 된 패턴의 일부를 "지우기"위해 사용할 수 있습니다.
"\/\/\/\/\/" " " .e<
e# This pushes " \/\/\/".
전체 예를 보려면 Me Want Honeycomb에 대한 내 답변을 참조하십시오 .
.e>
최대 연산자 e>
는 최소 연산자로 작동하며 반대 결과가 나타납니다.
공백의 코드 포인트가 낮기 때문에 .e>
공백 블록에 인쇄 가능한 문자 패턴을 삽입하는 데 사용할 수 있습니다.
[[" " " " " " " "] [" " " " " " " "]][["+" "" "-" ""]["" "*" "" "/"]] ..e>
e# This pushes [["+" " " "-" " "] [" " "*" " " "/"]].
전체 예를 보려면 Seven Slash Display에 대한 답변을 참조하십시오 .
.e&
논리 AND 연산자 e&
는 왼쪽 인수가 거짓이면 오른쪽 인수를, 그렇지 않으면 오른쪽 인수를 푸시합니다.
어떤 패턴에도 거짓 요소가 포함되어 있지 않은 경우 하나의 패턴을 다른 패턴에 무조건 적용 할 수 있습니다.
"################" " * * * *" .e&
e# This pushes " * * * *########".
전체 예를 보려면 미국 국기 인쇄에 대한 나의 답변을 참조하십시오 ! .
.e|
논리 OR 연산자 e|
는 인수 순서를 반대로하여 위와 같이 사용할 수 있습니다.
" * * * *" "################" .e|
e# This pushes " * * * *########".
&
항목이 목록에 있는지 확인하는 데 사용에 대한
1 [1 2 3] #W>
1 [1 2 3] #)
당신이 사용할 수있는
1 [1 2 3] &,
1 [1 2 3] &
대신 0/1과 진실 / 거짓을 각각 반환합니다.
z
직사각형이 아닌 배열zip 연산자 z
는 2 차원 1 배열 A 의 행과 열을 바꿉니다.이 배열 의 요소는 반복 가능할 수도 있습니다.
직사각이 아닌 배열의 경우 – zip
파이썬 (행을 같은 길이로 자르기) 또는 루비 (로 행을 nil
채우는 것) 와 같은 내장 함수 와 달리 CJam은 단순히 배열의 열을 행으로 변환하여 길이를 무시하고 격차.
예를 들어, 배열을 압축
[
[1]
[2 4]
[3 5 6]
]
배열을 압축하는 것과 같습니다.
[
[1 4 6]
[2 5]
[3]
]
또는 배열
[
[1]
[2 4 6]
[3 5]
]
세 가지 행동 모두가
[
[1 2 3]
[4 5]
[6]
]
스택에.
이것은 그것이 z
진화가 아니라는 것을 의미하지만 (경우에 따라 유용 할 수 있음) 몇 가지 응용 프로그램이 있습니다.
예를 들면 다음과 같습니다.
우리는 두 번 압축하여 배열의 열을 상단에 정렬 할 수 있습니다 (즉, 첫 번째 배열을 두 번째 배열로 바꿉니다).
zz
상기 방법의 사소한 수정은 유사한 문제에 사용될 수있다.
예를 들어, 배열의 열을 맨 아래에 맞추기 위해 (즉, 두 번째 배열을 첫 번째 배열로 바꾸려면) 행 순서를 반대로하여 두 번 압축 할 수 있습니다.
W%zzW%
문자열 배열이 주어지면 다음과 같이 가장 긴 문자열의 길이를 계산할 수 있습니다.
:,:e>
그러나 결과의 행 수를 압축하고 계산하면 3 바이트를 절약 할 수 있습니다.
z,
1 A 의 "행"이 반복 가능하지 않은 경우, 단일 행으로 취급하므로 임의 배열에 대해 압축이 작동합니다.z
z
빈 값을 건너 뛰고 열을 행으로 변환 하는 것을 그림 으로 표시 하면 동작이 훨씬 논리적 입니다. 이 예에서 입력의 첫 번째 열은 1, 2, 3이고 두 번째 열은 4, 5 (빈 위치는 건너 뜁니다), 세 번째 열은 6입니다. 그런 다음 결과의 행입니다.
CJam에서는 모든 예외가 치명적입니다. 이후 STDERR로 출력은 기본적으로 무시됩니다 , 우리는 우리의 장점이를 사용할 수 있습니다.
CJam의 모든 운영자는 스택에서 0 개 이상의 요소를 팝하고 일부 작업을 수행하며 스택에서 0 개 이상의 요소를 푸시하여 작업합니다. 작업이 수행되는 동안 예외가 발생하므로 여전히 요소가 팝업되지만 그에 대한 답은 없습니다.
몇 가지 사용 사례는 다음과 같습니다.
작은 스택 지우기
두 가지 요소가 포함 된 스택을 지우려면 @
사용할 수 있습니다. @
세 개의 스택 요소를 팝하려고 시도하지만 두 번째 스택 요소를 팝한 후 실패합니다.
세 가지 요소를 표시하는 다른 연산자는 동일한 용도로 사용됩니다.
스택에서 두세 개의 요소 제거
이러한 특정 요소에 대해 구현되지 않은 연산자는 종료 직전에 스택에서 두세 개의 요소를 표시하는 데 사용할 수 있습니다.
두 요소를 팝하려면 요소 b
중 하나가 문자이거나 정수가 아닌 경우 작동합니다.
세 개의 요소를 팝하려면 t
맨 아래 두 개 중 어느 것도 iterable이거나 맨 아래가 iterable이 비어 있거나 정수가 아닌 경우 작동합니다.
루프에서 나가기
때로는 정수가 0이되거나 문자열이 너무 짧아지면 루프를 종료해야합니다. 이러한 조건을 테스트하는 대신 관련 작업이 빈 문자열 또는 싱글 톤 인 0으로 실패하면 프로그램이 자연스럽게 진행되도록 할 수 있습니다.
조건부 실행
특정 유형의 입력에 대해 소스 코드를 실행하지 않아야 할 경우 때때로 해당 유형의 입력에 실패한 연산자를 사용할 수 있습니다.
예를 들어, i
정수로 평가되지 않은 ew
문자열의 경우 실패하고 길이가 0 또는 1 인 문자열의 경우 실패합니다.
여기 초보자를위한 것이 있습니다!
배열에서 최대 또는 최소 숫자를 찾아야 할 때 가장 쉽고 작은 방법은 배열을 정렬 한 다음 첫 번째 또는 마지막 요소를 꺼내는 것입니다.
따라서 배열이 변수에 있으면 A
A$W=
최대이며
A$0=
최소입니다.
동시에 둘 다 얻을 수도 있습니다
A$)\0=
이것은 읽은 후에 명백해 보일 수 있지만, 누군가의 첫 번째 시도 는 배열 의 사용 e<
또는 e>
배열을 통한 반복을 향하는 경향이 있습니다.
A{e<}*
최대 및 최소를 모두 원한다면 2 바이트 더 길고 더 길어집니다.
(
하고 )
대신 0=
과 W=
.
:e<
와:e>
매우 크지 만 임의의 숫자가 필요한 경우 일반적으로 과학적 표기법을 사용 9e9
하거나 큰 내장 변수 중 하나를 유사한 힘으로 올립니다 KK#
. 그러나 실제 숫자가 무엇인지 신경 쓰지 않고 일관되게 동일해야 할 필요가없는 경우 (예 : 임의의 숫자의 상한과 같이) 다음을 사용하여 2 바이트로 할 수 있습니다
es
대신에. 이것은 현재 타임 스탬프를 밀리 초 단위로 제공하며 10 12 정도입니다.
e9
.
때로는 두 개의 문자열이나 배열이 같지 않으면 진실한 값을 원하고 거짓이면 거짓 값을 원합니다. 확실한 해결책은 2 바이트입니다.
=!
평등을 확인하고 결과를 반전시킵니다. 그러나 일부 조건에서는
#
되면 #
제의 부분 배열로 제 2 어레이에 대해 두 배열 그것이 실제로 검색인가 (당신에게 인덱스 시작 부분 배열을 제공)된다. 따라서 두 배열이 동일하면 시작시 바로 하위 배열을 찾아 0
허위를 나타냅니다. 그러나 두 번째 배열을 찾을 수 없으면 -1
진실 을 줄 것입니다.
두 배열에 추가 조건이 필요한 이유는 두 번째 배열이 첫 번째 배열의 사소한 접두어 인 경우 잘못된 값을 생성하기 때문입니다.
"abc""ab"#
0
문자열이 같지 않지만 제공합니다 . 이 경우를 배제하는 가장 간단한 조건은 두 배열의 길이가 동일하다는 것을 아는 경우입니다. 그러나 특정 상황에서는 약한 조건이 충분할 수도 있습니다. 예를 들어 문자열이 정렬되어 있다는 것을 알고 있으면 접두사는 항상 두 번째가 아닌 첫 번째 문자열이됩니다.
배열이 있고 해당 배열의 모든 가능한 하위 집합이있는 배열을 원한다고 가정하십시오. 비결은 빈 배열로 시작한 다음 각 요소에 대해 이미 가지고있는 부분 집합을 복제하고 새 요소를 추가하는 것입니다 (요소 가 추가되지 않은 이전 결과 유지 ). 기본 사례, 즉 빈 배열 만 포함하는 배열을 사용하여 스택을 초기화해야합니다.
[1 2 3 4 5]La\{1$f++}/
이것에 대한 좋은 점은 문자를 추가하지 않고도 부분 집합에서 일부 계산을 즉시 실행할 수 있다는 것입니다. 모든 서브 세트의 제품을 원한다고 가정하십시오. 이 경우 기본 사례는을 포함하는 배열 1
이며 각 단계에서 가능한 제품의 이전 목록을 가져 와서 복제하고 중복 된 모든 항목에 새 요소를 곱합니다.
[1 2 3 4 5]1a\{1$f*+}/
나는 이것 또한 언급 할 가치가 있다고 생각합니다. 사용하다:
)-
모두 동일하지 않은 경우 진실을 반환하거나 모두 같으면 빈 목록을 반환합니다. 목록이 비어 있으면 오류가 발생합니다.
추출 된 항목이 배열 (또는 문자열) 자체 인 경우 :
)a-
부울 값을 얻으려면 !
또는 !!
을 사용하십시오 . 추출 된 항목이 배열 일 수 있고 최대 두 종류의 다른 항목이 있고 모두 같지 않은 경우 1이되도록하려면이 값이 더 짧습니다.
_|,(
0=
문자열배열의 첫 번째 요소를 검색하려면을 사용해야합니다 0=
(또는 (
배열의 나머지 부분을 스택에 남겨 두지 않아도되는 경우).
그러나 해당 배열이 문자열이면 문자로 캐스트하면 충분합니다.
"xyz"c e# Pushes 'x.
c
배열의 첫 번째 요소를 추출 하지 않는지 알지 못합니다 . 더 유용하고 일관성이 있습니다.
CJam에는 왼쪽으로 회전 연산자 m<
가 있는데, 일반적으로 배열을 임의의 수의 왼쪽으로 회전하는 데 사용해야합니다.
에서 어떤 경우에, 당신은 또한 사용할 수 있습니다 (+
이동과 추가하려면 :
[1 2 3] (+ e# Pushes [2 3 1].
[[1] [2] [3]] (+ e# Pushes [[2] [3] 1].
두 번째 예제는 배열의 첫 번째 요소도 반복 가능하므로 +
추가하는 대신 연결 되어 있기 때문에 작동하지 않았습니다 .
또한 회전 된 배열을 스택에 덤프하려면 :\
무조건 사용할 수 있습니다 (스왑하여 축소).
[1 2 3] :\ e# Pushes 2 3 1.
[[1] [2] [3]] :\ e# Pushes [2] [3] [1].
open이없는 [
한이 트릭은 전체 스택을 회전하는 데 사용할 수 있습니다.
]:\
스택에 문자열 / 숫자 / 등의 목록이 있다고 가정 해 봅시다. 상단과 그 밖의 다른 추가 항목. 즉
123 "waste" ["a" "b" "rty" "print" "me" "please"]
이제 마지막 목록 만 인쇄하는 데 관심이 있으므로
S*]W=
어떤 출력
a b rty print me please
스택 트릭을 지우고 공백으로 연결된 목록 만 인쇄하면 실제로 똑똑해 보입니다 (때로는 목록을 인쇄하는 바람직한 방법이 아닐 수도 있음).
이것은 더 골프 수 있습니다!
p];
2 바이트 더 짧습니다 !
목록 이외의 스택에 항목이 하나만 있으면 더 짧습니다!
p;
의 아름다움은 p
이 코드의 완료를 기다리지 않고, 스택의 최상위 항목, 즉시 STDOUT에 stringifies를 (또한 마지막에 줄 바꿈을 추가) 및 지문을 제거하는 것입니다.
위의 코드는
["a" "b" "rty" "print" "me" "please"]
그것은 스택에있을 때 목록의 정확한 표현입니다!
CJam은 내장 된 직교 제품 계산기 m*
를 가지고 있으며,이 목록에는 상위 2 개의 배열 목록 / 문자열을 가져와 가능한 모든 쌍을 만듭니다. 예를 들어
[1 2 3 4]"abc"m*
이파리
[[1 'a] [1 'b] [1 'c] [2 'a] [2 'b] [2 'c] [3 'a] [3 'b] [3 'c] [4 'a] [4 'b] [4 'c]]
스택으로
그러나 두 개 이상의 목록 / 문자열에서 가능한 모든 조합을 원한다면 어떻게해야합니까? 당신 m*
은 여러 번 사용합니까? 예를 들어
[1 2 3 4][5 6]"abc"m*m*
스택에 다음을 남길 것입니다
[[1 [5 'a]] [1 [5 'b]] [1 [5 'c]] [1 [6 'a]] [1 [6 'b]] [1 [6 'c]] [2 [5 'a]] [2 [5 'b]] [2 [5 'c]] [2 [6 'a]] [2 [6 'b]] [2 [6 'c]] [3 [5 'a]] [3 [5 'b]] [3 [5 'c]] [3 [6 'a]] [3 [6 'b]] [3 [6 'c]] [4 [5 'a]] [4 [5 'b]] [4 [5 'c]] [4 [6 'a]] [4 [6 'b]] [4 [6 'c]]]
제품은 여전히 페어이며 항목 중 하나는 페어 자체입니다. 이것은 예상되지 않았으며 평평한 조합을 원합니다.
그렇게하는 쉬운 방법이 있습니다. 데카르트 제품에 대해 원하는 모든 목록을 배열로 감싸고 카테 시안 제품을 쌍으로 작성하여 매번 평평하게 만드십시오.
[1 2 3 4][5 6]"abc"]{m*{(+}%}*
이 잎
[['a 5 1] ['b 5 1] ['c 5 1] ['a 6 1] ['b 6 1] ['c 6 1] ['a 5 2] ['b 5 2] ['c 5 2] ['a 6 2] ['b 6 2] ['c 6 2] ['a 5 3] ['b 5 3] ['c 5 3] ['a 6 3] ['b 6 3] ['c 6 3] ['a 5 4] ['b 5 4] ['c 5 4] ['a 6 4] ['b 6 4] ['c 6 4]]
스택에.
주문 유지를 원하십니까? 팝업 된 항목을 배열에 다시 추가하기 전에 간단히 교체하십시오. 즉
{m*{(\+}%}*
순열 만 원하십니까?
{m*{(+$}%_&}*
조합에서 고유 한 요소 만 원하십니까?
{m*{(+_&}%}*
그게 다야 지금은 .
]:m*:e_
여러 배열로 도 할 수 있습니다
복잡한 데이터 구조로 작업하는 경우 항목이 단순하지만 문자열로 변환하는 것이 도움이 될 수 있습니다.
예를 들어, 2D 비트 배열에서 처음 또는 마지막 몇 개의 항목을 가져오고 반환 된 유형에 신경 쓰지 않으려면 또는 sA<
에서 바이트를 저장합니다 .0=A<
:+A<
또는 입력에서 일부 비트를 수정하려는 경우 문자열을 평가하기 전에 수정할 수 있습니다.
또는이 구조를 가지고 간단한 목록으로 변환하려면 다음을 수행하십시오.
[[[[[[[[[1]2]3]4]5]6]7]8]9]
다른 방법으로 많은 문자로 할 수 있습니다.
[a{~)\}h;]W%
그러나 문자열의 경우 훨씬 짧을 수 있습니다.
s:~
두 자리 이상의 숫자가 있어도 더 짧습니다.
[`La`-~]
또는:
`']-~]
그러한 배열을 많이 포함하는 다른 배열이 필요하지 않은 경우.
e_
지금
s
여전히 더 잘 작동합니다.
N
대신에 사용La
대부분의 경우 빈 배열을 유일한 요소로 포함하는 배열로 초기화 된 것이 La
필요합니다.
많은 경우에 당신은 또한 같은 무언가를 인쇄하기 전에 각 요소 다음에 줄 바꿈을 추가하는 것이다 필요 No
나 N*
.
그러나 둘 다 참이면 때로는 N
개행 문자를 유일한 요소로 사용 하여 배열을 초기화 할 수 있음을 알 수 있습니다 . 나머지 코드에서 요소 앞에만 항목을 추가하고 맨 앞에 추가하는 것은 항상 문자 또는 배열입니다. 또는 선행 줄 바꿈이 허용되고 더 짧아지는 경우에만 추가하십시오.
S
출력을 공백으로 분리 해야하는 경우 에도 작동합니다.
드문 경우이지만 초기 요소는 문자열이어야합니다. 그러나 Na
나중에 줄 바꿈을 추가하는 것보다 짧은 것을 사용할 수 있습니다.
줄이 있고 "abbcdbbfghbdbb"
그것을 나누고 싶다고 가정 해보 십시오.b
"abbcdbbfghbdbb"'b/
이것은 스택에 남습니다.
["a" "" "cd" "" "fgh" "d" "" ""]
빈 문자열을 보시겠습니까? 그것들은 두 사람 b
이 함께 있었고 그들 사이에 아무것도 없었기 때문에 거기 에 있습니다. 때때로, 당신은 이것을 피하고 싶어합니다. 당신은 이것을 할 수 있습니다
"abbcdbbfghbdbb"'b/La-
또는 빈 문자열을 필터링
"abbcdbbfghbdbb"'b/{},
그러나 그것은 3 여분의 바이트입니다.
특정 용도의 경우에 덜 알려진 연산자이다 %
. 숫자 ( "abcd"2%
= "ac"
)를 기준으로 mod 및 map 및 split을 수행하는 것 외에도 %
string / array로 분할 할 수도 있습니다. 위의 사용 사례의 경우 :
"abbcdbbfghbdbb"'b%
떠날 것이다
["a" "cd" "fgh" "d"]
스택에.
오늘 내 대답 중 하나에서 이것을 지적 해 주신 @ user23013에게 감사합니다.
우리는 및 (또는 단항인지 이진 인지에 따라) :x
속기입니다 . 불행히도 단축 할 수있는 동등한 연산자는 없습니다 . 그러나, 매우 자주 우리가 할 때 , 반복적으로 스택에 항목 거짓말 아래를 수정하는 바이너리 연산자는 사실이다. 이 경우에 해당 항목이 배열이 아닌 경우 foreach와 같이 fold / reduce를 사용하여 바이트를 절약 할 수 있습니다.{x}%
{x}*
x
{x}/
{x}/
x
5 [1 2 3 4]{-}/ e# Gives -5
5 [1 2 3 4]+:-
접기는 항상 첫 번째 요소를 건드리지 않기 때문에 작동합니다. 불행히도 수정 된 요소가 배열 인 경우 바이트를 저장하지 않으므로 추가하면 래핑되지 않습니다. 그러나 때로는 배열에 이미 해당 요소가 포함되어 있기 때문에 운이 좋은 경우가 있습니다 {}/
.이 경우 나머지 를 사용하기 전에 요소를 수동으로 제거하는 대신 축소를 명심해야합니다 .
CJam에는 print
운영자가 o
있습니다. 작동하지만 모든 코드가 실행 된 직후 스택이 인쇄됩니다. 프로그램 끝에서 스택을 지우면 중지 할 수 있습니다. 간단히 이것을 끝에 넣으십시오.
];
당신이 사용할 수에 println하기 위해 oNo
또는 p
(같은 작품 `oNo
)
o
와 사이에 더 큰 차이가 있습니다p
. p
인쇄 할 항목을 명확한 문자열 표현으로 변환하여 시작합니다. p
를 실행하는 것과 같습니다 `oNo
.