Car Database Loop - vb.net

This code doesn't seem to be working. I don't really know what loop to use to get it too add the information the user puts into the machine to print again.
The aim of this is for the user to either pick:
to print a menu that they have typed in an earlier database. If they haven't typed anything into the database, then it should be blank
Should let the user enter information into the database (What I am mostly struggling with) and do error checking so that it tells them if they have entered a number when they should have entered a letter and
To end the program.
When I do (2) It lets me type but it doesn't recall the information back in the database. Also it needs a number (4) which should return to the main menu. I think this is where the loops come in but I don't know which one to use.
Here is the code:
Structure Cars
Public carmake As String
Public carmodel As String
Public caryear As Integer
Public carlicence As String
End Structure
Module Module1
Sub Main()
Dim userchoice
Console.WriteLine("Choose weather to open the database(1), print it (2) or end (3)")
userchoice = Console.ReadLine()
If userchoice = 1 Then
Dim cardatabase(4) As Cars
Console.WriteLine("This will allow you to view the database.")
Console.WriteLine("Please enter the car make,licence,model and year")
cardatabase(1).carmake = Console.ReadLine()
cardatabase(1).carlicence = Console.ReadLine()
cardatabase(1).carmodel = Console.ReadLine()
cardatabase(1).caryear = Console.ReadLine()
ElseIf userchoice = 2 Then
Console.WriteLine("The database is,")
ElseIf userchoice = 3 Then
Console.WriteLine("Thanks for using this program.")
End If
Console.ReadLine()
End Sub
End Module

You have several issue with this code. Here's what I would recommend:
You need some sort of looping structure such as a While loop. Your test condition could be the userchoice variable.
In your If statements, you need to check if userchoice is equal to a string value instead of an integer value. So the line If userchoice = 1 Then should actually be If userchoice = "1" Then.
The cardatabase array should be declared outside of the loop. When you declare it in the loop, it will keep re-creating the array instead of adding more items to it.
Your Cars structure needs to be inside the Module Module1 block.
Since you don't know how many times the user may want to add a new car before they quit, I'd recommend using a List instead of an Array. Lists allow for easy dynamic re-sizing.
You need an integer variable to track the number of cars entered and use this as an index for your cardatabase collection.
Array/List indexes start with 0.
Cars should probably be a class instead of a structure. Also, it should be named Car. It's a single structure (or class, if you change it). The array itself should be called cars as it is a collection of a multiple Car structures (or objects if you change it to a class).
I was going to write example code here to demonstrate my points but it would be nearly an entire re-write and this would not help you understand why I made the changes I did.
My best advice to you is to go back through your book or tutorials that you read previously to get to this point and really try to understand what they are saying. If you don't get the concept, look it up elsewhere until you do.
Disclaimer: My recommendations are not comprehensive. I stopped examining your code when I identified all of the above issues right off the bat.

Related

Match Words and Add Quantities vb.net

I am trying to program a way to read a text file and match all the values and their quantites. For example if the text file is like this:
Bread-10 Flour-2 Orange-2 Bread-3
I want to create a list with the total quantity of all the common words. I began my code, but I am having trouble understanding to to sum the values. I'm not asking for anyone to write the code for me but I am having trouble finding resources. I have the following code:
Dim query = From data In IO.File.ReadAllLines("C:\User\Desktop\doc.txt")
Let name As String = data.Split("-")(0)
Let quantity As Integer = CInt(data.Split("-")(1))
Let sum As Integer = 0
For i As Integer = 0 To query.Count - 1
For j As Integer = i To
Next
Thanks
Ok, lets break this down. And I not seen the LET command used for a long time (back in the GWBASIC days!).
But, that's ok.
So, first up, we going to assume your text file is like this:
Bread-10
Flour-2
Orange-2
Bread-3
As opposed to this:
Bread-10 Flour-2 Orange-2 Bread-3
Now, we could read one line, and then process the information. Or we can read all lines of text, and THEN process the data. If the file is not huge (say a few 100 lines), then performance is not much of a issue, so lets just read in the whole file in one shot (and your code also had this idea).
Your start code is good. So, lets keep it (well ok, very close).
A few things:
We don't need the LET for assignment. While older BASIC languages had this, and vb.net still supports this? We don't need it. (but you will see examples of that still floating around in vb.net - especially for what we call "class" module code, or "custom classes". But again lets just leave that for another day.
Now the next part? We could start building up a array, look for the existing value, and then add it. However, this would require a few extra arrays, and a few extra loops.
However, in .net land, we have a cool thing called a dictionary.
And that's just a fancy term of for a collection VERY much like an array, but it has some extra "fancy" features. The fancy feature is that it allows one to put into the handly list things by a "key" name, and then pull that "value" out by the key.
This saves us a good number of extra looping type of code.
And it also means we don't need a array for the results.
This key system is ALSO very fast (behind the scene it uses some cool concepts - hash coding).
So, our code to do this would look like this:
Note I could have saved a few lines here or there - but that would make this code hard to read.
Given that you look to have Fortran, or older BASIC language experience, then lets try to keep the code style somewhat similar. it is stunning that vb.net seems to consume even 40 year old GWBASIC type of syntax here.
Do note that arrays() in vb.net do have some fancy "find" options, but the dictionary structure is even nicer. It also means we can often traverse the results with out say needing a for i = 1 to end of array, and having to pull out values that way.
We can use for each.
So this would work:
Dim MyData() As String ' an array() of strings - one line per array
MyData = File.ReadAllLines("c:\test5\doc.txt") ' read each line to array()
Dim colSums As New Dictionary(Of String, Integer) ' to hold our values and sum them
Dim sKey As String
Dim sValue As Integer
For Each strLine As String In MyData
sKey = Split(strLine, "-")(0)
sValue = Split(strLine, "-")(1)
If colSums.ContainsKey(sKey) Then
colSums(sKey) = colSums(sKey) + sValue
Else
colSums.Add(sKey, sValue)
End If
Next
' display results
Dim KeyPair As KeyValuePair(Of String, Integer)
For Each KeyPair In colSums
Debug.Print(KeyPair.Key & " = " & KeyPair.Value)
Next
The above results in this output in the debug window:
Bread = 13
Flour = 2
Orange = 2
I was tempted here to write this code using just pure array() in vb.net, as that would give you a good idea of the "older" types of coding and syntax we could use here, and a approach that harks all the way back to those older PC basic systems.
While the dictionary feature is more advanced, it is worth the learning curve here, and it makes this problem a lot easier. I mean, if this was for a longer list? Then I would start to consider introduction of some kind of data base system.
However, without some data system, then the dictionary feature is a welcome approach due to that "key" value lookup ability, and not having to loop. It also a very high speed system, so the result is not much looping code, and better yet we write less code.

How to make my module move an object using value set in UserForm/

I'm trying to automatize some processes I often do at work. Unfortunately I have no clue about programming so I've been struggling a lot with this.
I have an userform that has a textbox where you're supposed to type in how much you want the object to be moved on X axis. There are multiple objects and I can't wait to experiment how to move them all in proper direction, but the issue is, I can't even move one.
I created a variable, but I can't seem to be able to use it with Object.Move.
Right now VBA tells me to assign the values to an array, so I did that, but I can't put variables into an array apparently.
I've tried simply declaring the variable as public, calling it let's say for example "Value", and using Object.Move (Value), 0
or
Object.Move Value(), 0
Tried both, because I was not sure which one is correct.
After many trials I finally skipped most of the previous errors I was getting, and now I'm stuck at trying to set up an Array using a variable from the UserForm.
Here's the code inside Userform
VBA
Public Sub TextBox1_Initialize()
M = TextBox1
Unload M
End Sub
And here's the code inside the module
VBA
Public M As Integer
Sub Move()
Dim XY(M, 0) As Integer
Object.Move XY
End Sub

Visual Basic - newbie question - unable to assign user input to a class property

I am trying to take the user input and assign it to a property defined in a class. When I run the program, it asks for user input as expected, but displays a different result. Can someone point out where my mistake is ?
I was trying to base my simple program on this tutorial
https://learn.microsoft.com/en-us/dotnet/core/tutorials/vb-with-visual-studio
but trying to extend it to classes.
I am using the latest version of Visual Studio and Visual Basic. It's a visual basic Console App
Module Module1
Sub Main()
Dim ClassInstance As New Class1()
Console.WriteLine("Input Property 1: ")
ClassInstance.Property1 = Console.Read()
Console.Write(ClassInstance.Property1)
Console.ReadKey(True)
End Sub
Public Class Class1
Public Property1 As Integer
Public Property2 As Integer
End Class
End Module
Expected output:
"Input Property 1:" |
User input 50 |
Output 50
Console.Read reads the next character from the input, and gives you that character's code. If, for instance, you typed 5 at the prompt1, Console.Read would return 53. Why? Because that's the ASCII/Unicode code for that character (in Unicode terms, it's U+0035, which is the same number represented in hexadecimal).
If you want to read multiple characters and interpret them as an integer, you should a) be using something other than Console.Read to take the input and b) use Int32.TryParse to try to turn it into a number (because users don't always give us the input we expect).
Something like:
Module Module1
Sub Main()
Dim ClassInstance As New Class1()
Console.WriteLine("Input Property 1: ")
Dim inp = Console.ReadLine()
Dim value as Int32
If Int32.TryParse(inp, value) Then
ClassInstance.Property1 = value
Console.Write(ClassInstance.Property1)
Console.ReadKey(True)
End If
End Sub
Public Class Class1
Public Property1 As Integer
Public Property2 As Integer
End Class
End Module
(With apologies if I've made syntax errors - my VB's quite rusty)
In reality, you'd probably want to write some form of loop that prompts for user input and doesn't terminate until it successfully parses. I think Do/While would fit there - but if you're going to prompt the user more than once, you probably would want to extract the "Loop until valid input received" code into a function that takes the prompt as a parameter.
More reading - ASCII/Unicode. For characters in the "7-bit ASCII" range, basic latin characters without accents, it doesn't make much difference which references you check
1And it doesn't matter if you carried on and typed any more characters, your program only asks for/gets one of them

Visual Basic Console - A global command & anwser string

I'm creating a text based adventure game and would like to create some "global" commands & answers that would work anywhere no matter where your are.
For the global answers if we look at this code:
Module Module1
Private Property answer1 As String
Private Property answer2 As String
Sub Main()
Console.WriteLine("Welocome to the training grounds!")
Console.WriteLine("What would you like to do? 1. I would like to train on dummies")
answer1 = Console.ReadLine()
Console.WriteLine()
If answer1 = "1" Then
Console.WriteLine("Okay what now?")
answer2 = Console.ReadLine
If anwser2 = "1" Then Console.WriteLine("New option")
End If
End Sub
Now as you can see I have to create a string for each new user input. I've tried doing a Public answer As String = Console.ReadLineand then having things react to "answer" but if I reused a keyword like number 1 in the code up top the program would not wait for user input and just go down the path of number 1. The first option seems like a bunch of spagettih code and the second option dose not seem to work or I myself am not getting it to work so any tips here would be nice.
I also want to know if its possible to create a global string or something of sorts. Say that No matter if I were at the point where I'm supposed to give input to answer 1 or 2, if I typed in "inventory" it would open another sub called inventory. Now if possible I want to do this without having to have an if answer = inventory then Inventory().
Thanks in advance everyone ^^
Following the advice given to my by b.pell I was able to create a "GameCommand" sub but I'm not facing a problem of how to implement these into the game itself/make them accessible without ruining the game flow. I am also not quite sure how to write a command that will modify something in GameCommand.vb (say if the player gets an item how would I add it to the inventory list?)
Module Module1
Sub Main()
Dim gc As New GameCommand
If Console.ReadLine = "Go to dummy" Then Dummy() Else
CallByName(gc, Console.ReadLine, CallType.Method, "")
End Sub
Sub Dummy()
Console.WriteLine("I am dummy hear me roar")
Return
End Sub
End Module
The GameCommand.vb file is the same as the one in p.bells comment.
You could create an interpreter function that processes all commands and then do what you want in there. So everytime you read input in, just pass it along to the interpreter sub.
interpreter("inventory")
Inside of there, you could do an break that command up (if it has arguments). You could do a basic if statement and execute your sub procedures based off of that.
You could go above and beyond (this answers your question about not having to write the if's) and create a commands class that has all of your command methods on it (Inventory, North, South, East, West, Look) and then when a user enters a command you could use reflection to check that class to see if that sub/function exists (and then invoke it). The benefit of that is, as you add methods to the command class you never have to update the if logic in your interpreter again.
E.g. You would add a "Public Sub Look()" or "Public Sub Look(args as String) to the command class.. your interpreter would then try to invoke the look command (and maybe pass it the rest of the arguments). If it wasn't found, you tell the user it wasn't a command, if it was, it executes (google search for invoking). This means as you add Sub's the interpreter just picks them up.
Here is an MSDN article that should get you going, you can use VB's CallByName function, you pass it your class, then the proc name you want to execute with an args:
https://msdn.microsoft.com/en-us/library/chsc1tx6(v=vs.80).aspx
Here is a simple example (a console application):
Module1:
Module Module1
Sub Main()
Dim gc As New GameCommand
CallByName(gc, "Inventory", CallType.Method, "")
' Will look south
CallByName(gc, "Look", CallType.Method, "south")
' Will try to look southeast, but we don't accept that as a valid direction
CallByName(gc, "Look", CallType.Method, "southeast")
Console.ReadKey()
End Sub
End Module
GameCommand.vb:
Public Class GameCommand
Sub New()
End Sub
Public Shared Sub Inventory(arg As String)
Console.WriteLine("Execute code to show inventory")
End Sub
Public Shared Sub Look(direction As String)
If direction <> "north" And _
direction <> "south" And _
direction <> "east" And _
direction <> "west" Then
Console.WriteLine("Invalid direction")
Exit Sub
End If
Console.WriteLine("You look " & direction)
End Sub
End Class
I would approach a text adventure with the following general structure:
In your main module, loop through the process of each "turn".
Display any prompt text, as appropriate.
Read user input.
Check list of global commands and execute as appropriate.
Check list of local commands and execute as appropriate.
Display an error message.
Each command you execute should do the following:
Calculate changes to any variables affected by the command
Check each possible change in game status from the top down, and execute subsequent commands as appropriate. (E.G. Player death, mission success/failure, enemy defeated, etc.)
Advance the story to the appropriate place.

Is there a simpler way to process check boxes?

In vb.net, I have a form that has a set of four Check Boxes. Each Check Box signifies that (when checked) the user wants to add a special instruction to their order. The code looks like this:
If SpecialInstruction1CheckBox.Checked Then
AddSpecialInstruction(SPECIAL_INSTRUCTION_1_String)
End If
If SpecialInstruction2CheckBox.Checked Then
AddSpecialInstruction(SPECIAL_INSTRUCTION_2_String)
End If
If SpecialInstruction3CheckBox.Checked Then
AddSpecialInstruction(SPECIAL_INSTRUCTION_3_String)
End If
If SpecialInstruction4CheckBox.Checked Then
AddSpecialInstruction(SPECIAL_INSTRUCTION_4_String)
End If
I have a feeling that this code is unnecessarily verbose, feels repetitive, and could be simplified. How would I go about doing this, or is this not as "wrong" as it feels?
The first problem is that your special instructions should not be stored in separate variables. They should be stored in an array or some other kind of list. Then you could access them by index (e.g. specialInstructions(1)).
Then you can loop through the check boxes by index like this:
For i As Integer = 1 to 4
Dim box As CheckBox = DirectCast(Me.Controls("SpecialInstruction" & i.ToString() & "CheckBox"), CheckBox)
If box.Checked Then list.Add(specialInstructions(i))
Next
Alternatively, you could store references to your check boxes in an array and then loop through them more easily, for instance:
Dim checkBoxes() As CheckBox = {
SpecialInstruction1CheckBox,
SpecialInstruction2CheckBox,
SpecialInstruction3CheckBox,
SpecialInstruction4CheckBox}
' ...
For i As Integer = 0 to checkBoxes.Length - 1
If checkBoxes(i).Checked Then list.Add(specialInstructions(i))
Next
Another option would be to store the special instructions in the Tag property of each check box, then you could just retrieve the value from the control, like this:
For Each i As CheckBox In checkBoxes
If i.Checked Then list.Add(i.Tag)
Next
But that only makes sense if you don't need to reuse those special instructions values elsewhere in your code.
Actually the code isn't that bad in itself. It mainly depends on what AddSpecialInstruction does, exactly. Depending on your specifics it might be better to pass it a list of string instructions instead:
Dim list As New List(Of String)
If SpecialInstruction1CheckBox.Checked Then list.Add(SPECIAL_INSTRUCTION_1_String)
If SpecialInstruction2CheckBox.Checked Then list.Add(SPECIAL_INSTRUCTION_2_String)
If SpecialInstruction3CheckBox.Checked Then list.Add(SPECIAL_INSTRUCTION_3_String)
If SpecialInstruction4CheckBox.Checked Then list.Add(SPECIAL_INSTRUCTION_4_String)
AddSpecialInstructions(list)
Since you also required code shrinking, I made If statements holding on one line. Shorter variable names would help on that too.