Code iterating through whole string in hangman - vb.net

How can I stop my code from iterating through a whole string stating whether the input from the user matches that of the random string bearing in mind this is for a hangman game, I want the code to just display once if the user's chosen letter is either correct or incorrect rather than displaying up too eight times.
Sub letterInput()
For i As Integer = 0 To randomWord.Length - 1
If userInput = randomWord(i) Then
MessageBox.Show("correct")
ElseIf userInput <> randomWord(i) Then
MessageBox.Show("incorrect")
Label4.Text = counter
Exit for
End If
Next
End Sub
Sub wordGeneration()
Dim wordUsed As Array = {"pizza", "noodle", "zombie", "object", "rowin", "running", "elephant", "lion"}
Dim random As New Random
randomWord = wordUsed(random.Next(0, 9))
Label2.Text = randomWord
End Sub

What I meant in the comments was that you just need to replace your for loop with a simple if/else. String.Contains checks the whole string already, so there is no need to iterate through each letter anymore:
Sub letterInput()
If randomWord.Contains(userInput) Then
MessageBox.Show("correct")
Else
MessageBox.Show("incorrect")
Label4.Text = counter
End If
End Sub

Related

I want to save a file in VB.net from the amount of tries a user has

I'm a student trying to learn Console App .Net Framework and I want to code a random number between 0000 and 9999 (as a pin that you need to guess). Thus far I've had to set it as a random number from 1000 to 9999 as the system wont let me do 0000. Furthermore, I want to save the amount of tries the user has as a text file e.g. if the user tries 50 times, I'd like it to say
Username Tries
I've tried Randomise() Rnd(*9999) and X = EasyNum.Next(1000, 9999) but then I can't compare unless I convert that to an integer.
Module Module1
Dim Tries As String = 0
Dim EasyNum As New Random
Dim HardNum As New Random
Dim Attempt As String
Sub Main()
Dim Difficulty As String
Console.WriteLine("Welcome to MasterMind")
Console.WriteLine("Choose between Easy and Hard difficulty")
Difficulty = Strings.LCase(Console.ReadLine)
While Difficulty <> "easy" And Difficulty <> "hard"
Console.WriteLine("That's not a correct mode")
Difficulty = Strings.LCase(Console.ReadLine)
End While
If Difficulty = "easy" Then
Easy()
ElseIf Difficulty = "hard" Then
Hard()
End If
End Sub
Dim EasyGuess1 As Integer
Dim EasyGuess2 As Integer
Dim X As String
Dim Y As Integer
Sub Easy()
Console.WriteLine("You have chosen the easy difficulty")
Console.WriteLine("You have to guess a 4 Digit number between 1000 and 9999")
Console.WriteLine("Enter your guess")
X = EasyNum.Next(1000, 9999)
Console.WriteLine(X)
EasyGuess1 = Console.ReadLine
Tries = +1
If Mid(CStr(EasyGuess1), 1, 1) = Mid(CStr(X), 1, 1) Then
Console.WriteLine("You have 1 number correct, try again?")
Attempt = Strings.LCase(Console.ReadLine)
While Attempt <> "yes" And Attempt <> "no"
Console.WriteLine("Enter either yes or no")
Attempt = Strings.LCase(Console.ReadLine)
End While
ElseIf Mid(CStr(EasyGuess1), 2, 1) = Mid(CStr(X), 2, 1) Then
Console.WriteLine("You have 1 number correct, try again?")
Attempt = Strings.LCase(Console.ReadLine)
While Attempt <> "yes" And Attempt <> "no"
Console.WriteLine("Enter either yes or no")
Attempt = Strings.LCase(Console.ReadLine)
End While
End If
If Attempt = "yes" Then
EasyYes()
ElseIf Attempt = "no" Then
EasyNo()
End If
Console.WriteLine("incorrect")
Console.ReadKey()
End Sub
Sub EasyYes()
Console.WriteLine("Enter a new guess")
EasyGuess1 = Console.ReadLine
End Sub
Sub EasyNo()
Dim Save As String
Dim File As System.IO.File
Console.WriteLine("Do you want to save your tries? Enter Yes or no")
Save = Strings.LCase(Console.ReadLine)
If Save = "yes" Then
System.IO.File.Create(Tries, "C:\X\Code\VB\Challenges\Challenge 1\MasterMind Test")
End If
End Sub
Sub Hard()
Console.WriteLine("You have chosen the hard difficulty")
End Sub
Sub HardYes()
End Sub
Sub HardNo()
End Sub
End Module
When I try to save the tries, I get this:
System.InvalidCastException: 'Conversion from string "C:\X\Code\VB\Challenges\Cha" to type 'Integer' is not valid.'
InnerException
FormatException: Input string was not in a correct format.
Which I don't understand myself.
Comments in line. Please read all comments. This program is still not working too well but I will leave it to you to tidy up.
Module Module1
Dim Tries As Integer = 0
'Use only a single instance of Random
Dim EasyNum As New Random
'Dim HardNum As New Random
Dim Attempt As String
Sub Main()
Dim Difficulty As String
Console.WriteLine("Welcome to MasterMind")
Console.WriteLine("Choose between Easy and Hard difficulty")
Difficulty = Strings.LCase(Console.ReadLine)
'AndAlso prevents the second condition from executing if the first condition is true
While Difficulty <> "easy" AndAlso Difficulty <> "hard"
Console.WriteLine("That's not a correct mode")
Difficulty = Strings.LCase(Console.ReadLine)
End While
If Difficulty = "easy" Then
Easy()
'ElseIf Difficulty = "hard" Then
' Hard() 'Not implemented
End If
End Sub
'Dim EasyGuess2 As Integer
'Dim X As String
'Dim Y As Integer
Sub Easy()
Dim EasyGuess1 As Integer
Console.WriteLine("You have chosen the easy difficulty")
Console.WriteLine("You have to guess a 4 Digit number between 1000 and 9999")
Console.WriteLine("Enter your guess")
'X = EasyNum.Next(1000, 9999)
'The next method returns a non-negative integer not a string
'To get 0 to 9999 with leading zeros do the following
'Returns a non-negative random integer that is less than the specified maximum.
Dim X = EasyNum.Next(10000).ToString("0000")
Console.WriteLine(X)
'Console.ReadLine returns a String. You should Not assign a String to an Integer
'EasyGuess1 = Console.ReadLine
'Never trust a user :-) Use .TryParse to set the variable
Integer.TryParse(Console.ReadLine, EasyGuess1)
'This just assigns the value of 1 to Tries
'Tries = +1
'If you want to increment Tries
Tries += 1
'Let's compare apples and apples
'If you just convert EasyGuess1 To a string and EasyGuess1 is 54
'the string is "54" You want a 4 character string
'If Mid(EasyGuess1.ToString("0000"), 1, 1) = Mid(CStr(X), 1, 1) Then
' 'but you only compared the first character, what about the rest?
' 'Mid is aroung for backward compatibility. It should not be used for new code.
' 'The position Integer is one based which is not at all sympatico with .net
' Console.WriteLine("You have 1 number correct, try again?")
' Attempt = Strings.LCase(Console.ReadLine)
' While Attempt <> "yes" And Attempt <> "no"
' Console.WriteLine("Enter either yes or no")
' Attempt = Strings.LCase(Console.ReadLine)
' End While
'ElseIf Mid(CStr(EasyGuess1), 2, 1) = Mid(CStr(X), 2, 1) Then
' Console.WriteLine("You have 1 number correct, try again?")
' Attempt = Strings.LCase(Console.ReadLine)
' While Attempt <> "yes" And Attempt <> "no"
' Console.WriteLine("Enter either yes or no")
' Attempt = Strings.LCase(Console.ReadLine)
' End While
'End If
Dim CorrectCharacters = TestInput(EasyGuess1, X)
Console.WriteLine($"You have guessed {CorrectCharacters} correctly. Try again?")
'Use the .net way. The framework is available to all languages in .net
'so it will be easier to learn other languages.
Attempt = (Console.ReadLine).ToLower
If Attempt = "yes" Then
EasyYes()
ElseIf Attempt = "no" Then
EasyNo()
End If
Console.WriteLine("incorrect")
Console.ReadKey()
End Sub
Sub EasyYes()
Dim guess As Integer
Console.WriteLine("Enter a new guess")
'You are doing this twice ???
'EasyGuess1 = Console.ReadLine
Integer.TryParse(Console.ReadLine, guess)
'EasyGuess1 will be 0 if the entry is other than an integer
'Very nice bu this Sub doesn't do anything
End Sub
Sub EasyNo()
Dim Save As String
'Unused local variable and if you needed this it is a poor choice for a variable name
'Dim File As System.IO.File
Console.WriteLine("Do you want to save your tries? Enter Yes or no")
Save = Console.ReadLine.ToLower
If Save = "yes" Then
'Give the file name an extension.
'When you pass (String, Integer) to the Create method, the Integer is the number of bytes
'buffered for reads And writes to the file.
'Not exactly what you were expecting.
'System.IO.File.Create("C:\X\Code\VB\Challenges\Challenge 1\MasterMind Test.txt", Tries)
'Imports System.IO at top of file
File.WriteAllText("C:\X\Code\VB\Challenges\Challenge 1\MasterMind Test.txt", Tries.ToString)
End If
End Sub
Sub Hard()
Console.WriteLine("You have chosen the hard difficulty")
End Sub
Private Function TestInput(Guessed As Integer, RandString As String) As Integer
Dim Correct As Integer
Dim Guess As String = Guessed.ToString("0000")
'A String can be a Char array
'Here we check each character in the 2 strings for equality
'and if true then increment Correct
For i = 0 To 3
If Guess(i) = RandString(i) Then
Correct += 1
End If
Next
Return Correct
End Function
End Module
There are a lot of issues, but I don't want to spoil it for you.
I definitely recommend to put "Option Strict On" in the project settings, so you immediately see where there are conversion errors (a string assigned to a integer etc).
To save the file, it should be something like
If Save = "yes" Then
File.WriteAllText("C:\X\Code\VB\Challenges\Challenge 1\MasterMind Test", Tries.ToString())
End If
(there are also File.Append... functions).
The Random class is a bit tricky, this is an object that provides random values and is not yet the random value itself. Always use the same random object for all different numbers, otherwise you might get the same number:
Private Randomizer As New Random(Environment.TickCount)
Private EasyNum As Int32 = Randomizer.Next(0, 10000) '0 to 9999
Private HardNum As Int32 = Randomizer.Next(0, 100000) '0 to 99999
The "from" value of the randomizer's Next method is always inclusive, the "to" value exclusive, for whatever reasons.
To increment a variable, the syntax is
Tries += 1
instead of "Tries = +1"
To write a number with leading digits, use might use
Console.Out.WriteLine($"The correct solution would have been: {EasyNum:0000}")
or
EasyNum.ToString("0000")

If condition being ignored

I'm currently writing code for a game called Caladont.
The game is about first player saying the word and the next one has to say the word that starts with last two letters of previous word.
The problem comes when I want to check if word contains less than 3 letters or if it's empty.
In the first cycle when list for filling is still empty, everything is fine.
However, after I type for example 5 or more words and type a single letter or leave it empty, it prints two "You've lost!" messages, which means that code from if statement is being ignored since it changes bool variable to false and is supposed to exit the While loop.
I've tried replacing ok = false with Exit While in condition which checks if words contains less than 3 letters and it worked, but I want to understand what is the problem.
The code can also be found here [Caladont game
GitHub](https://github.com/whistleblower91/VB.net/blob/master/Caladont%20game):
Module Module1
Sub Main()
Kaladont()
End Sub
Sub Kaladont()
Const msg As String = "You've lost!"
Dim list As New List(Of String)
Dim word As String
Dim i As Integer
Dim ok As Boolean
ok = True
While ok
Console.Write("Insert word:")
word = Console.ReadLine()
list.Add(word)
If word.Length < 3 Or word = "" Then
Console.WriteLine(msg)
ok = False
End If
If list.Count > 1 Then 'Skip checking first word
For i = 0 To list.Count - 2
If word.ToLower = lista(i).ToLower Then
Console.WriteLine(msg)
ok = False
End If
Next
If LastTwo(word) = "ka" Or LastTwo(word)="nt" Then
Console.WriteLine("KALADONT! You won!")
ok = False
End If
If FirstTwo(list.Last) <> LastTwo(list(list.Count - 2)) Then
Console.WriteLine(msg)
ok = False
End If
End If
End While
Check()
End Sub
Function FirstTwo(ByVal s1 As String) As String
Return Left(s1.ToLower, 2)
End Function
Function LastTwo(ByVal s2 As String) As String
Return Right(s2.ToLower, 2)
End Function
Sub Check()
Dim sign As Char
Console.WriteLine("Do you want to start new game? y\n")
sign = Console.ReadLine()
If sign = CChar("y") Then
Console.Clear()
Kaladont()
ElseIf sign = CChar("n") Then
Exit Sub
End If
End Sub
End Module
Any solutions?
Even if you set ok to false, it will still go inside the other loop, you'll need to use Else
If word.Length < 3 Or word = "" Then
Console.WriteLine(msg)
ok = False
Else If list.Count > 1 Then 'Skip checking first word
An other way would be to exit the while with End while.
If word.Length < 3 Or word = "" Then
Console.WriteLine(msg)
ok = False
Exit While
End If

Encode and Decode VBA Program

in my programming class I have to create a program which allows the user in order to enter a sentence, with the buttons "Encode" and "Decode" as options. So, for "Encode", you have to translate the sentence into Asc numbers (already did this). However, I'm currently stuck on the "Decode" section, for you have to use a For loop and an array to separate the Asc numbers by spaces, then translate them into characters one by one. Here's what I have so far:
Public Class Form1
Dim Message As String
Dim NewMessage As String
Dim Part As String
Dim Part2 As Integer
Dim Letter As String
Dim Length As String
Dim ints() As Integer
Dim intlength As Integer
Private Sub btn_Enter_Click(sender As Object, e As EventArgs) Handles btn_Enter.Click
Message = txt_Message.Text
Length = Message.Length() - 1
If rbn_Encode.Checked = True Then
For Num As Integer = 0 To Length
Letter = Message(Num)
Me.lbl_Code.Text = lbl_Code.Text & Asc(Letter) & " "
Next
End If
If rbn_Decode.Checked = True Then
For Num As Integer = 0 To intlength Step 1
If Message(Num) <> " " Then
Part = Part & Message(Num)
Else
NewMessage = NewMessage & ChrW(Part) & " "
End If
Next
Me.lbl_Code.Text = NewMessage
End If
End Sub
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
Application.Exit()
End Sub
End Class
I've been stuck on this for about 2 week, and I'm still clueless. Thank you for your help and have a wonderful day.
This might seem to veer off the topic of the question, but it all meanders towards a better answer.
OK there are a few issues with your code. Firstly, make sure that "Option Strict" is on - have a look here. This will force you to convert types properly and reduce the potential for problems. Bearing the above in mind,
Dim Length As String
should be
Dim Length As Integer
on to the next bit
Each procedure should have a single responsibility. Your btn_Enter.Click event handler includes code for encoding text and decoding numbers. These should be separated out into their own procedures. In a relatively short bit of code like yours, it's not too much of a problem, but even here, it makes things a little fuzzier. Have a look at the code below. There are more issues, but we'll look at them in a moment. The code below is a bit clearer and more maintainable.
Private Sub btn_Enter_Click(sender As Object, e As EventArgs) Handles btn_Enter.Click
Message = txt_Message.Text
Length = Message.Length() - 1
If rbn_Encode.Checked = True Then
EncodeTextToAscii()
End If
If rbn_Decode.Checked = True Then
DecodeToText()
End If
End Sub
Private Sub DecodeToText()
For Num As Integer = 0 To intlength Step 1
If Message(Num) <> " " Then
Part = Part & Message(Num)
Else
NewMessage = NewMessage & ChrW(Part) & " "
End If
Next
Me.lbl_Code.Text = NewMessage
End Sub
Private Sub EncodeTextToAscii()
For Num As Integer = 0 To Length
Letter = Message(Num)
Me.lbl_Code.Text = lbl_Code.Text & Asc(Letter) & " "
Next
End Sub
Next.
In your code to encode the string as ASCII, you store the resulting data directly in the label lbl_Code's text property. The user interface should never be used as the primary store for data. It's bad practice and potentially allows the user to change data accidentally - in textboxes for example. In the case of a label, it's not to important, but it's far better to get into the good habits.
To store your encoded ASCII numbers, you can use the array ints, but as your code stands, the declaration of ints is just that. There is no space in the array to store data. So, in the Encode procedure, you need to resize ints to the same as the number of characters in the string.
So now we have ..
Private Sub EncodeTextToAscii()
ReDim ints(Length)
For Num As Integer = 0 To Length
Letter = Message(Num)
ints(Num) = Asc(Letter)
Next
End Sub
Finally onto the meat of your question. The Decode procedure can now be written as this ..
Private Sub DecodeToText()
NewMessage = ""
For Each asciiNumber As Integer In ints
NewMessage = NewMessage & ChrW(asciiNumber) & " "
Next
Me.lbl_Code.Text = NewMessage
End Sub
Instead of mucking around getting the length of a loop and getting the ascii number in each element of an array, you can simplyfy it using a For Each statement. You dont need to know the length of the array. It just loops over the whole length. Much easier.
As an excercise, try applying the For Each idea to the Encode procedure. :-)

How to stop message box repeating because of array?

I'm trying to make a hangman game and to input "incorrect" if the user picks the wrong letter but it will keep repeating because of the randomWord which chooses the word from an array how do I stop this?
Sub wordGeneration()
Dim wordUsed As Array = {"pizza", "noodle", "zombie", "object", "rowin", "running", "elephant", "lion"}
Dim random As New Random
randomWord = wordUsed(random.Next(0, 8))
Label2.Text = randomWord
End Sub
Sub letterInput()
For i As Integer = 0 To randomWord.Length - 1
If userInput = randomWord(i) Then
MessageBox.Show("correct")
ElseIf userInput <> randomWord(i) Then
MessageBox.Show("incorrect")
Label4.Text = counter
End If
Next
End Sub
Simpler and faster to let VB do the search for you.
Sub letterInput()
if InStr(randomWord.Length, userInput) > 0
MessageBox.Show("correct")
Else
MessageBox.Show("incorrect")
Label4.Text = counter
End If
End Sub
Note: I am assuming userInput is a single character.

permutation not accepting large words

the vb.net code below permutates a given word...the problem i have is that it does not accept larger words like "photosynthesis", "Calendar", etc but accepts smaller words like "book", "land", etc ...what is missing...Pls help
Module Module1
Sub Main()
Dim strInputString As String = String.Empty
Dim lstPermutations As List(Of String)
'Loop until exit character is read
While strInputString <> "x"
Console.Write("Please enter a string or x to exit: ")
strInputString = Console.ReadLine()
If strInputString = "x" Then
Continue While
End If
'Create a new list and append all possible permutations to it.
lstPermutations = New List(Of String)
Append(strInputString, lstPermutations)
'Sort and display list+stats
lstPermutations.Sort()
For Each strPermutation As String In lstPermutations
Console.WriteLine("Permutation: " + strPermutation)
Next
Console.WriteLine("Total: " + lstPermutations.Count.ToString)
Console.WriteLine("")
End While
End Sub
Public Sub Append(ByVal pString As String, ByRef pList As List(Of String))
Dim strInsertValue As String
Dim strBase As String
Dim strComposed As String
'Add the base string to the list if it doesn't exist
If pList.Contains(pString) = False Then
pList.Add(pString)
End If
'Iterate through every possible set of characters
For intLoop As Integer = 1 To pString.Length - 1
'we need to slide and call an interative function.
For intInnerLoop As Integer = 0 To pString.Length - intLoop
'Get a base insert value, example (a,ab,abc)
strInsertValue = pString.Substring(intInnerLoop, intLoop)
'Remove the base insert value from the string eg (bcd,cd,d)
strBase = pString.Remove(intInnerLoop, intLoop)
'insert the value from the string into spot and check
For intCharLoop As Integer = 0 To strBase.Length - 1
strComposed = strBase.Insert(intCharLoop, strInsertValue)
If pList.Contains(strComposed) = False Then
pList.Add(strComposed)
'Call the same function to review any sub-permutations.
Append(strComposed, pList)
End If
Next
Next
Next
End Sub
End Module
Without actually creating a project to run this code, nor knowing how it 'doesn't accept' long words, my answer would be that there are a lot of permutations for long words and your program is just taking much longer than you're expecting to run. So you probably think it has crashed.
UPDATE:
The problem is the recursion, it's blowing up the stack. You'll have to rewrite your code to use an iteration instead of recursion. Generally explained here
http://www.refactoring.com/catalog/replaceRecursionWithIteration.html
Psuedo code here uses iteration instead of recursion
Generate list of all possible permutations of a string