KTUG마당은 KTUG를 방문하는 모든 이용자가 대화를 나누고 소식을 전하는 곳입니다.

  • 로그인 없이 자유롭게 글을 읽고 쓸 수 있는 철학은 처음과 같이 계속됩니다.
  • Team Blog의 글을 이곳 게시판의 "정보글"로 모았습니다. Team blog는 기고자가 올린 글에 질문을 받는 부담을 줄이기 위하여 댓글을 허용하지 않았습니다. 그러나 이곳 게시판으로 모으면서 댓글을 달 수 있습니다. 게시물을 작성하실 때 댓글을 원하지 않으시면 댓글을 허용하시지 않으시기를 바랍니다. 또한 불필요한 소모성 댓글을 달지 않도록 주의하여 주시기를 바랍니다.
  • TeX과 관련된 질문이나 답변은 QnA 마당을 이용하십시오. TeX과 관련된 질문은 지웁니다
  • MathJax를 이용한 수식조판을 사용하실 수 있습니다. 여기를 참조하세요.
  • 스팸 글을 막기 위하여 짧은 시간 내에 다시 글이 등록되는 IP를 막거나, 광고 글을 막기 위하여 금지어로 .com, .net 등을 설정하고 있습니다. 다소간의 불편함이 있으시더라도 양해 바랍니다.
    • 금지어에서 stackexchange, stackoverflow, ctan, overleaf, , github, google.com, gmail.com, .org, .io, sil.org, wiki.com, tistory.com등은 해제하였습니다.
  • 사용하는 편집기는 CKeditor입니다. 편집기에서 [enter]를 누르면 <p> 태그가 들어가고, 문단으로 생각하고 한줄을 비웁니다. 글줄만 바꾸려면 shift-enter 를 누르시면 <BR>가 들어가므로 용도에 맞게 나누어 쓸 수 있습니다.

자유글 ksbaduk 패키지 이야기(1): 흰돌과 검은돌

2015.06.06 22:38

nanim 조회 수:5841

원래 이런 글은 재미도 없고 쓸 생각이 없었는데요,

요즘 ktug 분위기가 뭔가 뒤숭숭해보여서 글 하나라도 써야될 거 같더라고요.
얼마 전에 ksbaduk이라는 패키지를 하나 제작했는데, 코드 전체에 대해 해설하면 좋겠지만 그 역시 재미도 없을 거고,
몇몇 군데 저 스스로 코딩하면서 재미있었다고 생각한 부분을 한 두어 차례 코드 해설 겸해서 연재하려 합니다.
(반응이 없으면... 바로 중단...)
첫 글은 가장 기본적인 흑돌/백돌 그리기에 대한 거구요.

==========

"잠수탔던 하수"께서 어느날 수면 위로 부상하시어서 재미있는 문서를 하나 보여주셨습니다.
디씨인사이드 바둑갤에서도 활동하시는 듯. 그곳에서 연재되었던 "병국세해"라는 글을 모아서 pdf책으로 제작한 거였더랬죠.
"그림은 TikZ로 그렸다"고 하셔서 소스를 보여주실까 내심 기대했는데, 안 보여주시더라구요.
그래서... "이런 그림은 어떻게 그릴 수 있을까?" 생각하다가 한 번 해보게 된 것이었어요.
잠/하 님께 감사드립니다. 그 책이 아니었으면 이런 작업은 시작되지도 않았을 거여요.

==========

일단 바둑판 자체를 그리는 거야... 뭐... 간단하였습니다. 계산을 쉽게 하기 위하여 선 사이를 모두 1(cm)로 하고,
tikzpicture 환경을 scaling하는 방식으로 해보았습니다.

\begin{tikzpicture}[scale=0.5]
\foreach \i in {2.5,3.5,...,18.5} \draw (\i,1.5) -- (\i,19.5);
\foreach \j in {2.5,3.5,...,18.5} \draw (1.5,\j) -- (19.5,\j);
\foreach \i in {4.5,10.5,16.5} \foreach \j in {4.5,10.5,16.5} \filldraw (\i,\j) circle (3pt);;
\end{tikzpicture}

왼쪽 하단을 (0,0)으로 하고 오른쪽 상단을 (19,19)로 해서, 
0.5, 1.5, 2.5, 3.5... 18.5로 가로세로 선을 그으면 끝이죠.
나중에 좌표 이름을 붙이도록 하라고 하셔서 이것을 (1,1)에서 (20,20)으로 바꿨지만 기본적으로는 동일합니다.
위의 코드만 실행하면 외곽선이 안 나올텐데, 그건 조금 두껍게 rectangle로 그려주면 돼요. (1.5,1.5)--(19.5,19.5)로 하는 거죠.
(직접 해보시기 바랍니다.)
마지막의 3포인트짜리 채운 원은 화점과 천원을 그린 거고요.
처음 보시는 분들은 tikz의 \foreach문이 얼마나 강력한지 주의깊게 보시면 되겠네요.

==========

이제 흰돌 하나를 그리려고 합니다. 좌하귀 화점의 좌표는 (D4). 이곳에 적당한 반지름을 가진 circle을 filldraw하면 되겠지요.
(D4)는 가만히 생각해보면 (4,4)란 말이거든요. 그런데 위에서 그린 바둑판 (1,1)--(20,20)에서 이 점의 좌표는 어디일까요?
tikz로 그린 tikzpicture 영역에서 좌표계는 1사분면과 같은 방식으로 매겨지니까, (4,4)를 (4.5,4.5)에 대응시킬 수 있습니다.

\filldraw (4.5,4.5) circle (0.45);

반지름의 길이가 0.5가 되면 나란히 놓인 돌이 맞닿게돼요. 그러니 0.5보다 조금 작게 그리는 것이 좋습니다.
그리는 것 자체는 어렵지 않네요. 다만 이것을 같은 tikzpicture 속에서 그려야 하니까 overlay하는 게 좋겠죠.

여기까지 하면, 바둑판 위에 바둑알을 그리는 것이 가능해집니다. filldraw에 색상만 정해주면 흰돌도 그릴 수 있네요.

\filldraw [fill=white,draw=black] (16.5,16.5) circle (0.45);

참 쉽죠?

이제 문제는 사용자 입력 명령입니다. \White{Q16}, \Black{D4} 이런 식으로 입력하고 싶단 말이죠.
규칙은 알파벳이 먼저 오고 그 뒤에 한 자리 또는 두 자리 숫자가 따라붙습니다.
다행히 알파벳이 두 글자 이상 되는 건 없으니까요, 다음처럼 하기로 했습니다.
(TeX 코딩은 사실 아이디어와의 싸움입니다. 언어 자체보다 해결방법이 더 중요하지요.)
  1. 이 token list의 첫 글자를 떼어내서 이것을 숫자로 변환한다.
  2. 첫 글자를 떼고 남은 글자들을 숫자로 간주한다.
이렇게 하면 숫자 두 개를 얻을 수 있어요. 여기에 각각 0.5씩 더하면 그려야 할 좌표가 나온다는 것입니다.

문자를 숫자로 변환하는 것이 또 문제였는데요, 처음에는 \int_from_alph:n 이라는 함수를 써보려고 했습니다.
이것도 괜찮긴 한데 두 가지 문제가 있더라고요, 하나는 이 함수를 변수와 결합하여 다른 함수로 처리할 때의 확장 문제가 골치아파요.
두 번째는 A-H까지는 이걸로 얻은 숫자를 그냥 써도 되는데 J-T까지는 1씩 줄여줘야 한다는 거였죠. (왜냐면 I를 안 쓰니까)
그래서 쉽게 가기로 했습니다. \str_case:nn으로 문자를 검사하기로 한 거죠. 특별한 트릭이 없기 때문에 간명하고요.

\str_case:nn { \l_tmpa_tl }
{
   { D } { \int_set:Nn \x_pos_int { 4 } }
   { Q } { \int_set:Nn \x_pos_int { 16 } }
}

위의 루틴을 \firstchar_to_int:n 이라고 정의하고 \White 명령을 만들어봅니다.
이 코드에서 \exp_args: 어쩌구는 인자를 확장하는 명령인데 나중에 설명할 수 있는 기회가 있기를 바랍니다.
이걸 무시하면 이 코드가 무슨 일을 하는지 금방 알 수 있을 겁니다.

\NewDocumentCommand \White { m }
{
   \exp_args:Nx \firstchar_to_int:n { \tl_head:n { #1 } }   %% 첫 글자만 \firstchar_to_int:n 에게 먹입니다.
   \exp_args:NNx \int_set:Nn \y_pos_int { \tl_tail:n { #1 } }  %% 남은 숫자를 \y_pos_int로 설정합니다.
   \filldraw [ fill=white, draw=black, overlay ] 
      ( \fp_eval:n { \x_pos_int + 0.5 } , \fp_eval:n { \y_pos_int + 0.5 } ) circle (0.45);
}

위에 그린 바둑판 위에 \White{D4}를 놓아봤습니다. 첨부 그림처럼 되었네요.
스크린샷 2015-06-06 오후 10.24.44.png

=======


지금까지 한 것의 소스를 첨부했습니다. (lsbd-1.tex)

========

[연습문제(초급)]: 만약 \White{4D} 또는 \Black{15Q}와 같이 입력받으려면 어떻게 해야 할까요?
이와 같이 입력받아서 바둑돌을 그리는 명령을 정의해주세요.

[연습문제(중급)]: 입력이 \White{4D} 또는 \White{D4} 어떤 식으로 입력되더라도 같은 위치에 바독돌을 그리게 하는 명령 \White를 정의하세요.

좋은 답안을 제출해주시면 뭔가 있을는지... 없을는지... 도...




XE Login