1

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.

4
  • possible duplicate of Non-repetitive random number C# Commented Mar 1, 2014 at 23:12
  • Hard to follow the differences in your methods, but don't declare the Random class in a method. Just use a single instance throughout your code. Commented Mar 1, 2014 at 23:13
  • Pierre-Luc, he is asking for the same method, but for Int not string. L.B. Sorry for the messy code... Wil move the random class :) Commented Mar 1, 2014 at 23:21
  • I have edited your title. Please see, "Should questions include “tags” in their titles?", where the consensus is "no, they should not". Commented Mar 1, 2014 at 23:31

6 Answers 6

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

In the second method, the strings that have been chosen gets removed with: "names.RemoveAt(index);". But when i run this multiple times i still get duplicates...
2

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();

Comments

0
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;
}

6 Comments

Random.Next has odd semantics. The second parameter is one higher than the upper bound you need. So your call should be Rnd.Next(0, Words.Length) without the ` - 1`.
Also, how does this code keep track of what words have already been used?
Not keeping used words, removing used words from collection, if you need to know used words then wordArr.Except(Words) will be enough.
I dont need to keep track of what words I've already used when all the used words are deleted. I can keep track of how many tries I've used with a simple Int Counter :)
@TolgahanAlbayrak - My apologies - I missed the RemoveAt in your code. I think I need to get some more sleep. :-)
|
0

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>>

2 Comments

Yeah, same thing. :P I only used List because that's what he was already working with.
0

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.

Comments

0

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" };
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.