Able
Askowl Base Library Enabler
Selector.cs
1 // Copyright 2018 (C) paul@marrington.net http://www.askowl.net/unity-packages
2 
3 using System;
4 using System.Collections.Generic;
5 using UnityEngine;
6 using Random = UnityEngine.Random;
7 
8 namespace Askowl {
9  /// <a href="http://bit.ly/2OrRfQp">Pick one item from a list.</a> <inheritdoc />
10  public sealed class Selector<T> : Pick<T> {
11  /// <a href="http://bit.ly/2OrRfQp">Defaults to random. Set false to cycle through entries sequentially</a>
12  public bool IsRandom = true;
13 
14  /// <a href="http://bit.ly/2OvCQ5Q">If the list is shorter then select items randomly, but never choose one a second time until all have been picked. This is useful for short lists to reduce repeats.</a>
15  public int ExhaustiveBelow = 1;
16 
17  private T[] choices = { };
18  private Func<T> picker;
19 
20  /// <a href="http://bit.ly/2OrRfQp">Method called to pick an item</a> <inheritdoc />
21  public T Pick() {
22  if (picker != null) return picker();
23 
24  if (choices.Length == 0) {
25  picker = () => default;
26  } else if (choices.Length == 1) {
27  picker = () => choices[0];
28  } else if (!IsRandom) { // cycle through list
29  cycleIndex = -1;
30  picker = () => choices[++cycleIndex % choices.Length];
31  } else if (choices.Length >= ExhaustiveBelow) { // random selection
32  picker = () => choices[cycleIndex = Random.Range(0, choices.Length)];
33  } else {
34  remainingSelections = new List<T>(collection: choices);
35 
36  picker = () => { // different random choice until list exhausted, then repeat
37  if (remainingSelections.Count == 0) remainingSelections = new List<T>(collection: choices);
38 
39  cycleIndex = Random.Range(0, remainingSelections.Count);
40  T result = remainingSelections[index: cycleIndex];
41  remainingSelections.RemoveAt(index: cycleIndex);
42  return result;
43  };
44  }
45 
46  next = -1;
47  return picker();
48  }
49 
50  /// <a href="">Called when a pick fails and we need to try something else</a> //#TBD#//
51  public T Next() {
52  if (next == -1) next = cycleIndex;
53  next = (next + 1) % choices.Length;
54  return next == (cycleIndex % choices.Length) ? default : choices[next];
55  }
56 
57  /// <a href=""></a> //#TBD#//
58  public void Top() => cycleIndex = -1;
59 
60  /// <a href="http://bit.ly/2OvDtMK">Used to update the choices to a new set using the same picker.</a>
61  public T[] Choices {
62  get => choices;
63  set {
64  choices = value;
65  picker = null;
66  }
67  }
68 
69  private int cycleIndex, next;
70 
71  /// <a href="http://bit.ly/2NU0GsC">The location of the next choice in the sequence.</a>
72  public int CycleIndex => cycleIndex % choices.Length;
73 
74  private List<T> remainingSelections;
75 
76  /// <a href="http://bit.ly/2OrRfQp">Remove all choices for an empty list</a>
77  public void Reset() => choices = emptyChoices;
78 
79  private readonly T[] emptyChoices = { };
80  }
81 }
Definition: Clock.cs:3
void Reset()
Remove all choices for an empty list
T Pick()
Method called to pick an item
Definition: Selector.cs:21
T [] Choices
Used to update the choices to a new set using the same picker.
Definition: Selector.cs:61
T Next()
Called when a pick fails and we need to try something else //#TBD#//
Definition: Selector.cs:51
bool IsRandom
Defaults to random. Set false to cycle through entries sequentially
Definition: Selector.cs:12
void Top()
//#TBD#//
int ExhaustiveBelow
If the list is shorter then select items randomly, but never choose one a second time until all have ...
Definition: Selector.cs:15
Pick one item from a list.
Definition: Selector.cs:10
int CycleIndex
The location of the next choice in the sequence.
Definition: Selector.cs:72
Interface so that code can use a picker without know more about the source. A picker returns a value ...
Definition: Pick.cs:5