Lisp로 주문 외기 - 9 -

2009-05-25

게임의 특별한 동작 만들기

이제 완성까지 딱 하나만 더 하면 됩니다. 플레이어가 게임을 끝내기 위한 특별한 동작을 좀 더하는 거죠. 첫 번째 명령은 플레이어가 쇠사슬을 다락방에 있던 양동이에 용접하는 게 될 겁니다.

(setf chain-welded nil)

(defun weld (subject object) (cond ((and (eq location ‘attic) (eq subject ‘chain) (eq object ‘bucket) (have ‘chain) (have ‘bucket) (not chain-welded)) (setf chain-welded ’t) ‘(the chain is now securely welded to the bucket.)) (t ‘(you cannot weld like that.))))

그러니 일단 이미 행동을 했는지 안했는지 알려주는 새 전역변수를 만듭시다. 다음에, 용접할 수 있는 상황인지 확인하고 용접할 수 있게 해 주는 용접 함수를 만들어 봅시다. weld

새 명령을 시험해 볼까요.

(weld ‘chain ‘bucket)

==> (YOU CANNOT WELD LIKE THAT.)

이런… 양동이나 쇠사슬이 없군요. 그렇죠? 근처에 용접기도 없구요. …아 그래요..

그럼 이제 쇠사슬과 양동이를 우물에 집어넣는 명령을 만들어 볼까요?

(setf *bucket-filled* nil)

(defun dunk (subject object) (cond ((and (eq location ‘garden) (eq subject ‘bucket) (eq object ‘well) (have ‘bucket) chain-welded) (setf bucket-filled ’t) ‘(the bucket is now full of water)) (t ‘(you cannot dunk like that.))))

주의를 기울였다면 이제, 이 명령이 용접 명령과 흡사하다는 걸 알아챘을 겁니다. 두 명령은 위치, 대상, 조건을 검사할 필요가 있습니다. 하지만 둘은 다른 점이 충분히 많아서, 비슷한 부분을 하나로 묶을 수가 없습니다. 슬프군요…

…하지만 이건 Lisp니까, 그냥 함수를 쓰는 것보단 더 많은 일을 할 수 있어요. 주문(SPEL)을 욀 수 있죠! 아래의 주문(SPEL)을 만들어 봅시다.

(defspel game-action (command subj obj place &rest rest) `(defspel ,command (subject object) `(cond ((and (eq *location* ',',place) (eq ',subject ',',subj) (eq ',object ',',obj) (have ',',subj)) ,@',rest) (t '(i cant ,',command like that.)))))

이 주문 (SPEL)이 얼마나 흥미로운 복합체인가 보세요. 무지 많은 이상한 따옴표, 역 따옴표, 콤마, 다른 이상한 기호들이 있지요. 이건 보통 주문이 아니라 실제로 다른 주문(SPEL)을 외는 주문이에요! 숙련된 Lisp 프로그래머라도 이런 괴물 같은 걸 만들어내려면 좀 생각을 해야 합니다. (그리고 사실 이런 주문(SPEL)은 고상하지 못한 걸로 생각하고, 좀 더 난해한 단계들을 더 거쳐서 더 잘 돌아가는 걸 만들테지만, 여기서 신경쓸 일은 아니죠…)

game_action

이 주문(SPEL)의 요점은 여러분이 이런 주문들을 다룰 수 있다면, 얼마나 교육받았고 똑똑한지 알려줄 수 있다는 겁니다. 거기다, 이걸 단 한번만 쓰고서, 더 큰 어드벤처 게임을 위한 몇 백개의 명령을 한 번에 만들 수 있다면, 모양새 나쁜 건 문제가 아니죠.

자, 그럼 새 주문(SPEL)으로 전에 만든 볼품없는 weld명령을 대체해 볼까요.

(game-action weld chain bucket attic (cond ((and (have 'bucket) (setf *chain-welded* 't)) '(the chain is now securely welded to the bucket.)) (t '(you do not have a bucket.))))

명령을 얼마나 이해하기 쉬워졌는지 한 번 보세요 -game-action 주문(SPEL)은 기름기없이 정확히 말하고 싶은 것만 쓰게 해 줍니다- 거의 게임 명령을 만들기 위한 컴퓨터 언어를 만든 것이나 다름 없어요. SPEL로 개별 의사 언어를 만드는 것은 특정 도메인 언어 프로그래밍(Domain Specific Language Programming)이라 불리는데, 프로그램을 아주 빠르고 우아하게 짤 수 있는 방법입니다.

(weld chain bucket) ==> (YOU DO NOT HAVE THE CHAIN.) ...아직도 용접하기엔 적합한 상황이 아니군요, 하지만 명령은 제대로 돌아가고 있어요. dunk

다음엔 dunk 명령을 새로 짜 봅시다.

(game-action dunk bucket well garden (cond (chain-welded (setf bucket-filled ’t) ‘(the bucket is now full of water)) (t ‘(the water level is too low to reach.))))

용접(weld)명령이 어떻게 용접할 물체를 가지고 있는지 검사했는지에 주목하세요, 하지만 dunk 명령은 이 단계를 건너뜁니다. - 새 game-action 주문(SPEL)이 코드를 더 쉽게 쓰고 이해하도록 만들어줬습니다.

splash

이제 마법사에게 물을 쏟아붇는 마지막 코드입니다. (game-action splash bucket wizard living-room (cond ((not bucket-filled) ‘(the bucket has nothing in it.)) ((have ‘frog) ‘(the wizard awakens and sees that you stole his frog. he is so upset he banishes you to the netherworlds- you lose! the end.)) (t ‘(the wizard awakens from his slumber and greets you warmly. he hands you the magic low-carb donut- you win! the end.))))

donut 텍스트 어드벤처 게임을 완전히 다 만들었습니다!!

게임의 전체 진행을 보려면 여기를 클릭 Lisp프롬프트에 한 번 Copy&Paste 로 끝날 수 있는 소스코드를 보려면 여기를 클릭

이 연습서를 가능한 간단히 만들기 위해, Lisp가 어떻게 작동하는가 하는 많은 세부 사항은 주석 처리되거나 별도 페이지로 넘어갔습니다. 그러니 그 세부 사항이 어떤지 봅시다….

윈도에서 USB 메모리에 우분투 설치 씨디 담기 난 명복 못 빌겠다.