1/* Outrun, by Ziyi Yang */
    2
    3:- dynamic i_am_at/1, car_at/1, at/2, holding/1, locked/1, incar/0, ignited/0,
    4	miles/1, answer/1, stolen/0.    5:- retractall(at(_, _)), retractall(i_am_at(_)), retractall(car_at(_)),
    6	retractall(holding(_)), retractall(locked(_)), retractall(incar),
    7	retractall(ignited), retractall(miles(_)), retractall(answer(_)),
    8	retractall(stolen).    9
   10path(living_room, n, garage).
   11path(garage, s, living_room).
   12
   13path(living_room, s, bedroom).
   14path(bedroom, n, living_room).
   15
   16path(living_room, e, study).
   17path(study, w, living_room).
   18
   19path(living_room, w, bathroom).
   20path(bathroom, e, living_room).
   21
   22path(garage, w, shelf).
   23path(shelf, e, garage).
   24
   25path(downtown, s, mall).
   26path(mall, n, downtown).
   27
   28/* The distance between each two places. */
   29road(garage, 5, gasstation).
   30road(garage, 30, bank).
   31road(garage, 100, downtown).
   32
   33road(gasstation, 5, garage).
   34road(gasstation, 25, bank).
   35road(gasstation, 110, downtown).
   36
   37road(bank, 30, garage).
   38road(bank, 25, gasstation).
   39road(bank, 90, downtown).
   40
   41road(downtown, 100, garage).
   42road(downtown, 110, gasstation).
   43road(downtown, 90, bank).
   44
   45/* Items you can take with. */
   46at(key, living_room).
   47at(smartphone, study).
   48at(charger, bathroom).
   49at(battery, shelf).
   50
   51/* This is player's initial state */
   52i_am_at(living_room).
   53car_at(garage).
   54locked(car).
   55locked(safe).
   56miles(10).
   57
   58/* These rules describe how to pick up an object. */
   59
   60take(X) :-
   61        holding(X),
   62        write('You''re already holding it!'),
   63        !, nl.
   64
   65take(X) :-
   66        i_am_at(Place),
   67        at(X, Place), 
   68        retract(at(X, Place)),
   69        assert(holding(X)),
   70        write('OK.'),
   71        !, nl.
   72
   73take(_) :-
   74        write('I don''t see it here.'),
   75        nl.
   76
   77
   78/* These rules describe how to put down an object. */
   79
   80drop(X) :-
   81        holding(X),
   82        i_am_at(Place),
   83        retract(holding(X)),
   84        assert(at(X, Place)),
   85        write('OK.'),
   86        !, nl.
   87
   88drop(_) :-
   89        write('You aren''t holding it!'),
   90        nl.
   91
   92
   93/* These rules define the direction letters as calls to go/1. */
   94
   95n :- go(n).
   96s :- go(s).
   97e :- go(e).
   98w :- go(w).
   99
  100/* This rule tells how to move in a given direction. */
  101
  102go(_) :-
  103		incar,
  104		write('You are in the car. You can only drive.'), nl, !, fail.
  105
  106go(Direction) :-
  107        i_am_at(Here),
  108        path(Here, Direction, There),
  109        retract(i_am_at(Here)),
  110        assert(i_am_at(There)),
  111        !, look.
  112
  113go(_) :-
  114        write('You can''t go that way.').
  115
  116/* This rule tells how to look about you. */
  117
  118look :-
  119		incar, car_at(X),
  120		write('The car is in the '), write(X), nl,
  121		inspect_car, nl, inspect_fuel, !.
  122
  123look :-
  124        i_am_at(Place),
  125        describe(Place),
  126        nl,
  127        notice_objects_at(Place),
  128        nl.
  129
  130/* These rules set up a loop to mention all the objects
  131   in your vicinity. */
  132
  133notice_objects_at(Place) :-
  134        at(X, Place),
  135        write('There is a '), write(X), write(' here.'), nl,
  136        fail.
  137
  138notice_objects_at(_).
  139
  140inventory :- write('Items you have: '), nl,
  141	holding(X), write(X), nl, fail.
  142inventory :- true.
  143
  144i :- inventory.
  145
  146getin :-
  147	incar,
  148	write('You are already in your car.'), nl, !, fail.
  149
  150getin :-
  151	\+ (i_am_at(X), car_at(X)),
  152	write('You are not with your car.'), nl, !, fail.
  153
  154getin :-
  155	locked(car),
  156	write('Your car is locked. You can''t get in.'), nl, !, fail.
  157	
  158getin :-
  159	assert(incar),
  160	write('Now you are in your car.'), nl,
  161	look.
  162	
  163getoff :-
  164	incar,
  165	retract(incar),
  166	write('You are now out of your car.'), nl,
  167	car_at(X), describe(X), nl, notice_objects_at(X), !.
  168	
  169getoff :-
  170	write('You are already out of your car.'), nl, !, fail.
  171	
  172drive(_) :-
  173	\+ incar,
  174	write('You are not in your car. You can''t drive.'), nl, !, fail.
  175	
  176drive(_) :-
  177	\+ ignited,
  178	write('You have not ignited your car. You can''t drive.'), nl, !, fail.
  179
  180drive(Here) :-
  181		car_at(Here),
  182		write('You can''t drive to the same place.'), nl, !, fail.
  183
  184drive(Somewhere) :-
  185		\+ road(_, _, Somewhere),
  186		write('You can''t drive there'), nl, !, fail.
  187		
  188drive(There) :-
  189		car_at(Here), i_am_at(Here),
  190		road(Here, Dist, There),
  191		retract(car_at(Here)), assert(car_at(There)),
  192		retract(i_am_at(Here)), assert(i_am_at(There)),
  193		miles(X), Y is X - Dist,
  194		retract(miles(X)),
  195		assert(miles(Y)), fail.
  196
  197drive(downtown) :-
  198		holding(smartphone),
  199		write('Along the long way to the downtown, someone kept'), nl,
  200		write('calling your phone. You have to answer it'), nl,
  201		write('and your car strayed away. You crashed into a light'), nl,
  202		write('pole and got injured. You will need to spend your'), nl,
  203		write('weekend at hospital.'), nl, !, die.
  204
  205drive(_) :-
  206		holding(smartphone),
  207		write('When driving, someone kept calling your phone.'), nl,
  208		write('Luckily the travel is short so everything is fine.'), nl,
  209		write('But you started to wonder whether should you get away'), nl,
  210		write('from the phone...'), nl, nl, fail.
  211
  212drive(_) :- !, look.
  213
  214use(_) :-
  215	incar,
  216	write('You are inside your car. Focus on driving,'), nl,
  217	write('don''t use any items!'), nl, !, fail.
  218
  219use(safe) :-
  220	i_am_at(bedroom), \+ locked(safe),
  221	write('The safe is already unlocked.'), nl, !.
  222
  223use(safe) :-
  224	i_am_at(bedroom),
  225	write('What''s the combination? You can hardly remember it.'), nl,
  226	write('But you decided to give it a try.'), nl,
  227	write('Enter the combination and end with a period.'), nl,
  228	read(X), X == 1248,
  229	assert(holding(bankcard)),
  230	retract(locked(safe)),
  231	write('Great! You opened it up and got your banking card.'), nl, !.
  232	
  233use(safe) :-
  234	i_am_at(bedroom),
  235	write('No, it does not open the safe.'), nl, !, fail.
  236	
  237use(X) :-
  238	\+ holding(X),
  239	write('Your don''t have a '), write(X), write(' .'),
  240	nl, !, fail.
  241	
  242use(key) :-
  243	\+ (i_am_at(X), car_at(X)),
  244	write('Your are not with your car.'), nl, !, fail.
  245	
  246use(key) :-
  247	locked(car),
  248	retract(locked(car)),
  249	write('The car is now unlocked.'), nl, !.
  250	
  251use(key) :-
  252	assert(locked(car)),
  253	write('The car is now locked.'), nl, !.
  254
  255use(smartphone) :-
  256	\+ holding(charger),
  257	write('The smart phone is not working. The battery is completely'), nl,
  258	write('dead. You need a charger.'), nl, !, fail.
  259	
  260use(smartphone) :-
  261	write('You turned on your smart phone with the charger connected'), nl,
  262	write('to the wall and found a memo with an unannotated number: 1248.'), nl, !.
  263	
  264use(battery) :-
  265	i_am_at(X), car_at(Y), X \= Y,
  266	write('You are not with your car.'), nl, !, fail.
  267
  268use(battery) :-
  269	assert(ignited),
  270	retract(holding(battery)),
  271	write('You replaced your car''s battery and you can now ignite'), nl,
  272	write('your car.'), nl, !.
  273	
  274use(_) :-
  275	write('Your can''t use it here.'), nl, !, fail.
  276
  277/* Under UNIX, the "halt." command quits Prolog but does not
  278   remove the output window. On a PC, however, the window
  279   disappears before the final output can be seen. Hence this
  280   routine requests the user to perform the final "halt." */
  281
  282finish :-
  283        nl,
  284        write('The game is over. Please enter the "halt." command.'),
  285        nl.
  286
  287die :-
  288		!, finish.
  289
  290/* This rule just writes out game instructions. */
  291
  292instructions :-
  293        nl,
  294		write('You are living in a large house in rural area,'), nl,
  295		write('away from downtown. Your neighbourhood has all been'), nl,
  296		write('out for vacation. Void of anything meaningful to do,'), nl,
  297		write('you decided to spend the weekend in front of TV with'), nl,
  298		write('your favourite potato chips. Realizing you have just'), nl,
  299		write('run out of chips yesterday, you decided to drive all'), nl,
  300		write('the way to the downtown to get your favourite snack'), nl,
  301		write('so that you can really enjoy your endless weekend.'), nl, nl,
  302        write('Enter commands using standard Prolog syntax.'), nl,
  303        write('Available commands are:'), nl,
  304        write('start.           -- to start the game.'), nl,
  305        write('n.  s.  e.  w.   -- to go in that direction.'), nl,
  306        write('take(Object).    -- to pick up an object.'), nl,
  307        write('drop(Object).    -- to put down an object.'), nl,
  308		write('use(Object).     -- to use an object.'), nl,
  309		write('getin.           -- to get in your car.'), nl,
  310		write('getoff.          -- to get off your car.'), nl,
  311		write('drive(Place).    -- to drive your car to other places (only when you are in the car).'), nl,
  312        write('look.            -- to look around you again.'), nl,
  313        write('instructions.    -- to see this message again.'), nl,
  314		write('inventory. i.    -- to show what items you have.'), nl,
  315        write('halt.            -- to end the game and quit.'), nl,
  316        nl.
  317
  318
  319/* This rule prints out instructions and tells where you are. */
  320
  321start :-
  322        instructions,
  323        look.
  324
  325describe(living_room) :-
  326		holding(potato),
  327		write('You have finally gotten back to your house with your favourite'), nl,
  328		write('potato chips and you are ready to begin your TV series and potato'), nl,
  329		write('marathon! Enjoy the weekend!'), nl, !, finish.
  330		
  331describe(living_room) :-
  332		write('You are in your living room. You have your 108 inch'), nl,
  333		write('ultra HD television and your super soft leather couch here.'), nl,
  334		write('You decided not to turn on the TV because you don''t have'), nl,
  335		write('potato chips.'), nl, nl,
  336		write('To the north is your garage'), nl,
  337		write('To the south is your bedroom.'), nl,
  338		write('To the east is your study.'), nl,
  339		write('To the west is the bathroom.'), nl.
  340		
  341describe(study) :-
  342		write('You are in your study. All books here remain untouched'), nl,
  343		write('for 10 years since they have been bought. The only thing'), nl,
  344		write('meaningful to you is the WiFi coverage here.'), nl, nl,
  345		write('To the west is the living room.'), nl.
  346		
  347describe(garage) :-
  348		write('You are in your garage. You see your car down the steps.'), nl, nl,
  349		write('To the south is the living room.'), nl,
  350		write('To the west is the shelf.'), nl.
  351		
  352describe(bedroom) :-
  353		write('This is your bedroom. Your safe is here but you don''t know'), nl,
  354		write('what''s inside it, neither can you remember its combination.'), nl, nl,
  355		write('To the north is the living room.'), nl.
  356
  357describe(bathroom) :-
  358		write('This is your bathroom. You have your automatic massage'), nl,
  359		write('bathtub here. But you only take showers.'), nl, nl,
  360		write('To the east is the living room.'), nl.
  361		
  362describe(shelf) :-
  363		write('This is your large shelf stacked with spare parts of your car.'), nl, nl,
  364		write('To the east is the garage.'), nl.
  365		
  366describe(gasstation) :-
  367		write('Welcome to Ultra Petrol gas station, the closest one in your town,'), nl,
  368		write('and you can only pay in cash.'), nl, nl,
  369		write('Do you want to refuel (yes./no.)? '),
  370		read(X), assert(answer(X)), fail.
  371		
  372describe(gasstation) :-
  373		answer(X), X = yes,
  374		holding(money),
  375		retract(miles(_)),
  376		assert(miles(300)),
  377		retract(answer(X)),
  378		write('Your tank is full now.'), nl, !.
  379
  380describe(gasstation) :-
  381		answer(X), X = yes,
  382		retract(miles(_)),
  383		assert(miles(60)),
  384		retract(answer(X)),
  385		write('You didn''t bring enough money. You only added a few litres of fuel.'), nl, !.
  386		
  387describe(gasstation) :-
  388		retract(answer(_)),
  389		write('Ok.'), nl, !.
  390		
  391describe(bank) :-
  392		write('Welcome to Bank of Potato, the only branch near your county.'), nl,
  393		write('It''s weekend so the bank is closed. However you can still draw'), nl,
  394		write('some money from the auto teller machine, if you brought your'), nl,
  395		write('banking card.'), nl,
  396		\+ holding(bankcard),
  397		write('You didn''t bring your banking card.'), nl, !.
  398		
  399describe(bank) :-
  400		write('Do you want to withdraw money (yes./no.)? '),
  401		read(X), assert(answer(X)), fail.
  402		
  403describe(bank) :-
  404		answer(X), X = yes,
  405		\+ holding(money),
  406		assert(holding(money)),
  407		retract(answer(X)),
  408		write('You have withdrawn all the money in your card.'), nl, !.
  409		
  410describe(bank) :-
  411		answer(X), X = yes,
  412		retract(answer(X)),
  413		write('Your deposit is empty now. You can''t withdraw any more.'), nl, !, fail.
  414		
  415describe(bank) :-
  416		retract(answer(_)),
  417		write('Ok.'), nl, !.
  418
  419describe(downtown) :-
  420		stolen,
  421		write('You got back to the parking lot and nowhere could you find'), nl,
  422		write('your car. It must have been stolen. You need to call for help,'), nl,
  423		write('and definitely, your happy weekend is no longer there.'), nl, !, die.
  424		
  425describe(downtown) :-
  426		write('You are in the downtown. People and shops are everywhere.'), nl,
  427		write('However you only care about the shopping mall to the south,'), nl,
  428		write('which sells your favourite potato chips. Just when you got'), nl,
  429		write('off your car, you saw some suspicious peeps on your super'), nl,
  430		write('luxury exotic limousine. Maybe you should not forget to'), nl,
  431		write('lock your car...'), nl, nl,
  432		write('To the south is the mall.'), nl.
  433		
  434describe(mall) :-
  435		write('You got to the mall. Non-fat, no-sugar, low sodium, no deal.'), nl,
  436		write('You just want to rush to the value pack snacks shelf.'), nl, fail.
  437		
  438describe(mall) :-
  439		\+ holding(potato),
  440		assert(holding(potato)),
  441		nl,
  442		write('There it is! You got your chips! You can''t wait to'), nl,
  443		write('enjoy it at home.'), nl, fail.
  444		
  445describe(mall) :-
  446		\+ locked(car),
  447		assert(stolen), fail.
  448		
  449describe(mall) :- true.
  450
  451inspect_car :-
  452		\+ ignited,
  453		write('You try to start your car but it didn''t work. It seems the'), nl,
  454		write('starter has run out of battery and you need to replace it'), nl,
  455		write('with a new one. Fortunately you have foreseen it and bought'), nl,
  456		write('a new one the other day. Check it out on the shelf.'), nl, !.
  457
  458inspect_car :-
  459		write('You started your car. You are ready to go.'), nl,
  460		write('Use drive(Place) command to get to other places.'), nl, nl,
  461		write('You can drive to:'), nl,
  462		road(X, Dist, Y), i_am_at(Z), X = Z,
  463		write(Y), write(' is '), write(Dist), write(' miles away.'), nl, fail.
  464inspect_car :- true.
  465
  466inspect_fuel :-
  467		miles(X), X < 0,
  468		write('Your car has run out of fuel on the half way.'), nl,
  469		write('You can only stand along the road hopelessly begging for help.'), nl,
  470		write('Your weekend is ruined.'), !, die.
  471
  472inspect_fuel :-
  473		miles(X), X =< 10,
  474		write('Your car is low on fuel. You can only drive '),
  475		write(X), write(' miles until you refuel.'), !.
  476
  477inspect_fuel :-
  478		miles(X),
  479		write('You can drive '), write(X), write(' miles.')