6

我不确定我到底想问什么。我希望能够制作一些可以轻松获取初始和最终状态以及一些规则的代码,并确定到达那里的路径/选择。

所以想想,例如,在星际争霸这样的游戏中。要建造工厂,我需要已经建造了一个兵营和一个指挥中心。所以如果我什么都没有,我想要一个工厂,我可能会说->指挥中心->兵营->工厂。每件事都需要时间和资源,这应该在路径中加以注意和考虑。如果我希望我的工厂在 5 分钟内完成,那么如果我希望在 10 分钟内完成,那么选择会更少。

此外,引擎应该能够计算可用资源并有效利用它们。这三座建筑总共可能花费 600 矿物,但引擎应该计划指挥中心,当它有 200 时(或 w/e 它成本)。

这最终将具有类似于 10 名海军陆战队 @ 5 分钟、步兵武器升级在 6:30、30 名海军陆战队员在 10 分钟、Factory @ 11 等的要求......

那么,我该如何去做这样的事情呢?我的第一个想法是使用一些程序语言并从头开始做出所有决定。我可以模拟系统和分支并做出不同的选择。最终,一些选择很快就会使以后无法实现目标(如果我建造 20 个补给站,我很可能无法按时建造那个工厂。)

那么我认为功能语言不是为此而设计的吗?我试图写一些序言,但我在时间和距离计算等问题上遇到了麻烦。而且我不确定返回“计划”的最佳方式。

我在想我可以写:

depends_on(factory, barracks)
depends_on(barracks, command_center)
builds_from(marine, barracks)
build_time(command_center, 60)
build_time(barracks, 45)
build_time(factory, 30)
minerals(command_center, 400)
...
build(X) :- 
  depends_on(X, Y),
  build_time(X, T),
  minerals(X, M),
...

这就是我感到困惑的地方。我不知道如何构造这个函数和一个查询来得到任何接近我想要的东西。我将不得不以某种方式考虑在建造过程中收集矿物的速度以及其他可能的额外黄金路径。如果我在 10 分钟内只想要 1 名海军陆战队员,我希望引擎生成很多计划,因为有很多方法可以在 10 分钟内以 1 名海军陆战队员结束(也许在这么多之后将其切断,不知道你是如何在序言中做到这一点的) )。

我正在寻找有关如何继续这条道路的建议或有关其他选择的建议。我找不到比河内塔和 AI 祖先例子更有用的东西,所以即使是一些解释如何使用 prolog 做真实事情的好文章也会令人惊叹。如果我能以某种有用的方式设置这些规则,除了像所有河内塔示例那样写入标准输出之外,我如何获得“计划”序言(解决查询的方法)?还是这是首选方式?

我的另一个问题是,我的主要代码是 ruby​​(可能还有其他语言),与 prolog 通信的选项是从 ruby​​ 中调用我的 prolog 程序,从 prolog 中访问虚拟文件系统,或者某种数据库结构(不太可能)。我正在使用 SWI-Prolog atm,在 Ruby 中以程序方式执行此操作会更好,还是以 prolog 或 haskall 之类的功能语言构建它是否值得额外努力集成?

如果不清楚,我很抱歉,我很感激任何帮助的尝试,我会重新措辞不清楚的事情。

4

2 回答 2

7

对于第一次尝试 Prolog 的过程语言用户来说,您的问题是典型且非常常见的。这很容易解决:你需要考虑你世界的连续状态之间的关系。您的世界的状态包括例如经过的时间、可用的矿物、您已经建造的东西等。这种状态可以很容易地用 Prolog 术语表示,例如看起来像time_minerals_buildings(10, 10000, [barracks,factory]))。给定这样一个状态,您需要描述该状态可能的后继状态是什么样的。例如:

state_successor(State0, State) :-
     State0 = time_minerals_buildings(Time0, Minerals0, Buildings0),
     Time is Time0 + 1,
     can_build_new_building(Buildings0, Building),
     building_minerals(Building, MB),
     Minerals is Minerals0 - MB,
     Minerals >= 0,
     State = time_minerals_buildings(Time, Minerals, Building).

我使用显式命名约定 ( State0-> State) 来明确我们正在讨论连续状态。当然,您也可以将统一拉到子句头中。示例代码纯粹是假设性的,在您的最终应用程序中可能看起来完全不同。在这种情况下,我描述的是新状态的经过时间是旧状态的时间 + 1,新的矿物数量减少了建造所需的数量Building,并且我有一个谓词can_build_new_building(Bs, B),当新建筑B可以假设建筑物在Bs已经建成。我假设它通常是一个非确定性谓词,并且会在回溯时产生所有可能的答案(= 可以建造的新建筑物),我把它留给你定义这样一个谓词的练习。

给定这样一个谓词state_successor/2,它将世界状态与其直接可能的后继者联系起来,您可以轻松定义导致所需最终状态的状态路径。在其最简单的形式中,它看起来类似于以下描述连续状态列表的 DCG:

states(State0) -->
     (   { final_state(State0) } -> []
     ;   [State0],
         { state_successor(State0, State1) },
         states(State1)
     ).

然后,您可以使用例如迭代深化来搜索解决方案:

?- initial_state(S0), length(Path, _), phrase(states(S0), Path).

此外,您可以跟踪您已经考虑过的状态并避免重新探索它们等。

您对发布的示例代码感到困惑的原因本质上build/1是没有足够的参数来描述您想要的内容。你至少需要两个参数:一个是世界的当前状态,另一个是这个给定状态的可能继承者。有了这样的关系,你需要的一切都可以很容易地描述出来。我希望这回答了你的问题。

于 2013-09-03T21:40:32.980 回答
2

警告:我的 Prolog 生锈而且很浅,所以这可能是错误的

也许“差异引擎”方法是合适的:

  • 给定一个像“建造工厂”这样的目标,
  • 反向链接关系将检查 has-barracks 并告诉您首先建立-barracks,
  • 它将检查 has-command-center 并告诉您构建命令中心,
  • 等等,
  • 在此过程中积累计划(和成本)

如果这是可行的,它可能比基于状态的方法更灵活......或者它可能是同一件事情穿不同的 T 恤!

于 2013-09-05T15:05:25.390 回答