% FILE: rummy.pl % LINE: Defines all rules related to Rummy gameplay % DATE: February 20, 2021 % write a game where only runs are found % write a game where one player looks for only sets and one looks for only runs % use these to test the performance of each player % write some kind of method where you can pass in the heuristic as an argument % loading prolog files :- consult("melds.pl"). :- consult("demos.pl"). :- consult("human_readable.pl"). :- consult("game_types.pl"). % name, hand, melds, score player((player1, [], [], 0)). player((player2, [], [], 0)). % human player for later on human_player(name, [], [], 0). % Deck representation deck([card(ace, hearts, 1),card(two, hearts, 2),card(three, hearts, 3),card(four, hearts, 4),card(five, hearts, 5),card(six, hearts, 6), card(seven, hearts, 7),card(eight, hearts, 8),card(nine, hearts, 9),card(ten, hearts, 10),card(jack, hearts, 11),card(queen, hearts, 12), card(king, hearts, 13),card(ace, clubs, 1),card(two, clubs, 2),card(three, clubs, 3),card(four, clubs, 4),card(five, clubs, 5), card(six, clubs, 6),card(seven, clubs, 7),card(eight, clubs, 8),card(nine, clubs, 9),card(ten, clubs, 10),card(jack, clubs, 11), card(queen, clubs, 12),card(king, clubs, 13),card(ace, hearts, 1),card(two, diamonds, 2),card(three, diamonds, 3),card(four, diamonds, 4), card(five, diamonds, 5),card(six, diamonds, 6),card(seven, diamonds, 7),card(eight, diamonds, 8),card(nine, diamonds, 9),card(ten, diamonds, 10), card(jack, diamonds, 11),card(queen, diamonds, 12),card(king, diamonds, 13),card(ace, spades, 1),card(two, spades, 2),card(three, spades, 3), card(four, spades, 4),card(five, spades, 5),card(six, spades, 6),card(seven, spades, 7),card(eight, spades, 8),card(nine, spades, 9),card(ten, spades, 10), card(jack, spades, 11),card(queen, spades, 12),card(king, spades, 13)]). % shuffles deck, deal cards to players, deals one card to discard pile init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)) :- shuffle(Deck, NewDeck), deal_out(NewDeck, NewerDeck, Hand1, NewHand1, Hand2, NewHand2, 13), deal_discard(NewerDeck, NDeck, DiscardPile). % Shuffles cards shuffle(Deck, NewDeck) :- random_permutation(Deck, NewDeck). % Deals cards into the player's hands % Deck, NewDeck, Hand1, NewHand1, Hand2 NewHand2, Terminate deal_out([_|Rest], Rest, Hand1, Hand1, Hand2, Hand2, 0). deal_out([First, Second|Rest], NewDeck, Hand1, NewHand1, Hand2, NewHand2, Terminate) :- NewTerm is Terminate - 1, deal_out(Rest, NewDeck, [First|Hand1], NewHand1, [Second|Hand2], NewHand2, NewTerm). % initializes the discard pile by dealing one card into it deal_discard([First|Rest], Rest, [First]). % takes one card from a player's hand and puts it in the discard pile discard([FirstCard|RestHand], DiscardPile, RestHand,[FirstCard|DiscardPile]). % Randomly discards a card from the player's hand random_discard([], _, [], _). random_discard(Hand, DiscardPile, RestHand, [Card|DiscardPile]) :- pick(Hand, Card), human_readable([Card], HRCard), write("DISCARDING: "), write(HRCard), nl, remove(Card, Hand, RestHand). % picks an item at random out of a List (Credit: Prof. Craig Graci) pick(L, Item):- length(L, Length), random(0, Length, RN), nth0(RN, L, Item). % removes and item from a list (Credit: Prof. Craig Graci) remove(_, [], []). remove(First, [First|Rest], Rest). remove(Element, [First|Rest], [First|RestLessElement]) :- remove(Element, Rest, RestLessElement). % takes one card off the top of the deck draw_from_deck([Card|RestDeck], RestDeck, Hand, [Card|Hand]) :- human_readable([Card], HRCard), write("DRAWING FROM DECK: "), write(HRCard), nl. % binds the card on top of the deck to a variable draw([First|_], First). % calculates the total score of each player calculate_score((_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2) :- get_score_from_melds(Melds1, Score1, NewScore1), get_score_from_melds(Melds2, Score2, NewScore2), subtract_out_hand(Hand1, NewScore1, UpdateScore1), subtract_out_hand(Hand2, NewScore2, UpdateScore2). % Calculates the score of every meld a player has. get_score_from_melds([], Score, Score). get_score_from_melds([FirstMeld|RestMelds], OldScore, NewScore) :- get_score_from_meld(FirstMeld, OldScore, UpdateScore), get_score_from_melds(RestMelds, UpdateScore, NewScore). % Calculates the point values contained in each meld get_score_from_meld([], Score, Score). get_score_from_meld([card(_, _, 1)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 2)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 3)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 4)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 5)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 6)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 7)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 8)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 9)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 5, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 10)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 10, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 11)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 10, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 12)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 10, get_score_from_meld(RestCards, UpdateScore, NewScore). get_score_from_meld([card(_, _, 13)|RestCards], OldScore, NewScore) :- UpdateScore is OldScore + 10, get_score_from_meld(RestCards, UpdateScore, NewScore). % Subtracts the point values contained in a player's hand from the score provided. subtract_out_hand([], Score, Score). subtract_out_hand([card(_, _, 1)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 2)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 3)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 4)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 5)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 6)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 7)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 8)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 9)|RestCards], Score, NewScore) :- UpdateScore is Score - 5, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 10)|RestCards], Score, NewScore) :- UpdateScore is Score - 10, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 11)|RestCards], Score, NewScore) :- UpdateScore is Score - 10, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 12)|RestCards], Score, NewScore) :- UpdateScore is Score - 10, subtract_out_hand(RestCards, UpdateScore, NewScore). subtract_out_hand([card(_, _, 13)|RestCards], Score, NewScore) :- UpdateScore is Score - 10, subtract_out_hand(RestCards, UpdateScore, NewScore). % FILE: game_types.pl % LINE: Defines all variants of games tested % DATE: February 20, 2021 % takes the most basic turn for a player % draws from the deck, % possibly add variable for player for writing purposes % GAME WHERE ONLY SETS ARE USED AS MOVES % --------------------------------------------------------------------------------------------------------------------------------------------------------- % The player given will take a turn, where a turn consists of picking a card (from the deck), checking to see if any melds can be played % and then randomly discarding a card take_turn_sets((_, Hand, Melds, _), Deck, DiscardPile, (_, NewHand3, NewMelds, _), NewDeck1, NewDiscardPile) :- draw_from_deck(Deck, NewDeck1, Hand, NewHand1), write("LOOKING FOR SETS..."), nl, find_set(NewHand1, NewHand1, Melds, NewMelds, NewHand2), random_discard(NewHand2, DiscardPile, NewHand3, NewDiscardPile). % initializes the game and plays an entire round of rummy play_rummy_sets :- deck(Deck), player((player1, Hand1, Melds1, Score1)), player((player2, Hand2, Melds2, Score2)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_sets(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, _, _). % Plays an entire game of rummy with basic moves and no heuristics play_entire_game_sets(Score1, _) :- Score1 >= 500, write("Player1 wins with score "), write(Score1). play_entire_game_sets(_, Score2) :- Score2 >= 500, write("Player2 wins with score "), write(Score2). play_entire_game_sets(Score1, Score2):- deck(Deck), player((player1, Hand1, Melds1, _)), player((player2, Hand2, Melds2, _)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_sets(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2), play_entire_game_sets(UpdateScore1, UpdateScore2). % Plays an entire round of rummy. The round ends when either the deck, or one of the players' % hands is empty play_rummy_round_sets([], (_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_sets(_, (_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_sets(_, (_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_sets(Deck, (Player1, Hand1, Melds1, Score1), (Player2, Hand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2) :- human_readable(Deck, HRDeck), write("Deck: "), write(HRDeck), nl, human_readable(DiscardPile, HRDiscardPile), write("Discard Pile: "), write(HRDiscardPile), nl, nl, write("Player 1 turn!"), nl, print_info(Hand1, Melds1, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_sets((Player1, Hand1, Melds1, Score1), Deck, DiscardPile, (_, NewHand1, NewMeld1, _), NewDeck1, NewDiscard1), nl, print_info(NewHand1, NewMeld1, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, write("Player 2 turn!"), nl, print_info(Hand2, Melds2, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_sets((Player2, Hand2, Melds2, Score2), NewDeck1, NewDiscard1, (_, NewHand2, NewMeld2, _), NewDeck2, NewDiscard2), nl, print_info(NewHand1, NewMeld1, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, nl, play_rummy_round_sets(NewDeck2, (Player1, NewHand1, NewMeld1, Score1), (Player2, NewHand2, NewMeld2, Score2), NewDiscard2, UpdateScore1, UpdateScore2). % --------------------------------------------------------------------------------------------------------------------------------------------------------- % GAME WHERE ONLY RUNS ARE USED AS MOVES %---------------------------------------------------------------------------------------------------------------------------------------------------------- % The player given will take a turn, where a turn consists of picking a card (from the deck), checking to see if any melds can be played % and then randomly discarding a card take_turn_runs((_, Hand, Melds, _), Deck, DiscardPile, (_, NewHand4, NewestMelds, _), NewDeck1, NewDiscardPile) :- draw_from_deck(Deck, NewDeck1, Hand, NewHand1), merge_sort(NewHand1, NewHand2), write("LOOKING FOR RUNS..."), nl, find_run(NewHand2, NewHand3, [diamonds, clubs, hearts, spades], Melds, NewestMelds), random_discard(NewHand3, DiscardPile, NewHand4, NewDiscardPile). % initializes the game and plays an entire round of rummy play_rummy_runs :- deck(Deck), player((player1, Hand1, Melds1, Score1)), player((player2, Hand2, Melds2, Score2)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_runs(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, _, _). % Plays an entire game of rummy with basic moves and no heuristics play_entire_game_runs(Score1, _) :- Score1 >= 500, write("Player1 wins with score "), write(Score1). play_entire_game_runs(_, Score2) :- Score2 >= 500, write("Player2 wins with score "), write(Score2). play_entire_game_runs(Score1, Score2):- deck(Deck), player((player1, Hand1, Melds1, _)), player((player2, Hand2, Melds2, _)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_runs(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2), play_entire_game_runs(UpdateScore1, UpdateScore2). % Plays an entire round of rummy. The round ends when either the deck, or one of the players' % hands is empty play_rummy_round_runs([], (_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_runs(_, (_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_runs(_, (_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_runs(Deck, (Player1, Hand1, Melds1, Score1), (Player2, Hand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2) :- human_readable(Deck, HRDeck), write("Deck: "), write(HRDeck), nl, human_readable(DiscardPile, HRDiscardPile), write("Discard Pile: "), write(HRDiscardPile), nl, nl, write("Player 1 turn!"), nl, print_info(Hand1, Melds1, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_runs((Player1, Hand1, Melds1, Score1), Deck, DiscardPile, (_, NewHand1, NewMeld1, _), NewDeck1, NewDiscard1), nl, print_info(NewHand1, NewMeld1, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, write("Player 2 turn!"), nl, print_info(Hand2, Melds2, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_runs((Player2, Hand2, Melds2, Score2), NewDeck1, NewDiscard1, (_, NewHand2, NewMeld2, _), NewDeck2, NewDiscard2), nl, print_info(NewHand2, NewMeld2, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, nl, play_rummy_round_runs(NewDeck2, (Player1, NewHand1, NewMeld1, Score1), (Player2, NewHand2, NewMeld2, Score2), NewDiscard2, UpdateScore1, UpdateScore2). % GAME WHERE BOTH PLAYERS USE BOTH SETS AND RUNS %---------------------------------------------------------------------------------------------------------------------------------------------------------- take_turn_both((_, Hand, Melds, _), Deck, DiscardPile, (_, FinalHand, NewestMelds, _), NewDeck1, NewDiscardPile) :- draw_from_deck(Deck, NewDeck1, Hand, NewHand1), write("LOOKING FOR SETS..."), nl, find_set(NewHand1, NewHand1, Melds, NewMelds, NewHand2), merge_sort(NewHand2, SortedHand), write("LOOKING FOR RUNS..."), nl, find_run(SortedHand, NewHand3, [diamonds, clubs, hearts, spades], NewMelds, NewestMelds), random_discard(NewHand3, DiscardPile, FinalHand, NewDiscardPile). % initializes the game and plays an entire round of rummy play_rummy_both :- deck(Deck), player((player1, Hand1, Melds1, Score1)), player((player2, Hand2, Melds2, Score2)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_both(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, _, _). % Plays an entire game of rummy where one player uses only runs and one player uses only sets play_entire_game_both(Score1, _) :- Score1 >= 500, write("Player1 wins with score "), write(Score1). play_entire_game_both(_, Score2) :- Score2 >= 500, write("Player2 wins with score "), write(Score2). play_entire_game_both(Score1, Score2):- deck(Deck), player((player1, Hand1, Melds1, _)), player((player2, Hand2, Melds2, _)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_both(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2), play_entire_game_both(UpdateScore1, UpdateScore2). % Plays an entire round of rummy. The round ends when either the deck, or one of the players' % hands is empty play_rummy_round_both([], (_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_both(_, (_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_both(_, (_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_both(Deck, (Player1, Hand1, Melds1, Score1), (Player2, Hand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2) :- human_readable(Deck, HRDeck), write("Deck: "), write(HRDeck), nl, human_readable(DiscardPile, HRDiscardPile), write("Discard Pile: "), write(HRDiscardPile), nl, nl, write("Player 1 turn!"), nl, print_info(Hand1, Melds1, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_both((Player1, Hand1, Melds1, Score1), Deck, DiscardPile, (_, NewHand1, NewMeld1, _), NewDeck1, NewDiscard1), nl, print_info(NewHand1, NewMeld1, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, write("Player 2 turn!"), nl, print_info(Hand2, Melds2, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_both((Player2, Hand2, Melds2, Score2), NewDeck1, NewDiscard1, (_, NewHand2, NewMeld2, _), FinalDeck, FinalDiscard), nl, print_info(NewHand2, NewMeld2, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, nl, play_rummy_round_both(FinalDeck, (Player1, NewHand1, NewMeld1, Score1), (Player2, NewHand2, NewMeld2, Score2), FinalDiscard, UpdateScore1, UpdateScore2). % GAME WHERE ONE PLAYER USES SETS AND ONE USES RUNS %---------------------------------------------------------------------------------------------------------------------------------------------------------- % initializes the game and plays an entire round of rummy play_rummy_one_of_each :- deck(Deck), player((player1, Hand1, Melds1, Score1)), player((player2, Hand2, Melds2, Score2)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_one_of_each(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, _, _). % Plays an entire game of rummy where one player uses only runs and one player uses only sets play_entire_game_one_of_each(Score1, _) :- Score1 >= 500, write("Player1 wins with score "), write(Score1). play_entire_game_one_of_each(_, Score2) :- Score2 >= 500, write("Player2 wins with score "), write(Score2). play_entire_game_one_of_each(Score1, Score2):- deck(Deck), player((player1, Hand1, Melds1, _)), player((player2, Hand2, Melds2, _)), init_rummy(Deck, (_, Hand1, _, _), (_, Hand2, _, _), DiscardPile, NewDeck, (_, NewHand1, _, _), (_, NewHand2, _, _)), play_rummy_round_one_of_each(NewDeck, (player1, NewHand1, Melds1, Score1), (player2, NewHand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2), play_entire_game_one_of_each(UpdateScore1, UpdateScore2). % Plays an entire round of rummy. The round ends when either the deck, or one of the players' % hands is empty play_rummy_round_one_of_each([], (_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_one_of_each(_, (_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, [], Melds1, Score1), (_, Hand2, Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_one_of_each(_, (_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), _, UpdateScore1, UpdateScore2) :- calculate_score((_, Hand1, Melds1, Score1), (_, [], Melds2, Score2), UpdateScore1, UpdateScore2), write("Player 1 Score: "), write(UpdateScore1), nl, write("Player 2 Score: "), write(UpdateScore2), nl. play_rummy_round_one_of_each(Deck, (Player1, Hand1, Melds1, Score1), (Player2, Hand2, Melds2, Score2), DiscardPile, UpdateScore1, UpdateScore2) :- human_readable(Deck, HRDeck), write("Deck: "), write(HRDeck), nl, human_readable(DiscardPile, HRDiscardPile), write("Discard Pile: "), write(HRDiscardPile), nl, nl, write("Player 1 turn!"), nl, print_info(Hand1, Melds1, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_sets((Player1, Hand1, Melds1, Score1), Deck, DiscardPile, (_, NewHand1, NewMeld1, _), NewDeck1, NewDiscard1), nl, print_info(NewHand1, NewMeld1, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, write("Player 2 turn!"), nl, print_info(Hand2, Melds2, "HAND BEFORE TURN: ", "MELDS BEFORE TURN: "), nl, take_turn_runs((Player2, Hand2, Melds2, Score2), NewDeck1, NewDiscard1, (_, NewHand2, NewMeld2, _), NewDeck2, NewDiscard2), nl, print_info(NewHand2, NewMeld2, "HAND AFTER TURN: ", "MELDS AFTER TURN: "), nl, nl, nl, play_rummy_round_one_of_each(NewDeck2, (Player1, NewHand1, NewMeld1, Score1), (Player2, NewHand2, NewMeld2, Score2), NewDiscard2, UpdateScore1, UpdateScore2). %---------------------------------------------------------------------------------------------------------------------------------------------------------- print_info(Hand, Melds, HandMessage, MeldMessage) :- human_readable(Hand, HRHand), write(HandMessage), write(HRHand), nl, human_readable_melds(Melds, HRMelds), write(MeldMessage), write(HRMelds), nl. % 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 three of a kind in a player's hand % Original Hand, Hand to iterate through, find_four_of_a_kind(OrigHand, [], OldMelds, OldMelds, OrigHand). find_four_of_a_kind(OrigHand, [card(Face1, Suit1, Rank1)|_], OldMelds, [Move|OldMelds], NewHand) :- find_same_card(OrigHand, card(Face1, Suit1, Rank1), Move, NewHand), length(Move, L), L=4. find_four_of_a_kind(OrigHand, [_|RestHand], OldMelds, NewMelds, NewHand) :- find_four_of_a_kind(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).