2013-03-21 1 views
1

저는 처음으로 프롤로그를 사용하는 사람입니다. 약 1 주 동안 사용했는데 here의 다양한 기초에 대해 배웠습니다. 어느 정도 도움이되었다. 나는 허구 적 게임 타이틀을위한 데이터베이스 검색을 디자인 해왔다. 사용자는 게임에서 주어진 캐릭터의 통계를 얻기 위해 별미 기사와상의 할 수있다. 당신이 내게 묻는다면 굉장한 프로젝트처럼 들리네.Prolog - SWI : 주어진 값을 계산하기위한 구조체를 만드는 방법

나는 내 노드를 설명하는 "프레임"과 그 사용법을 배우기 위해 노력했다. 그래서 내가 사용하게 될 형식은이 라인을 따라 될 것이다. . 내가 배우는 가장 최근의 항목은 프롤로그에서 "Numbers"이며 어떻게 작동하는지, 좀 더 동적 인 방식으로 사용하기 전까지는 튜토리얼에서 꽤 단순 해 보였습니다.

데이터 노드에 대해 다음과 같은 설정을했습니다. (의사 코드)

프레임 : 이름 (문자), 상위 (없음), base_stat (8.0).

프레임 : 이름 (npc), 상위 (문자).

프레임 : 이름 (적), 부모 (npc).

프레임 : 이름 (red_faction), 부모 (적), atk_bonus (1.5), spd_bonus (1.25), def_bonus (0.25).

프레임 : 이름 (blue_faction), 부모 (적), atk_bonus (1), spd_bonus (1), def_bonus (1).

프레임 : 이름 (fire_warrior), 부모 (red_faction), 레벨 (1.0), 보유 (nothing).

프레임 : 이름 (water_consort), 상위 (blue_faction), 레벨 (1.0), 보유 (nothing).

위와상의 할 때 공격 (?), 속도 (?), 방어 (?)와 같은 통계를 사용자에게 반환하고 싶습니다.

나는 방정식을 사용하여 "?" 다음 방정식을 사용할 내 프로그램 영역 "(base_stat + level) * stat_bonus". 이 같은 뭔가 : -

compute(attribute) :- 
    stat_bonus(stat bonus from parent node for required stat example:atk_bonus) 
    base_stat(value from the character node's base_stat) 
    level(value from the character we are looking up: eg water_consort lvl1) 
    attribute is (level+base_stat) * stat_bonus 

내가 대수에 관한 교사의 간단한 설명 후,이 구조를 내놓았다는 프롤로그의 숫자에 접근한다. 이 예는 같은 것을했다 : -

student(jack, 25). 
student(jill, 21). 

avg_Score(Z) :- 
    student(jack, X), 
    student(jill, Y), 
    Z = (X + Y)/2. 

나는 X와 Y의 값을 추출 할 필요가 있음을 이해하고, 내가 그 값을 reconsult하려면 내가 그들을 사용하는 것을 추출을 반복해야합니다.

이제는 내 작은 프로젝트로 돌아가서, 전체 팀원 수는 3 명입니다 (전체 다이어그램에는 3 개가 있지만, 프로세스가 필요한 것은 N 번 적용 할 수 있다고 가정 할 때 두 가지를 넘는 점은 없습니다), 어떻게 계산에 필요한 정보는 어떻게 얻을 수 있습니까?

소방관의 데이터를 요청한다고 가정 할 때, 시스템은 stat (합시다)를 계산하고 내가 가지고있는 방정식을 참고합니다. 부모 노드 "red_faction"

  • G.G.에 의해 주어진 base_stat에 의해 주어진

    1. 공격 보너스 : 나는 다음과 같은 정보가 필요합니다조부모 노드 "문자"
    2. 인스턴스 노드의 수준

    내 교사 내가 모든 것을 내 요청에 하드 코드이고 매우 제한되어있는 경우 나에만 작동합니다 준 예. "N"파벌과 각 파벌의 "M"캐릭터 인스턴스에 사용할 수있는 방법이 있습니까? 나는 그녀를 다시 괴롭 히 겠지만 부활절 이후까지 그녀는 무료가 아니며 주말 내내 언젠가 끝내기를 기대하고있다. 내가 Prolog가 상속을 잘한다고 말할 수는 있지만 이것을 해결하는 방법을 모른다.

    당신이 줄 수있는 건설적인 입력에 대해 미리 감사드립니다.

  • 답변

    3

    Prolog에 오신 것을 환영합니다! 네가 한 번 해보니 기쁘다. 네가 많이 가진 것처럼 보이기 때문에 그것이 상상력을 잘 발휘할 수 있기를 바란다.

    여기 Prolog에는 많은 이상한 용어가 사용됩니다. "프레임"또는 "노드"또는 "추출"이란 의미가 무엇인지 명확하게 알지 못합니다. 저는 여러분이 "consult"를 사용하고 있다고 확신합니다. 이 튜토리얼이 SICStus 용으로 작성되었거나 보통의 혼동 일 뿐이 기 때문에 이것이 맞는지는 모르겠습니다. 나는 또한 Prolog에서 상속을하는 것을 보통 생각하지 않을 것이지만,이 부분은 내가 실제로 이해한다고 생각한다. 그래서 나는 당신이 따라 놀 것이고 어쨌든 내가 당신의 질문에 대답 할 수 있는지를 알게 될 것입니다.

    첫 번째 사항부터 큰 문제는 아니지만 평균 점수는 다음과 같이 구현해야합니다.

    avg_score(Z) :- 
        student(jack, X), 
        student(jill, Y), 
        Z is (X + Y)/2. % <-- note the use of 'is' instead of '=' 
    

    이것은 일반적인 초보자 실수입니다. Prolog는 기본적으로 대수를 평가하지 않으므로 (X + Y)/2과 같은 것을 말하면 실제로하는 것은 표현식을 작성하는 것입니다 (div(plus(X, Y), 2)과 다를 수 없음). 한 가지 차이점은 실제로 is(X + Y)/2과 같은 대수 식을 계산하는 방법을 알고 있지만 div(plus(X, Y), 2)이 아닌 것을 알고 있다는 것입니다. (난 당신이 처음부터 clpfd을 사용하기 시작하면 프롤로그가 더 많은 의미가 찾아 #= 대신 is를 사용할 것이다 당신을-경고 사전 수 있습니다.)

    아니, avg_score에 대해 도움이되지 않는 것입니다, 물론, jackjill이 포함되어 있습니다. 언젠가는 모든 학생들의 평균 점수를 계산하고 싶을 것입니다.

    average(L, Average) :- 
        sum(L, Sum), 
        length(L, Length), 
        Average is Sum/Length. 
    
    % this is overly complex because I wanted to show you 
    % the tail recursive version 
    sum(L, Sum) :- sum(L, 0, Sum). 
    
    sum([], Sum, Sum). 
    sum([X|Xs], Acc, Sum) :- Acc1 is X + Acc, sum(Xs, Acc1, Sum). 
    

    이제 우리는 다음과 같이 모든 학생들의 평균을 얻을 수 있습니다 :이 무엇을 요구하거나하고 관련 있는지 알고 발생하지 않는

    avg_score(Z) :- 
        findall(X, student(_, X), Scores), 
        average(Scores, Z). 
    

    우선의 평균을 계산하자 아니,하지만 그것이 도움이 될 것 같아 보이네.

    물론 다른 것들은 매개 변수화하는 것입니다. 우리는 원래의 코드를 가지고 학생을 매개 변수화 할 수 있습니다 : 그것은 동물 우화집를 쿼리에 더 적절한 수 있습니다처럼

    avg_score(Student1, Student2, Z) :- 
        student(Student1, X), 
        student(Student2, Y), 
        Z is (X + Y)/2. 
    

    이 보인다. attack(X)을 묻기보다는 attack(fire_warrior, X)을 물어볼 것입니다.

    Prolog를 처음 접했을 때 Logtalk로 연결되는 것을 싫지만 의심되는 답변이있을 수 있습니다. 바닐라 프롤로그가 그렇지 않은 방식으로 상속을 처리하는 것이 특히 좋습니다. 하지만 큰 전환이 될 수 있습니다.예를 들어, 다음과 같이 공격 합계 쿼리에 대한 상속 체인을 처리 할 수있는 :이 동작을 원하는 경우

    ?- calc_attack_bonus(fire_warrior, Bonus). 
    Bonus = 1.5. 
    
    ?- calc_attack_bonus(character, Bonus). 
    Bonus = 0. 
    

    나도 몰라 :

    % this is the inheritance tree 
    parent_class(character, base). 
    parent_class(npc, character). 
    parent_class(enemy, npc). 
    parent_class(red_faction, enemy). 
    parent_class(blue_faction, enemy). 
    parent_class(fire_warrior, red_faction). 
    parent_class(water_consort, blue_faction). 
    
    % these are the attack bonuses 
    attack_bonus(base, 0). 
    attack_bonus(red_faction, 1.5). 
    attack_bonus(blue_faction, 1). 
    
    calc_attack_bonus(X, Bonus) :- 
        attack_bonus(X, Bonus), !. 
    calc_attack_bonus(X, Bonus) :- 
        \+ attack_bonus(X, Bonus), 
        parent_class(X, Parent), 
        calc_attack_bonus(Parent, Bonus). 
    

    이 몇 가지 기본적인 쿼리 작업이 나타납니다 여부 : 그것은 (parent_class이 실패 할 경우, 그렇지 않으면 0 보너스를 통합 재발)하지 않을 경우 해결하기 위해 쉽게

    ?- calc_attack_bonus(tree, Bonus). 
    false. 
    

    .

    그러나 이것은 모두 확장 할 수있는 것은 아닙니다.

    calc_attribute(X, Attribute, Value) :- 
        attribute(X, Attribute, Value), !. 
    calc_attribute(X, Attribute, Value) :- 
        \+ attribute(X, Attribute, Value), 
        parent_class(X, Parent), 
        calc_attribute(Parent, Attribute, Value). 
    

    그리고 지금은 공격이 쉽게된다 :

    % these are the attack bonuses 
    attribute(attack_bonus, base, 0). 
    attribute(attack_bonus, red_faction, 1.5). 
    attribute(attack_bonus, blue_faction, 1). 
    
    % base stats 
    attribute(base_stat, character, 8.0). 
    
    attribute(level, fire_warrior, 1.0). 
    

    이제 우리는 우리가 많은 고통없이 필요한 규칙을 작성할 수 있습니다 더 확장 방법이 될 수

    attack(X, Value) :- 
        calc_attribute(X, attack_bonus, Bonus), 
        calc_attribute(X, base_stat, Base), 
        calc_attribute(X, level, Level), 
        Value is (Level + Base) * Bonus. 
    

    우리 이상적으로는 compute(fire_warrior, attack, Value)과 같은 것을 말하고 싶기 때문에 compute을 쓸 수있는 곳으로 가려면 좀 더 일반화해야합니다. 그런 일이 일어나기 위해서는 attack_bonusattack과 관련이 있다는 것을 알아야합니다.

    % these are the attack bonuses 
    attribute(base,   bonus(attack), 0). 
    attribute(red_faction, bonus(attack), 1.5). 
    attribute(blue_faction, bonus(attack), 1). 
    
    % base stats 
    attribute(character, base_stat, 8.0). 
    
    attribute(fire_warrior, level, 1.0). 
    

    이제 우리는 요리하고 있습니다 :

    compute(X, Attribute, Value) :- 
        calc_attribute(X, bonus(Attribute), Bonus), 
        calc_attribute(X, base_stat, Base), 
        calc_attribute(X, level, Level), 
        Value is (Level + Base) * Bonus. 
    

    을 보라 : 이제 attribute 약간의 구조 조정을 보자

    ?- compute(fire_warrior, attack, Value). 
    Value = 13.5. 
    

    을 나는 그게 당신이 원하는 무엇 바랍니다. :)

    큰 편집 재미를 들어

    은 내가이 Logtalk, 프롤로그를위한 객체 지향 확장 언어 어떨까 볼 수있을 거라고 생각했다. 나는 매우 Logtalk를 처음 사용하기 때문에 이것이 좋은 접근 방법 일 수도 있고 그렇지 않을 수도 있지만 "속임수"를 했으므로 원하는 것을 선택하는 것이 더 많은지 알아 보겠습니다. 첫째, 기본 오브젝트 :

    :- object(base). 
    
        :- public(base_stat/1). 
        :- public(attack/1). 
        :- public(bonus/2). 
        :- public(level/1). 
        :- public(compute/2). 
    
        bonus(attack, 0). 
        base_stat(0). 
        level(0). 
    
        compute(Attribute, Value) :- 
         ::bonus(Attribute, Bonus), 
         ::base_stat(Base), 
         ::level(Level), 
         Value is (Level + Base) * Bonus. 
    
    :- end_object. 
    

    이것은 기본적으로 우리는 각각의 일에 대해 저장하는거야 사실을 정의하는 방법과 관심있는 속성을 계산하는 것이다 다음으로 우리가 객체 계층 구조를 확립 :.

    :- object(character, extends(base)). 
        base_stat(8.0). 
    :- end_object. 
    
    :- object(npc, extends(character)). 
    :- end_object. 
    
    :- object(enemy, extends(npc)). 
    :- end_object. 
    
    :- object(red_faction, extends(enemy)). 
        bonus(attack, 1.5). 
        bonus(speed, 1.25). 
        bonus(defense, 0.25). 
    :- end_object. 
    
    :- object(blue_faction, extends(enemy)). 
        bonus(attack, 1). 
        bonus(speed, 1). 
        bonus(defense, 1). 
    :- end_object. 
    
    :- object(fire_warrior, extends(red_faction)). 
        level(1.0). 
        holding(nothing). 
    :- end_object. 
    
    :- object(water_consort, extends(blue_faction)). 
        level(1.0). 
        holding(nothing). 
    :- end_object. 
    

    이제이 꽤 많이 간단합니다 사용 :

    ?- fire_warrior::compute(attack, X). 
    X = 13.5. 
    
    ?- water_consort::compute(attack, X). 
    X = 9.0. 
    

    내가 희망이 도움이!

    +0

    와우, 처음에는 "predicate (list [], Variables, Variable)"쿼리가보다 세련된 쿼리를 작성하는 방법을 알아보기 위해 추적을 실행하는 흥미로운 읽기가있었습니다. –

    +0

    Logtalk의 권장 사항을 살펴보면 오늘 밤 읽어 볼 수 있습니다.당신의 예제를 보았을 때, 그것은 내가 필요한 애드온과 프로그래밍 스타일임을 알 수 있습니다. 당신은 관계를 명확하게 볼 수 있습니다. 그리고 의미 론적 다이어그램을 보면, 어떻게 보일지 이미 이해할 수 있습니다. 프레임이 무엇인지 이해하지 못할 수도 있지만 Logtalk은 시각적 인면을 코드로 변환하는 데 적합합니다. 나는 오늘 밤 이것을 보게되어 정말 기쁩니다. –

    +0

    이 설명이 없으면 관련성을 보지 못했기 때문에 당신은 잘 마시는 음료를 마셔야합니다. –