12

我目前正在为用 C++ 编写的游戏编写 AI。AI 在概念上相当简单,它只是遍历决策树并选择适当的动作。我以前使用 prolog 作为决策引擎,但由于其他开发人员使用 c++ 以及集成 prolog 代码的一些问题,我现在正尝试将其移植到 c++。

目前我在序言(100+)中有一堆事实和规则。许多表达形式的东西,如果game_state然后做动作xyz。大多数规则都相当简单,有些则相当复杂。我研究了一种有限状态机方法,但这似乎并不能很好地适应更大的情况。我第一次尝试用 c++ 编写代码是一个巨大的噩梦,即 if then else case 语句。我到处都弹出这样的代码:

    if( this->current_game_state->some_condition == true ){
        if( this->current_game_state->some_other_condition == false ){      
                //some code
        }else{
            return do_default_action();
        }
    }else if( this->current_game->another_condition ){
        //more code
    }

复杂性很快变得难以控制。

如果有一种在 C++ 中编写此类问题的好方法?有没有好的设计模式来处理这种情况?不需要逻辑必须包含在源代码中,它只需要可以从 c++ 访问。唯一真正的要求是它相当快。

我还查看了规则引擎,如果速度足够快,它们可能是合适的。您知道是否有合适的开源 C++ 规则引擎?

4

6 回答 6

10

代码就是数据,数据就是代码。你已经有了工作代码——你只需要以它可以编译的方式将它暴露给 C++,然后你可以实现一个最小的解释器来评估它。

一种可能性是采用您的 Prolog 规则并以最直接的方式将它们转换为数据结构。也许您可以设计一个简单的表格,例如:

struct {
    State coming_from;
    Event event;
    void (*func)(some, args);
    State going_to;
} rules[] = {
    { WANDERING_AROUND, HEAR_SOUND, look_around, ENEMY_SEEN },
    { ENEMY_SEEN,       GUN_LOADED, fire_gun,    SNEEK_AWAY },
    { next, rule, goes, here },
    etc... 
}

同样,函数调用可以填充数据结构,使其看起来类似于原始 Prolog:

void init_rules () {
    rule("Parent", "Bill", "John");
    rule("Parent", "Paul", "Bill");
    // 99 more rules go here...
}

然后您实现一个简单的解释器来遍历该数据结构并找到您需要的答案。使用少于 1000 条规则,蛮力搜索的方法可能足够快,但你总是可以在以后变得聪明,并在时机成熟时尝试像真正的 Prolog 环境那样做事。

于 2010-09-14T08:09:42.733 回答
5

您可以使用多态性。调用虚函数实际上是编译器为您完成和优化的一个大开关/案例。

class GameState {
    virtual void do_something() { std::cout << "GameState!"; }
    // some functions
    virtual ~GameState() {}
};
class SomeOtherState : public GameState {
    // some other functions
    virtual void do_something() { std::cout << "SomeOtherState!"; }
};
class MyFinalState : public GameState {
    virtual void do_something() { std::cout << "MyOtherState!"; }
};
class StateMachine {
    std::auto_ptr<GameState> curr_state;
public:
    StateMachine()
        : curr_state(NULL) {}
    void DoSomething() { curr_state->DoSomething(); }
    void SetState(GameState* ptr) { curr_state = ptr; }
    template<typename T> void SetState() { curr_state = new T; }
};
int main() {
    StateMachine sm;
    sm.SetState(new SomeOtherState());
    sm.SetState<SomeOtherState>();
    sm.DoSomething(); // prints "SomeOtherState!"
    sm.SetState<MyFinalState>();
    sm.DoSomething(); // prints "MyFinalState!"
}

在上面的例子中,我不需要切换任何状态,甚至不需要知道不同的状态存在或它们做了什么(在 StateMachine 类中,无论如何),选择逻辑是由编译器完成的。

于 2010-09-15T14:53:38.210 回答
3

如果您想将 prolog 代码转换为 c++ 代码,请查看启用 C++ 逻辑编程的 Castor 库 (C++): http ://www.mpprogramming.com/Cpp/Default.aspx

我自己没有尝试过,所以我对它的性能一无所知。

如果您想使用状态机,请查看 Boost.Meta State Machine

于 2010-09-15T11:38:25.367 回答
2

我真的不明白为什么有限状态机不足以满足您的游戏。这是做你想做的事的常用方法。您可以使其数据驱动,以使您的代码从具体操作中保持干净。有限状态 m。在“AI for Game Dev”O'Reilly(David M. Bourg 和 Glenn Seemann)中也有描述。您可能希望将您的规则拆分为几个较小的规则集,以保持机器小巧且易于理解。

于 2010-09-11T15:36:49.767 回答
1

使用水银怎么样?它基本上是为与 C 代码交互而构建的。

于 2010-09-15T14:41:50.387 回答
0

试图将 Prolog 的表达能力与状态机相匹配,就像试图用自行车超越汽车一样。

蓖麻可能是要走的路。它非常轻量级,允许逻辑编程和其他 C++ 之间的平滑互操作。看看http://www.mpprogramming.com/cpp上的教程视频

于 2010-09-24T07:37:58.867 回答