|
Thank you for sharing this! It's nice to see Prolog used for such tasks, which are a good fit for a logic programming language. I have one small suggestion that I hope you find useful: Currently, the code is rather imperative: It contains lots of side-effects that have immediate consequences which cannot be easily reasoned about. You can use Prolog this way. However, you forfeit its most interesting advantages if you use it as an imperative language instead of a declarative one. A major attraction of Prolog is that it allows you to declaratively describe what holds. Therefore, I recommend to aim for declarative descriptions of situations, and limit side-effects to a few isolated areas of your program. Here is an example: In brexit.pl, you currently have the following: notice_persons_at(Place) :-
person_at(X, Place),
write('Apparently '),
write(X),
writeln(' is here, that is your'),
writeln('chance for a quick chat. Type "\e[1mtalk.\e[0m" to start'),
writeln('start the conversation').
Consider formulating this declaratively, for example as follows: notice_persons_at(Place) -->
{ person_at(X, Place) },
['Apparently ',X,' is here, that is your ',
'chance for a quick chat. Type ', bold(talk), 'to start',
' the conversation'].
I am using a Prolog definite clause grammar (DCG) to describe the output that is expected to occur at this place. Since I am decoupling this description from the actual side-effect of emitting the output, I have won a lot of convenience, flexibility and versatility. You see that this description is shorter and can be used not only for actually emitting the output, but also to easily test whether the program (still) behaves as intended.In addition, it allows you to later switch to a different way of outputting this text altogether. For example, at one point, you may want to convert this into a web-based application: In that case, the output should no longer be emitted on the system terminal, but sent as HTML snippets to the client. Thus, I recommend to first focus on a clear declarative description of everything that should occur in your program, formulated as a DCG or via a domain-specific language you may want to design for this specific task of implementing a text-based game. Later, you can flexibly interpret this language in any way you want! The same goes for the uses of assert/1 and rectract/1 that are currently sprinkled through your code: This imperative style prevents you from using the predicates in all directions. If you use a more declarative formulation, you will be able to use the code in much more flexible ways. A declarative way to express state changes is to think in terms of relations between states. Think about it this way: There is an initial state, and a user's actions relate any given state to a new state. Thus, state changes can be modeled as relations between states, and you will be able to use such predicates in reverse and also in the most general way! |