1/* Look Before You Leap, by John Lewis. */
    2
    3:- dynamic i_am_at/1, at/2, holding/1, dead/1, inspected/1, unvisited/1,
    4        dark/1, invisible/1, locked/1, empty/1, alive/1, health/1.    5:- retractall(at(_, _)), retractall(i_am_at(_)), retractall(alive(_)).    6
    7/* The player's state */
    8
    9i_am_at(hamlet).
   10health(100).
   11
   12/* The paths between areas */
   13
   14path(hamlet, n, apothecary).
   15path(outside_church, e, hamlet).
   16path(hamlet, e, narrow_pass).
   17
   18path(hamlet, d, well) :-
   19    unvisited(well), !,
   20    retract(unvisited(well)),
   21    write('You decide to jump down the well. That was rather silly, '), nl,
   22    write('you land in a heap at the bottom only to notice there was a '), nl,
   23    write('ladder you could have used.'), nl,
   24    decrease_health(30).
   25
   26path(hamlet, d, well).
   27
   28path(outside_church, n, church).
   29path(beach, n, outside_church).
   30
   31path(church, d, crypts) :-
   32        dark(crypts),
   33        holding(torch), !,
   34        retract(holding(torch)),
   35        retract(dark(crypts)),
   36        write('When you arrive in the crypt you light a series of braziers'), nl,
   37        write('and cast the spent torch aside, having sufficiently'), nl,
   38        write('illuminated the area.'), nl.
   39
   40path(church, d, crypts).
   41path(crypts, u, church).
   42
   43path(crypts, _, crypts) :-
   44        dark(crypts), !,
   45        write('You stumble blindly through the dark and hit your head.'), nl,
   46        write('That''s going to leave a mark.'), nl,
   47        decrease_health(20).
   48
   49path(crypts, n, fancy_tomb).
   50
   51path(narrow_pass, e, chasm).
   52
   53path(chasm, e, outside_castle) :-
   54        invisible(bridge),
   55        write('You walk out over the chasm and promptly fall. It briefly '), nl,
   56        write('occurs to you that that wasn''t wise before you hit the bottom'),
   57        nl,
   58        !, die.
   59
   60path(chasm, e, outside_castle) :-
   61        locked(castle),
   62        holding(ring), !,
   63        retract(locked(castle)),
   64        write('When you near the castle gates the signet ring you''re'), nl,
   65        write('wearing glows momentarily and the castle gates slowly'), nl,
   66        write('open granting you passage. Neat!'), nl.
   67
   68path(chasm, e, outside_castle).
   69
   70path(outside_castle, n, outside_castle) :-
   71        locked(castle), !,
   72        write('The castle gates are closed tight with no hope of being '), nl,
   73        write('forced open.'), nl.
   74
   75path(outside_castle, n, castle).
   76
   77path(castle, n, castle) :-
   78        alive(vampire), !,
   79        write('The vampire is not impressed by your bravery and takes a'), nl,
   80        write('sizable chunk out of your neck before you manage to stagger'), nl,
   81        write('away.'), nl,
   82        decrease_health(50).
   83
   84path(castle, n, throne_room).
   85
   86path(X, w, Y) :- path(Y, e, X).
   87path(X, s, Y) :- path(Y, n, X).
   88path(X, u, Y) :- path(Y, d, X).
   89
   90/* The locations of items */
   91at(coin, well).
   92at(jar, apothecary).
   93at(sand, beach).
   94at(driftwood, beach).
   95at(crown, throne_room).
   96
   97/* The state of areas */
   98unvisited(hamlet).
   99unvisited(well).
  100unvisited(castle).
  101dark(crypts).
  102invisible(bridge).
  103locked(castle).
  104empty(basin).
  105alive(vampire).
  106
  107/* Prominent features of areas that can be inspected. */
  108feature_of(hamlet, well).
  109feature_of(hamlet, fire).
  110feature_of(beach, sand).
  111feature_of(hamlet, sky).
  112feature_of(beach, sky).
  113feature_of(outside_church, sky).
  114feature_of(narrow_pass, sky).
  115feature_of(chasm, sky).
  116feature_of(outside_castle, sky).
  117feature_of(fancy_tomb, sarcophagus).
  118feature_of(church, altar).
  119feature_of(chasm, chasm).
  120feature_of(outside_castle, gate).
  121feature_of(castle, vampire).
  122
  123/* These rules describe how to pick up an object. */
  124
  125take(crown) :-
  126        i_am_at(throne_room), !,
  127        write('You eagerly grab the crown and put it on your head. You'), nl,
  128        write('wait a few seconds but nothing magical happens, even so you'), nl,
  129        write('feel pretty cool wearing a crown.'), nl, nl,
  130        write('Congratulations you have beaten the game!'),
  131        finish.
  132
  133take(X) :-
  134        holding(X),
  135        write('You''re already holding it!'),
  136        !, nl.
  137
  138take(X) :-
  139        i_am_at(Place),
  140        at(X, Place),
  141        retract(at(X, Place)),
  142        assert(holding(X)),
  143        write('OK.'),
  144        !, nl.
  145
  146take(_) :-
  147        write('I don''t see it here.'),
  148        nl.
  149
  150
  151/* These rules describe how to put down an object. */
  152
  153drop(X) :-
  154        holding(X),
  155        i_am_at(Place),
  156        retract(holding(X)),
  157        assert(at(X, Place)),
  158        write('OK.'),
  159        !, nl.
  160
  161drop(_) :-
  162        write('You aren''t holding it!'),
  163        nl.
  164
  165
  166/* These rules define the direction letters as calls to go/1. */
  167
  168n :- go(n).
  169
  170s :- go(s).
  171
  172e :- go(e).
  173
  174w :- go(w).
  175
  176d :- go(d).
  177
  178u :- go(u).
  179
  180
  181/* This rule tells how to move in a given direction. */
  182
  183go(Direction) :-
  184        i_am_at(Here),
  185        path(Here, Direction, There),
  186        retract(i_am_at(Here)),
  187        assert(i_am_at(There)),
  188        !, look.
  189
  190go(_) :-
  191        write('You can''t go that way.').
  192
  193
  194/* This rule tells how to look about you. */
  195
  196look :-
  197        i_am_at(Place),
  198        describe(Place),
  199        nl,
  200        notice_objects_at(Place),
  201        nl.
  202
  203/* This rule tells how to inspect a thing or item */
  204
  205inspect(Object) :-
  206        i_am_at(Place),
  207        feature_of(Place, Object), !,
  208        describe_feature(Object),
  209        nl.
  210
  211inspect(Object) :-
  212        holding(Object), !,
  213        write('A plain '), write(Object), write('.'), nl.
  214
  215inspect(Object) :-
  216        i_am_at(Place),
  217        at(Object, Place), !,
  218        write('There is a '), write(Object), write(' here.'), nl.
  219
  220inspect(_) :-
  221    write('Nothing to see here.'), nl.
  222
  223/* These rules set up a loop to mention all the objects
  224   in your vicinity. */
  225
  226notice_objects_at(Place) :-
  227        at(X, Place),
  228        write('There is a '), write(X), write(' here.'), nl,
  229        fail.
  230
  231notice_objects_at(_).
  232
  233/* This rule list all items the player is holding. */
  234
  235i :-
  236    write('You are holding: '), nl,
  237    holding(X),
  238    write(X), nl,
  239    fail.
  240
  241i.
  242
  243/* This rule tells how to use an item */
  244
  245use(X) :-
  246    \+ holding(X), !,
  247    write('You don''t have that.'), nl.
  248
  249use(coin) :-
  250    i_am_at(church), !,
  251    retract(holding(coin)),
  252    retract(empty(basin)),
  253    write('You put the coin into the offering box and the basin fills'), nl,
  254    write('with holy water!'), nl.
  255
  256use(jar) :-
  257    i_am_at(church),
  258    \+ empty(basin), !,
  259    retract(holding(jar)),
  260    assert(holding(holy_water)),
  261    write('You fill the jar with holy water.'), nl.
  262
  263use(holy_water) :-
  264    i_am_at(castle), !,
  265    retract(holding(holy_water)),
  266    retract(alive(vampire)),
  267    write('You splash the vampire with the holy water. The vampire howls'), nl,
  268    write('in pain and vanishes in a puff of smoke. You feel rather proud'), nl,
  269    write('of yourself.'), nl.
  270
  271use(sand) :-
  272    i_am_at(chasm), !,
  273    retract(holding(sand)),
  274    retract(invisible(bridge)),
  275    write('You start throwing sand at the gap and find that it sticks'), nl,
  276    write('in the air revealing the location of an invisible bridge.'), nl.
  277
  278use(driftwood) :-
  279    i_am_at(hamlet), !,
  280    retract(holding(driftwood)),
  281    assert(holding(torch)),
  282    write('You light the end of the driftwood in the fire giving you a'), nl,
  283    write('makeshift torch.'), nl.
  284
  285use(_) :-
  286    write('You can''t use that here'), nl.
  287
  288
  289/* This rule decreases the player health, causing them to die if
  290    their health reaches zero */
  291
  292decrease_health(Dmg) :-
  293    health(MyHealth),
  294    retract(health(MyHealth)),
  295    NewHealth is MyHealth - Dmg, nl,
  296    write('You take '), write(Dmg), write('damage!'), nl,
  297    NewHealth > 0, !,
  298    assert(health(NewHealth)),
  299    write('You have '), write(NewHealth), write('health remaining.'), nl, nl.
  300
  301decrease_health(_) :-
  302    die.
  303
  304/* This rule tells how to die. */
  305
  306die :-
  307        write('You have died.'),
  308        assert(dead(me)),
  309        finish.
  310
  311
  312/* Under UNIX, the "halt." command quits Prolog but does not
  313   remove the output window. On a PC, however, the window
  314   disappears before the final output can be seen. Hence this
  315   routine requests the user to perform the final "halt." */
  316
  317finish :-
  318        nl,
  319        write('The game is over. Please enter the "halt." command.'),
  320        nl.
  321
  322
  323/* This rule just writes out game instructions. */
  324
  325instructions :-
  326        nl,
  327        write('Enter commands using standard Prolog syntax.'), nl,
  328        write('Available commands are:'), nl,
  329        write('start.             -- to start the game.'), nl,
  330        write('n.  s.  e.  w.     -- to go in that direction.'), nl,
  331        write('d.  u.             -- to go down or up'), nl,
  332        write('i.                 -- list the items in your inventory.'), nl,
  333        write('take(Object).      -- to pick up an object.'), nl,
  334        write('drop(Object).      -- to put down an object.'), nl,
  335        write('use(Object).       -- to use an object.'), nl,
  336        write('look.              -- to look around you again.'), nl,
  337        write('inspect(Object)    -- to look at an object or thing in the area.'), nl,
  338        write('instructions.      -- to see this message again.'), nl,
  339        write('halt.              -- to end the game and quit.'), nl,
  340        nl.
  341
  342
  343/* This rule prints out instructions and tells where you are. */
  344
  345start :-
  346        instructions,
  347        look.
  348
  349
  350/* These rules describe the various rooms.  Depending on
  351   circumstances, a room may have more than one description. */
  352
  353describe(_) :-
  354        dead(me), !, true.
  355
  356describe(hamlet) :-
  357        unvisited(hamlet),
  358        retract(unvisited(hamlet)),
  359        write('You are an intrepid treasure hunter and lately you''ve'), nl,
  360        write('been chasing rumors of a magical crown which has led'), nl,
  361        write('you to this remote region.'), nl, nl,
  362        fail.
  363
  364describe(hamlet) :-
  365        write('You are in a small deserted hamlet. There is a dried up well'), nl,
  366        write('leading down here as well as a large bonfire. To the North is'), nl,
  367        write('is an open hut. Off to the West is a church and to the'), nl,
  368        write('there is a narrow_pass.'), nl.
  369
  370describe(well) :-
  371        write('You are at the bottom of the well. There doesn''t'), nl,
  372        write('seem to be anywhere to go except up the ladder.'), nl.
  373
  374describe(apothecary) :-
  375        write('You are inside what appears to have been the residence'), nl,
  376        write('of an apothecary. There are many shelves full of jars'), nl,
  377        write('of various substances.'), nl.
  378
  379describe(outside_church) :-
  380        write('You are outside the church to the North. To the south'), nl,
  381        write('lies the beach.  The hamlet is to the East.'), nl.
  382
  383describe(beach) :-
  384        write('You are on the beach. It is covered in white sand and'), nl,
  385        write('driftwood. To the North is the church.'), nl.
  386
  387describe(church) :-
  388        empty(basin), !,
  389        write('You are in a small church. In the center is an altar with'), nl,
  390        write('an empty basin and an offering box. There are stairs'), nl,
  391        write('leading down to the crypt.'), nl.
  392
  393describe(church) :-
  394        write('You are in a small church. In the center is an altar with'), nl,
  395        write('a basin of holy water and an offering box. There are'), nl,
  396        write('stairs leading down to the crypt.'), nl.
  397
  398describe(crypts) :-
  399        dark(crypts), !,
  400        write('You are in the crypt. It is very dark, you can''t tell'), nl,
  401        write('which directions it goes.  There are stairs leading up'), nl,
  402        write('to the church.'), nl.
  403
  404describe(crypts) :-
  405        write('You are in the crypt. To the north is a larger decorated'), nl,
  406        write('chamber.  There are stairs leading up to the church.'), nl.
  407
  408describe(fancy_tomb) :-
  409        write('You are in the decorate chamber. There is a large'), nl,
  410        write('sarcophagus in the center of the room which is slightly'), nl,
  411        write('ajar.  It looks like it must have been someone important.'), nl.
  412
  413describe(narrow_pass) :-
  414        write('You are in a narrow pass. To the West is the hamlet,'), nl,
  415        write('the path continues to the East.'), nl.
  416
  417describe(chasm) :-
  418        invisible(bridge), !,
  419        write('To the East you can see a castle but your way is blocked'), nl,
  420        write('by a large chasm with no apparent way to cross it. The'), nl,
  421        write('narrow pass is back to the West.  While you stand there'), nl,
  422        write('pondering a bird bumps into the air in the chasm. Weird.'), nl.
  423
  424describe(chasm) :-
  425        write('You are at the chasm. The sand covers the invisible bridge'), nl,
  426        write('making it safe to cross. To the East is a castle, to the'), nl,
  427        write('West is a narrow pass.'), nl.
  428
  429describe(outside_castle) :-
  430        locked(castle), !,
  431        write('There is a large castle immediately North, but the gate is'), nl,
  432        write('shut and no one appears to be home. To the West is the'),
  433        write('chasm.'), nl.
  434
  435describe(outside_castle) :-
  436        write('There is a large castle immediately North with gates wide'), nl,
  437        write('open. To the West is the chasm.'), nl.
  438
  439describe(castle) :-
  440        alive(vampire), !,
  441        write('You are in a large, richly decorated room.  It doesn''t'), nl,
  442        write('look like anyone has been here for a while though. Maybe that'), nl,
  443        write('vampire over by the throne room knows why everyone is'), nl,
  444        write('gone. To the North is the throne room, South leads outside.'), nl.
  445
  446describe(castle) :-
  447        write('You are in a large, richly decorated room.'), nl,
  448        write('To the North is the throne room, South leads outside.'), nl.
  449
  450describe(throne_room) :-
  451        write('You are in the throne room and there lying on the throne'), nl,
  452        write('in front of the you is the crown, yours for the taking!'), nl.
  453
  454/* These rules describe prominent features of different areas */
  455
  456describe_feature(sky) :-
  457        write('The sky is clear and blue with a large cloud that '), nl,
  458        write('looks kind of like a duck floating along.'), nl.
  459
  460describe_feature(well) :-
  461        write('The well appears to be very deep. You notice a ladder leading '),
  462        write('down into the well but you can''t make out what is at the bottom.'),
  463        retract(unvisited(well)).
  464
  465describe_feature(sarcophagus) :-
  466        inspected(sarcophagus), !,
  467        write('The skeleton is still lying there minding his own business.'), nl.
  468
  469describe_feature(sarcophagus) :-
  470        assert(at(ring, fancy_tomb)),
  471        assert(inspected(sarcophagus)),
  472        write('Inside the sarcophagus is a skeleton in the remains of'), nl,
  473        write('some rich garment.  On his finger is a golden signet ring.'), nl.
  474
  475describe_feature(fire) :-
  476        write('The fire burns brightly.'), nl.
  477
  478describe_feature(sand) :-
  479        write('There''s lots and lots of sand. I''m sure no one would'), nl,
  480        write('mind if you took some.'), nl.
  481
  482describe_feature(altar) :-
  483        empty(basin), !,
  484        write('There is an empty basin and small box for alms with a coin'), nl,
  485        write('sized slot.'), nl.
  486
  487describe_feature(altar) :-
  488        write('The basin is full of holy water.'), nl.
  489
  490describe_feature(chasm) :-
  491        invisible(bridge), !,
  492        write('If you strain you eyes really hard it almost looks as if'), nl,
  493        write('there is something in the gap. It''s probably just an'), nl,
  494        write('illusion.'), nl.
  495
  496describe_feature(chasm) :-
  497        write('The sand shows where the bridge is.'), nl.
  498
  499describe_feature(gate) :-
  500        write('There really doesn''t appear to be any way to open this'), nl,
  501        write('gate.  If only there was a doorbell you could ring.'), nl.
  502
  503describe_feature(vampire) :-
  504        write('Batsy over there doesn''t look too friendly.'), nl