Programming Assignment 2
60 points
Part 1 (5 points): Adding an event_execute clause for polonius_scold_ophelia.
In ophelia.prolog, there is an event_available clause for polonius_scold_ophelia. This clause determines if the event polonius_scold_ophelia is available in the current story state. Some other part of the game logic decides whether this event should execute if it’s available.
If the game does decide to execute the event, we will need to update the story state in prolog. One way to do this is to create a clause for a new predicate, execute_event, that if called by the game takes the appropriate actions to update the state.
So, just like with event_available, where we have a clause for each specific story event (e.g. event_available(polonius_scold_opheila) ), we want to define a specific clause (rule) for event_execute(polonius_scold_ophelia) that updates the story state when the polonius_scold_ophelia event happens. For this event, the only thing we need to keep track of is that the event happened so that event_available(polonius_scold_ophelia) isn’t true anymore.
Write the clause (rule) for event_execute(polonius_scold_ophelia) such that, after it executes, polonius_scold_ophelia is no longer available. This will be a simple, short rule.
Part 2 (15 points): Adding support for the event claudius_confesses_murder.
Now we’re going to add support for the event claudius_confesses_murder. Processing this event will make use of character knowledge. Characters can know facts and this affects event availability. In this case, there’s a fact characters learn from this event called claudius_killed_king_hamlet. Addapredicatetorepresentthatthisisavalidfact(inthesame way that we have predicates to represent the valid locations). You’ll also want to declare a dynamic fact with two arguments to represent that a character knows a fact.
Create an event_available clause for claudius_confesses_murder. The event should be available under the following conditions:
● That it hasn’t already happened.
● That the event play_depicting_murder has already happened (“The play’s the
thing/Wherein I’ll catch the conscience of the king.”). This is a new event. You can just
state that it’s already happened as a fact (not implementing the logic for the event).
● Hamlet doesn’t already know that Claudius killed the King.
● Claudius and Hamlet are in the chapel (the event only takes place in the chapel).
● In addition to Claudius and Hamlet, Ophelia can be in the Chapel. But if anyone else is
in the chapel, the event won’t happen. There’s already a helper predicate for this that was used in event_available(polonius_scold_ophelia).
To test this you’ll want to make sure that you haven’t already asserted that claudius_confesses_murder happened.
Createanevent_executeclauseforclaudius_confesses_murder. Whenthiseventexecutes we’ll want to update the story state as follows:
● That claudius_confesses_murder has happened.
● That Hamlet now knows that Claudius killed the King.
● If Ophelia is present, then Ophelia knows that Claudius killed the King.
For the last step, we’ll create a helper predicate, knows_if_present(Char, Loc, Fact), which, given a character, location and fact, changes the story state to represent that the character knows the fact only if they are in the location. We also want to test that the character, location and fact arguments are valid (for example, that someone hasn’t accidentally made the typo chaple for the chapel) . If any of these are not valid, then knows_if_present should fail. If the character isn’t in the location, however, we don’t want knows_if_present(Char, Loc, Fact) to fail. This is a normal case that should succeed, just not update anything about character knowledge. To do this, we’ll want a second clause for knows_if_present that succeeds if the character isn’t in the location. You may find yourself duplicating your code that tests the validity of the character, location and fact arguments. You can avoid this if you wish by creating another helper predicate that does the actual location testing and asserting, which is called by knows_if_present.
To test your code, make sure that claudius_confesses_murder is available when you think it should be, and that the story state has been updated appropriately after event_execute.
Part 3 (10 points): Add type checking to knows_if_present.
For the knows_if_present predicate in the previous problem, we added code to make sure that the character, fact and location are valid. This is good, as it will prevent errors that come from typos like adding knowledge about a non-existent fact or testing where a character is in a location that doesn’t exist. In this case, knows_if_present fails, but we don’t know why. It may take a fair amount of staring at the code and experimenting to find the problem, especially as the prolog portion of the interactive story becomes bigger.
We can help ourselves out by printing error messages if the character, location or fact don’t type check. To do this we’re going to use the write\1 and nl built in predicates. Here’s a little experiment you can play with just to see these at work.
mortal(X) :- human(X), write(‘Yup, ‘), write(X), write(‘ is human.’), nl.
human(socrates).
Try proving mortal(X) and you’ll see stuff be printed out.
The other built in predicate we’re going to use is call\2. This predicate lets you create goals for prolog to try to prove dynamically. That is, the predicate name and its argument can be in variables that get set in other code.
Using the simple “humans are mortal” example above, try the following goal in the Tau Prolog sandbox:
Pred = mortal, Arg = socrates, call(Pred, Arg).
We’re going to define clauses for a new predicate, type_check(Type, Value), that given a type and a value, succeeds if the Value is of that Type. If not, it prints out an error message of the form “
ophelai is not of type character
and then fail. To force the clause that prints out the error message to fail, use the fail built-in predicate. Write the clauses for type_check that implement this and use type_check in your knows_if_present clause.
Keep the original version of knows_if_present in your code so we can look at it – just comment it out.
Part 4 (15 points): Add bury_the_hatchet to mini-prom-week.
Now we’re going to move away from the Ophelia example to Mini Prom Week. We’re going to add a new social exchange called bury_the_hatchet, in which two people who are enemies but have a mutual friend decide to start being nice to each other. For this part we’re only going to work on the prolog part, not the javascript part, but here’s what the dialog exchange looks like just to make it concrete:
#initiator#: Hey #responder#, I know we’ve never gotten along… #responder#: You can say that again!
#initiator#: But you know, we both think #mutualFriend# is pretty #complimentary#. So for their sake, let’s try to get along.
#responder#: Yeah… you’re right. Or at least we can try to hate each other less.
For the prolog part of this, we need to write another clause of the social_exchange_available/2
predicate for bury_the_hatchet.
The first thing we need to do is add support for compliment, the same way that we have support for pejorative. The compliment_spec for each character is as follows:
● Monica – dope.
● Simon – l33t.
● Oswald – sick.
● Naomi – radical.
The compliment_default can be cool.
The parameters for the bury_the_hatchet content unit are:
● Enemy1 – the first enemy character.
● Enemy2 – the second enemy character.
● MutualFriend – the mutual friend.
● Complement – the compliment the initiator (Enemy1) will use to describe their mutual friend.
Define a social_exchange_available/2 clause for bury_the hatchet with the following tests:
● Enemy1 and 2 are enemies.
● They’re both friends with the same mutual friend.
● Testing (or binding) enemy1’s compliment.
To make bury_the_hatchet available, you will need to change the initial social state (who are enemies and friends in the initial state).
Part 5 (15 points): Modify the javascript to implement the text for bury_the_hatchet.
Modify mini-prom-week.js to print the text for the bury_the_hatchet exchange. You’ll want to read through the code and comments in this file to understand how it works. We’ll also be talking about it in class.
You’ll need to modify execute_social_exchange(binding) to add a case for the appropriate exchangeName and define a function bury_the_hatchet(params) to extract the parameters and print the text.
Turning in the assignment
To turn in the assignment, submit a zip file called assignment2-
The zip file should contain the following:
● ophelia.prolog – your modification of the file containing the answers to the first three
parts.
● mini-prom-week.prolog – your modification of the file containing the answer to part 4.
● mini-prom-week.js – your modification of the file containing the answer to part 5.