首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >人工智能决策树

人工智能决策树
EN

Code Review用户
提问于 2017-01-27 14:46:55
回答 1查看 4.5K关注 0票数 10

我创建了一个小决策树,你认为它是什么,我能纠正什么?我想为树创建一个代码,它看起来是这样的:

我的实施:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Text;

public interface TreeNode
{
    bool nodeState { get; }
    bool Evaluate();
}

/// <summary>
/// Returns true when one of childs returns true
/// </summary>
public class Selector : TreeNode
{
    private List<TreeNode> childNodes;
    public bool nodeState { get; private set; } = false;

    public Selector(List<TreeNode> childNodes) { this.childNodes = childNodes; }

    public bool Evaluate()
    {
        foreach (TreeNode node in childNodes)
            if (node.Evaluate())
            {
                nodeState = true;
                return true;
            }
        nodeState = false;
        return false;
    }
}

/// <summary>
/// Returns true when all childs return true
/// </summary>
public class Sequence : TreeNode
{
    private List<TreeNode> childNodes;
    public bool nodeState { get; private set; } = false;

    public Sequence(List<TreeNode> childNodes) { this.childNodes = childNodes; }

    public bool Evaluate()
    {
        foreach (TreeNode node in childNodes)
            if (!node.Evaluate())
            {
                nodeState = false;
                return false;
            }
        nodeState = true;
        return true;
    }
}

/// <summary>
/// Has only one child, negate it
/// </summary>
public class Inverter : TreeNode
{
    private TreeNode nodeToInvert;
    public bool nodeState { get; private set; } = false;

    public Inverter(TreeNode nodeToInvert) { this.nodeToInvert = nodeToInvert; }

    public bool Evaluate()
    {
        nodeState = !nodeToInvert.Evaluate();
        return !nodeToInvert.Evaluate();
    }
}

/// <summary>
/// Leaf of tree, returns delegate of bool function that is setted in it's constuctor
/// </summary>
public class ActionNode : TreeNode
{
    public delegate bool ActionNodeDelegate();
    private ActionNodeDelegate action;
    public bool nodeState { get; private set; } = false;

    public ActionNode(ActionNodeDelegate action)
    {
        this.action = action;
    }

    public bool Evaluate()
    {
        nodeState = action();
        return action();
    }
}

public static class DecisionTree
{
    public static void Test()
    {
        while (true)
        {
            AITree tree = new AITree();
            Console.ReadKey();
            Console.Clear();
        }
    }
}

public class AITree
{
    private float      playerDistanceFromEnemy;
    private int        playerPower;

    private ActionNode IsInAttackRange;
    private ActionNode IsVisible;
    private ActionNode EstimatePlayerPower;
    private Sequence   Attack;
    private Inverter   Patrol;
    private Sequence   Escape;
    private Selector   Root;

    bool PlayerIsInAttackRange() => playerDistanceFromEnemy < 5;
    bool PlayerIsVisible()       => playerDistanceFromEnemy < 8;
    bool PlayerIsTooPowerful()   => playerPower > 3;

    public AITree()
    {
        Random rnd = new Random();
        playerDistanceFromEnemy = (float)rnd.Next(10, 100) / 10;
        playerPower = rnd.Next(1, 6);

        IsInAttackRange     = new ActionNode(PlayerIsInAttackRange);
        IsVisible           = new ActionNode(PlayerIsVisible);
        EstimatePlayerPower = new ActionNode(PlayerIsTooPowerful);
        Attack              = new Sequence(new List<TreeNode> { IsInAttackRange, IsVisible });     // Attack only when player is visible and is in attack range
        Patrol              = new Inverter(Attack);                                                // Patrol only when not attacking
        Escape              = new Sequence(new List<TreeNode> { IsVisible, EstimatePlayerPower }); // Escape when player is visible and player is too powerful 
        Root                = new Selector(new List<TreeNode> { Escape, Patrol, Attack });         // Escape has the biggest priority

        Root.Evaluate();
        ShowCommunicats();
    }

    private void ShowCommunicats()
    {
        StringBuilder sb = new StringBuilder();
        Console.WriteLine($"Player distance: {playerDistanceFromEnemy}, Player power: {playerPower}");
        sb.AppendLine();

        Console.WriteLine(Patrol.nodeState          ? "enemy will patrol"                      : "enemy will not patrol");
        Console.WriteLine(Escape.nodeState          ? "enemy escapes"                          : "enemy will not escape");
        Console.WriteLine(IsVisible.nodeState       ? "enemy see player"                       : "enemy dont see player");
        Console.WriteLine(IsInAttackRange.nodeState ? "player is in the enemy attack distance" : "player is too far to hit");
        Console.WriteLine(Attack.nodeState          ? "enemy attacks"                          : "enemy will not attack");
    }
}
EN

回答 1

Code Review用户

发布于 2017-01-27 16:25:08

Bugs

  • Evaluate()方法Selector/Sequence不会在所有子节点上调用Evaluate()。因此,您不能确定noteState对所有节点都是正确的。但是您的示例代码在运行Root.Evaluate()后使用所有节点的节点状态。

Selector/Sequence.Ctor

  • 检查参数是否为null (否则可以在方法Evaluate中获得NRE )
  • 您可以使用IEnumerable<TreeNode>作为参数类型,以便更灵活。
  • childNodes集合可以是只读的。

Selector/Sequence.Evaluate

您可以使用LINQ:

代码语言:javascript
复制
public bool Evaluate() => nodeState = childNodes.Any(n => n.Evaluate());

public bool Evaluate() => nodeState = childNodes.All(n => n.Evaluate());

但是,如上所述,您应该为所有子节点调用Evaluate()

代码语言:javascript
复制
public bool Evaluate()
{
    childNodes.ForEach(n => nodeState |= n.Evaluate());
    return nodeState;
}

public bool Evaluate()
{
    nodeState = true;
    childNodes.ForEach(n => nodeState &= n.Evaluate());
    return nodeState;
}

命名约定

命名约定中有C#

  • 接口应该以“i”开头
  • 财产应以大写字母开头。
  • ……

您的需求让我想起了框架来自@Dmitry的可数和不可数集

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/153773

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档