2

Problem:

I want to build a class for a custom dice. But it should also provide the following:

  1. Every side can contain an other dice
  2. The number of sides should be dynamically expandable, but must at least contain one
    • Logically the dice need to have a currentSide
  3. Every side has a property, which provides the content of this side (on a D6, it would be "4")

So far so good, I went and made two classes dice and side and gave them the properties I think they needed.

public class Side
{
    //public bool HasDice { get { return Dice != null; } } - Removed not needed
    public Dice Dice { get; set; }
    public string Value { get; set; }
}

public class Dice
{
    public ObservableCollection<Side> Sides { get; set; }
    public string Name { get; set; }
    public Side CurrentSide { get; set; }
}

Is this right, I never made any recursive classes so I'm not sure ?

Also how am I able to detect if the same dice and side are "endlessly" referring to them self.

Like:

D1.CurrentSide = Side1; Side1.Dice = D1;

Should I check this when building objects ?

Edit:

Example Dice Image

  • If D1 rolls S2 then D2 shouldn't be rolled. Also D2.Dice = Null.

  • If D1 rolls S1 then D2 should be rolled.

  • If D2 rolls S1 then D3 should be rolled.

  • If D2 rolls S2 then D4 should be rolled.

D3 and D4 shouldn't trigger any roll.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Firen
  • 272
  • 1
  • 13
  • 5
    Good programming practices aside, who suggested this design? Public property saying if the side has a dice? Does it make ANY sense to you? – walther Oct 24 '14 at 12:34
  • @walther I plan on using this in an WP app, along with WPF and I thought a bool in the class would be nicer to bind to, then the Dice Property of the Side and a Converter to get the boolean then. For simplicity I cut out the INotifyPropertyChanged implementation, because this is not needed to answer the question :) – Firen Oct 24 '14 at 12:37
  • 1
    http://memegenerator.net/instance/55596564 – Niels Keurentjes Oct 24 '14 at 12:46
  • @NielsKeurentjes :D Can you give me a better approach though ? – Firen Oct 24 '14 at 12:48
  • 1
    Is the `Dice` reference in the `Side` suppose to refer to the Die that the side belongs to, or do you actually have dice on top of other dice? – juharr Oct 24 '14 at 12:48
  • 1
    Maybe it's a hyper-dice, so on each side there is another dice? @NielsKeurentjes This is so unprofessionally good +1. – luk32 Oct 24 '14 at 12:49
  • It should refer to another Dice. So for example you roll D1 on and S1 triggers a roll on D2, but the other sides don't. Hope that makes seens to you. – Firen Oct 24 '14 at 12:49
  • @MichaM. not without an answer to juharr's question :P – Niels Keurentjes Oct 24 '14 at 12:50
  • 2
    So `Side.Dice` can optionally refer to any `Dice` except the one it contains? – Niels Keurentjes Oct 24 '14 at 12:51
  • 1
    It shouldn't reference back yes. – Firen Oct 24 '14 at 12:52
  • @MichaM. You need to decide, where you need a `Trigger` or a `Side` contains a `Dice`. – luk32 Oct 24 '14 at 12:52
  • @luk32 I don't quite now what you mean by that. Would the `Trigger` be an other class ? – Firen Oct 24 '14 at 12:53
  • I do not understand why `Dice.SomeSide.Dice` should not be equal to the `Dice` itself. That seems to be illogical. – AgentFire Oct 24 '14 at 12:54
  • @AgentFire It shouldn't. Dice.Side.Dice should be an other Dice, but I was wondering IF i could avoid writing a complicated check, to check if D1 is set as the value of ANY D1.Sides or even D1.Side.Dice.Sides .... so on. Because if I try to display or serialise this I would have a problem because it is an infinit loop (and yes I know that you can serialize those, but still I don't need to create them so I don' want to bother with that) – Firen Oct 24 '14 at 12:57
  • Personally I think the dice shouldn't know about each other and the logic for determining what dice to roll next should be handled in a different class. How do you plan to build up this chain, loaded from a file, setup in a gui, or hard coded? – juharr Oct 24 '14 at 12:59
  • @juharr I would like to let the user create the dices and sides. And then they can decide whether or not the side XY will let another dice roll or should only display the "Value". – Firen Oct 24 '14 at 13:02
  • In that case you should be able to avoid loops by not allowing the user to select a dice that was previously selected in the current chain. If you really need to check an existing chain for a loop you can use the [Tortoise and hare](http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) algorithm. – juharr Oct 24 '14 at 13:06
  • @MichaM. what would you like to happen if someone tries to execute `D1.CurrentSide = Side1; Side1.Dice = D1;`? – Dialecticus Oct 24 '14 at 13:11
  • Ok, so I think I will check on user input and filter then. @Dialecticus With that said I think, this question don't need to be answered :) – Firen Oct 24 '14 at 13:14
  • Now that we have an explanation in the picture I would suggest that you rename `Dice` to `State` and `Side` to `Action`. It is just a cosmetic change, but if you have done it so from the beginning this comment section would be much shorter. – Dialecticus Oct 24 '14 at 13:25
  • @Dialecticus Sorry D: Didn't think of it, will do next time. And appart from the cosmetics the struktur is right for this or should it be changed? Also is it better to name the `Side` `Aktion` ? Even if I only CAN contain an other `Dice`? And why `State` the `Dice` contains multiple possible states, most dices anyway? – Firen Oct 24 '14 at 13:27
  • 1
    For further learning see [state machine](http://en.wikipedia.org/wiki/Finite-state_machine). There you can see that loops are normal. Imagine that you have a state named "Are we there yet?". Action "No" should direct to that same state, and action "Yes" should move the logic to another state. – Dialecticus Oct 24 '14 at 13:54
  • @Dialecticus Thanks, post that as an answer and I will accept it. – Firen Oct 24 '14 at 14:31

2 Answers2

2

What you are making is called a state machine. Your program (the "machine") is always in some state, but can change the state as a consequence of performing some action. Depending on the logic it can be quite acceptable that the machine can be in the same state more than once. So, I wouldn't bother too much about loops in the machine's logic. If a user wants the loop then let him have it, as long as the machine can reach some final state and program reaches the end of execution.

Dialecticus
  • 16,400
  • 7
  • 43
  • 103
1

Based on what you've said, I suggest you to create an object graph of the dices, where one dice is connected through to the other dices and then run a topological sorting algorythm to reveal cyclic dependencies.

To do that I'd recommend either write it yourself, you use the QuickGraph tool.

Now, I myself did once use it and wrote an extension to the IEnumerable thing where it returns sorted IList in a way, where first items returned are the items never referenced by the other items. The latter are the most referenced. (Or mayhaps the other way around.) In case of cyclic dependencies the exception in thrown. My extension uses the QuickGraph library.

public static IList<T> OrderTopologically<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> dependenciesSelector)
{
    var graph = new AdjacencyGraph<T, Edge<T>>();

    foreach (T item in e)
    {
        graph.AddVertex(item);

        foreach (T dependecy in dependenciesSelector(item))
        {
            graph.AddEdge(new Edge<T>(item, dependecy));
        }
    }

    var topSort = new TopologicalSortAlgorithm<T, Edge<T>>(graph);

    try
    {
        topSort.Compute();
    }
    catch (NonAcyclicGraphException cyclicException)
    {
        throw new ElQueueException("Circular reference detected while processing javascript dependency order.", cyclicException);
    }
    catch (KeyNotFoundException keyNotFoundException)
    {
        throw new ElQueueException("Dependency could not be found.", keyNotFoundException);
    }

    return topSort.SortedVertices;
}
AgentFire
  • 8,944
  • 8
  • 43
  • 90
  • I updated my post with an image on how I want the dices to behave, can this be achived with an object graph ? If so I will read more into it. :) – Firen Oct 24 '14 at 13:18