Why is this program ignoring the Values field? - vb.net

Structure WeightElement
Dim LowPointer As Integer
Dim HighPointer As Integer
Dim TraitPointer As Integer
Dim Values As WeightedTrait()
Dim Num As Integer
End Structure
Structure WeightedTrait
Dim TraitName As String
Dim TraitNum As Integer
Dim WeightValue As Decimal
End Structure
Function DefaultWeights()
Dim Weight(39) As WeightElement
Weight(0).LowPointer = 1
Weight(0).HighPointer = 2
Weight(0).Num = 5
Weight(0).Values = DefaultValues({"Black", "White", "East Asian", "South Asian", "Middle Eastern"}, {26, 30, 27, 28, 29})
Return Weight
End Function
Function DefaultValues(NameArray() As String, NumArray() As Integer)
Dim Weight(NameArray.Length) As WeightedTrait
For x = 0 To NameArray.Length - 1
Weight(x).TraitName = NameArray(x)
Weight(x).TraitNum = NumArray(x)
Weight(x).WeightValue = 1
Next
Return Weight
End Function
Sub Main()
Dim Query As String = ""
Dim Weight() As WeightElement = DefaultWeights()
For x = 0 To 38
Query += Str(Weight(x).LowPointer)
Query += ","
Query += Str(Weight(x).HighPointer)
Query += ","
Query += Str(Weight(x).TraitPointer)
Query += ","
Query += Str(Weight(x).Num)
Query += ","
Try
For y = 0 To Weight(x).Values.Length - 1
Query += Str(Weight(x).Values(y).TraitName)
Query += ","
Query += Str(Weight(x).Values(y).TraitNum)
Query += ","
Query += Str(Weight(x).Values(y).WeightValue)
Query += ","
Next
Catch
Query += "FLOCK"
End Try
Query += ";"
Next
Console.WriteLine(Query)
End Sub
The code is supposed to transform a weight into a string, yet when I run it the values in the Values array in the weight is nowhere to be seen. Instead, for some reason it decides to always go down the catch statement, and append that instead. Why won't it acknowledge the Values array?

DefaultWeights() only initializes one WeightElement so only Weight(0).Values is set. Weight(1).Values to Weight(39).Values remain set to Nothing so the Length property is not available and an error is raised.
Note that the most accurate way to find the upper bound of an array is to use the GetUpperBound function. For one-dimensional arrays, the dimension parameter = 0.In this case, the array has been created with the upper bound set to 39 (room for 40 elements). If this size was changed, the Main code would not need to be updated with the new size.
I have also modified the code to only output the Query string if Weight(x).Values has been populated.
Sub Main()
Dim Query As String = ""
Dim Weight() As WeightElement = DefaultWeights()
For x = 0 To Weight.GetUpperBound(0)
Try
If Weight(x).Values IsNot Nothing Then
Query += CStr(Weight(x).LowPointer)
Query += ","
Query += CStr(Weight(x).HighPointer)
Query += ","
Query += CStr(Weight(x).TraitPointer)
Query += ","
Query += CStr(Weight(x).Num)
For y = 0 To Weight(x).Values.GetUpperBound(0)
Query += ","
Query += CStr(Weight(x).Values(y).TraitName)
Query += ","
Query += CStr(Weight(x).Values(y).TraitNum)
Query += ","
Query += CStr(Weight(x).Values(y).WeightValue)
Next
Query += ";"
End If
Catch
Query += "FLOCK;"
End Try
Next
Console.WriteLine(Query)
End Sub

Related

I want to make a maths quiz on vb.net that uses bracket questions

So I've used visual basics (vb.net) for a bit now and understand some stuff. Right now I want to make a maths quiz that when I click a button it takes me to a new form and starts the quiz. When the quiz starts I want it so it gives the user random numbers and the user needs to answer it in a textbox and if correct it moves on to the next question (Basic, I should be able to do). IMPORTANT - my question is, there's a maths rule called BODMAS (Bracket.Order.Division.Multiply.Add.Subtract) and I want to add this rule into my coding instead of doing regular simple maths...
EXAMPLE question is 2 x (2+3) - 1 = ?
2 x 5 - 1 = ?
10 - 1 = ?
9 = 9
person writes answer to textbox and moves to next similar question
This is my first time using this but I wanted to write in-depth so people can understand. Please help me if you find a video explaining what I'm looking for or if someone has a file with a similar code I could download would be greatly appreciated!
Basically,you need to determine the range of numbers you use, and then match them randomly among '*', '/', '+', '-'. Then randomly insert brackets into it.
Private codeStr As String
Private Function GenerateMathsQuiz() As String
Dim r As Random = New Random()
Dim builder As StringBuilder = New StringBuilder()
'The maximum number of operations is five, and you can increase the number [5] to increase the difficulty
Dim numOfOperand As Integer = r.[Next](1, 5)
Dim numofBrackets As Integer = r.[Next](0, 2)
Dim randomNumber As Integer
For i As Integer = 0 To numOfOperand - 1
'All numbers will be random between 1 and 10
randomNumber = r.[Next](1, 10)
builder.Append(randomNumber)
Dim randomOperand As Integer = r.[Next](1, 4)
Dim operand As String = Nothing
Select Case randomOperand
Case 1
operand = "+"
Case 2
operand = "-"
Case 3
operand = "*"
Case 4
operand = "/"
End Select
builder.Append(operand)
Next
randomNumber = r.[Next](1, 10)
builder.Append(randomNumber)
If numofBrackets = 1 Then
codeStr = InsertBrackets(builder.ToString())
Else
codeStr = builder.ToString()
End If
Return codeStr
End Function
Public Function InsertBrackets(ByVal source As String) As String
Dim rx As Regex = New Regex("\d+", RegexOptions.Compiled Or RegexOptions.IgnoreCase)
Dim matches As MatchCollection = rx.Matches(source)
Dim count As Integer = matches.Count
Dim r As Random = New Random()
Dim numIndexFirst As Integer = r.[Next](0, count - 2)
Dim numIndexLast As Integer = r.[Next](1, count - 1)
While numIndexFirst >= numIndexLast
numIndexLast = r.[Next](1, count - 1)
End While
Dim result As String = source.Insert(matches(numIndexFirst).Index, "(")
result = result.Insert(matches(numIndexLast).Index + matches(numIndexLast).Length + 1, ")")
Return result
End Function
When you finish this, you will get a math quiz, then you need to know how to compile and run code at runtime.
Private Function GetResult(ByVal str As String) As String
Dim sb As StringBuilder = New StringBuilder("")
sb.Append("Namespace calculator" & vbCrLf)
sb.Append("Class calculate " & vbCrLf)
sb.Append("Public Function Main() As Integer " & vbCrLf)
sb.Append("Return " & str & vbCrLf)
sb.Append("End Function " & vbCrLf)
sb.Append("End Class " & vbCrLf)
sb.Append("End Namespace" & vbCrLf)
Dim CompilerParams As CompilerParameters = New CompilerParameters()
CompilerParams.GenerateInMemory = True
CompilerParams.TreatWarningsAsErrors = False
CompilerParams.GenerateExecutable = False
CompilerParams.CompilerOptions = "/optimize"
Dim references As String() = {"System.dll"}
CompilerParams.ReferencedAssemblies.AddRange(references)
Dim provider As VBCodeProvider = New VBCodeProvider()
Dim compile As CompilerResults = provider.CompileAssemblyFromSource(CompilerParams, sb.ToString())
If compile.Errors.HasErrors Then
Dim text As String = "Compile error: "
For Each ce As CompilerError In compile.Errors
text += "rn" & ce.ToString()
Next
Throw New Exception(text)
End If
Dim Instance = compile.CompiledAssembly.CreateInstance("calculator.calculate")
Dim type = Instance.GetType
Dim methodInfo = type.GetMethod("Main")
Return methodInfo.Invoke(Instance, Nothing).ToString()
End Function
Finally, you can use these methods like:
Private Sub GetMathQuizBtn_Click(sender As Object, e As EventArgs) Handles GetMathQuizBtn.Click
Label1.Text = GenerateMathsQuiz()
End Sub
Private Sub ResultBtn_Click(sender As Object, e As EventArgs) Handles ResultBtn.Click
If TextBox1.Text = GetResult(Label1.Text) Then
MessageBox.Show("bingo!")
TextBox1.Text = ""
Label1.Text = GenerateMathsQuiz()
Else
MessageBox.Show("result is wrong")
End If
End Sub
Result:

How to use the Compute to calculate the total with Double Datatype

I have expression string:
dim str as string = "999999999 * 999999999"
I use DataTable.Compute to calculate:
dim dt as new datatable
dim result as double = 0
result = cdbl(dt.Compute(str))
And I get an error:
Value is either too large or too small for Type 'Int32'.
How can I control result datatype in this case?
Solution:
This function work like Windows's Calculator. Code so confuse but it work :)
'input = "999,999,999 x 888,888,888 + 112,365 ÷ 15 − 987,653"
Public Shared Function strCalc(ByVal input As String) As String
If input.Substring(input.Length - 1, 1) = " " Then input = input.Substring(0, input.Length - 3)
input = input.Replace("−", "-").Replace("x", "*").Replace("÷", "/").Replace(",", "")
Dim temp As Double = 0
Dim arr() As String = input.Split(" ")
If arr.Length > 1 Then
temp = New DataTable().Compute(If(arr(0).Contains("."), arr(0), arr(0) & ".0") & " " & arr(1) & " " &
If(arr(2).Contains("."), arr(2), arr(2) & ".0"), "")
If arr.Length > 3 Then
For i As Integer = 3 To arr.Length - 1 Step 2
temp = New DataTable().Compute(temp & " " & arr(i) & " " &
If(arr(i + 1).Contains("."), arr(i + 1), arr(i + 1) & ".0"), "")
Next
End If
Return temp
End If
Return input
End Function
Runtime is treating your expression 999999999 * 999999999 as a multiplication of two integer values, and trying to return it as an object which is the return type of Compute API. The output of multiplication of those numbers is resulting in a very large value which is crossing the maximum value which can be stored in a variable of int (System.Int32) data type.
It results in arithmetic overflow exception. To give a hint to the runtime so that it considers the expression as a multiplication of two double numbers please use following code:
dim str as string = "999999999.0 * 999999999.0"

Compare two strings and find where letter positions match

I want to do a bitwise and on two strings so that:
Given:
Dim word As String = "abcd"
Dim temp As String = "a-d-"
I want to return only the 'a'
Given:
Dim word As String = "abcd"
Dim temp As String = "a--d"
I want to return only the 'a--d'
I have tried intersect, but it only finds characters in one string that match the characters in the other regardless of position.
I've used the '-' to represent spaces here.
Any suggestions would be appreciated.
This will handle strings with mis-matched lengths:
Public Function CheckMask(ByVal word As String, ByVal mask As String) As String
Dim wordChars() As Char = word.ToCharArray()
Dim maskChars() As Char = mask.ToCharArray()
Dim i As Integer = 0
While i < wordChars.Length AndAlso i < maskChars.Length
If wordChars(i) <> maskChars(i) Then wordChars(i) = " "c
i = i + 1
End While
'If string lengths are equal or the mask is longer, we're done
'If the word is longer, need to set remaining characters to " "
While i < wordChars.Length
wordChars(i) = " "c
End While
Return New String(wordChars)
End Function
Dim Res As String = ""
For i = 0 To Math.Min(StrA.Length, StrB.Length) - 1
If StrA(i) = StrB(i) Then Res &= StrA(i) Else Res &= " "
Next
Return Res
This basically loops to the end of the shorter one of the two strings. If the letters at a given position match the letter is added to the result, else a space is added.
Dim sFirstWord As String = "qwerty"
Dim sSecndWord As String = "qseftg"
Dim sResult As String = ""
For i As Integer = 0 To Math.Min(sFirstWord.Length, sSecndWord.Length) - 1
If sFirstWord(i) = sSecndWord(i) Then
sResult &= sFirstWord(i)
Else
sResult &= " "
End If
Next
sResult will hold: "q e t "

Comparing Strings

I would like to compare two strings in a vb.net windows application
Imports System.Windows
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim s As String = "$99"
Dim y As String = "$9899"
If s > y Then
MessageBox.Show("Hi")
End If
End Sub
End Class
Could anyone one correct the logic if there is any mistake in that?
You are comparing strings, not integers.
You could compare them as integers by replacing "$" with "" and then convert it to an integer.
Replace the $ to ""
s = s.Replace("$", "");
y = y.Replace("$", "");
Convert both of them to integers
Dim result1 As Integer
Dim result2 As Integer
result1 = Convert.ToInt32(s)
result2 = Convert.Toint32(y);
Then you can do
if (result1 > result2) { ... }
Dim sum1 As Int32 = 99
Dim sum2 As Int32 = 9899
'this works as expected because you are comparing the two numeric values'
If sum1 > sum1 Then
MessageBox.Show("$" & sum1 & " is greater than $" & sum2)
Else
MessageBox.Show("$" & sum2 & " is greater than $" & sum1)
End If
'if you really want to compare two strings, the result would be different than comparing the numeric values'
'you can work around this by using the same number of digits and filling the numbers with leading zeros'
Dim s As String = ("$" & sum1.ToString("D4")) '$0099'
Dim y As String = ("$" & sum2.ToString("D4")) '$9899'
If s > y Then
MessageBox.Show(s & " is greater than " & y)
Else
MessageBox.Show(y & " is greater than " & s)
End If
I recommend always to use Integers for numeric values, particularly if you want to compare them. You can format the values as string after you compared the numeric values.
What do you mean compare by length or content?
dim result as string
dim s as string = "aaa"
dim y as string = "bbb"
if s.length = y.length then result = "SAME" '= true
if s = y then result = "SAME" '= false
MessageBox.Show(result)

for loop for a string variable

this is my code -
for i as integer = 0 to rows.count - 1
output &= "Name =" & row(i)("Name")
output &= "lastName =" & row(i)("lastName")
... 50 more fields
next
i need the output to be like this
Applicant1Name = MikeApplicant1lastName = ditkaApplicant2Name = TomApplicant2lastName = Brady ...
how do i do this without putting the following code 50 times -
output &= "Applicant" & i.tostring() + 1 &"Name =" & row(i)("Name")
... and so on.
is there a way to make a for loop and run applicant 1,2,3,4.... in one shot?
thanks
Try:
Dim output as New StringBuilder("")
For i as Integer = 0 To rows.Count - 1
output.append("Applicant" + i.ToString())
Foreach(col as DataColumn in dt.Columns) ' The datatable where your rows are
Dim colName as string = col.ColumnName
output.append(colName & "=" & rows(i)(colName).ToString())
Next
If i < rows.Count - 1 Then output.Append("|")
Next
StringBuilder is faster for string concatenations, and if you keep your rows in a datatable (which I assume is happening because that's how it looks like you're accessing them), then you can just iterate through the columnnames at the top level.
You really cant as you are trying to append 50 different fields.
The only thing you can shorten is the variable name:
Dim strLN as String = row(i)("lastName")
Dim strFirstName as String = row(i)("firstName")
Then you simply put it all together
output &= strLN & strFirstName...etc
looks like you want to create an array of all the fields you have and then include a nested loop.
Dim fields As String() = {"Name", "LastName", "SSN", "Birthdate"}
Dim output As String = ""
For i As Integer = 1 To rows.count
For Each field As String In fields
output = String.Concat(output, "Applicant ", i, field, "=", row(i)(field), " ")
Next
Next