1

我想知道处理具有关系的复杂结构的最佳方法是什么?

我正在为我的项目实现一个星系生成算法,基本上我有简单的枚举

GalaxySize { Small, Medium, Large };
GalaxyAge { Young, Mature, Ancient}; 
StarTypes { Black = 1, White = 3, Yellow = 1, Red = 3 };

到目前为止,我正在生成受 GalaxySize 值限制的星星。然后我从 StarTypes 中随机获取一个类型并从该类型创建一个星。我想做的是在 StarTypes 和 GalaxyAge 之间建立关系。

这意味着(例如)在年轻的星系中,黄色和白色恒星的几率更高,而在古老的星系中,黑色和红色恒星的几率更高。

我在想的是让 StarType 有一个基本的机会“滚动”,然后根据 GalaxyAge 添加修饰符,这将导致特定星系年龄中更多更常见的恒星。

Example: weight (chance) of a white star in young galaxy is 3 base + 3 
from the "young" galaxy age modifier 
against the weight of a red star which has 3 base + 1 from the "young" modifier.


Resulting in:
White star type weight = (3 + 3 ) * rand.nextDouble() 
Red star type weight = (3 + 1) * rand.nextDouble()

关于如何实现/表示此功能的任何建议,因为显然仅枚举是不够的?:)

4

3 回答 3

0

为什么不为你的星系创建一个类层次结构?

using System.Collections.Generic;

enum StarTypes { Black, White, Yellow, Red };

abstract class Galaxy {
    Dictionary<StarTypes, float> _baseProbabilities;
    protected Galaxy() {
        _baseProbabilities = new Dictionary<StarTypes, float>();
        _baseProbabilities[StarTypes.Black] = 1.0f;
        _baseProbabilities[StarTypes.White] = 3.0f;
    }
    public float GetStarProbability(StarTypes starType) {
        return _baseProbabilities[starType] + GetStarProbabilityModifier(starType);
    }
    protected abstract float GetStarProbabilityModifier(StarTypes starType);
}

class YoungGalaxy : Galaxy {
    protected override float GetStarProbabilityModifier(StarTypes starType) {
        switch (starType) {
        case StarTypes.White:
            return 3.0f;
        default:
            return 0;
        }
    }
}
于 2012-12-14T16:02:07.823 回答
0

对,所以你想生成随机恒星,但要根据星系的年龄来加权?我假设您已将这些权重存储在某个地方。

所以:

年轻的银河。让我们假设:

  1. 白星:40%几率
  2. 黄色星星:40% 几率
  3. 红星:10%几率
  4. 黑星:10%几率

如果是这种情况,那么让我们构建一个列表并包含 4 个白色和黄色星以及 1 个红色和黑色星。

现在,对于每个星槽,让我们执行以下操作:

    var start=GetListOfStarsBasedOnGalaxyAge(galaxyAge);
    var starList=new List<StarTypes>();
    for(int starCount=0;starCount<starsInGalaxy,starCount++)
{
    var star=var stars.OrderBy(a => Guid.NewGuid()).First();
 starList.Add(star);
}

基本上我们是按随机 Guid 排序,这是一种廉价但有效的 shuffle方式。这将确保您的星级选择是随机的,但也使用了您想要的适当权重。你可能仍然会得到一个完全充满黑星的星系,但这极不可能。

于 2012-12-14T16:04:11.900 回答
0

我不太了解算法,但你可以从这里开始:

sealed class Age
{
    public static readonly Young = new Size(3.0);
    public static readonly Mature = new Size(2.0);
    public static readonly Ancient = new Size(1.0);

    public double Weight
    {
        get;
        private set;
    }

    private Age(float weight)
    {
        Weight = weight;
    }
}

sealed class Size
{
    public static readonly Small = new Size(3.0);
    public static readonly Medium = new Size(2.0);
    public static readonly Large = new Size(1.0);

    public double Weight
    {
        get;
        private set;
    }

    private Size(float weight)
    {
        Weight = weight;
    }
}

现在让我们定义一个类Galaxy

sealed class Galaxy
{
    public Age Age
    {
        get;
        set;
    }

    public Size Size
    {
        get;
        set;
    }
}

现在你必须定义一个类来定义星星:

abstract class Star
{
    protected Star(string color, Galaxy galaxy)
    {
        Color = color;
        Galaxy = galaxy;
    }

    public string Color
    {
        get;
        private set;
    }

    public Galaxy Galaxy
    {
        get;
        private set;
    }

    public abstract float Chances(Random rnd);
}

现在让我们为每个星定义一个新类(不要忘记根据每种类型的实际情况更改算法、公式和权重):

sealed class WhiteStar : Star
{
    public WhiteStar(Galaxy galaxy) : base("White", galaxy)
    {
    }

    public override float Chances(Random rnd)
    {
        return (3 + Galaxy.Age + Galaxy.Size) * rnd.NextDouble();
    }
}

当然,这不能是最终代码,但您可以将其用作组织代码的提示。

最大的好处是Galaxy不知道获得特定类型星星的规则,每个星星类型都知道自己的规则(这意味着如果您添加新的星星类型,您将不需要搜索遍布各地的规则很多课)。当然这对其他类也有效(例如,如果您添加一个MiddleAge星系的年龄,您将不需要更新任何其他类)。

最后不要忘记将Weight属性名称更改为对您的域更有意义的名称。

于 2012-12-14T16:07:14.330 回答