Einsteins Riddle Prolog

前端 未结 3 2117
情歌与酒
情歌与酒 2020-11-27 08:45

I need some help with a prolog homework for my AI class. The question is to write prolog code for einstein\'s puzzle. I know how to write it down in my own but there are som

3条回答
  •  广开言路
    2020-11-27 08:58

    A Prolog translation can be straightforward, rule by rule, still following the paradigm of instantiating the domain by selecting from it. Here it's the domain of house attributes; in the linked answer house attributes are fixed by a human programmer and the domain is the actual inhabited houses, which allows for a very succinct encoding.

    In other words the difference is in the notation: a sophisticated notation takes us half way there already, but it was a human who invented it and followed it (like the programmer having to write down norwegian in the first house's specification directly, at the appropriate argument position) -- not a computer.

    Here we try to inject as little human knowledge into the code as possible, following the homework's constraints. (though anything is debatable of course, and the ultimate in eschewing human interference would be a computer program that takes English text as its input ... which would again be open to criticism as to how specifically tailored that program is for finding solutions to this specific puzzle, or type of puzzles, etc., etc.)

    We code it in the top-down style. Apparently, the question is missing. It should be "who drinks water? who owns the zebra?":

    zebra( Z, W ,HS) :-         
        length(        HS, 5),      % nation? color? what's that? define it later...
        member(  H1,   HS),    nation( H1, eng    ),    color( H1, red    ),
        member(  H2,   HS),    nation( H2, spa    ),    owns(  H2, dog    ),            
        member(  H3,   HS),    drink(  H3, coffee ),    color( H3, green  ),         
        member(  H4,   HS),    nation( H4, ukr    ),    drink( H4, tea    ),
        right_of(B, A, HS),    color(  A , ivory  ),    color( B , green  ),
        member(  H5,   HS),    smoke(  H5, oldgold),    owns(  H5, snails ),   
        member(  H6,   HS),    smoke(  H6, kools  ),    color( H6, yellow ), 
        middle(  C,    HS),    drink(  C , milk   ),  
        first(   D,    HS),    nation( D , nor    ),
        next_to( E, F, HS),    smoke(  E , chester),    owns(  F , fox    ),
        next_to( G, H, HS),    smoke(  G , kools  ),    owns(  H , horse  ),
        member(  H7,   HS),    smoke(  H7, lucky  ),    drink( H7, orange ),
        member(  H8,   HS),    nation( H8, jpn    ),    smoke( H8, parlamt),
        next_to( I, J, HS),    nation( I , nor    ),    color( J , blue   ),
        member(  W,    HS),    drink(  W , water  ),
        member(  Z,    HS),    owns(   Z , zebra  ).
    
    right_of( B, A, HS) :- append( _, [A, B | _], HS).
    next_to( A, B, HS) :- right_of( B, A, HS) ; right_of( A, B, HS).
    middle( A, [_,_,A,_,_]).
    first( A, [A | _]).
    
    nation(H, V) :-  attr( H, nation-V).
    owns(  H, V) :-  attr( H, owns-V).        % select an attribute
    smoke( H, V) :-  attr( H, smoke-V).       %   from an extensible record H
    color( H, V) :-  attr( H, color-V).       %   of house attributes
    drink( H, V) :-  attr( H, drink-V).       %   which *is* a house
    
    attr(House, Attr-Value) :- 
        memberchk( Attr-X, House),            % unique attribute names
        X = Value.
    

    Testing, performing exhaustive search with a failure-driven loop,

    3 ?- time((zebra(Z,W,_), maplist(nation,[Z,W],R), writeln(R), false ; true)).
    [jpn,nor]
    % 180,974 inferences, 0.016 CPU in 0.020 seconds (78% CPU, 11600823 Lips)
    true.
    

    Here's how the houses end up being defined:

    5 ?- zebra(_, _, HS), maplist( writeln, HS),
         false.
    [smoke-kools,  color-yellow, nation-nor,    owns-fox,      drink-water |_G859]
    [nation-ukr,   drink-tea,    smoke-chester, owns-horse,    color-blue  |_G853]
    [nation-eng,   color-red,    smoke-oldgold, owns-snails,   drink-milk  |_G775]
    [nation-spa,   owns-dog,     color-ivory,   smoke-lucky,   drink-orange|_G826]
    [drink-coffee, color-green,  nation-jpn,    smoke-parlamt, owns-zebra  |_G865]
    false.
    

    or, with attributes lists "frozen" by fixing their length, and then sorted,

    7 ?- zebra( _, _, HS), maplist( length, HS, _), !, maplist( sort, HS, S),
         maplist( writeln, S), false.
    [color-yellow, drink-water,  nation-nor,  owns-fox,    smoke-kools  ]
    [color-blue,   drink-tea,    nation-ukr,  owns-horse,  smoke-chester]
    [color-red,    drink-milk,   nation-eng,  owns-snails, smoke-oldgold]
    [color-ivory,  drink-orange, nation-spa,  owns-dog,    smoke-lucky  ]
    [color-green,  drink-coffee, nation-jpn,  owns-zebra,  smoke-parlamt]
    false.
    

    It is also easy to make the attr/2 predicate accept lists of Name-Value pairs, allowing for more naturally flowing, higher-level looking coding style with kind of "extensible records" -- one might even say "objects" -- specifications, like

    zebra( Z, W ,HS):-         
        length(       HS, 5), 
        member(  H1,  HS),    attr( H1,  [nation-eng,   color-red  ] ),
        member(  H2,  HS),    attr( H2,  [nation-spa,   owns-dog   ] ),
        member(  H3,  HS),    attr( H3,  [drink-coffee, color-green] ),
        ......
    

    etc..

提交回复
热议问题