How to pick a random string from string array only once

I'm trying to make Hangman in C#, and in the beginning of a game you will need a word to guess, and so the game wont be boring you can get many words (only one at a time). But when you start a new game you wont get a word you've already guessed. So i have to choose a random string that i havent chosen already.

I've tried multiple methods to solve this, but none have succeded.

Method #1:

Here I run the NewWord-function, and then add 1 to numberOfTries.

string[] wordArr = { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };
int numberOfTries = 0;
int randomNumber = -1;


protected string NewWord()
{
    if (!(numberOfTries >= wordArr.Length))
    {
        randomNumber = RandomNumberFromTo(0, (wordArr.Length - numberOfTries));

        ChangeWord(((wordArr.Length - numberOfTries)-1), randomNumber);

        return wordArr[(randomNumberl)];
    }
    else
    {
        return "There are no more new words!! :(";
    }
}


private int RandomNumberFromTo(int NumberA, int NumberB)
{
    System.Threading.Thread.Sleep(2);
    Random minRandomGenerator = new Random();
    System.Threading.Thread.Sleep(3);
    return minRandomGenerator.Next(NumberA, NumberB);
}



protected void ChangeWord (int NumberA, int NumberB)
{
    string cashe1 = wordArr[NumberA];
    wordArr[NumberA] = wordArr[NumberB];
    wordArr[NumberB] = cashe1;
    return;
}

Method #2 I've found here on StackOverflow but it didn't work.

Here I also run the NewWord-function, and then add 1 to numberOfTries.

string[] wordArr = { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };       
int numberOfTries = 0;
Random random = new Random();
protected string NyttOrd()
{
    if (!(numberOfTries >= wordArr.Length))
    {
        var names = new List<string> { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };

        System.Threading.Thread.Sleep(3);
        int index = random.Next(names.Count);
        var name = names[index];
        names.RemoveAt(index);
        return name;
    }
    else
    {
        return "There are no more new words!! :(";
    }
}

I have also tried a version where I had two different arrays, one an Int-Array and the second a String-Array. It was really messy and did not work.

I am also very new to C# i only know of the basics, like +-/*, convert, functions, and arrays.

Answers


static readonly List<string> Words = new List<string>(wordArr);
static readonly Random Rnd = new Random();

public string Next()
{
    if(Words.Count < 1)
        return "There are no more new words!! :(";

    var index = Rnd.Next(0, Words.Length);
    var result = Words[index];
    Words.RemoveAt(index);

    return result;
}

Conceptually, you either keep track of strings you already used, or you remove strings from the list of optional strings as you use them.

To implement the first method, you can keep a hashtable of strings you've already used, and when pulling a new string - see if it is present in the hashtable (and if so, pick another one, until a "fresh" string is picked).

To implement the second method, just remove the strings you picked from the list as you pick them.


If you shuffle your word array:

var r = new Random();
var shuffledWords = wordArr.OrderBy(_ => r.Next());

then push your words into a Stack:

var wordStack = new Stack<string>(shuffledWords);

now you have a structure that will hand you random word from the collection while simultaneously removing it from the collection by using the Pop method of Stack<T> (considerably more efficiently than removing items from the front/middle of a List<T>, although your collection is so small, it hardly matters).

var someWord = wordStack.Pop();

Use KeyValuePair.

The key will be your word, the value will be how many times it's been used, then just take the least used word and increment its counter.

List<KeyValuePair<string, int>>

You should represent your WordArr as a list. It's easier to work with to suit your needs.

Here's an easy way to randomize your list:

List<string> wordArr = new List<string>()
{
    "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO"
};
Random random = new Random();
wordArr = wordArr.OrderBy(x => random.Next()).ToList();

Then just always take the first word in the list so that you can simply remove each word that you use like this:

wordArr.RemoveAt(0);

When the wordArr is empty then you are done.


Since you've said you're new to programming, I'll explain the key line quickly:

.Except() compares your array to the other array and returns only unique elements. .OrderBy(x => rn.Next()) will return the array in a random order. .FirstOrDefault() will get the first entry from the array or, if the array is empty, return null.

public void GenerateWord()
{
    Random rn = new Random();
    string[] attemptedWords = LoadUsedWords();
    string[] wordArr = { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL", "STUDIO" };
    string word = wordArr.Except(attemptedWords).OrderBy(x => rn.Next()).FirstOrDefault();
    if (string.IsNullOrEmpty(word))
    {
        Console.WriteLine("Oh no");
    }
    else
    {
        Console.WriteLine(word);
    }
}

public string[] LoadUsedWords()
{
    return new string[] { "PROGRAMMERING", "CSHARP", "STOL", "ELEV", "VISUAL" };
}

Need Your Help

COUNT number of rows in a GROUP on higher aggregate level

sql-server

I am trying to find out how many rows of a certain item exist in the table, e.g. in the following example for itemID 1 I need the result 5 (not 3, which is what I currently get). I am tempted to add

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.