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

ほとんどのファクトデータをレコードオブジェクトとしてリファクタリングできます

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,
   .....
   }

これはあなたにbulti-inアクセサ機能を与えます

if kickOff fr then something else somethingelse

したがって、すべてのチェック関数を作成する必要はありませんが、代わりに作成します。

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

本当に存在するかもしれないし存在しないかもしれない事実がある場合、それらは多分何かのタイプである可能性があり、任意の回数存在する可能性がある事実がある場合、それらはリストである可能性があります。

于 2012-11-24T09:23:35.337 に答える