diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/agent.prolog | 278 | ||||
-rw-r--r-- | src/command.prolog | 47 | ||||
-rw-r--r-- | src/main.prolog | 34 | ||||
-rw-r--r-- | src/map.prolog | 135 | ||||
-rw-r--r-- | src/misc.prolog | 20 | ||||
-rw-r--r-- | src/parser.prolog | 77 |
6 files changed, 591 insertions, 0 deletions
diff --git a/src/agent.prolog b/src/agent.prolog new file mode 100644 index 0000000..4085bf9 --- /dev/null +++ b/src/agent.prolog @@ -0,0 +1,278 @@ + +:- module(agent, [init, look/0, move/1, take/1, shoot/1, hazardAt/1, somethingAt/1]). + + +:- consult('misc.prolog'). +:- consult('parser.prolog'). +:- consult('map.prolog'). + + + + +% initialisation + +init :- + initPos, + initPits, + initWumpus, + initGold, + initBats, + roomList(Rooms), + filter(Rooms, hazardAt, Walkable), + isConnected(Walkable) *-> !; init. + + +initPos :- + retractall(moves(_)), + asserta(moves(0)), + retractall(here(_)), + roomList(Rooms), + filter(Rooms, somethingAt, Emptyrooms), + random_member(X,Emptyrooms), + asserta(here(X)). + + +initPits :- + retractall(pitAt(_)), + insert(5,pitAt). + + +initWumpus :- + retractall(wumpusAt(_)), + roomList(Rooms), + filter(Rooms, somethingAt, Emptyrooms), + random_member(X,Emptyrooms), + asserta(wumpusAt(X)). + + +initGold :- + retractall(goldAt(_)), + retractall(haveGold(_)), + insert(3,goldAt), + asserta(haveGold(0)). + + +initBats :- + retractall(batsAt(_)), + insert(2,batsAt). + + +insert(N,Thing) :- + N > 0, + Nx is N - 1, + insert(Nx,Thing), + roomList(Rooms), + filter(Rooms, somethingAt, Emptyrooms), + random_member(X,Emptyrooms), + P =.. [Thing,X], + asserta(P). +insert(0,_) :- true. + + + + +% command functions + +look :- + here(Location), + writeSenses(Location), + writeExits(Location). + + +move(Direction) :- + here(Location), + connects(Location, New, Direction), + retract(here(Location)), + asserta(here(New)), + join(['You move to the ',Direction,'.\n\n'],W), + write(W), + checkHazards, + incrementMoves, + look, !. + + +move(_) :- + write('Unknown direction.\n\n'). + + +take(gold) :- + here(Location), + goldAt(Location), + retract(goldAt(Location)), + haveGold(G), + Gx is G + 1, + retract(haveGold(G)), + asserta(haveGold(Gx)), + write('You find some gold. Lucky you.\n\n'), + incrementMoves, !. + + +take(_) :- + write('You cannot take that.\n\n'). + + +shoot(Direction) :- + here(Location), + connects(Location, Target, Direction), + wumpusAt(Target), + write('You hear an unearthly scream.\n\n'), + retract(wumpusAt(Target)), + incrementMoves, + win. + + +shoot(Direction) :- + here(Location), + connects(Location, Target, Direction), + not(wumpusAt(Target)), + write('Thunk. Missed.\n\n'), + incrementMoves, + moveWumpus. + + +shoot(_) :- + write('Unknown target.\n\n'). + + + + +% letting the player know what's going on + +writeSenses(Location) :- + glitter(Location), + breeze(Location), + bats(Location), + stench(Location). + + +glitter(Location) :- + current_predicate(goldAt/1), + goldAt(Location), + write('You see a glitter along the sandy floor of the cave.\n'). +glitter(_) :- true. + + +breeze(Location) :- + current_predicate(pitAt/1), + connects(Location, ConnectedRoom, _), + pitAt(ConnectedRoom), + write('A cold breeze blows through the room, making you shiver slightly.\n'). +breeze(_) :- true. + + +bats(Location) :- + current_predicate(batsAt/1), + connects(Location, ConnectedRoom, _), + batsAt(ConnectedRoom), + write('All available surfaces are covered in guano. How unsanitary.\n'). +bats(_) :- true. + + +stench(Location) :- + current_predicate(wumpusAt/1), + connects(Location, ConnectedRoom, _), + wumpusAt(ConnectedRoom), + write('An overpowering stench fills your nose.\n'). +stench(_) :- true. + + +writeExits(Location) :- + findall(X, connects(Location,_,X), Exits), + intercalate(Exits, ', ', O), + join(['There are exits to the ',O,'.\n'],W), + write(W). + + + + +% modifying things and checking the ramifications + +moveWumpus :- + wumpusAt(Old), + findall(X, connects(Old,X,_), PossibleNews), + random_member(New, PossibleNews), + retract(wumpusAt(Old)), + asserta(wumpusAt(New)), + checkWumpus. + + +checkHazards :- + checkWumpus, + checkBats, + checkPit. + + +checkWumpus :- + current_predicate(wumpusAt/1), + here(Location), + wumpusAt(Location), + lose(eaten). +checkWumpus :- true. + + +checkBats :- + current_predicate(batsAt/1), + here(Location), + batsAt(Location), + write('A giant bat swoops down, picks you up, and deposits you elsewhere in the cave.\n\n'), + roomList(Rooms), + random_member(NewLocation, Rooms), + retract(here(Location)), + asserta(here(NewLocation)), + checkHazards. +checkBats :- true. + + +checkPit :- + current_predicate(pitAt/1), + here(Location), + pitAt(Location), + lose(pit). +checkPit :- true. + + + + +% winning, losing, and otherwise + +incrementMoves :- + moves(N), + retractall(moves(_)), + Nx is N + 1, + asserta(moves(Nx)). + + +win :- + write('*** YOU WIN ***\n'), + moves(M), + haveGold(G), + join(['\nWin accomplished in ',M,' moves with ',G,' gold found\n'],W), + write(W), + halt(0). + + +lose(eaten) :- + write('You have been eaten by the wumpus.\n'), + write('*** GAME OVER ***\n'), + halt(0). + + +lose(pit) :- + write('You have fallen into a bottomless pit.\n'), + write('*** GAME OVER ***\n'), + halt(0). + + + + +% miscellaneous clauses + +somethingAt(X) :- current_predicate(here/1), here(X). +somethingAt(X) :- current_predicate(goldAt/1), goldAt(X). +somethingAt(X) :- hazardAt(X). + + +hazardAt(X) :- current_predicate(wumpusAt/1), wumpusAt(X). +hazardAt(X) :- current_predicate(pitAt/1), pitAt(X). +hazardAt(X) :- current_predicate(batsAt/1), batsAt(X). + diff --git a/src/command.prolog b/src/command.prolog new file mode 100644 index 0000000..f897735 --- /dev/null +++ b/src/command.prolog @@ -0,0 +1,47 @@ + + +:- module(command, [getCommand/2]). + + +:- consult('parser.prolog'). + + + + +% functions for parsing a list of words into a recognised command + +getCommand(['quit'],C) :- C =.. [quit]. +getCommand(['exit'],C) :- C =.. [quit]. + + +getCommand(['go',X],C) :- C =.. [move,X]. +getCommand(['move',X],C) :- C =.. [move,X]. + + +getCommand(['n'],C) :- C =.. [move,north]. +getCommand(['north'],C) :- C =.. [move,north]. +getCommand(['s'],C) :- C =.. [move,south]. +getCommand(['south'],C) :- C =.. [move,south]. +getCommand(['e'],C) :- C =.. [move,east]. +getCommand(['east'],C) :- C =.. [move,east]. +getCommand(['w'],C) :- C =.. [move,west]. +getCommand(['west'],C) :- C =.. [move,west]. + + +getCommand(['nw'],C) :- C =.. [move,northwest]. +getCommand(['northwest'],C) :- C =.. [move,northwest]. +getCommand(['ne'],C) :- C =.. [move,northeast]. +getCommand(['northeast'],C) :- C =.. [move,northeast]. +getCommand(['sw'],C) :- C =.. [move,southwest]. +getCommand(['southwest'],C) :- C =.. [move,southwest]. +getCommand(['se'],C) :- C =.. [move,southeast]. +getCommand(['southeast'],C) :- C =.. [move,southeast]. + + +getCommand(['take',X],C) :- C =.. [take,X]. +getCommand(['shoot',X],C) :- C =.. [shoot,X]. + + +getCommand(['l'],C) :- C =.. [look]. +getCommand(['look'],C) :- C =.. [look]. + diff --git a/src/main.prolog b/src/main.prolog new file mode 100644 index 0000000..ef23f4f --- /dev/null +++ b/src/main.prolog @@ -0,0 +1,34 @@ + + +:- consult('parser.prolog'). +:- consult('agent.prolog'). +:- consult('command.prolog'). + + + + +play :- + init, + look, + playLoop. + + +playLoop :- + prompt(Line), + evalLine(Line). + + +evalLine(Line) :- + getCommand(Line,Command), + Command, + playLoop. + + +evalLine(_) :- + write('What?\n\n'), + playLoop. + + +quit :- + halt(0). + diff --git a/src/map.prolog b/src/map.prolog new file mode 100644 index 0000000..f5bb863 --- /dev/null +++ b/src/map.prolog @@ -0,0 +1,135 @@ + +:- module(map, [roomList/1, isConnected/1, connects/3]). + + +:- consult('misc.prolog'). + + + + +% map has 20 rooms, labelled a through t +% connections between rooms inscribe a dodecahedron, with the rooms +% corresponding to the vertices and the connections between them to +% the edges + + +roomList(X) :- X = [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]. + + +isConnected([]) :- true. +isConnected(X) :- + head(Y,X), + tail(Z,X), + connectTail([Y],Z). + +connectTail(_,[]) :- true. +connectTail([],_) :- false. +connectTail(Open,G) :- + head(X,Open), + tail(Y,Open), + findall(N, connects(X,N,_), Ns), + subtract(G,Ns,Gx), + subtract(G,Gx,Nx), + append(Y,Nx,Yx), + connectTail(Yx,Gx). + + +% loop around the middle + +connects(a,b,northeast). +connects(b,c,southeast). +connects(c,d,northeast). +connects(d,e,southeast). +connects(e,f,northeast). +connects(f,g,southeast). +connects(g,h,northeast). +connects(h,i,southeast). +connects(i,j,northeast). +connects(j,a,southeast). + + +% loop in the other direction around the middle + +connects(a,j,northwest). +connects(j,i,southwest). +connects(i,h,northwest). +connects(h,g,southwest). +connects(g,f,northwest). +connects(f,e,southwest). +connects(e,d,northwest). +connects(d,c,southwest). +connects(c,b,northwest). +connects(b,a,southwest). + + +% connections from the middle loop up to the top pentagon + +connects(b,k,north). +connects(d,l,north). +connects(f,m,north). +connects(h,n,north). +connects(j,o,north). + + +% connections from the top pentagon down to the middle loop + +connects(k,b,south). +connects(l,d,south). +connects(m,f,south). +connects(n,h,south). +connects(o,j,south). + + +% connections around the top pentagon + +connects(k,l,east). +connects(l,m,east). +connects(m,n,east). +connects(n,o,east). +connects(o,k,east). + + +% connections around the top pentagon in the other direction + +connects(l,k,west). +connects(m,l,west). +connects(n,m,west). +connects(o,n,west). +connects(k,o,west). + + +% connections from the middle loop to the bottom pentagon + +connects(a,p,south). +connects(c,q,south). +connects(e,r,south). +connects(g,s,south). +connects(i,t,south). + + +% connections from the bottom pentagon up to the middle loop + +connects(p,a,north). +connects(q,c,north). +connects(r,e,north). +connects(s,g,north). +connects(t,i,north). + + +% connections around the bottom pentagon + +connects(p,q,east). +connects(q,r,east). +connects(r,s,east). +connects(s,t,east). +connects(t,p,east). + + +% connections around the bottom pentagon in the other direction + +connects(q,p,west). +connects(r,q,west). +connects(s,r,west). +connects(t,s,west). +connects(p,t,west). + diff --git a/src/misc.prolog b/src/misc.prolog new file mode 100644 index 0000000..6d8ad68 --- /dev/null +++ b/src/misc.prolog @@ -0,0 +1,20 @@ + +:- module(misc, [filter/3, head/2, tail/2]). + + + + +filter(List, Predicate, Result) :- + Test =.. [Predicate,X], + findall(X, Test, No), + subtract(List, No, Result). + + +head(X,[Y]) :- X = Y. +head(X,[Y|_]) :- X = Y. + + +tail(X,[]) :- X = []. +tail(X,[_]) :- X = []. +tail(X,[_|Y]) :- X = Y. + diff --git a/src/parser.prolog b/src/parser.prolog new file mode 100644 index 0000000..c9f9771 --- /dev/null +++ b/src/parser.prolog @@ -0,0 +1,77 @@ + +:- module(parser, [prompt/1, readList/1, readLine/1, split/2, join/2, intercalate/3]). + + +% functions for dealing with lines of text +% eg obtaining one, parsing it into a list of words, and rejoining it + +% prompt provides the user with a '>' prompt +% readList merely obtains and parses the input +% readLine obtains a raw line of input +% split parses a line of text into words +% join takes a list of words and joins them into one string + + +prompt(L) :- + write('> '), + readList(L). + + +readList(L) :- + readLine(X), + split(X,L). + + +readLine(L) :- + get_char(C), + readLine_tail(C,L). + + +readLine_tail('\n',[]) :- !. +readLine_tail(C,[C|X]) :- + get_char(C2), + readLine_tail(C2,X). + + +split(X,R) :- + wordList(R,X,[]), !. + + +join([X|Y],R) :- + join(Y,Rx), + atom_concat(X,Rx,R). +join([X],R) :- + R = X. + + +intercalate([X|Y], Spacer, Result) :- + intercalate(Y, Spacer, Tail), + atom_concat(X, Spacer, Head), + atom_concat(Head, Tail, Result). +intercalate([X], _, Result) :- Result = X. + + +wordList(X) --> whitespace, wordList(X). +wordList([X]) --> word(X). +wordList([X]) --> word(X), whitespace. +wordList([X|Y]) --> word(X), whitespace, wordList(Y). + + +word(W) --> charList(X), {atom_chars(W,X)}. + + +charList([X|Xs]) --> char(X), charList(Xs). +charList([X]) --> char(X). + + +whitespace --> whsp, whitespace. +whitespace --> whsp. + + +whsp --> oneOf(_,[' ', '\r', '\n', '\t']). +char(X) --> noneOf(X,[' ', '\r', '\n', '\t']). + + +oneOf(X,L) --> [X], {member(X,L)}. +noneOf(X,L) --> [X], {not(member(X,L))}. + |