Your Random.Range call is correct. Random.Range when using integers as the parameters is inclusive-exclusive. It is to do with the way random numbers or generated and also the modulo operator.
Fizix’s solution however has a number of fundamental bugs, not least of which is swapping the last number in the array with itself, i.e. as the iteration progresses, you receive diminishing returns on the swap order.
Whilst the solutions discussed are satisfactory, and also one of the many proposed solutions you will find on websites such as Stack Overflow, there are “better” ones if you don’t want to shuffle around elements of an array or list or squander precious memory. What you are after is a Full Cycle LCG PRNG or Full Cycle LFSR PRNG.
A modified Mersenne Twister with a period equal to the series of numbers to be generated is a great solution, though has a sizable computational overhead for small systems.
Alternatively, if all you need to do is shuffle a deck of cards, or a couple of decks, you can use an n-bit non-repeating generator such as a 6-bit LFSR, which is forced to only return results in the proper range. I believe OpenBSD uses such a system for generating certain ID numbers. This solution, in various incarnations, has been around since the late 1970’s at least.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace FullCyclePRNGThrowaway
{
class Program
{
/// <summary>
/// Generates a random list of numbers that guarantees all of the numbers
/// are unique, i.e. no number will be duplicated.
/// </summary>
static void Main(string[] args)
{
Debug.WriteLine("Shuffled: ");
Random rnd = new Random();
int lfsr = (rnd.Next() % 24) + 1;
for (int i = 0; i < 24; i++)
{
do
{
lfsr ^= (lfsr << 9);
lfsr = 31;
lfsr ^= (lfsr >> 2);
lfsr = 31;
lfsr ^= (lfsr << 3);
lfsr = 31;
} while (lfsr > 24);
Debug.Write(lfsr.ToString() + ", ");
}
}
}
}
And the output:
Shuffled: 21, 16, 20, 7, 22, 11, 1, 9, 19, 15, 12, 23, 2, 18, 6, 24, 14, 5, 4, 13, 17, 10, 8, 3,
Twenty-four numbers, in the range 1…24, randomly shuffled, no repeats, using a very simple function.
If you were to extend the for loop to a value greater than the sample size, the sequence of randomly generated numbers would repeat, that is:
for (int i = 0; i < 24 * 3; i++)
With the result being:
Shuffled: 1, 9, 19, 15, 12, 23, 2, 18, 6, 24, 14, 5, 4, 13, 17, 10, 8, 3, 21, 16, 20, 7, 22, 11, 1, 9, 19, 15, 12, 23, 2, 18, 6, 24, 14, 5, 4, 13, 17, 10, 8, 3, 21, 16, 20, 7, 22, 11, 1, 9, 19, 15, 12, 23, 2, 18, 6, 24, 14, 5, 4, 13, 17, 10, 8, 3, 21, 16, 20, 7, 22, 11,
I’ve been using a variation of this code since about 1979 and I cringe every time I see someone put a list of numbers in to an array and then shuffle the array around for something so simple as a couple of random numbers being returned.
I’ll put up a re-usable Unity-fied C# class on my website (http://www.otakunozoku.com) for those that want a drop-in solution for Unity3D in the next day or so.