다음 디브온 2013 코드골프 문제 J로 풀기
이번 디브온에서 미니대안언어축제가 진행되던 M2 밖에 텍스트큐브 부스에서 재미있는 코드골프 문제 풀기가 있었습니다. 150자 이하로 푸신 분들에게는 즉석에서 제공되는 원두커피와 텀블러가 상으로 주어졌다고 합니다. 문제는 아래와 같습니다. 이 결과가 나와야 하는데 언어 제약은 없답니다.


*
*
* *
* *
* *
** **
* *
* *
* *
*
*


어제 1등은 강성훈님이 gzip으로 출력문자를 압축해서 쉘 스크립트 뒤에 덧붙이는 식으로 하여 73바이트까지 줄인 것이라고 합니다.

저는 집에 와서 J로 잠깐 풀어봤습니다. 30바이트입니다.

' *'{~(,{:)@|:@|.^:4]4=+/~|i:4


일단 이 코드를 이해하려면 J의 이디엄들을 이해해야 합니다. 몇 가지 덩어리가 눈에 띄는데요.

' *'{~(,{:)@|:@|.^:4]4=+/~|i:4


이 부분은 0과 1을 각기 빈칸과 *로 바꾸는 코드입니다. 뒤에 달린 ~는 능동형을 수동형으로 바꿔주는 것인데, 예를 들어 3-1은 2인데, 3-~1은 -2가 됩니다. 즉, 좌측과 우측 피연산자(operand)의 순서를 바꿔주는 부사(동사를 꾸며주는)입니다. 원래 형태는 0 1 3 2 1 {'ABCDEFG' 하면 오른쪽에서 0번째, 1번째, 3번째, 2번째, 1번째로 이루어진 스트링(ABDCB)을 반환하는 것이죠. 따라서 오른쪽에서 0과 1로 이루어진 행렬이 나오는데 그걸 빈칸과 *로 바꿔주는 역할을 합니다.

' *'{~(,{:)@|:@|.^:4]4=+/~|i:4


그 다음 부분은 J에서 포크라고 부르는 것인데, g와 h가 동사일 때 (g h) y는 y g (h y)와 같습니다. h한 걸 g한다라고 이해하면 쉽습니다. ,는 스트링이나 숫자를 추가(append)하는 것이고, {:는 마지막 원소를 가져오는(take last) 것입니다. 따라서 마지막 원소를 뒤에 추가한다고 보시면 됩니다.

' *'{~(,{:)@|:@|.^:4]4=+/~|i:4


이 부분은 행렬을 시계방향으로 90도 회전시킵니다. |:는 행렬의 행과 열을 바꿔주고(Axy를 Ayx로), |.는 행렬의 원소 순서(예컨대 행의 순서)를 거꾸로 뒤집습니다. 순서가 |.한 다음 |:이므로 결과적으로는 시계방향으로 90도 회전이 됩니다.

예컨대(아래 예에서 처음 세 칸 띄어쓴 것은 사용자가 입력하고 붙어나오는 건 컴퓨터가 보여주는 결과이며, NB에서 해당줄 끝까지는 주석)


i.3 3
0 1 2
3 4 5
6 7 8
|. i.3 3
6 7 8
3 4 5
0 1 2
|: i.3 3
0 3 6
1 4 7
2 5 8
|:@|.i.3 3
6 3 0
7 4 1
8 5 2
|:@|. |:@|.i.3 3 NB. 두 번 90도 회전하면 180도 회전과 같음
8 7 6
5 4 3
2 1 0


' *'{~(,{:)@|:@|.^:4]4=+/~|i:4


이 부분은 앞의 동사를 4번 연속 적용하게 됩니다. 우리가 수학에서 아는 지수승(거듭 곱하기)의 외연을 확장한 겁니다. 예를 들어


+: 3 NB. +:는 인자를 두 배 하는(double) 동사
6
+: +: 3 NB. 두 배 한 것에 다시 두 배 하면 네 배
12
+: +: +: 3
24
+:^:(3) 3
24
+:^:(4) 3
48
+:^:(0 1 2 3 4) 3
3 6 12 24 48


앞 동사가 90도 회전한 다음에 맨 아래 원소(2차원 행렬에서 원소는 1차원 배열)를 복사해 붙이기였으므로, 이걸 4번 연속하면 원래 행렬의 네 테두리줄을 돌아가며 복사하는 셈이 됩니다. (마름모 꼭지점에서 하나씩 튀어나온 부분 처리)

' *'{~(,{:)@|:@|.^:4]4=+/~|i:4


이 부분은 마름모를 만드는 코드입니다. 아래를 보시면 이해가 되실 겁니다.

i:3 NB. i: y는 -y에서 y까지의 정수 배열을 만듭니다(steps)
_3 _2 _1 0 1 2 3
|i:3 NB. 절대값
3 2 1 0 1 2 3
+/~|i:3 NB. 3 2 1 0 1 2 3을 서로 더하되(+) 한 원소와 전체 배열을(/) 더해서 테이블을 만듦
6 5 4 3 4 5 6
5 4 3 2 3 4 5
4 3 2 1 2 3 4
3 2 1 0 1 2 3
4 3 2 1 2 3 4
5 4 3 2 3 4 5
6 5 4 3 4 5 6
3=+/~|i:3 NB. 3과 같으면 1 아니면 0
0 0 0 1 0 0 0
0 0 1 0 1 0 0
0 1 0 0 0 1 0
1 0 0 0 0 0 1
0 1 0 0 0 1 0
0 0 1 0 1 0 0
0 0 0 1 0 0 0


전체 코드의 실행순서는 위에서 설명한 것의 역순으로 됩니다. 따라서 마름모를 만들고, 그걸 90도씩 돌려가면서 꼭지점에 하나씩 점을 찍고(사실은 가장 바깥 라인을 복사), 그 행렬을 문자로 변환해주면 결과가 나옵니다.
by 애자일컨설팅 | 2013/10/27 15:29 | 트랙백(1) | 덧글(3)
트랙백 주소 : http://agile.egloos.com/tb/5774107
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Tracked from 浩然之氣 at 2013/11/21 01:09

제목 : 다음 디브온 2013 코드골프 문제 Ruby로 풀기
* * * * * * * * ** ** * * ......more

Commented by ash84 at 2013/10/28 07:25
파이썬으로 26일에 마지막으로 본게 97자였고 전 124자였는데 후덜덜이네요 31자라니 ㅋㅋ
Commented by 애자일컨설팅 at 2013/10/28 14:07
네. 30자로 한 글자 더 줄였습니다. ㅎㅎ
Commented by sun at 2013/10/31 18:25
단순히 텀블러를 목표로 하자면.. 그냥 편하게 가면 될것 같아요ㅎ (예전에 유행했던 다양한 Hello World 작성하기가 생각나지만..)

# 101 bytes
echo " *
*
* *
* *
* *
** **
* *
* *
* *
*
*"

:         :

:

비공개 덧글

< 이전페이지 다음페이지 >