0

I try to create a simple program in prolog, but i have a problem:

:- dynamic at/2, i_am_holding/1, i_am_at/1.

/* some lines of code */

i_am_at(room1).

at(revolver, room1).

take(revolver) :- write('You picked up the revolver.'),nl.

take(X):- i_am_at(Place),
      assert(i_am_holding(X)),
      retract(at(X,Place)).

/* some lines of code */

I want the user to pick up the revolver,and then (the revolver)to be retracted from the place where he is in, so he won't be able to pick it up again.

When I run my code, the take(revolver) query runs, but the take(X) does not.

false
  • 10,264
  • 13
  • 101
  • 209
Shevliaskovic
  • 1,562
  • 4
  • 26
  • 43
  • 1
    When you say "When I run my code..." exactly what do you mean? What did you enter? I played with the code you showed and it behaves as I would expect. If you type `take(revolver).` you do need to keep in mind that there are multiple "solutions". The first will write, "You have picked up the revolver" and then the second (if you ask for it with `;`) will modify the data. – lurker Oct 19 '13 at 15:20
  • When i run the code, the revolver is being retracted from the `Place` , but how can I prevent the message `You picked up the revolver.` from being displayed again when the user uses again the `take(revolver)` query? – Shevliaskovic Oct 19 '13 at 15:29
  • take(X) :- i_am_holding(X), write('You''re already holding it!'), nl. i got it. thanks anyways – Shevliaskovic Oct 19 '13 at 15:32
  • Your first `take` rule simply says, "Every time you pick up the revolver, write...". Is this supposed to be hard-coded at "revolver" or do you want it to say, "You picked up the..." for whatever you pick up? In the case of the "revolver" you need a rule before the `write` which checks if you already have the revolver. – lurker Oct 19 '13 at 15:32
  • yeah, totally forgot about that. sorry – Shevliaskovic Oct 19 '13 at 15:38

1 Answers1

2

Mark is right on the money. You probably want to replace your whole code with something like this:

:- dynamic at/2, holding/1.

at(player, room1).
at(revolver, room1).

take(X) :-
    at(player, Place),
    at(X, Place),
    !,
    format('You pick up the ~a.~n', [X]),
    retract(at(X,Place)),
    assert(holding(X)).

take(X) :-
    holding(X),
    !,
    format('You''re already holding the ~a!~n', [X]).

There are a lot of interesting ways you could take this further. An operator is_at might make the code more readable:

take(X) :-
  player is_at Place,
  X is_at Place,
  ...

You could also have some nice case-based reasoning for getting the articles and whatnot right:

subject(X, Some_X) :- mass_noun(X), !, atom_concat('some ', X, Some_X).
subject(X, The_X)  :- atom_concat('the ', X, The_X).

mass_noun(water).

then you could integrate these into the output routines:

take(X) :- 
  ...
  subject(X, Subj),
  format('You take ~a.~n', [Subj]),
  ...

You could do some fun stuff with DCGs to generate the output too:

:- use_module(library(dcg/basics)).

success(take(X)) --> "You took ", subject(X).
subject(X) --> "the ", atom(X).

You can make that even more generic with some histrionics like this:

success_term(Command) --> { Command =.. CommandList }, success(CommandList).
success([Command, DirectObject]) --> 
  "You ", past_tense(Command), " ", subject(DirectObject), ".".

subject(Noun) --> "the ", atom(Noun).
past_tense(X) --> { past_tense(X, Y) }, atom(Y).

past_tense(take, took).
past_tense(X, Xed) :- atom_concat(X, 'ed', Xed).

Then run that like so: phrase(success_term(take(revolver)), X), format('~s~n', [X]) and you'll get You took the revolver., which is kind of neat.

These text adventures are a lot of fun to code. I recommend you go through the Amzi Prolog Nani Search tutorial if you haven't yet. There are a lot of great ideas in there!

Daniel Lyons
  • 22,421
  • 2
  • 50
  • 77
  • I'm not so good with prolog, so I don't really know what the `~` does. I barely understood a thing from what you posted :P – Shevliaskovic Oct 20 '13 at 17:29
  • @NickShev The `~` is used by `format/2` to introduce formatting codes. It doesn't mean anything without `format/2`, so if you're not using SWI that won't help you. What specifically is confusing you? I'd love to explain anything which is unclear. My objective was just to illustrate some directions you could take the code. Prolog has a lot of power, it can be hard to understand what's going on in code from one level more advanced. – Daniel Lyons Oct 21 '13 at 14:33
  • Is there somewhere to talk without the comments? – Shevliaskovic Oct 21 '13 at 16:45