# 우리 게임에서 특별한 동작을 생성하기 (Creating Special Actions in Our Game)

We have only one more thing to do now and our game will be complete: Add some special actions to the game that the player has to do to win in the game. The first command will let the player weld the chain to the bucket in the attic:

이제 할 일이 하나만 더 남았고, 게임이 곧 완성되겠네요: 플레이어가 게임에서 승리하기 위해 해야 하는 몇 가지 특별한 행동을 게임에 추가하세요. 첫 번째 명령은 플레이어가 다락방에 있는 양동이에 체인을 용접하도록 합니다:

(def chain-welded false)  

(defn weld [subject object]
  (cond (and (= location 'attic)  
             (= subject 'chain)  
             (= object 'bucket)  
             (have? 'chain)  
             (have? 'bucket)  
             (not chain-welded))  
        (do (def chain-welded true)  
            '(the chain is now securely welded to the bucket -))  
        :else '(you cannot weld like that -)))  

So first we created a new global variable that lets us tell whether we've done this action already. Next, we create a weld function that makes sure all the right conditions are in place for welding and lets us weld.

먼저 이 작업을 이미 수행했는지 여부를 알 수 있는 새로운 전역 변수를 만들었습니다. 다음으로 용접에 적합한 조건이 모두 갖추어졌는지 확인하고 용접할 수 있는 용접 함수를 생성합니다.

Welding

Let's try our new command:

새로운 명령을 사용해 보겠습니다:

(weld 'chain 'bucket)

user=> (weld 'chain 'bucket)
(you cannot weld like that -)

Oops... we're don't have a bucket or chain, do we? ...and there's no welding machine around... oh well...

이런... 버킷이나 체인이 없군요. 그렇죠? ...용접기도 없고... 오, 뭐...

Now let's create a command for dunking the chain and bucket in the well:

이제 체인과 양동이를 우물에 담그는 명령을 만들어 보겠습니다:

(def bucket-filled false)  

(defn dunk [subject object]
  (cond (and (= location 'garden)  
             (= subject 'bucket)  
             (= object 'well)  
             (have? 'bucket)  
             chain-welded)  
        (do (def bucket-filled true)  
            '(the bucket is now full of water))  
        :else '(you cannot dunk like that -)))

Now if you paid attention, you probably noticed that this command looks a lot like the weld command... Both commands need to check the location, subject, and object - But there's enough making them different enough so that we can't combine the similarities into a single function. Too bad...

이제 주의를 기울였다면 이 명령이 용접 명령과 매우 유사하다는 것을 눈치챘을 것입니다... 두 명령 모두 위치, 주어, 대상을 확인해야 하지만, 유사성을 단일 함수로 결합할 수 없을 정도로 충분히 다릅니다. 안타깝네요...

...but since this is Lisp, we can do more than just write functions, we can cast SPELs! Let's create the following SPEL:

...하지만 이것은 Lisp이므로 함수를 작성하는 것 외에도 SPEL을 캐스팅할 수 있습니다! 다음 SPEL을 만들어 봅시다:

(defspel game-action [command subj obj place & args]
    `(defspel ~command [subject# object#]
     `(spel-print (cond (and (= location '~'~place)  
                             (= '~subject# '~'~subj)  
                             (= '~object# '~'~obj)  
                             (have? '~'~subj))  
                        ~@'~args  
                        :else '(i cannot ~'~command like that -)))))  

Notice how ridiculously complex this SPEL is - It has more weird quotes, backquotes, commas and other weird symbols than you can shake a list at. More than that it is a SPEL that actually cast ANOTHER SPEL! Even experienced Lisp programmers would have to put some thought into create a monstrosity like this (and in fact they would consider this SPEL to be inelegant and would go through some extra esoteric steps to make it better-behaved that we won't worry about here...)

이 주문이 얼마나 우스꽝스러울 정도로 복잡한지 주목하세요. 목록에서 흔들 수 있는 것보다 더 많은 이상한 따옴표, 따옴표, 쉼표 및 기타 이상한 기호가 포함되어 있습니다. 그 이상으로 실제로 또 다른 스펠을 시전하는 스펠입니다! 숙련된 Lisp 프로그래머도 이런 괴물을 만들기 위해 약간의 고민을 해야 할 것입니다(사실 그들은 이 SPEL이 우아하지 않다고 생각하고 더 나은 동작을 위해 몇 가지 난해한 단계를 거칠 것입니다... 여기서는 걱정하지 않겠습니다...).

Game Action

The point of this SPEL is to show you just how sophisticated and clever you can get with these SPELs. Also, the ugliness doesn't really matter much if we only have to write it once and then can use it to make hundreds of commands for a bigger adventure game.

이 주문의 요점은 이 주문으로 얼마나 정교하고 영리하게 만들 수 있는지 보여드리는 것입니다. 또한 한 번만 작성하면 더 큰 어드벤처 게임에서 수백 개의 명령을 만드는 데 사용할 수 있다면 추악함은 그다지 중요하지 않습니다.

Let's use our new SPEL to replace our ugly weld command:

새로운 SPEL을 사용하여 못생긴 weld 명령을 대체해 보겠습니다:

(game-action weld chain bucket attic  
   (cond (and (have? 'bucket) (def chain-welded true))  
              '(the chain is now securely welded to the bucket -)  
         :else '(you do not have a bucket -)))  

Look at how much easier it is to understand this command - The game-action SPEL lets us write exactly what we want to say without a lot of fat - It's almost like we've created our own computer language just for creating game commands. Creating your own pseudo-language with SPELs is called Domain Specific Language Programming, a very powerful way to program very quickly and elegantly.

이 명령을 얼마나 쉽게 이해할 수 있는지 보세요. game-action SPEL을 사용하면 군더더기 없이 원하는 내용을 정확하게 작성할 수 있습니다. 마치 게임 명령을 만들기 위해 컴퓨터 언어를 직접 만든 것과 같습니다. SPEL로 자신만의 의사 언어를 만드는 것을 도메인 특화 프로그래밍(Domain Specific Language Programming)이라고 하는데, 이는 매우 빠르고 우아하게 프로그래밍할 수 있는 매우 강력한 방법입니다.

(weld chain bucket)

user=> (weld chain bucket) (you do not have a chain -)

...we still aren't in the right situation to do any welding, but the command is doing its job!

...아직 용접을 할 수 있는 적절한 상황은 아니지만, 명령이 제 역할을 하고 있습니다!

Dunking

Next, let's rewrite the dunk command as well:

다음으로 dunk 명령도 다시 작성해 보겠습니다:

(game-action dunk bucket well garden  
             (cond chain-welded   
                   (do (def bucket-filled true)  
                       '(the bucket is now full of water))  
                   :else '(the water level is too low to reach -)))  

Notice how the weld command had to check whether we have? the subject, but that the dunk command skips that step - Our new game-action SPEL makes the code easy to write and understand.

weld 명령은 주어가 있는지 확인해야 했지만 덩크 명령은 이 단계를 건너뛰었습니다. 새로운 게임 액션 스펠을 사용하면 코드를 쉽게 작성하고 이해할 수 있습니다.

Splash

And now our last code for splashing water on the wizard:

이제 마법사에 물을 뿌리는 마지막 코드입니다:

(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 -)  
                   :else '(the wizard awakens from his slumber and greets you  
                               warmly -  
                               he hands you the magic low-carb donut - you win!  
                               the end -)))  

Getting the Donut

You have now written a complete text adventure game!

이제 완전한 텍스트 어드벤처 게임을 작성했습니다!

Click HERE for a complete walkthrough of the game,

게임 전체 안내를 보려면 여기를 클릭하세요,

Click HERE for a copy of the source code you can copy & paste into your Clojure prompt in a single step.

여기를 클릭하여 소스 코드 사본을 복사하여 Clojure 프롬프트에 한 번에 붙여넣을 수 있습니다.

In order to make this tutorial as simple as possible, many details about how Lisp works have been glossed or fudged over, so let's look at what those details are...

이 자습서를 최대한 간단하게 만들기 위해 Lisp의 작동 방식에 대한 많은 세부 사항이 광택이 나거나 가려져 있으므로 이러한 세부 사항이 무엇인지 살펴 보겠습니다...