Skip to content

Instantly share code, notes, and snippets.

@wilg
Last active September 1, 2022 22:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wilg/e310da134389d0e2cdcef3aafee6a338 to your computer and use it in GitHub Desktop.
Save wilg/e310da134389d0e2cdcef3aafee6a338 to your computer and use it in GitHub Desktop.
Unity serializable list shuffling
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
#nullable enable
public static class ShuffleExtensions {
// Returns a random element from the list.
public static T? RandomElement<T>(this IList<T> list) {
if (list.Count == 0) {
return default;
}
return list[Random.Range(0, list.Count)];
}
// Returns a randomly-ordered version of the enumerable. Only iterates once.
// Use when you are going to immediately iterate over the result.
public static IEnumerable<T> Shuffled<T>(this IEnumerable<T> source) {
var list = source.ToArray();
var n = list.Length;
for (int i = 0; i < (n - 1); i++) {
var r = i + Random.Range(0, n - i);
(list[i], list[r]) = (list[r], list[i]);
yield return list[i];
}
}
// Returns a copy of the enumeration as an array, with a random order.
public static T[] ShuffledArray<T>(this IEnumerable<T> source) {
var list = source.ToArray();
list.Shuffle();
return list;
}
// Shuffles the list in-place.
public static void Shuffle<T>(this IList<T> list) {
var n = list.Count;
for (int i = 0; i < (n - 1); i++) {
var r = i + Random.Range(0, n - i);
(list[i], list[r]) = (list[r], list[i]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
#nullable enable
// Like a queue, but it never runs out. It is always shuffled and will never dequeue the same item twice in a row.
// The order reshuffles every time the queue resets, so it will never repeat.
// There is a small amount of garbage generated on initialization and when the queue resets.
// Serialized, so you can use it in place of an array in the inspector.
[Serializable]
public class Shuffler<Item> {
public List<Item> items;
Item? lastDequeued;
Queue<Item>? queue;
public Shuffler(IEnumerable<Item> items) {
this.items = items.ToList();
Shuffle();
}
void Shuffle() {
queue = new Queue<Item>(items.Shuffled());
}
public Item Dequeue() {
if (queue == null || queue.Count == 0) {
Shuffle();
}
var item = queue!.Dequeue();
if (lastDequeued != null && ReferenceEquals(item, lastDequeued)) {
return Dequeue();
}
lastDequeued = item;
return lastDequeued;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment