3

我的小足球比赛的 AI 代码基本上是这样工作的:有一个函数可以得出描述球场当前情况的事实:

deriveFacts :: GameState -> [Fact]

...事实看起来像这样:

data Fact =
    FactCanIntercept ObjId ObjId
  | FactBestPosition Team Spot Spot
  | FactKickOff
  | FactBallCarrier ObjId
  | FactBestShootingVector Velocity3
  | FactBestPassingVector Velocity3
  | ...

...并且有些规则看起来像这样:

rule_shoot facts = do
    FactBallCarrier ballCarrier <- checkBallCarrier facts
    FactBestShootingVector goalVector <- checkBestShootingVector facts
    return [message (ballCarrier, shoot goalVector)]

然后有一个规则引擎运行所有规则并收集结果消息。

到目前为止还不错,而且效果很好。不过,有什么烦人的:在这种方法中,我需要一个像这样的“访问器”函数来处理每个事实:

checkBestShootingVector :: [Fact] -> Maybe Fact
checkBestShootingVector facts = 
   listToMaybe [e | e@(FactBestShootingVector {}) <- facts]

这种方法会导致很多丑陋的样板代码。我的问题:是否有一个优雅的解决方案可以消除手动创建这些访问器函数的需要?

4

1 回答 1

4

您可以将大部分 Fact 数据重构为记录对象

data FactRec = FR {
   canIntercept :: [(ObjId,ObjId)], -- use lists for things you previously had multiple times
   factBestPosition :: [(Team,Spot,Spot)], -- not sure about this one, maybe two entries not one list 
   kickOff :: Bool,
   ballCarrier :: ObjID,
   factBestShootingVector :: Velocity3, 
   factBestPassingVector :: Velocity3,
   .....
   }

它为您提供了内置访问器功能

if kickOff fr then something else somethingelse

所以你不需要写所有的检查函数,而是做

rule_shoot facts = message (ballCarrier facts, shoot $ goalVector facts)

如果某些事实确实可能存在或可能不存在,则它们可能是 Maybe 类型,如果某些事实可以存在任意次数,则它们可以是列表。

于 2012-11-24T09:23:35.337 回答