0

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?

false
  • 10,264
  • 13
  • 101
  • 209
  • 2
    Can you share your current attempt as a [mre]? Where specifically in that attempt are you getting stuck? See [ask] – esqew Jun 02 '22 at 18:44

2 Answers2

0

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]]].

brebs
  • 3,462
  • 2
  • 3
  • 12
0

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
TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
  • Should be "clpfd" on first line. Differs from my revised answer - probably made the same mistake as me in rule 1, where a higher placement (better named as "rank" I suppose) is a *lower* number. – brebs Jun 04 '22 at 14:49
  • @brebs oops, posted in a rush and copied the wrong module line, thanks. I'm not sure about the rule 1; it feels like either way should work - the difference will be the same magnitude but different sign, so should work either way around? "*The language student placed higher than Bob as much as Bob placed higher than the law student*" - so language student gets 1st and Bob gets 3rd, I did (Bob - Language) to get positive 2 on the left And Bob gets 3rd, Law gets 5th, I did (Law - Bob) to get positive 2 on that side. – TessellatingHeckler Jun 04 '22 at 16:26
  • 1
    Apologies, yours is correct, I've fixed my TopicsP order, now I get the same answer as you :-) – brebs Jun 04 '22 at 21:33