我正在为一个用c ++编写的游戏编写AI。 AI在概念上相当简单,它只是通过决策树运行并选择适当的操作。我以前使用prolog作为决策引擎,但由于其他开发人员使用c ++以及集成prolog代码的一些问题,我现在正尝试将其移植到c ++。
目前我在prolog(100+)中有一堆事实和规则。许多表达形式的东西,如果game_state然后做动作xyz。大多数规则都相当简单,有些规则相当复杂。我看了一个有限的状态机方法,但这似乎并没有如此好地扩展到更大的情况。 我在c ++中编写这个代码的第一次尝试是一个巨大的噩梦,如果是其他案例陈述。我把这种代码随处可见:
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 ++规则引擎?
答案 0 :(得分: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环境的方式做事。
答案 1 :(得分: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类中,无论如何),选择逻辑由编译器完成。
答案 2 :(得分:3)
如果要将prolog代码转换为c ++代码, 看一下使用C ++编写逻辑编程的Castor库(C ++): http://www.mpprogramming.com/Cpp/Default.aspx
我自己没有尝试过,所以我对它的表现一无所知。
如果您想使用状态机,请查看Boost.Meta状态机
答案 3 :(得分:2)
我真的不明白为什么有限状态机不适合你的游戏。这是做你想做的事的常用方法。您可以使其数据驱动,以使代码从具体操作中保持清洁。有限状态m。在“AI for Game Dev”中也有描述O'Reilly(David M. Bourg&amp; Glenn Seemann) 您可能希望将规则拆分为几个较小的规则集,以保持机器小巧且易于理解。
答案 4 :(得分:1)
如何使用汞?它基本上是为了与C代码接口而构建的。
答案 5 :(得分:0)
试图将Prolog的表现力与国家机器相匹配就像试图用自行车超越汽车一样。
蓖麻可能是要走的路。它非常轻量级,允许逻辑编程和C ++其余部分之间的平滑互操作。看看http://www.mpprogramming.com/cpp
上的教程视频