2013-03-21 15 views
1

我是prolog的第一次使用者,我已经使用它约一周,现在了解here的各种基本知识,对学位有帮助。我一直在为一个虚构的游戏标题设计一个数据库查询,用户可以通过这个查询来获得游戏中给定角色的统计数据。听起来像一个很棒的项目,如果你问我:)Prolog - SWI:如何创建计算给定值的结构

我一直在努力学习有关“帧”来描述我的节点和如何使用它们,所以我将使用的格式将沿着这些线。我一直在学习的最新内容是序言中的“数字”以及它们是如何工作的,在教程中它似乎非常简单,直到我想以更动态的方式使用它。

我有以下设置为我的数据节点。 (伪代码)

框架:名称(字符),父(无),base_stat(8.0)。

框架:名称(npc),父级(字符)。

框架:名称(敌人),父母(npc)。

Frame:name(red_faction),parent(敌人),atk_bonus(1.5),spd_bonus(1.25),def_bonus(0.25)。 (name)(blue_faction),parent(敌人),atk_bonus(1),spd_bonus(1),def_bonus(1)。

Frame:name(fire_warrior),parent(red_faction),level(1.0),hold(nothing)。

框架:name(water_consort),parent(blue_faction),level(1.0),hold(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个,但没有意义超出两个,因为我假设需要的过程可以应用N次),如何应用我是否可以获取我的计算信息?

假设我要为消防战士提供数据,我的系统想要计算一个统计数据(比如说攻击数据)并查阅我的等式。我需要以下信息:

  1. 由父节点“red_faction”
  2. 由G.G.给出的base_stat给出的攻击加成祖父母节点“人物”
  3. 实例节点的水平

我的导师给了,如果我硬编码在我的要求的一切,是非常有限的我只会工作的例子。有没有一种方法可以用于每个阵营的“N”派系和“M”个角色实例?我会再次打扰她,但直到复活节之后她才会自由,而且我希望在周末的某个时候完成这个任务。从我可以告诉Prolog继承得很好,但我不知道如何解决这个问题。

非常感谢您提供任何建设性意见。

回答

3

欢迎来到序言!我很高兴你给它一个镜头,我希望你发现它能够很好地发挥你的想象力,因为你似乎有很多!

您在这里为Prolog使用了很多奇怪的术语。我不清楚你的意思是“帧”或“节点”或“提取”,我敢肯定你正在使用“咨询”的方式。我不知道这是因为该教程是为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,但我怀疑它可能会有你想要的一些答案。它在处理继承方面非常出色,而且Prolog可能不是。但它可能是一个很大的转移。举例来说,你可以处理继承链查询攻击统计是这样的:

% 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). 

这似乎是一些基本的查询工作:

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

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

我不知道,如果你想这种行为或不:

?- calc_attack_bonus(tree, Bonus). 
false. 

很容易解决,如果没有(如果parent_class失败,统一用0奖金,否则易复发)。

然而,这不是所有可扩展的。更可扩展的方法可能是这样的:

% 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). 

现在我们可以写我们需要没有很多痛苦的规则:

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

而且现在的攻击变得容易:

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的地方,因为理想情况下,我们想要说些类似compute(fire_warrior, attack, Value)的东西。为了实现这一点,我们需要知道attack_bonusattack有关,我们不知道。让我们重组attribute一点:

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

看哪:

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

我希望这是你想要的。 :)

大编辑

为了好玩,我想我会看到这会变成什么样子Logtalk,用于Prolog的面向对象的扩展语言。我是非常新 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

哇,开始是一个有趣的阅读本身,运行轨迹以查看“谓词(list [],变量,变量)”查询是如何一直工作到做出更精炼的查询。 – 2013-03-23 16:58:12

+0

我正在研究Logtalk的建议,它看起来像今晚读的地狱。看到你的例子,我可以看到它只是我需要的插件和编程风格。你可以清楚地看到这些关系,并且当我查看我的语义图时,我已经可以了解它的全貌。您可能无法理解Frame是什么,但Logtalk也可以很好地将视觉方面转换为代码。我很高兴今晚进一步了解这一点。 – 2013-03-23 17:05:42

+0

对于这种解释,你应该得到一杯好喝的饮料,因为如果没有这些例子,我就不会看到相关性。 – 2013-03-23 17:06:05