/* Robbing Mrs. Moneybags using logical programming. */

/* First, the notation used in this file:
	Ź means NOT
	v means OR
	^ means AND
	=> means IMPLIES
	S1 means Switch No. 1, and so on up to S9
	'keke' = true, i.e. if S4 is set to 'keke' then 4
	'baba' = false, i.e. if S4 is set to 'baba' then Ź4
The entire program is  written WITHOUT the use the Prolog OR operator (;) and WITHOUT the use of the Prolog NOT() operator.

For the full text of the exercise please see the end of the file.						*/


/* RULE 1
english:		Switches 6, 7 and 9 may not all be set keke. 
written as: 	Ź(6 ^ 7 ^ 9)
simplifies as: 	Ź6 v Ź7 v Ź9
called as:  	rule1(S6, S7, S9)				*/

rule1(baba, _, _).  		/* Ź6 */
rule1(_, baba, _).		/* Ź7 */
rule1(_, _, baba).		/* Ź9 */

/* RULE 2
english:		Only when 8 or 2 are not keke is 3 set baba. 
written as: 	Ź3 => Ź8 v Ź2
simplifies as: 	3 v Ź8 v Ź2
called as: 	rule2(S3, S8, S2)				*/

rule2(keke, _, _).		/* 3 */
rule2(_, baba, _).		/* Ź8 */
rule2(_, _, baba).		/* Ź2  */

/* RULE 3
english:		Switches 4 and 1 may not be set baba at the same time. 
written as: 	Ź(Ź4 ^ Ź1)
simplifies as: 	4 v 1
called as: 	rule3(S4, S1)				*/

rule3(keke, _).		/* 4 */
rule3(_, keke).		/* 1 */

/* RULE 4
english:		If 8 is baba, then 9 is keke.
written as: 	Ź8 => 9
simplifies as: 	8 v 9
called as: 	rule4(S8, S9)				*/

rule4(keke, _).		/* 8 */
rule4(_, keke).		/* 9 */

/* RULE 5
english: 		If neither 6 is keke nor 2 is baba then switch 5 must be set baba.
written as: 	Ź6 v 2 => Ź5
simplifies as: 	Ź(Ź6 v 2) v Ź5
simplifies as:	6 ^ Ź2 v Ź5
called as: 	rule5(S6, S2, S5)				*/

rule5(keke, baba, _).	/* 6 ^ Ź2 */
rule5(_, _, baba).		/* Ź5 */

/* RULE 6
english:		And when 2 is baba, then 1 is baba and 7 keke. 
written as: 	Ź2 => Ź1 ^ 7
simplifies as: 	2 v Ź1 ^ 7
called as: 	rule6(S2, S1, S7)				*/

rule6(keke,_,_).		/* 2 */
rule6(_, baba, keke).	/* Ź1 ^ 7 */

/* RULE 7
english:		If at least one of the switches 4 or 9 is set keke, then 3 must be set to baba. 
written as: 	4 v 9 => Ź3
simplifies as: 	Ź(4 v 9) v Ź3
simplifies as: 	Ź4 ^ Ź9 v Ź3
called as: 	rule7(S4, S9, S3)				*/

rule7(baba, baba, _).	/* Ź4 ^ Ź9 */
rule7(_, _, baba). 		/* Ź3 */

/* RULE 8
english:		Switches 2 and 5 cannot both be set to baba. 
written as: 	2 v 5
called as: 	rule8(S2, S5)				*/

rule8(keke, _).		/* 2 */
rule8(_, keke).		/* 5 */

/* RULE 9
english:		The same is true of switches 3 and 5. 
written as: 	3 v 5
called as: 	rule9(S3, S5)				*/

rule9(keke, _).		/* 3 */
rule9(_, keke).		/* 5 */

/* RULE 10
english:		Switches 3 and 8 may not have the same setting.
written as: 	Ź(3 <=> 8)
simplifies as:	(3 v 8) ^ Ź(3 ^ 8)
simplifies as:	(3 v 8) ^ (Ź3 v Ź8)
simplifies as: 	3 ^ Ź3 v 3 ^ Ź8 v 8 ^ Ź3 v 8 ^ Ź8		<- the first and the last are contradictions, can be omitted
simplifies as:	3 ^ Ź8 v Ź3 ^ 8
called as: 	rule10(S3, S8)				*/

rule10(keke, baba).		 /* 3 ^ Ź8 */
rule10(baba, keke). 	 /* Ź3 ^ 8 */


/* If switches 1, 7 and 9 must all be set to the same position, then this implies that keke means down and baba means up. */
kekeorbaba(S1, S7, S9, Keke, Baba) :-
	S1 = S7,
	S7 = S9,
	Keke = down,
	Baba = up.

/* Otherwise they have the opposite meaning. */
kekeorbaba(_,_,_, up, down) .


doit :- run.
start :- run.
go :- run.
run  :-
	rule1(S6, S7, S9),				/* apply the rules */
	rule2(S3, S8, S2),
	rule3(S4, S1),
	rule4(S8, S9),
	rule5(S6, S2, S5),
	rule6(S2, S1, S7),
	rule7(S4, S9, S3),
	rule8(S2, S5),
	rule9(S3, S5),
	rule10(S3, S8),

	kekeorbaba(S1,S7,S9, Keke, Baba), 		 /* solution found, now determine Keke and Baba */

	nl,
	write('Keke is '), write(Keke), write(', Baba is '), write(Baba), nl,
	write_list([S1,S2,S3,S4,S5,S6,S7,S8,S9], Keke, Baba), nl,
	nl.

/* just a little bit of recursion to list the states of the switches */
write_list([], _, _).
write_list([Head|Tail], Keke, Baba) :- 
	my_write(Head, Keke, Baba), 
	write_list(Tail, Keke, Baba).

/* this converts keke and baba to their corresponding up or down */
my_write(baba, _, Baba) :- write(Baba), write(' | ').
my_write(keke, Keke, _) :- write(Keke), write(' | ').


/* The complete text:
Ms. Moneybags is fed up with the problems she has had with her safe. For the fifth time now, she has forgotten the combination, and each time she has had to have the safe cut open - a process both dirty and costly!
Now she has invented a locking mechanism using nine switches, each one of which can assume one of two possible positions. Only one particular combination of switch settings for all nine switches will allow the safe to be opened.  Since she has a terrible memory for such things, she has written the proper combination of switch settings, in a somewhat cryptic form, onto a piece of paper which is taped to the door of the safe! We quote:
Switches 6, 7 and 9 may not all be set keke. Only when 8 or 2 are not keke is 3 set baba. Switches 4 and 1 may not be set baba at the same time. If 8 is baba, then 9 is keke. If neither 6 is keke nor 2 is baba then switch 5 must be set baba. And when 2 is baba, then 1 is baba and 7 keke. If at least one of the switches 4 or 9 is set keke, then 3 must be set to baba. Switches 2 and 5 cannot both be set to baba. The same is true of switches 3 and 5. Switches 3 and 8 may not have the same setting. If switches 1, 7 and 9 must all be set to the same position, then this implies that keke means down and baba means up. Otherwise they have the opposite meaning.
Ms. Moneybags now has no more problems opening her safe. At the same time, she is certain that a thief would have great difficulty decoding her instructions.
How must she set all the switches in order to open the safe?.
*/



/* (c) 2001 Jan Strojil, 
	an ERASMUS student at Staffordshire University, School Of Computing, AI Level 2
	a full time student at Palacký University, Faculty of Medicine				*/
