CSE2AIF – Artificial Intelligence Fundamentals
2020 Individual Assignment 2
Due Monday 5 October 2020, 10:00am
This assignment is to be done individually, and contributes 20% of your final mark for this subject. The submission date is Monday 5th October 10:00am. There are five questions, each worth 15 marks. You should attempt all questions.
Submission is electronic and via the LMS. Details of what to submit are provided below each question. Make sure that you follow the directions carefully and that the files are named exactly as specified in the instructions. Do NOT zip your files or use any other archiving process — submit each of the files individually.
The assignment is to be done individually. You must not collude with other students in any way, and you must not outsource your work to any other party. For information on plagiarism, see the La Trobe University policy on academic misconduct at http://www.latrobe.edu.au/students/academic-integrity.
Penalties are applied to late assignments (5% of total possible marks for that task is deducted per day, accepted up to 5 days after the due date only). An assignment submitted more than five working days after the due date will not be accepted. Delays caused by computer downtime cannot be accepted as a valid reason for a late submission without penalty. You must plan your work to allow for both scheduled and unscheduled downtime.
1
Question 1 – Game of the Amazons (15 marks)
Game of the Amazons is a two-person strategy game played on a chessboard. Each player has a specified number of amazons, which are placed on the board in some predetermined configuration. Usually the amazon pieces are represented by chess queens. The typical default position is on a 10×10 board as follows:
Each turn consists of two separate movements:
1. A player first moves one of their pieces any number of spaces in any one direction (horizontally, vertically, or diagonally), but it may not cross or enter a square occupied by an amazon of either colour or an arrow.
2. After moving, the amazon shoots an arrow to another square, in any direction from the place where it has landed. Just like movement of the amazon, the arrow cannot cross or enter a square occupied by another piece.
Once an arrow has been fired, the square it lands in is blocked off and can no longer be used. The arrows are represented on the boards below using solid circles.
The goal of the game is to “trap” the opposing player: if a player cannot make a move on their turn, they are the losing player.
A video about the Game of Amazons with mathematician/computer scientist Elwyn Berlekamp can be found here: https://www.youtube.com/watch?v=kjSOSeRZVNg
For this question, you will be investigating a simplified version of the game using two pieces on a smaller board. An example showing two possible moves starting with the configuration below is on the next page.
A possible starting configuration.
A losing position for player 1 (white) – a victory for player 2.
2
Example play
Here Player 1 begins by moving their piece.
After moving their piece, they choose the location of the arrow.
Player 2 now moves their piece. They cannot move their piece through the arrow.
After moving, they shoot their arrow. They also cannot shoot their arrow through another piece.
3
Instructions
You have been provided with the following two files for this problem:
• minimax.lisp, which contains LISP code for the minimax algorithm, and
• amazons.lisp, which contains a working LISP implementation of the simplified Amazons game.
The following LISP interaction show you how to play a game. Try it.
[1]> (load ‘minimax)
;; Loading file C:\CSE2AIF\minimax.lisp …
;; Loaded file C:\CSE2AIF\minimax.lisp
T
[2]> (load ‘amazons)
;; Loading file C:\CSE2AIF\amazons.lisp …
;; Loaded file C:\CSE2AIF\amazons.lisp
T
[3]> (play)
The program plays poorly because it has a poor-quality heuristic. The function static, which evaluates a position from the point of view of a given player, is currently defined as follows:
(defun static (pos player) (- (random 20) 10)
This means that each board configuration is given a random score between -10 and 10 inclusive. The result is that the program plays completely at random.
Your task for this question is to develop and implement a better heuristic for the Amazons game by following the steps below.
Functions that have been provided for you
The included file amazons.lisp includes a parameter and two functions which you can (and should) use in your
code. The parameter/functions you can use are:
– *directions*
o A list of the directions a piece can move: (defparameter *directions*
‘(up down left right up-left up-right down-left down-right)) – get-element(board coordinates)
o The function get-element returns the piece on the board which is in the position specified by the coordinates. If the square is empty, it returns nil.
– locate(board player)
o The function locate will return the coordinates on board of the piece player.
– range-in-direction(coordinates direction)
o The function range-in-direction will return all the coordinates in the given direction relative to coordinates. The value of coordinates is not included in the list. The list is sorted in order from closest to farthest relative to coordinates.
You do not need to write code for the functions described above. They are already provided for you. Examples are shown on the next page.
4
The representation
In the game, the player’s pieces are represented by X and O and the squares blocked by arrows are represented by the @ symbol. The coordinates of a board are represented from top-left to the bottom-right, as shown:
0123
0 1 2 3
The board is represented in the code as a list of rows, from top-to-bottom. To bind the board above to the parameter *test-board* you would write:
(defparameter *test-board*
‘((@ nil nil @) (nil nil nil nil) (nil X nil @) (@ nil @ O)))
Thus, the functions described above would behave as follows:
[1]> (locate *test-board* ‘x)
(1 2)
[2]> (locate *test-board* ‘o)
(3 3)
[3]> (get-element *test-board* ‘(3 0))
@
[4]> (get-element *test-board* ‘(1 2))
X
[5]> (get-element *test-board* ‘(1 0))
NIL
[6]> (range-in-direction ‘(1 2) ‘up)
((1 1) (1 0))
[7]> (range-in-direction ‘(0 2) ‘left) NIL
[8]> (range-in-direction ‘(2 3) ‘up-left) ((1 2) (0 1))
You do not need to write code for the functions described above. They are already provided for you.
Note: you should not use any of the functions from amazons.lisp other than the four functions described on page 4. Make good use of mapcar and lambda functions for good functional programming style.
Make sure to try playing the game before proceeding. Part (vi) includes some details about changing the starting parameters.
@
@
X
@
@
@
O
5
Implementing the heuristic
You are required to write various LISP functions which will be used to define the heuristic. Parts (i) to (iv) ask you to define various helper functions. You will define the actual heuristic in part (v). The code that you write should be in a file named q1.lisp. Do not include any other code in this file other than any helper functions required by the functions below.
Part (i)
Write a function pieces-in-direction (board coordinates direction) that takes as input a board, coordinates representing a position on the board, and a direction. The direction should be one of: ‘up, ‘down, ‘left, ‘right, ‘up-left, ‘up-right, ‘down-left, ‘down-right. The function returns the contents of the board in the given direction from the given coordinates, not including the contents at coordinates. Using *test-board* defined above, the function should behave as follows:
[1]> (pieces-in-direction *test-board* ‘(0 0) ‘right) (NIL NIL @)
[2]> (pieces-in-direction *test-board* ‘(1 2) ‘up-right) (NIL @)
[3]> (pieces-in-direction *test-board* ‘(2 3) ‘up-left) (X NIL)
[4]> (pieces-in-direction *test-board* ‘(0 3) ‘down) NIL
Reminder: you can (and should) make use of the functions that have been provided for you on page 4.
Part (ii)
Write a function count-until-not-nil (lst) that takes a list as input and returns the number of elements in the list before the first non-nil element. If lst is an empty list, it should return 0. The function should behave as follows:
[5]> (count-until-not-nil ‘(nil nil @ nil x)) 2
[6]> (count-until-not-nil ‘(nil @ nil nil @)) 1
[7]> (count-until-not-nil ‘(@ nil @))
0
[8]> (count-until-not-nil nil)
0
Part (iii)
Write a function number-of-movements-in-direction (board player direction) that takes a board and player as input and returns the number of possible places the player can move their piece to in that direction. (Note: this is not the same as the number of available moves, as this heuristic is not counting the number of arrows that could be fired.) You should find it useful to use count-until-not-nil as a helper function. Using the same test board state as defined above, the function should behave as follows:
[9]> (number-of-movements-in-direction *test-board* ‘x ‘up)
2
[10]> (number-of-movements-in-direction *test-board* ‘x ‘down) 1
[11]> (number-of-movements-in-direction *test-board* ‘o ‘up)
0
[11]> (number-of-movements-in-direction *test-board* ‘o ‘up-left) 2
6
Part (iv)
Write a function board-value (board player) which takes a board and player as input and returns the number of possible board spaces the player can move their piece to in all directions.
The *directions* parameter and your number-of-places-in-direction function will be useful. Part (v) – the actual heuristic function
Finally, write the function static (board player), which accepts a board and player as input arguments, and returns the board value of player, minus the board value for opponent. This is the function that will be used as the heuristic. You should find it useful to use board-value as a helper function.
Part (vi)
Play some games against the algorithm.1 Experiment with some of the following:
• Changing the parameter *max-depth*. This affects the quality of the game play. Make sure that you
include a *max-depth* value of 1 as one of your cases.
• Changing the starting player. You can give the program the first move by running (play t).
• Changing the size of the board. The file amazons.lisp has a function change-board-size(n)
which allows you to play the game on different board sizes. To play on a 5×5 board:
[1]> (load ‘minimax)
[2]> (load ‘amazons)
[3]> (change-board-size 5)
[4]> (play)
Note: if you load the amazons.lisp file after defining parameters, they will be over-written.
Write a short paragraph summarising your findings and include it as a commented section at the top of your source code. Include discussion about the smallest value of *max-depth* for which it is difficult to beat the algorithm, including a *max-depth* value of 1 as one of your cases.
1 You might like to try playing on some different starting boards. The starting board can be changed by redefining *start*; e.g. calling (defparameter *start* ‘((@ nil x nil) (nil nil nil nil) (nil nil nil nil) (nil o nil @))) after loading amazons.lisp will pre-fill the top-left and bottom-right corners of the board. If you want to change the starting board for a larger board, call change-board-size first. However, there is no input validation in the code, so proceed with caution.
7
Submit the following:
• Electronic copy of a file q1.lisp. This file should contain definitions of the functions described above, as well as any helper function required by these. Do not include any of the code from minimax.lisp or amazons.lisp in this file. Make sure that your name and student number appear in the header documentation. Don’t forget to include a short summary of your findings as a commented section at the top of your source code.
Note on assessment:
Your code will be tested using the following test function
(defun q1test()
(load ‘minimax)
(load ‘amazons)
(load ‘q1)
(play)
)
It is your responsibility to ensure that your code loads correctly, and that all required functions are present. Your solution will be marked according to the following criteria:
• Functioning code that operates as specified above
• Programming style
– Code displays good functional programming style with appropriate use of local variable definitions, higher-order functions, etc.
– Appropriate documentation and indentation. Documentation should be concise, but clear. Indentation should reflect the logical structure of the code.
8
Question 2 – LISP implementation of finite state machines (15 marks)
Background – finite state machines.
Your task for this question is to write LISP functions for managing a finite state machine. If you have done the subject MAT1DM, you have already encountered finite state machines.
Finite state machines are a computational model based around states, events, and transitions. They can be used as an active record of the current state of a program. For instance, video game AI may use a finite state machine to represent the active state of an enemy that can change between searching/fighting/running away.
Formally, a finite state machine (FSM) consists of:
1. A finite set of states.
2. An initial state.
3. A set of accepting states.
4. A finite set of possible inputs to the machine, called the alphabet.
5. A transition function.
The FSM depicted above has states S0, S1 and S2, initial state S0, accepting state S2, alphabet {a,b}, and transition function represented by the following table:
For example, while at state S1, if 0 is the input, then the FSM transitions to state S0. Likewise, if 1 is the input while at state S1, then the FSM will transition to state S2.
The extended transition function, which we will denote here by etf(state,word), tells you the state you arrive at by following a sequence of transitions when starting from a given state. Sequences of transitions are often represented as a string of symbols. For instance, the sequence “1, 0, 0” would often be abbreviated to 100. Sequences are processed from left-to-right. For example, etf(S2, 100) means to start at S2 and follow the symbols 1, 0, 0 in order. The path is S2 → S0 → S2 → S1. Since the final state is S1 this means that etf(S2, 100) returns S1
A sequence of transitions is accepted by a finite state machine if etf(start_state, transition_sequence) returns an accepting state (where start is the starting state of the FSM). Accepting states are represented in the diagram by a circle with a double line. Thus, for example, the words 0, 0000, 100 and 11 are examples of accepted words, but 00, 111 and 110 are not.
State
Input
ab
S0
S2 S1
S0 S2
S1 S0
S1
S2
9
Implementation details
You will be implementing a finite state machine which will be defined by:
• An alphabet, which will be represented as a list. The alphabet will not necessarily be single letters –
look at the machines.lisp file for some examples.
• A transition table, represented as a list of rows of the transition table. The elements in the table are
indices, representing the index of a state.
• An integer which is the index of the initial state of the FSM.
• A list of accepting states, represented as a list of integers.
The number of states can be derived from the number of rows in the transition table.
States will be referenced by an index from 0 upwards, so (for example) states S0, S1 and S2 will be referenced by 0, 1 and 2 respectively.
A transition sequence will be represented as a list of atoms. For example, the word 10010 will be represented as the sequence ‘(1 0 0 1 0). The empty sequence is permitted, and will be represented by ‘().
The file machines.lisp has the following code, which defines a struct called fsm with 5 fields.
(defstruct fsm
(alphabet ‘(a))
(table ‘((0)))
(initial 0)
(accepting ‘(0)))
This allows you to create a finite state machine by using the make-fsm function. The values listed above are the default values, so calling (make-fsm) will generate the following (rather uninteresting) finite state machine:
To instantiate a finite state machine, each field can be specified with a :field key like so:
(defparameter *test-machine*
(make-fsm
:alphabet ‘(a b)
:table ‘((2 1) (0 2) (1 0))
:initial 0
:accepting ‘(2)))
This code binds the finite state machine shown on the previous page to the parameter *test-machine*. Accessor functions for each field are defined automatically by LISP in the format(fsm-field fsm); e.g.:
[1]> (fsm-alphabet *test-machine*)
(A B)
[2]> (fsm-initial *test-machine*)
0
[3]> (fsm-accepting *test-machine*)
(1)
10
The Task
You are required to write the following LISP functions, together with any helper functions that they require. Load the file machines.lisp first to make use of the fsm struct.
• table-element (table row column)
Function table-element takes a table containing a list of rows (a transition table, for example).
It returns the element of the table in the given row and column. Indices start at 0.
[1]> (table-element ‘((0 2 1) (1 2 1) (2 0 2)) 2 1) 0
[2]> (table-element ‘((0 2 1) (1 2 1) (2 0 2)) 1 2) 1
• transition-function (fsm state-index transition)
Function transition-function will take an FSM (as defined by the previous section), a transition (which is assumed to be an element of the alphabet of fsm), and state-index, which is the index of the current state in the list of states. It returns the index of the state obtained by following the transition from the state indexed by state-index when transition is received.
[3]> (transition-function *test-machine* 0 ‘a) 2
[4]> (transition-function *test-machine* 0 ‘b) 1
[5]> (transition-function *test-machine* 2 ‘b) 0
Tip: the built-in function position will return the index of an element in a list if that element exists. For example, (position ‘3 ‘(1 2 0 2 3 5 6)) will return 4. Note that though the alphabet for the test machine is ‘(a b), in machines.lisp there are other machines with different alphabets.
• extended-transition-function (fsm state-index transition-sequence)
Function extended-transition-function takes as input: fsm, the designated finite state machine; state-index, which is the state to begin from; and transition-sequence, which is the sequence of transitions. It should return the sequence of states visited while processing the transition sequence, including the starting index state-index.
[6]> (extended-transition-function *test-machine* 0 ‘(a b (0 2 0 1 0 1)
[7]> (extended-transition-function *test-machine* 0 ‘(b b (0 1 2 1 2)
[8]> (extended-transition-function *test-machine* 1 ‘(b b (1 2 0 2 0)
[9]> (extended-transition-function *test-machine* 2 ‘(b b (2 0 1 0 1)
[10]> (extended-transition-function *test-machine* 1 ‘()) (1)
Tip: approach this problem recursively.
b a b))
a b))
a b))
a b))
11
• accepted? (fsm transition-sequence)
The function accepted? takes two inputs: fsm, the designated finite state machine, and transition-sequence, which is a list of transitions to be processed in the given order.
If transition-sequence leads to an accepting state, it should return the sequence of states visited while processing the word. Otherwise, it should return nil.
[11]> (accepted? *test-machine* ‘(a b b a b)) NIL
[12]> (accepted? *test-machine* ‘(a b b a)) NIL
[13]> (accepted? *test-machine* ‘(a b b b))
(0 2 0 1 2)
[14]> (accepted? *test-machine* ‘(a b b a b b)) (0 2 0 1 0 1 2)
• filter-accepted-sequences (fsm list-of-sequences)
The function filter-accepted-sequences takes two inputs: fsm, the designated finite state machine, and list-of-sequences, which is a list of words to be tested.
It should return the elements of list-of-sequences which are accepted by fsm.
[15]> (filter-accepted-sequences *test-machine*
‘((a b b a b b) (a b b b) (a b b a)))
((A B B A B B) (A B B B))
• all-accepting-sequences-up-to-length (fsm n)
The function all-accepting-sequences-up-to-length takes two inputs: fsm, the designated finite state machine, and n, which is the maximum length of sequences. It should return the list of sequences accepted by fsm which have length up to and including n.
[16]> (all-accepting-sequences-up-to-length *test-machine* 3) ((A) (B B) (A A B) (A B A) (B A A))
For this part, you can and should make use of the function all-sequences-of-length defined for you in machines.lisp. Read the comments and experiment with the function to see precisely how it works.
Testing your code on some sample machines
You could test your code as follows:
(defun q2test()
(load ‘machines) ;supplied file
(load ‘q2) ;source code containing th functions you write (all-accepting-sequences-up-to-length *test-machine* 5))
;make sure to define *test-machine* somewhere
The file machines.lisp has a few example finite state machines suited to various purposes. Use them to test and investigate your code. Your code will be tested on these machines.
12
Submit the following:
• Electronic copy of a file q2.lisp. This file should contain definitions of the functions described above, as well as any helper function required by these. Make sure that your name and student number appear in the header documentation.
Note on assessment:
Your code will be tested using a script similar to the one above. It is your responsibility to ensure that your code loads correctly, and that all required functions are present.
Your solution will be marked according to the following criteria:
• Functioning code that operates as specified above
• Programming style
– Code displays good functional programming style with appropriate use of local variable definitions, higher-order functions, etc.
– Appropriate documentation and indentation. Documentation should be concise, but clear. Indentation should reflect the logical structure of the code.
13
Question 3 – Resolution Refutation (15 marks)
Consider the following information:
“Joe is Murray’s tennis trainer. Joe will be at the park whenever the weather condition is dry. If it is wet on a weekend, then Joe will be at the sports centre. Murray is enthusiastic, and all enthusiastic trainees will be with their trainer on a dry weekday. If it is not a dry weekday then an enthusiastic trainee will be at the sports centre. On Wednesday it is dry.”
(a) Represent the above information, as well as any relevant background information, in full predicate form (i.e., you must show any existential or universal quantifiers). You must use ONLY the following predicates and constants:
trainee(X) X is a trainee
enthusiastic(X) X is enthusiastic
weekday(X) X is a weekday
trainer(X,Y) X is the tennis trainer of Y conditions(X,Y) The weather conditions on day X is Y
e.g., conditions(mon, wet) location(X,Y,Z) The location of X on day Y is Z
joe Joe
murray Murray
wet wet (assumed to be a weather condition) dry dry (assumed to be a weather condition) mon Monday (a day)
tue Tuesday (a day)
wed Wednesday (a day)
thur Thursday (a day)
fri Friday (a day)
park park (a location)
centre sports centre (a location)
(b) Convert the predicate calculus expression you wrote in part (a) to clause form. This means that each individual clause in the database must be a disjunction of literals, where a literal is an atomic expression or the negation of an atomic expression.
(c) Using your database of clauses from part (b), manually use resolution refutation to extract the answer to the question “Where is Murray on Wednesday?”. Make sure that you show all steps, and show clearly the substitutions required in order to answer the question.
Submit the following:
• Electronic copy of a file q3.doc that contains your answers to parts (a), (b) and (c). (Handwritten and scanned is OK, but make sure that it is easy to read). Make sure that your name and student number appear in the header documentation.
Your submission will be marked according to the following criteria:
• Correctness and completeness of the expressions in part (a) and part (b).
• Correctness and completeness of the proof.
14
Question 4 – River crossing in Prolog (15 marks)
Consider yet another variation of the river crossing problem:
Three monsters and three humans must cross a river using a boat that can carry at most two people. For each side of the river, if there are humans on that side of the river, then they cannot be outnumbered by the monsters (as otherwise, the monsters would eat the humans).
The boat cannot cross the river by itself – it must have at least one human or monster on board. The three monsters and humans are initially on the east side of the river. How can all the monsters and humans get to the west bank alive?
Your task is to write a Prolog program to solve this problem. You should model your code based on the solution to the Farmer, Wolf, Goat and Cabbage problem from the Week 8 labs.
Represent the state of the program as a relationship state, so that state(M, H, S) represents the state with M monsters and H humans on the east, and the boat is on side S.
You will need to create predicates for unsafe states and valid movements. To help you, here is one example of a valid movement relationship in English:
A west state can be obtained from an east state IF
There is at least one monster on the east, AND
The number of monsters on the east in the new state is one less than the old number, AND The west state is safe.
Of course, this is not the only way that new states can be obtained – you will have to think of the remaining ones yourself.
Submit the following:
• Electronic copy of a file q4.pl. This file should contain your Prolog code. Make sure that your name and student number appear in the header documentation.
• Electronic copy of a file q4_run.txt, which contains a run of your program captured to a text file (see instructions at end of this document for capturing a session using SWI-Prolog).
Note on assessment:
Your submission will be marked according to the following criteria:
• Program design. Have you chosen suitable predicates? Are your procedures well-designed? Have you
included appropriate documentation?
• Program correctness. Does your solution load and run correctly? Does it find a valid solution?
15
Question 5 – An expert system rule base (15 marks)
Your task for this question is to develop a small rulebase that can be used in the CLIPS expert system shell. You may choose any appropriate domain for your system; however, it should be in an area in which you have some expertise. Suitable domains may include:
• recommending a movie to watch (you might want to focus on a particular genre);
• recommending a suitable pet (e.g., you might want to focus on a specific breed of dog);
• real estate advisor; • etc.
but there are hundreds of others. Hopefully you will develop something that is both useful and fun!
The system that you develop should be engineered to return a single result (e.g., which restaurant to dine at, which movie to watch). As a rough guide, there should be approximately 3 or 4 outcomes (e.g., restaurants or movies to recommend) but this will depend on your particular domain.
Remember that the expert system approach is most appropriate when using ‘deep’ knowledge, and inferencing involves several layers of intermediate-level hypotheses. While many real expert systems can contain hundreds of rules, for the purpose of this exercise, approximately 15 to 20 rules (not counting helper rules, whose purpose, for example, might be solely to obtain input) should be sufficient. It is usually a good idea to use some rules which are more general (i.e., only one or two conditions in the antecedent), and some which are more specific (e.g., three or more conditions in the antecedent. Obviously, with such a small number of rules, the expert system will not work well in all consultations. Try to engineer your system so that it performs well in a couple of particular cases (i.e., one or two particular restaurants; one or two particular movies).
Testing the system
Create at least three test scenarios, each corresponding to a different set of facts to be presented to the system when prompted. The scenarios should be carefully selected to test your system and to demonstrate the quality of its inferencing. Select two scenarios to demonstrate when your system works well, and at least one scenario to show when your system works poorly (i.e., gives bad advice). You will need to submit runs of these test scenarios, so you must capture the sessions to a text file. Instructions on how to capture input into a text file in CLIPS, see the Appendix).
Submit the following:
• Electronic copy of the file q5.clp that contains your CLIPS code. The documentation in the header section should describe the problem domain that you have selected (e.g., pet recommendation), with a justification for why you believe that an expert system approach is appropriate for this problem (it should rely on intermediate hypotheses – see above). Make sure that your name and student number appear in the header documentation.
• Electronic copy of the file q5_run.txt that contains a run of your CLIPS code, demonstrating performance on three different scenarios. (See instructions at end of this document for capturing a session using CLIPS). Make sure that your name and student number appear in the header documentation
Marking Criteria
• Appropriateness of problem to an expert system solution. Chosen domain should be sufficiently complex to warrant an expert system approach – the problem should not be one that could be solved trivially using a lookup table, or some other ‘conventional’ approach.
• Rule Base. Development of a rule base containing approx. 15 to 20 rules, as appropriate.
• Depth of complexity as measured by levels of intermediate hypotheses. Depending on the nature of
the problem, rules should use at least two or three levels of intermediate hypotheses.
• Test scenarios. Scenarios are well selected to demonstrate both good performance, as well as poor
performance.
16
Appendix 1
Directions for capturing a session using CLISP
The function dribble can be used to capture a session with the CLISP interpreter to a text file. To begin capture, call the function dribble with the double-quoted filename as an argument (if a file with that filename does not exist, it will be created, otherwise the session will be appended to the end of it). For example, the following command
[1]> (dribble “sample.txt”)
will cause the session to be captured to the file sample.txt. When you want to stop dribbling, call the function dribble without any arguments.
[10]> (dribble)
Directions for capturing a session using SWI-Prolog
To capture a session using SWI-Prolog, use the commands protocol and noprotocol. For example, to start capturing a session, give the command:
1 ?- protocol(‘sample.txt’).
where sample.txt is the name of the file to which you want to capture the interaction. To stop capturing,
give the command:
10 ?- noprotocol.
Directions for capturing a session using CLIPS
To capture a session using CLIPS, use the commands dribble-on and dribble-off. For example, to start capturing a session, give the command:
CLIPS> (dribble-on “sample.txt”)
where dump.txt is the name of the file to which you want to dribble. To stop dribbling, give the command:
CLIPS> (dribble-off)
17