% FILE: melds.pl % LINE: Defines rules for finding melds in a player's hand % DATE: March 14, 2021 % checks if a hand has N of one card in it find_same_card([], _, [], []). find_same_card([card(Face1, Suit1, Rank1)|RestHand], card(Face1, _, _), [card(Face1, Suit1, Rank1)|Move], NewHand) :- find_same_card(RestHand, card(Face1, _, _), Move, NewHand). find_same_card([card(Face1, Suit1, Rank1)|RestHand], card(Face2, Suit2, Rank2), Move, [card(Face1, Suit1, Rank1)|NewHand]) :- find_same_card(RestHand, card(Face2, Suit2, Rank2), Move, NewHand). % finds three of a kind in a player's hand % Original Hand, Hand to iterate through, find_set(OrigHand, [], OldMelds, OldMelds, OrigHand) :- write("NO SETS FOUND"), nl. find_set(OrigHand, [card(Face1, Suit1, Rank1)|_], OldMelds, [Move|OldMelds], NewHand) :- find_same_card(OrigHand, card(Face1, Suit1, Rank1), Move, NewHand), length(Move, L), L>=3, human_readable(Move, HRMove), write("SET FOUND: "), write(HRMove), nl. find_set(OrigHand, [_|RestHand], OldMelds, NewMelds, NewHand) :- find_set(OrigHand, RestHand, OldMelds, NewMelds, NewHand). % finds a run of any length greater than or equal to three in a player's hand % Hand must be sorted before calling this method % try with suit, if move is found, add it to melds, repeat until no more suits find_run(Hand, Hand, [], Melds, Melds) :- write("NO RUNS FOUND."), nl. find_run(Hand, NewHand, [FirstSuit|_], Melds, [CardsFound|Melds]) :- find_run_suit(Hand, NewHand, 1, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 2, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 3, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 4, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 5, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 6, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 7, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 8, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 9, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 10, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 11, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl. find_run(Hand, NewHand, [_|RestSuits], Melds, NewMelds) :- find_run(Hand, NewHand, RestSuits, Melds, NewMelds). % finds a run in the suit provided starting at rank NextRank find_run_suit([], [], _, _,[]). find_run_suit([card(Face, Suit, Rank)|Hand], NewHand, Rank, Suit, [card(Face, Suit, Rank)|CardsFound]) :- NewRank is Rank +1, find_run_suit(Hand, NewHand, NewRank, Suit, CardsFound). find_run_suit([card(Face, Suit, Rank)|Hand], [card(Face, Suit, Rank)|NewHand], AnotherRank, Suit2, CardsFound) :- find_run_suit(Hand, NewHand, AnotherRank, Suit2, CardsFound). % Sorts hand in order by the following rule % A - K with suit order being Diamonds, Clubs, Hearts, Spade merge_sort([], []). merge_sort([Item], [Item]). merge_sort(List,Sorted):- List=[_,_|_], split(List, L1, L2), merge_sort(L1,Sorted1), merge_sort(L2,Sorted2), merge(Sorted1,Sorted2,Sorted). % merges two lists together, sorting them on the way up merge([], L, L). merge(L, [], L) :- L \= []. merge([card(Face1, Suit1, Rank1)|T1], [card(Face2, Suit2, Rank2)|T2], [card(Face1, Suit1, Rank1)|T]) :- less_than(card(Face1, Suit1, Rank1), card(Face2, Suit2, Rank2)), merge(T1, [card(Face2, Suit2, Rank2)|T2], T). merge([X|T1],[Y|T2],[Y|T]) :- merge([X|T1],T2,T). % true if card 1 is less than card 2 less_than(card(_, _, Rank1), card(_, _, Rank2)) :- Rank1 < Rank2. less_than(card(_, Suit1, Rank1), card(_, _, Rank2)) :- Rank1 = Rank2, Suit1 = diamonds. less_than(card(_, Suit1, Rank1), card(_, Suit2, Rank2)) :- Rank1 = Rank2, Suit1 = clubs, Suit2 = hearts. less_than(card(_, Suit1, Rank1), card(_, Suit2, Rank2)) :- Rank1 = Rank2, Suit1 = clubs, Suit2 = spades. less_than(card(_, Suit1, Rank1), card(_, Suit2, Rank2)) :- Rank1 = Rank2, Suit1 = hearts, Suit2 = spades. split([], [], []). split([Card], [Card|[]], []). split([Card1, Card2|RestCards], [Card1|RestCards1], [Card2|RestCards2]) :- split(RestCards, RestCards1, RestCards2). % ----------------------------------------------------------------------------------------------------------------------------------------------------------------- % PLAYING ON PREMADE SETS % checks the entire hand to see if a card can be played on any sets of melds play_on_meld_sets([], [], Melds, Melds, _, Sets, Sets) :- write("NO MELD PLAYABLE"), nl. play_on_meld_sets([FirstCard|RestHand], RestHand, Melds, NewMelds, CardWorked, Sets, NewSets) :- play_card_on_meld_sets(FirstCard, Melds, NewMelds, CardWorked, Sets, NewSets), length(CardWorked, L), L = 1, human_readable(CardWorked, HRCardWorked), write("MElD FOUND: "), write(HRCardWorked), nl. play_on_meld_sets([FirstCard|RestHand], [FirstCard|NewRestHand],Melds, NewMelds, CardWasFound, Sets, NewSets) :- play_on_meld_sets(RestHand, NewRestHand, Melds, NewMelds, CardWasFound, Sets, NewSets). % checks to see if a single card can be played the entire set of sets play_card_on_meld_sets(_, Melds, Melds, [], [], []). play_card_on_meld_sets(card(Face, Suit, Rank), Melds, [[card(Face, Suit, Rank)]|Melds], [card(Face, Suit, Rank)], [FirstSet|RestSet], [UpdateSet|RestSet]) :- is_playable_on_set(card(Face, Suit, Rank), FirstSet, UpdateSet). play_card_on_meld_sets(card(Face, Suit, Rank), Melds, NewMelds, [FirstSet|Sets], [FirstSet|NewSets]) :- play_card_on_meld_sets(card(Face, Suit, Rank), Melds, NewMelds, Sets, NewSets). find_set_all_melds(OrigHand, [], OldMelds, OldMelds, OrigHand, AllSets, AllSets) :- write("NO SETS FOUND"), nl. find_set_all_melds(OrigHand, [card(Face1, Suit1, Rank1)|_], OldMelds, [Move|OldMelds], NewHand, AllSets, [Move|AllSets]) :- find_same_card(OrigHand, card(Face1, Suit1, Rank1), Move, NewHand), length(Move, L), L>=3, human_readable(Move, HRMove), write("SET FOUND: "), write(HRMove), nl. find_set_all_melds(OrigHand, [_|RestHand], OldMelds, NewMelds, NewHand, AllSets, NewAllSets) :- find_set_all_melds(OrigHand, RestHand, OldMelds, NewMelds, NewHand, AllSets, NewAllSets). % Checks to see if a card can be played on a given set is_playable_on_set(card(Face1, Suit1, Rank1), [card(Face2, Suit2, Rank1)|RestMeld], [card(Face1, Suit1, Rank1), card(Face2, Suit2, Rank1)|RestMeld]). % ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- %PLAYING ON PREMADE RUNS play_on_meld_runs([], [], Melds, Melds, _, Runs, Runs) :- write("NO MELD PLAYABLE"), nl. play_on_meld_runs([FirstCard|RestHand], RestHand, Melds, NewMelds, CardWorked, Runs, NewRuns) :- play_card_on_meld_runs(FirstCard, Melds, NewMelds, CardWorked, Runs, NewRuns), length(CardWorked, L), L = 1, write("MELD FOUND: "), human_readable(CardWorked, HRCardWorked), write(HRCardWorked), nl. play_on_meld_runs([FirstCard|RestHand], [FirstCard|NewRestHand],Melds, NewMelds, CardWasFound, Runs, NewRuns) :- play_on_meld_runs(RestHand, NewRestHand, Melds, NewMelds, CardWasFound, Runs, NewRuns). play_card_on_meld_runs(_, Melds, Melds, [], [], []). play_card_on_meld_runs(card(Face, Suit, Rank), Melds, [[card(Face, Suit, Rank)]|Melds], [card(Face, Suit, Rank)], [FirstRun|RestRun], [UpdateRun|RestRun]) :- is_playable_on_run(card(Face, Suit, Rank), FirstRun, UpdateRun). play_card_on_meld_runs(card(Face, Suit, Rank), Melds, NewMelds, CardFound, [FirstRun|Runs], [FirstRun|NewRuns]) :- play_card_on_meld_runs(card(Face, Suit, Rank), Melds, NewMelds, CardFound, Runs, NewRuns). %Checks to see if a card can be played on a given set is_playable_on_run(card(Face1, Suit1, Rank1), [card(Face2, Suit1, Rank2)|RestMeld], [card(Face1, Suit1, Rank1), card(Face2, Suit1, Rank2)|RestMeld]) :- TestRank is Rank1 + 1, % problem area: Rank2 is set to TestRank if Rank2 is not defined! Rank2 = TestRank. is_playable_on_run(card(Face1, Suit1, Rank1), Meld, NewMeld) :- last(Meld, card(_, Suit1, Rank2)), TestRank is Rank2 + 1, % problem area: Rank1 is set to TestRank if Rank2 is not defined! Rank1 = TestRank, append(Meld, [card(Face1, Suit1, Rank1)], NewMeld). % finds a run in a player's hand and appends that run to a list containing all runs found in the game thus far find_run_melds(Hand, Hand, [], Melds, Melds, Runs, Runs) :- write("NO RUNS FOUND."), nl. find_run_melds(Hand, NewHand, [FirstSuit|_], Melds, [CardsFound|Melds], AllRuns, [CardsFound|AllRuns]) :- find_run_suit(Hand, NewHand, 1, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 2, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 3, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 4, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 5, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 6, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 7, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 8, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 9, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 10, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl ; find_run_suit(Hand, NewHand, 11, FirstSuit, CardsFound), length(CardsFound, L), L >= 3, human_readable(CardsFound, HRCardsFound), write("RUN FOUND: "), write(HRCardsFound), nl. find_run_melds(Hand, NewHand, [_|RestSuits], Melds, NewMelds, Runs, NewRuns) :- find_run_melds(Hand, NewHand, RestSuits, Melds, NewMelds, Runs, NewRuns). % write("card: "), write(card(Face1, Suit1, Rank1)), nl, % write("RestMeld: "), write(RestMeld), nl, % write("TestRank: "), write(TestRank), nl, % write("Rank2: "), write(Rank2), nl, %write("card: "), write(card(Face1, Suit1, Rank1)), nl, % write("Meld: "), write(Meld), nl, % write("TestRank: "), write(TestRank), nl, % write("Rank2: "), write(Rank2), nl,