user19258905
user19258905

Reputation:

Prolog logic task

the rules are five students won five different places in five different disciplines - Alex, Bob, John, Deo, Sam.

  1. The language student placed higher than Bob as much as Bob placed higher than the law student.

  2. The IT student placed three spots higher than John.

  3. Alex placed at an even rank and the math student at an odd one.

  4. Sam placed two places below the physicist.

Who placed where and what do they study?

How do I go about accounting for the two unknowns in the conditions?

Upvotes: 0

Views: 191

Answers (2)

brebs
brebs

Reputation: 4377

One method, after a bit of performance improvement:

go(Sol) :- 
    People = [alex, bob, john, deo, sam],

    Topics = [lang, law, it, math, phys],
    TopicsP = [LangP, LawP, ItP, MathP, PhysP],

    Placements = [1, 2, 3, 4, 5],

    CombLsts = [People, Topics, Placements],

    % Break symmetry by specifying the people order
    Sol = [
        [alex, _, AlexP],
        [bob, _, BobP],
        [john, _, JohnP],
        [deo, _, _],
        [sam, _, SamP]
    ],

    % Rule 1
    when((nonvar(LangP), nonvar(BobP)), (
        % Caution with "placed higher" = lower
        LangPDiff is BobP - LangP,
        LangPDiff >= 1,
        when(nonvar(LawP), (
            BobPDiff is LawP - BobP,
            LangPDiff =:= BobPDiff
        ))
    )),

    % Rule 2
    % Caution with "placed higher" = lower
    when_both(ItP, JohnP, ItP is JohnP - 3),

    % Rule 3
    freeze(AlexP, 0 is AlexP mod 2),
    freeze(MathP, 1 is MathP mod 2),

    % Rule 4
    % "places below" = higher number
    when_both(SamP, PhysP, SamP is PhysP + 2),

    % Find a solution
    find_combs(CombLsts, Sol, Topics, TopicsP).


find_combs(CombLsts, [Comb|Sol], Topics, TopicsP) :-
    % Select a combination, with remainder
    maplist(select, Comb, CombLsts, Rem),
    % Populate TopicsP
    Comb = [_, Topic, Placement],
    update_topic_topicp(Topics, Topic, Placement, TopicsP),
    % Continue down this combination path
    find_combs(Rem, Sol, Topics, TopicsP).
find_combs(CombLsts, _, _, _) :-
    % Nothing left to try
    maplist(=([]), CombLsts).

update_topic_topicp([HT|TT], Topic, Placement, [HTP|TTP]) :-
    (   HT = Topic -> HTP = Placement
    ;   update_topic_topicp(TT, Topic, Placement, TTP)
    ).

when_both(V1, V2, Cond) :-
    when((nonvar(V1), nonvar(V2)), Cond).

Result:

?- time(findall(S, go(S), Ss)).
% 23,998 inferences, 0.011 CPU in 0.011 seconds (101% CPU, 2111377 Lips)
Ss = [[[alex,lang,2],[bob,phys,3],[john,law,4],[deo,it,1],[sam,math,5]]].

Upvotes: 0

TessellatingHeckler
TessellatingHeckler

Reputation: 28963

How do I go about accounting for the two unknowns in the conditions?

I'm not sure which unknowns you are thinking of, but these kind of puzzles usually settle out into a single answer, and the rules that are given leave no choices for the other things. You know that the people need to be in five positions and five subjects; you can do as brebs does, and build a way for Prolog to try all possible answers and rule some out.

Or, this is ideal for the clpfd constraint solver, the people must get positions 1-5, and so must the languages, and they can't be several in the same position, and then it will find possible answers for which those constraints hold.

:- use_module(library(clpfd)).  % Finite domain constraints

constrain(People, Disciplines) :-
    People = [Alex, Bob, John, Deo, Sam],
    People ins 1..5,
    all_different(People),
    
    Disciplines = [Language, Law, IT, Math, Physics],
    Disciplines ins 1..5,
    all_different(Disciplines),
    
    (Bob - Language) #= (Law - Bob),   % Rule 1
    (Bob - Language) #>= 1,            % Rule 1 tiebreaker: difference can't be 0

    IT #= John - 3,     % Rule 2
    0 #= Alex mod 2,    % Rule 3
    1 #= Math mod 2,    % Rule 3
    Sam #= Physics + 2. % Rule 4

e.g.

?- constrain([Alex,Bob,John,Deo,Sam], [Language, Law, IT, Math, Physics]),
label([Alex,Bob,John,Deo,Sam]),
label([Language, Law, IT, Math, Physics]).

Deo = IT, IT = 1,
Alex = Language, Language = 2,
Bob = Physics, Physics = 3,
John = Law, Law = 4,
Math = Sam, Sam = 5

Upvotes: 0

Related Questions