Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get true randomness in this class without Thread.Sleep(300)?

Tags:

c#

random

I've made a class (code below) that handles the creation of a "matching" quiz item on a test, this is the output:

alt text

It works fine.

However, in order to get it completely random, I have to put the thread to sleep for at least 300 counts between the random shuffling of the two columns, anything lower than 300 returns both columns sorted in the same order, as if it is using the same seed for randomness:

LeftDisplayIndexes.Shuffle();
Thread.Sleep(300);
RightDisplayIndexes.Shuffle();

What do I have to do to make the shuffling of the two columns completely random without this time wait?

full code:

using System.Collections.Generic;
using System;
using System.Threading;

namespace TestSort727272
{
    class Program
    {
        static void Main(string[] args)
        {
            MatchingItems matchingItems = new MatchingItems();
            matchingItems.Add("one", "111");
            matchingItems.Add("two", "222");
            matchingItems.Add("three", "333");
            matchingItems.Add("four", "444");
            matchingItems.Setup();

            matchingItems.DisplayTest();
            matchingItems.DisplayAnswers();

            Console.ReadLine();

        }
    }

    public class MatchingItems
    {
        public List<MatchingItem> Collection { get; set; }
        public List<int> LeftDisplayIndexes { get; set; }
        public List<int> RightDisplayIndexes { get; set; }

        private char[] _numbers = { '1', '2', '3', '4', '5', '6', '7', '8' };
        private char[] _letters = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };

        public MatchingItems()
        {
            Collection = new List<MatchingItem>();
            LeftDisplayIndexes = new List<int>();
            RightDisplayIndexes = new List<int>();
        }

        public void Add(string leftText, string rightText)
        {
            MatchingItem matchingItem = new MatchingItem(leftText, rightText);
            Collection.Add(matchingItem);
            LeftDisplayIndexes.Add(Collection.Count - 1);
            RightDisplayIndexes.Add(Collection.Count - 1);
        }

        public void DisplayTest()
        {
            Console.WriteLine("");
            Console.WriteLine("--TEST:-------------------------");
            for (int i = 0; i < Collection.Count; i++)
            {
                int leftIndex = LeftDisplayIndexes[i];
                int rightIndex = RightDisplayIndexes[i];
                Console.WriteLine("{0}. {1,-12}{2}. {3}", _numbers[i], Collection[leftIndex].LeftText, _letters[i], Collection[rightIndex].RightText);
            }
        }
        public void DisplayAnswers()
        {
            Console.WriteLine("");
            Console.WriteLine("--ANSWERS:-------------------------");
            for (int i = 0; i < Collection.Count; i++)
            {
                string leftLabel = _numbers[i].ToString();
                int leftIndex = LeftDisplayIndexes[i];
                int rightIndex = RightDisplayIndexes.IndexOf(leftIndex);
                string answerLabel = _letters[rightIndex].ToString();

                Console.WriteLine("{0}. {1}", leftLabel, answerLabel);

            }
        }

        public void Setup()
        {
            do
            {
                LeftDisplayIndexes.Shuffle();
                Thread.Sleep(300);
                RightDisplayIndexes.Shuffle();
            } while (SomeLinesAreMatched());
        }

        private bool SomeLinesAreMatched()
        {
            for (int i = 0; i < LeftDisplayIndexes.Count; i++)
            {
                int leftIndex = LeftDisplayIndexes[i];
                int rightIndex = RightDisplayIndexes[i];
                if (leftIndex == rightIndex)
                    return true;
            }
            return false;
        }


        public void DisplayAsAnswer(int numberedIndex)
        {
            Console.WriteLine("");
            Console.WriteLine("--ANSWER TO {0}:-------------------------", _numbers[numberedIndex]);
            for (int i = 0; i < Collection.Count; i++)
            {
                int leftIndex = LeftDisplayIndexes[i];
                int rightIndex = RightDisplayIndexes[i];

                Console.WriteLine("{0}. {1,-12}{2}. {3}", _numbers[i], Collection[leftIndex].LeftText, _letters[i], Collection[rightIndex].RightText);
            }
        }
    }

    public class MatchingItem
    {
        public string LeftText { get; set; }
        public string RightText { get; set; }

        public MatchingItem(string leftText, string rightText)
        {
            LeftText = leftText;
            RightText = rightText;
        }
    }

    public static class Helpers
    {
        public static void Shuffle<T>(this IList<T> list)
        {
            Random rng = new Random();
            int n = list.Count;
            while (n > 1)
            {
                n--;
                int k = rng.Next(n + 1);
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }
    }

}
like image 541
Edward Tanguay Avatar asked Sep 07 '10 15:09

Edward Tanguay


1 Answers

Move Random rng = new Random(); to a static variable.

MSDN says "The default seed value is derived from the system clock and has finite resolution". When you create many Random objects within a small time range they all get the same seed and the first value will be equal to all Random objects.

By reusing the same Random object you will advance to the next random value from a given seed.

like image 161
Albin Sunnanbo Avatar answered Nov 15 '22 07:11

Albin Sunnanbo