% card definitions
card(ace, spades).
card(king, spades).
card(queen, spades).
card(jack, spades).
card(10, spades).
card(9, spades).
card(8, spades).
card(7, spades).
card(6, spades).
card(5, spades).
card(4, spades).
card(3, spades).
card(2, spades).

card(ace, hearts).
card(king, hearts).
card(queen, hearts).
card(jack, hearts).
card(10, hearts).
card(9, hearts).
card(8, hearts).
card(7, hearts).
card(6, hearts).
card(5, hearts).
card(4, hearts).
card(3, hearts).
card(2, hearts).

card(ace, clubs).
card(king, clubs).
card(queen, clubs).
card(jack, clubs).
card(10, clubs).
card(9, clubs).
card(8, clubs).
card(7, clubs).
card(6, clubs).
card(5, clubs).
card(4, clubs).
card(3, clubs).
card(2, clubs).

card(ace, diamonds).
card(king, diamonds).
card(queen, diamonds).
card(jack, diamonds).
card(10, diamonds).
card(9, diamonds).
card(8, diamonds).
card(7, diamonds).
card(6, diamonds).
card(5, diamonds).
card(4, diamonds).
card(3, diamonds).
card(2, diamonds).

% Points of the cards 
points(card(king, _), 3).
points(card(queen, _), 2).
points(card(X, _), 0) :- X\=king, X\=queen.

% case when the stack contains all figures 
all_figures([card(X, _), card(Y, _)]) :- 
	(X==king; X==queen; X==jack), 
	(Y==king; Y==queen; Y==jack).

% points value of a stack
value([X,Y], S) :- 
	points(X, S1), 
	points(Y, S2), 
	all_figures([X, Y]), 
	S is (5 + S1 + S2), !.
value([X,Y], S) :- 
	points(X, S1), 
	points(Y, S2), 
	S is S1 + S2.

% the all_figure rules was applied to the new cards.

% Insertion of an element at the end of a list
insert([], Y, [Y]).
insert([X|T], Y, [X |T1]):- insert(T, Y, T1).

% Produce the list of all cards
compose(L1, L2) :- 
	card(X, Y), 
	not(member(card(X, Y), L1)), 
	insert(L1, card(X, Y), L3), 
	compose(L3, L2), !.
compose(L1, L2) :- L2 = L1.

% Retract a card from a random position in the list of cards
retract_card(List1, Index, List2, Elem) :- 
	nth1(Index, List1, Elem), 
	delete(List1, Elem, List2).

% Randomly pick two cards
pick_Player(4-2, [C1, C2], [C1, C2], []) :- !. 
pick_Player(B, L, [C1, C2], L2) :-
	B \= 2, 
	N1 is random(B), N1 \= 0,
	retract_card(L, N1, L1, C1),
	N2 is random(B-1), N2 \= N1, N2 \= 0, 
	retract_card(L1, N2, L2, C2), !.
pick_Player(B, L, P , L2) :- pick_Player(B, L, P, L2). 

% Case when the ace of clubs is received: deduct 6 points
ace_of_clubs([card(ace, clubs), _], -6) :- !.
ace_of_clubs([_, card(ace, clubs)], -6) :- !.
ace_of_clubs([_, _], 0).

wins(P1, P2, J1, _) :- 	
	P1 > P2,
	writef('%t wins this round\n', [J1]).
wins(P1, P2, _, J2) :- 	
	P2 > P1,
	writef('%t wins this round\n', [J2]).
wins(P1, P2, _, _) :- 	
	P1 == P2,
	write('Nobody wins this round'), nl.

% Calculates the points of the players for one round
round(Player1, Player2, Stack1, Stack2, Points1, Points2) :-
	value(Stack1, Points1),
	writef('\nThe stack of %t has %t points\n', [Player1, Points1]), 
	value(Stack2, Points2),
	writef('The stack of %t has %t points\n', [Player2, Points2]),
	wins(Points1, Points2, Player1, Player2).


% Scores each round of the game
player(B, Stack, Player1, Player2, Score1, Score2) :- 
	writef('Describe the stack of %t :', [Player1]), nl,
	pick_Player(B, Stack, Stack1, StackR1),
	ace_of_clubs(Stack1, R1),
 
	writef('\t\t'), write(Stack1), nl,
	writef('Describe the stack of %t :', [Player2]), nl,
 	pick_Player(B-2, StackR1, Stack2, StackR2),
	ace_of_clubs(Stack2, R2),
	writef('\t\t'), write(Stack2), nl,
	round(Player1, Player2, Stack1, Stack2, Points1, Points2),

	NewScore1 is Score1 + Points1 + R1,
	NewScore2 is Score2 + Points2 + R2,
      
      %don't allow the scores to become negative
      ((NewScore1 =< 0, NS1 is 0); NS1 is NewScore1),
      ((NewScore2 =< 0, NS2 is 0); NS2 is NewScore2),

      % if the opponent has zero pints, add 10 points
      ((NS1 =:= 0, NNS2 is NS2 +10); NNS2 is NS2),
      ((NS2 =:= 0, NNS1 is NS1 +10); NNS1 is NS1),

	writef('\n%t has a total of %t points\n', [Player1, NNS1]),
	writef('%t has a total of %t points\n', [Player2, NNS2]),

	StackR2 \= [], 	
	write('-------------------------------'), nl,
	write('Do you want to continue [y/n]:  '),
	get(Response),
	writef('\n-------------------------------'), nl,
	Response == 121,  
	NewB is B-4,
	player(NewB, StackR2, Player1, Player2, NNS1, NNS2).

player(_, _, Player1, _, Score1, Score2) :- 
	Score1 > Score2, 
	writef('\n%t wins the game. Goodbye!', [Player1]), nl.

player(_, _, _, Player2, Score1, Score2) :- 
	Score2 > Score1, 
	writef('\n%t wins the game. Goodbye!', [Player2]), nl.

% Start the game with 52 cards
game(Player1, Player2) :- compose([], Stack), 
			 player(52, Stack, Player1, Player2, 0, 0).

% Start the game with the query
% game(john, peter).


%Note: if you interpreted some rules of the game in a different way (rules 3,4,5), 
%      that's OK too as long as it is a plausible interpretation. 
