That said, there are numerous ways to accomplish the same thing. For example, you don’t have to tumble the values around in order to rotate the list. You can instead move an imaginary list cursor. This will work much faster, because once its initialized, the list itself can be left alone (unless you intend to change the symbols on the fly, which we’ll also add).
Let the list be
- Two cookies <<<
- Broccoli
- Peas
- Broccoli
- Apple
- Something
- Pie
- Carrots
Notice the arrow. It points to an element that is the rightmost symbol on the panel.
Imagine if we had a value that keeps the position of this arrow. In this case it’s 0.
If you then rotate the list counter-clockwise, we know the Carrots should come out on top, but instead of modifying the list itself, we only move the arrow.
- Two cookies
- Broccoli
- Peas
- Broccoli
- Apple
- Something
- Pie
- Carrots <<<
Only the arrow will wrap around, while everything else is left intact.
The next time you do it, it’ll turn to this, much more efficient then removing/inserting
- Two cookies
- Broccoli
- Peas
- Broccoli
- Apple
- Something
- Pie <<<
- Carrots
Now Pie is the rightmost symbol.
Let’s try this in code
public class MyPanelSymbols {
public enum Symbol {
Cookies,
Broccoli,
Apple,
Peas,
Pie,
Carrots,
Something
}
List<Symbol> _list;
int _cursor;
public int Count => _list.Count;
public Symbol this[int index] => _list[(_cursor + index) % Count];
public MyPanelSymbols(int expectedCountOfSymbols) {
_list = new List<Symbol>(expectedCountOfSymbols);
_cursor = 0;
}
public void AddSymbol(Symbol symbol) {
_list.Add(symbol);
}
public void ChangeSymbol(int index, Symbol symbol) {
_list[(_cursor + index) % Count] = symbol;
}
public void RotateCW() {
_cursor--;
if(_cursor < 0) _cursor = Count - 1;
}
public void RotateCCW() {
_cursor++;
if(_cursor > Count - 1) _cursor = 0;
}
}
After we normally load all the symbols
Debug.Log(sigma.Count); // 8
Debug.Log(sigma[0]); // Cookies
Debug.Log(sigma[4]); // Apple
Debug.Log(sigma[10]); // Peas
sigma.RotateCCW();
Debug.Log(sigma[0]); // Carrots
sigma.ChangeSymbol(0, MyPanelSymbols.Symbol.Pie);
Debug.Log(sigma[0]); // Pie
Why this works?
Well because we made our index wrap around previously, we can now play with the fact.
You can supply any positive index whatsoever and it’ll always evaluate in the range from 0 to Count - 1
For this we use the division remainder operator (%)
When used with integers it’ll always return the remainder of the division operation.
For example 8 % 3 = 2 because you can fit 3 two times in 8, and what is left is 2.
This means that the result will never surpass the right operand (in this case 3), and you can reliably use this to compute a modulo.
We don’t support supplying negative indices here, however.
But look, our cursor is also confined to these rules. I could’ve used % as well in RotateCW and RotateCCW but didn’t to make it more readable. Because we always change cursor by 1, the outcome is easy to predict, and if it becomes -1, this means it should become 7 instead, and the other way around, if it becomes 8 it should become 0 instead.
When you add this “magic” number to your queried index, the resulting index is both confined within the range of the list AND offset by this magic internal number.
When we do RotateCCW and query sigma for index 5, the internal index evaluation is
(7+5) % 8
= 12 % 8
= 4
so Apple
And sure, if you look at your top left panel, and count slots from 0 (Cookies), to 5, counter-clockwise, this is the slot where you expect the Apple to be after you rotate the entire panel counter-clockwise.