-1

プロローグでこのなぞなぞを解決したい:

生徒のリリー、ジャック、デイジーは同じ大学に通っています。みんな違う国から来て、違う趣味を持っています。彼らは全員、アメリカの大学に通っており、そのうちの 1 人はそこに住んでいます。リリーはイタリア出身のリリーよりも成績がいい。ジャックは本を読むのが好きな人より成績がいい。最高の成績にはサッカーが好きな人がいます。ジャックはドイツ出身で、デイジーは料理が好きです。

誰(名前、国、趣味、成績)は誰?

正しい解決策は次のとおりです。

  • リリー、アメリカ、本を読む、2 年生
  • ジャック, ドイツ, フットボール, 1 年生
  • デイジー、イタリア、料理、3 年生

私が今抱えている問題は、このなぞなぞをどのように解決できるかわからないことです。事実をどのように定義すればよいですか?また、なぞなぞを解決する最善の方法は何ですか?

4

3 に答える 3

2

Prolog でこれらのパズルの質問に答える秘訣は、可能な回答を生成 (取得) し、論理的な制約に対してテストすることです。したがって、Lily が人物 P1 の場合、人物 P2 を取得して、その人物がイタリア出身かどうかをテストします。他のルールについても同様です。

つまり、最初に、可能性のある国、可能性のある趣味、可能性のある成績を含むいくつかの句が必要です。いくつかの可能性は質問によってすでに除外されているため、すべての可能性が必要なわけではありません。

以下の解決策は、Lily の人物 1、Jack の人物 2、Daisy の人物 3 を任意に作成することに基づいています。

Prolog にロードして、who(P1,C1,H1,G1, P2,C2,H2,G2, P3,C3,H3,G3) をクエリします。

country(italy).
country(usa).
hobby(football).
hobby(reading).
grade(c:1).
grade(b:2).
grade(a:3).



who(lily,C1,H1,Grade1, jack,germany,H2,Grade2, daisy,C3,cooking,Grade3):-
    country(C1), country(C3), C1 \= C3,
    hobby(H1), hobby(H2), H1 \= H2,
    grade(G1:Grade1), grade(G2:Grade2), grade(G3:Grade3),
    G1 \= G2, G2 \= G3, G1 \= G3,
    (C3=italy, G1@>G3),
    (H1=reading, G2@>G1),
    ((H1=football, G1@>G2, G1@>G3); (H2=football, G2@>G1, G2@>G3)).
于 2016-12-04T02:10:00.800 に答える
0

まず、最初のステートメントから取得した内容を埋めると、次のようになります。

(Lily, _, _, _)
(Jack,Germany, _, _)
(Daisy, _, Cooking, _)

_たちが何かを知らない状態。また、これは必ずしもプロローグではなく、何よりも常識です。

「リリーはイタリア出身者よりも成績が良い」というフレーズが出てきますが、これはデイジーがドイツ出身でリリーがアメリカ出身であることを意味します。ジャックがドイツ出身であるためです。

(Lily, USA, _, Grade>Daisy)
(Jack,Germany, _, _)
(Daisy, Italy, Cooking, Grade<Lily)

次に、「ジャックは本を読むのが好きな人よりも成績が良い」とあり、これは彼がサッカー選手であるという事実を示しており、次の行は彼が最高の成績を持っていることを示しています。その後、残りをすぐに埋めることができ、次のようになります。

(Lily, USA, Reading, Grade2)
(Jack,Germany, Football, Grade1)
(Daisy, Italy, Cooking, Grade3)

このパズルを非常に回りくどい方法で解決できるプロローグで書かれたプログラムが存在する可能性がありますが、このパズルは一般的なケースよりも具体的です。

于 2016-12-03T22:03:03.940 に答える
0

これが私の見解です。それは本質的に@RdRが持っているものであり、ロジックをより多くの述語に分割し、who()主な述語のオーバーロードを少なくしました。

name(lily).  % (1)
name(jack).
name(daisy).
country(italy).
country(usa).
country(germany).
hobby(football).
hobby(cooking).
hobby(reading).
grade(1).
grade(2).
grade(3).

student(N,C,H,G):-  % (2)
    name(N), country(C), hobby(H), grade(G).

permute(P,X,Y,Z):- (4)
    call(P,X), call(P,Y), call(P,Z)  % (6)
    , X\=Y, Y\=Z, X\=Z.

students(A,B,C):- (3)
    permute(name,N1,N2,N3)   % (5)
    , permute(country,C1,C2,C3)
    , permute(hobby,H1,H2,H3)
    , permute(grade,G1,G2,G3)
    , A = student(N1,C1,H1,G1)  % (7)
    , B = student(N2,C2,H2,G2)
    , C = student(N3,C3,H3,G3)
    .

who(A,B,C):-  % (8)
    students(A,B,C)
    , A = student(lily,C1,H1,G1)  % (9)
    , B = student(jack,C2,H2,G2)
    , C = student(daisy,C3,H3,G3)
    , C2 = germany                % (10)
    , H3 = cooking
    , (( C2=italy -> G1 < G2)     % (11)
      ;( C3=italy -> G1 < G3))
    , (( H1=reading -> G2 < G1)
      ;( H3=reading -> G2 < G3))
    , (( H1=football -> G1 < G2, G1 < G3)
      ;( H2=football -> G2 < G1, G2 < G3)
      ;( H3=football -> G3 < G1, G3 < G2))
    .

% Running it:
% ?- who(A,B,C).
% A = student(lily, usa, reading, 2),
% B = student(jack, germany, football, 1),
% C = student(daisy, italy, cooking, 3) ;
% false.

討論

したがって、ここではかなりのことが行われており (これに興味をそそられました)、別の方法で行うことができるいくつかの選択があります (したがって、おそらく @RdR のソリューションとは対照的です)。

  • 他の人が指摘したように、1 つの側面は、問題の説明で与えられた情報をエンコードする方法です。非常に具体的に表現することも (このケースだけを解決する)、より一般的に表現することもできます (たとえば、問題を 3 人以上の生徒に拡張できるようにするため)。
  • この問題が同様の他の問題と異なるのは、1 人の学生に影響する制約 (「ジャックはドイツから来ました」)、2 人の学生に影響する制約 (「リリーの成績はイタリアの成績よりも良い」)、または次のような制約が混在していることです。それらすべて(「サッカーが好きな人が最高の成績を持っています」)。
  • さらに、選言制約があります(「彼らはすべて異なる国から来ており、趣味も異なります」)。Prolog は、ファクトのすべての可能なインスタンスを調べるのに非常に優れていますが、1 つのインスタンスを選択して、述語の次の呼び出しのためにこれを除外するのはより複雑です。これにより、ペアごとに異なるファクトから一連の値を取得する方法を見つける必要があります。(例えば、Prolog が Lily の趣味が読書であると決めた場合、Jack の趣味として読書を割り当ててはなりません)。
  • したがって、すべての既知の事実とそれらの可能な値 (1) をリストした後、最初に述語student/4(2) を定義して、生徒がこれら 4 つのプロパティを持っていることを単純に述べました。これにより、学生とその属性のすべての可能な組み合わせが生成され、学生全員が同じ名前を持ち、同じ国 (asf) から来ることも可能になります。
  • これは、Prolog で大きすぎる結果セットを作成し、それをさらに絞り込む方法の良い例です (他の誰かが書いたように)。さらなる述語は、この「ジェネレーター」を利用して、その結果セットからさらに多くのソリューションをフィルタリングできます。これはテストも簡単で、各ステージで中間出力が意味をなすかどうかを確認できます。
  • 次の述語students/3(3) では、前に述べたことを正確に試して、少なくとも同じ属性を 2 回使用しない (同じ趣味を持つ 2 人の学生など) 学生インスタンスを作成します。これを実現するには、すべての属性ファクト (name/1、country/1、...) を実行し、それぞれに対して 3 つの値を取得して、ペアごとに異なることを確認する必要があります。
  • 属性の名前を除いて実装が常に同じである各属性に対してこれを明示的に行う必要がないようにpermute/4、属性名を渡すことができ、属性を検索するヘルパー述語 (4) を作成しました。事実として 3 回、バインドされた値がすべて同じではないことを確認します。
  • したがってpermute(name,N1,N2,N3)students/3(5) を呼び出すと、ルックアップcall(P,X), call(P,Y), call(P,Z)(6) が実行され、 を呼び出すのと同じ結果になりname(X), name(Y), name(Z)ます。(同じ属性の常に 3 つのファクトから 3 つの異なる値を収集しているため、これは実質的に 3 つの値セットの 3 つの順列を実行することと同じであるため、ヘルパー述語の名前が付けられています。)
  • (7) に到達すると、生徒の属性ごとに個別の値があることがわかり、それらを 3 つの生徒インスタンスに分散するだけです。(これは実際にはstudent/4述語なしで同じように機能するはずです。これは、Prolog でこのような構造化された用語をいつでもオンザフライで作成できるためです。student 述語を使用すると、"student(lily, 23 、asdf、-7.4)".)
  • したがって:- students(A,B,C).、関連する属性を 2 回使用せずに、3 人の学生とその属性の可能な組み合わせをすべて生成します。良い。また、(より難しい)student()構造を便利な 1 文字の変数でラップすることで、インターフェイスをよりクリーンにします。
  • しかし、これらの素性制約を除けば、他の制約は実装していません。who/3 これらは、(あまり洗練されていない)述語 (8)の後に続くようになりました。これは基本的students/3にジェネレーターとして使用し、さらに制約を追加することで不要なソリューションをすべて除外しようとします (したがって、基本的には と同じシグネチャーを持ちstudents/3ます)。
  • student個々のインスタンスをフィルタリングするだけでなく、それらを個別に ("デイジー"、"ジャック" など) およびそれぞれの属性 ("デイジーの趣味" など) を参照できるようにする必要があるため、ここで別の興味深い部分が始まります。 )。したがって、結果変数 A、B、および C をバインドする際に、特定の名前でパターン マッチを行います。したがって、(9) のリテラル名lilyasfjackです。これにより、Lily が 1 番目、2 番目、または 3 番目 (students/3このような順列を生成するため) になるケースを考慮する必要がなくなります。そのため、その順序にない 3 セットの生徒はすべて破棄されます。
  • N1 = lily後でasfのような明示的な制約でこれを行うこともできました。ジャックはドイツ出身で、デイジーは料理が好きだという単純な事実を強調するために、私はそうします (10)。それらが失敗すると、Prolog は への最初の呼び出しに戻り、students/3別の生徒のセットを取得するために試行できます。
  • ここで、リリーの成績、ジャックの成績、およびサッカー愛好家の成績に関する追加の既知の事実に従ってください (11)。これは特に醜いコードです。
  • 1 つには、「属性 X を持つ学生」というクエリに対する回答を返すことができるヘルパー述語があればいいでしょう。現在選択されている生徒 A、B、C、属性名 (「country」)、および値 (「italy」) を取得し、適切な生徒を返します。そのため、2 番目または 3 番目の学生である必要があると仮定するのではなく、イタリアからの学生をクエリすることができます (問題の説明では、Lily 自身はイタリア出身ではないことが示唆されています)。
  • したがって、この架空のヘルパー述語を呼び出すとstudent_from_attribute 、名前で学生構造の値を見つけて対応する値を返す別のヘルパーが必要になります。名前でその中のフィールドにアクセスできる、ある種のオブジェクト/名前付きタプル/レコードをサポートするすべての言語で簡単です。しかし、バニラのプロローグはそうではありません。そのため、頭のてっぺんから引き離すことができない何かを持ち上げる必要があります。
  • また、 「成績」など、who/3から返された学生とは異なる属性が必要になるため、述語はこの他のヘルパーを利用して、 student_from_attributeそれを Lily の成績と比較することもできます。のように、これらすべての制約がより適切になり student_from_attribute([A,B,C], country, italy, S), attrib_by_name(S, grade, G), G1 < Gます。これは、読書とサッカーの制約にも同じように適用できます。それは短くはありませんが、よりクリーンで一般的です。

誰もこれをすべて読むかどうかはわかりません:-)。とにかく、これらの考慮事項により、パズルは私にとって興味深いものになりました。

于 2016-12-05T21:53:40.423 に答える