Toggle navigation
?
users online
Logout
Open hangout
Open chat for current file
:- use_module(library(clpfd)). person(plum). person(white). person(scarlet). person(green). person(mustard). person(peacock). weapon(rope). weapon(dagger). weapon(wrench). weapon(pistol). weapon(candlestick). weapon(lead_pipe). room(courtyard). room(game_room). room(study). room(dining_room). room(garage). room(living_room). room(kitchen). room(bedroom). room(bathroom). card(Card) :- person(Card). card(Card) :- weapon(Card). card(Card) :- room(Card). %cluedo(4,[mustard, plum, game_room, garage],[dagger, courtyard],[ yes(1, 3, [rope, green, study], rope), yes(2, 1, [candlestick, plum, kitchen]), no(3, [candlestick, green, living_room]), no(4, [pistol, green, courtyard]) ], X). cluedo(NumberOfPlayers, HandCards, DiscardedCards, QuestionsAndResponses, EnvelopeCards) :- % Create a location variable for each card bagof(Card, card(Card), Cards), length(Cards, AmountOfCards), length(CardLocations, AmountOfCards), % The cards are dealt evenly among the players, and the rest are discarded AmountOfHandCards is (AmountOfCards - 3) div NumberOfPlayers, AmountOfDiscardedCards is (AmountOfCards - 3) mod NumberOfPlayers, (length(HandCards, AmountOfHandCards) -> true; print("Unexpected number of hand cards"), fail ), (length(DiscardedCards, AmountOfDiscardedCards) -> true; print("Unexpected number of discarded cards"), fail ), % Create a mapping of each card to its location variable pair(Cards, CardLocations, CardCardLocationPairs), dict_pairs(CardToCardLocation, _, CardCardLocationPairs), % Each card is either discarded (-1), hidden (0), or held by a player (>=1) CardLocations ins -1..NumberOfPlayers, % Constraints your_hand_cards_are_known(CardToCardLocation, HandCards), discarded_cards_are_known(CardToCardLocation, DiscardedCards), number_of_cards_per_location(NumberOfPlayers, CardLocations, AmountOfHandCards, AmountOfDiscardedCards), the_envelope_contains_one_card_of_each_category(NumberOfPlayers, CardToCardLocation), questions_and_responses(NumberOfPlayers, CardToCardLocation, QuestionsAndResponses), % Enumerate all combinations of cards that can be inside the envelope envelope_cards(Cards, CardLocations, EnvelopeCards). % Relates two lists with a list where all their contents are paired together pair([], [], []). pair([Element1|List1], [Element2|List2], [Element1-Element2|Zipped]) :- pair(List1, List2, Zipped). % Relates multiple keys to their respective values in a dictionary get_multiple_from_dict([], _, []). get_multiple_from_dict([Key|Keys], Dict, [Value|Values]) :- get_dict(Key, Dict, Value), get_multiple_from_dict(Keys, Dict, Values). your_hand_cards_are_known(CardToCardLocation, HandCards) :- get_multiple_from_dict(HandCards, CardToCardLocation, HandCardLocations), maplist(#=(1), HandCardLocations). discarded_cards_are_known(CardToCardLocation, DiscardedCards) :- get_multiple_from_dict(DiscardedCards, CardToCardLocation, DiscardedCardLocations), maplist(#=(-1), DiscardedCardLocations). number_of_cards_per_location(NumberOfPlayers, CardLocations, AmountOfHandCards, AmountOfDiscardedCards) :- bagof(Player-AmountOfHandCards, between(1, NumberOfPlayers, Player), PlayerCardinality), global_cardinality(CardLocations, [(-1)-AmountOfDiscardedCards, 0-3 | PlayerCardinality]). the_envelope_contains_one_card_of_each_category(NumberOfPlayers, CardToCardLocation) :- bagof(Person, person(Person), Persons), bagof(Weapon, weapon(Weapon), Weapons), bagof(Room, room(Room), Rooms), one_of_cards_is_in_envelope(NumberOfPlayers, CardToCardLocation, Persons), one_of_cards_is_in_envelope(NumberOfPlayers, CardToCardLocation, Weapons), one_of_cards_is_in_envelope(NumberOfPlayers, CardToCardLocation, Rooms). one_of_cards_is_in_envelope(NumberOfPlayers, CardToCardLocation, Cards) :- get_multiple_from_dict(Cards, CardToCardLocation, CardLocations), bagof(Player-_, between(1, NumberOfPlayers, Player), PlayerCardinality), global_cardinality(CardLocations, [(-1)-_, 0-1 | PlayerCardinality]). questions_and_responses(NumberOfPlayers, CardToCardLocation, QuestionsAndResponses) :- maplist(question_and_response(NumberOfPlayers, CardToCardLocation), QuestionsAndResponses). % Each player, except the one asking for the cards, didn't have them question_and_response(NumberOfPlayers, CardToCardLocation, no(Asker, Cards)) :- get_multiple_from_dict(Cards, CardToCardLocation, CardLocations), players_in_between_dont_have_cards(NumberOfPlayers, CardLocations, Asker, Asker). % Responder has one of the cards, and we know which one question_and_response(NumberOfPlayers, CardToCardLocation, yes(1, Responder, Cards, ShownCard)) :- % The responding player has the shown card get_dict(ShownCard, CardToCardLocation, ShownCardLocation), ShownCardLocation #= Responder, % Each player before the responding player in the list didn't have them get_multiple_from_dict(Cards, CardToCardLocation, CardLocations), players_in_between_dont_have_cards(NumberOfPlayers, CardLocations, 1, Responder). % TODO % Responder has one of the cards, but we don't know which one, since we weren't shown the card question_and_response(NumberOfPlayers, CardToCardLocation, yes(Asker, Responder, Cards)) :- Asker \= 1, get_multiple_from_dict(Cards, CardToCardLocation, CardLocations), % The responding player has at least one of the cards maplist(reified_equal_to(Responder), CardLocations, RespondingPlayerHasCard), sum(RespondingPlayerHasCard, #>=, 1), % Each player before the responding player in the list didn't have them players_in_between_dont_have_cards(NumberOfPlayers, CardLocations, Asker, Responder). % Each player between the asking and responding player in the list didn't have the listed cards players_in_between_dont_have_cards(NumberOfPlayers, CardLocations, Asker, Responder) :- (Asker < Responder -> % "Asking < Responder"-case bagof(Player, ( between(Asker, Responder, Player), Player \= Asker, Player \= Responder ), PlayersWithoutCards); % "Asking >= Responder"-case bagof(Player, ( between(1, NumberOfPlayers, Player), \+ between(Responder, Asker, Player) ), PlayersWithoutCards)), maplist(player_doesnt_have_cards(CardLocations), PlayersWithoutCards). % The given card locations are not the given player player_doesnt_have_cards(CardLocations, Player) :- maplist(#\=(Player), CardLocations). reified_equal_to(Value, Variable, True) :- Variable #= Value #<==> True. envelope_cards(Cards, CardLocations, EnvelopeCards) :- maplist(reified_equal_to(0), CardLocations, EnvelopeLocations), pair(Cards, EnvelopeLocations, CardEnvelopeLocationPairs), label(EnvelopeLocations), include(second_equals_one, CardEnvelopeLocationPairs, CardEnvelopeLocationPairsInEnvelope), pair(EnvelopeCards, _, CardEnvelopeLocationPairsInEnvelope). second_equals_one(_-1).