:- module(agent, [init, look/0, move/1, take/1, shoot/1]). :- 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). intercalate([X|Y], Spacer, Result) :- intercalate(Y, Spacer, Tail), atom_concat(X, Spacer, Head), atom_concat(Head, Tail, Result). intercalate([X], _, Result) :- Result = X. 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. 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).