gpt4 book ai didi

c++ - 状态机回放的流数据

转载 作者:行者123 更新时间:2023-11-28 08:27:07 33 4
gpt4 key购买 nike

我有一个需要支持播放的状态机设计。我们有执行 Action 的状态,有时需要生成随机数。如果程序在 FSM 执行过程中关闭,程序需要使用与之前相同的随机数来播放整个 FSM。

举一个基本示例,假设我有三个状态:A、B 和 C。FSM 将调用状态的 Execute() 函数。在函数结束时,状态将发布一个事件,FSM 将确定下一步进入哪个状态。在状态 A 中,它将调用 rand()。如果数字是偶数,它将发布一个事件转到状态 B,否则状态 C 应该是下一个状态。

void StateA::Execute(IEventQueue& rQueue)
{
int num = rand();
if( num % 2 == 0 )
{
rQueue.PostEvent("GoToStateB");
}
else
{
rQueue.PostEvent("GoToStateC");
}
}

如果随机数是 69,那么它应该进入状态 C。在状态 C 中,程序可能会退出。当程序再次启动时,它应该回放状态机。显然,要使其正常工作,它不能生成一个全新的随机数,需要再次使用 69 才能准确播放。

我有一个文件流接口(interface),可以用来将数据保存到文件中,但是代码有点难看:

void StateA::Execute(IEventQueue& rQueue, IFileStream& rStream)
{

int num = 0;

// fails if there's no more data to read
bool bSuccess = rStream.ReadInt(num);
if (!bSucess)
{
num = rand();
rStream.WriteInt(num);
}

// same code as before
}

此解决方案的唯一问题是我不关心必须先检查流中的数据然后有条件地写入同一流。

我想过这样隐藏它:

void StateA::Execute(IEventQueue& rQueue, IStream& rStream)
{

int num = 0;

num = rand();
rStream & num;

// same code as before
}

在 IStream 内部,operator&(可能不是重载的最佳用途)实际上会尝试从流中读取一个 int。如果那个流是空的,它就会写它。和以前一样,行为将是:先读取直到流结束,然后开始追加。

所以我想我的问题是:对于这种播放类型,是否有一个我可能忽略的常见习惯用法?有人有其他建议吗?我觉得我开始让设计过于复杂了。

谢谢!

最佳答案

为什么状态直接与文件流交互?单一职责说我们应该有一个类,它的工作是根据某些逻辑提供正确的数字。

struct INumberSource {
virtual int GenNextNumber() = 0;
}

// My job is to provide numbers from an RNG
struct RNGNumberSource : public INumberSource {
virtual int GenNextNumber() {
return rand();
}
}

// My job is to write any numbers sourced through me to a file
// I delegate to another source to get an actual number
class FileStreamTrackingNumberSource : INumberSource {
public:
FileStreamTrackingNumberSource(INumberSource& source, IFileStream& stream)
: altSource(source), fileStream(stream) { }

virtual int GenNextNumber() {
int num = altSource.GenNextNumber();
fileStream.WriteInt(num);
return num;
}
private:
INumberSource altSource;
IFileStream& fileStream;
}

// My job is to source numbers from a file stream delegating to an
// alternate source when I run out
class FileStreamNumberSource : public INumberSource {
public:
FileStreamNumberSource(INumberSource& source, IFileStream& stream)
: altSource(source), fileStream(stream), failedRead(false) { }

virtual int GenNextNumber() {
int num = 0;

if(failedRead || !(failedRead = fileStream.ReadInt(num))) {
num = altSource.GenNextNumber();
}

return num;
}

private:
INumberSource& altSource;
IFileStream& fileStream;
bool failedRead;
}

因此,在您的情况下,您将向 FileStreamTrackingNumberSource 提供 IFileStreamRNGNumberSource 并提供相同的 IFileStreamFileStreamNumberSourceFileStreamNumberSource 就是您要提供给您所在州的 INumberSource 参数的内容。

假设您只需要数字来选择下一个州,那么您的州代码可能如下所示:

void StateA::Execute(IEventQueue& rQueue, INumberSource& numberSource)
{
if( numberSource.GenNextNumber() % 2 == 0 )
{
rQueue.PostEvent("GoToStateB");
}
else
{
rQueue.PostEvent("GoToStateC");
}
}

关于c++ - 状态机回放的流数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3622134/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com