Нужен подход для автоматически распространяющихся значений в / между иерархическими структурами (система фракций для игры) - PullRequest
1 голос
/ 16 декабря 2009
public static class Global
{
    public static List <Faction> Factions;
    public static Dictionary <Faction, FactionRelation> FactionRelationships;
}    

public class Faction
{
    public Faction Parent;
}

public class FactionRelation
{
    public Faction ForeignFaction; //The enemy or friend of this faction
    public decimal Multiplier; //Standings gain/loss with the faction get applied to ForeignFaction by this percentage. Ex: I get +100 with NativeFaction. If multiplier is -0.1M, then I'll get -10 with ForeignFaction
}
public class Player
{
    public Dictionary <Faction, decimal> Standings;

    public void SetStandings(decimal mod)
    {
        foreach (Faction f in Global.Factions)
        {

        }
    }
}

Приведенный выше код представляет собой элементарную систему фракций для игры. Класс Global инициализирует игру, создавая объекты фракции из некоторого определения данных. Он также содержит коллекцию фракций и десятичных значений, которые представляют отношения между фракциями.

Фракции Допустим, у нас есть 2 основные фракции: DirectionFolk и ColorFolk. У них нет родительских фракций.

У нас также есть фракции UpFolk и DownFolk, родительская фракция которых - DirectionFolk. Наконец, у нас есть фракции RedFolk и BlueFolk, родительская фракция которых - ColorFolk.

Итак,

  • DirectionFolk
    • UpFolk
    • DownFolk
  • ColorFolk
    • RedFolk
      • PinkFolk
      • ScarletFolk
    • BlueFolk

Это вложение могло бы пойти намного глубже; например, RedFolk может иметь PinkFolk и ScarletFolk в качестве подфракций.

Любое постоянное усиление любой фракции должно распространяться вверх и вниз по дереву, пока не достигнет предела вложения в любой из сторон. Глубина вложения набора определяет количество постоянных изменений, которое должно происходить на любом уровне. Для простоты, скажем, он разделен на поровну. Так что, если я получу 100 очков с помощью ColorFolk, я получу 50 очков с RedFolk и BlueFolk и 25 с PinkFolk и ScarletFolk. Если бы вместо этого я получил 100, стоя непосредственно с RedFolk, я должен получить 50 с BlueFolk и 25 с PinkFolk и ScarletFolk. Идея состоит в том, что модификация фракции непосредственно с самыми низкими уровнями будет более выраженной, чем у самых высоких уровней. Так что с PinkFolk легче стать друзьями или врагами, чем с ColorFolk.

Если у этого алгоритма есть имя, я не знаю, что это такое.

Кроме того, любая фракция, у которой нет родителя, может иметь отношения с другой фракцией без родителей. Итак, допустим, что DirectionFolk и ColorFolk являются врагами. Любое усиление стояния фракции с ColorFolk должно привести к пропорциональному проигрышу с DirectionFolk. Поскольку отношения между фракциями могут иметь только родительские фракции (положительные или отрицательные множители), эта постоянная потеря всегда будет происходить в верхней части цепочки связанной фракции и уменьшаться.

В идеале я хотел бы иметь возможность назначать более интересные значения отношениям фракций, как кросс-родительской-фракции, так и среди подфракций родителя. Таким образом, постоянная модификация некоторой подфракции может распространяться через некоторые другие фракции в зависимости от множителей, и выигрыш в позиции с родительской фракцией в дереве будет более гранулированным.

Игроки У объекта Player есть список, в котором отражается их позиция в каждой фракции. Довольно просто - фракция и десятичное значение. Это значение, которое я буду изменять, поскольку каждый игрок хранит данные, представляющие их турнирную таблицу, с помощью фракции. (Сами фракции в этом смысле не знают игроков).

Мой вопрос заключается в том, должен ли я напрямую устанавливать коллекцию значений в объекте Player с помощью некоторого сложного рекурсивного процесса, или есть элегантный способ просто вычислить это на основе очень небольшого количества значений, сохраненных проигрывателем?

Кроме того, сделало бы это немного более интересным - скажем, если бы некоторые фракции были нейтральными друг к другу, даже в одном и том же дереве (например, RedFolk и BlueFolk не заботятся друг о друге) - или перепутали распределение так что это не совсем ровно - могут ли такие вещи серьезно усложнить дело, или возможно ли разработать алгоритм, более агностичный ко всему этому?

Я действительно просто хочу начать с того, как обернуть голову вокруг этого. Если бы кто-то еще придумал что-то подобное, я бы хотел услышать ваши мысли об этом.

Ответы [ 2 ]

3 голосов
/ 16 декабря 2009

Проблема, как я вижу, состоит в том, что вы не определили, что именно вы хотите, чтобы были правила распространения. На самом деле, вы приводите 2 примера, которые противоречат друг другу:

"Так что, если я получу 100, стоя прямо с ColorFolk, я должен получить 50, стоя с RedFolk и BlueFolk [etc]" - этот пример распространяется только вниз по дереву, а не братьям и сестрам. (Не упоминается усиление DirectionFolk.)

"Если бы вместо этого я получил 100, стоя непосредственно с RedFolk, я должен получить 50 с BlueFolk и 25 с PinkFolk и ScarletFolk." - тогда как этот пример распространяется на братьев и сестер .

Очевидно, что оба они не могут быть правдой, если не существует хотя бы еще одного правила, позволяющего решить, почему оно распространяется на одних братьев и сестер, а не на других. В частности, очень неудобно писать рекурсивный алгоритм, чтобы сделать это, если положение распространяется в сторону к братьям и сестрам, потому что ваши две дочерние фракции будут обновляться дважды, один раз от своего родителя и один раз от своего родного брата.

Вместо этого вы можете запустить общий алгоритм распространения, если хотите:

void propagateStanding(amount)
{
    // calculate relative weightings
    totalWeighting = 0.0;
    for (relationship in faction.relationships)
    {
        totalWeighting += relationship.weight;
    }

    // propagate value    
    for (relationship in faction.relationships)
    {
        amountToGive = amount * relationship.weight / totalWeighting;
        relationship.otherFaction.standing += amountToGive;
    }
}

Обратите внимание, что это распространяется только на распространение, а не на увеличение к исходной фракции.

2 голосов
/ 16 декабря 2009

Я не знаю, есть ли у него имя, но я бы использовал итеративный подход, предоставляя классу фракций, который знает структуру фракций, задачу обновления турнирной таблицы игрока.
Как то так:

using System;
using System.Collections.Generic;

class Faction { 
    // the parent faction
    protected Faction _parent;
    // list of children factions
    protected List<Faction> _children = new List<Faction>();

    // the Faction knows the structure, so this approach is iterative but not
    // for this difficult to maintain.
    public void ModifyStanding(Player p,Decimal amount) {
        p[this] += amount;
        foreach (Faction child in _children) {
            child.ModifyStanding(p, amount / 2);
        }
    }
}

class Player {
    // standings
    Dictionary<Faction, Decimal> _standings = new Dictionary<Faction,decimal>();
    // get / set standing indexing on faction
    public Decimal this[Faction f] {
        get { return _standings[f]; }
        set { _standings[f] = value; }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...