Is it possible for a picture box to detect colour in another picture box and avoid it? - vb.net

I am currently attempting to make a visual route planner interface for a local town.
The GUI is a map lacking in detail simply showing a green background with grey lines for the roads.
Is it possible for another picture box representing a vehicle to avoid and be unable to access the green coloured areas of the Map Picture box?
How can I make the car picture box follow certain routes along the map picture box that can be worked out through calculations?

We'll do this in a couple steps:
Build the map from the data.
Implement a flexible pathfinding algorithm.
Draw a human-friendly version of the map.
Wrap up with user interactions.
I'll enrich this answer as you progress so it stays relevant.
1
First thing, we'll manipulate data. A road map is basically a network of points (or nodes) linked by lines (which I'll call vertex).
The points have coordinates (so we can draw them later), and sometimes other values, like a name. They are every start and end of a road, and sometimes in-between. To keep things simple, the user will only be able to start and end on points.
Vertex have length and sometimes stuff like "difficulty", "max speed", etc. These stats will determinate which road is the most optimized for the user's trip. We can also make sure that the algorithm doesn't consider a vertex when the user doesn't want to go this way, or force him to go through a specific vertex if we choose so.
You'll find that I included a sample map by setting it up in the map's constructor. I included approximative coordinates and distances. You can change it any way you like. Here what the data represents:
2
I'm using the A* (read A STAR) algorithm here. You mentioned Dijkstra's algorithm sooner, which is nice, but for this purpose I'll stick to A*.
There are differences between these two methods. If you wikipedia them, you'll find these two images which, I think, show really well the main difference between the two:
Dijkstra's algorithm:
A* algorithm:
As you can see by yourself, both algorithm are doing a fine job.
I commented the code, but You'll probably have a ton of questions about all these things. I'll hang around to answer them.
To manipulate this algorithm, you have to know this:
the difficulty value of a vertex makes it seem longer to the algorithm. It's not necessary (which is why I put it to 1 everywhere), but if you want to compare a mountain road to a speedway or a road with a 30 km/h speed limit to another one where you can speed at 100 km/h, you can tweak this value.
the x and y coordinates of the nodes aren't very important in themselves, but the A* algorithm uses them to get this "I'm going toward my goal" effect you just saw in the image. Approximatives values are fine, as long as there are values that make some sense in there. You could calculate the H value otherwise, but as this is cartography I though it made sense.
a vertex MUST ALWAYS be connected to a starting point and an end point. Which is which have no meaning, as long as there are two of them (or the same point twice, but that would lead to the place where it started without any gain whatsoever).
a point may have any number of vertex.
you could make some points "impossible to pass", but I didn't code it that way. You can pump up the difficulty to an insane amount to get a somewhat similar result, except that if there are no other way the algorithm will eventually use the difficult path anyway.
if the end node has no connection to the network of the starting node, the algorithm will try everything then abandon and let you know that there is no path to the end point.
use the TestMyMap() sub to try some pathfinding. Calculate it by yourself to compare. Change the end point and the starting point for something else. Go wild!
The Code
#Region " Mapping "
Public Class MapPoint
Private _vertexList As New List(Of MapVertex) 'one point can have as many "roads" as you want
Private _xCoord As Decimal 'for now the coordinates are meaningless, but at some point we might want to use them to actually paint the map
Private _yCoord As Decimal
Private _name As String 'just a useful label
Public Parent As MapVertex = Nothing 'useful for backtracking at the end (and get an itinary)
'f is the total "cost" of the the node being analyzed (f = g + h) while doing pathfinding
'g is the distance between the node being analyzed and the starting point while doing pathfinding
'those values serve no other purpose
'h is the estimated minimal distance between the two points while doing pathfinding
'in the Sub 'CalculateH' I'm using the points coordinates and simple trigonometry to estimate h
'technically you can skip the square root part, but I decided against it. There are no dealmaking advantages to my decision.
'it's better to underestimate the minimal distance, that's why a theoretical straight line is a good choice
Public f As Decimal = 0
Public g As Decimal = 0
Public h As Decimal = 0
Public ReadOnly Property VertexList As List(Of MapVertex)
Get
Return _vertexList
End Get
End Property
Public ReadOnly Property X As Decimal
Get
Return _xCoord
End Get
End Property
Public ReadOnly Property Y As Decimal
Get
Return _yCoord
End Get
End Property
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Public Sub New(name As String, xx As Decimal, yy As Decimal, ParamArray vertex() As MapVertex)
_name = name
_xCoord = xx
_yCoord = yy
For Each v As MapVertex In vertex
_vertexList.Add(v)
Next
End Sub
Public Sub AddVertex(vertex As MapVertex)
_vertexList.Add(vertex)
End Sub
Public Sub CalculateH(startingPoint As MapPoint, endPoint As MapPoint)
h = Convert.ToDecimal(Math.Sqrt(Math.Pow((startingPoint.X - endPoint.X), 2) + Math.Pow((startingPoint.Y - endPoint.Y), 2)))
End Sub
Public Sub UpdateFandG(currentNodeG As Decimal, distance As Decimal)
g = currentNodeG + distance
f = g + h
End Sub
Public Sub ResetPathfindingValues()
f = 0
g = 0
h = 0
Parent = Nothing
For Each v As MapVertex In _vertexList
v.ResetPathfindingValues()
Next
End Sub
End Class
Public Class MapVertex
Private _name As String 'just a useful label
Private _length As Decimal 'length of the road. If you have straight roads we can use simple math to get the distances, but curvy roads have their own length, and I'll assume that your roads will be anything
Private _difficulty As Decimal 'if you want to make some roads faster than others, we can use a variable like this one. It could be something else, like "maxSpeed", but for a prototype "difficulty" will do fine
'I suggest making the difficulty a multiplier. It'll be easier to use that way (so a road twice faster would be a '0.5' and a road twice harder to use would be a '2.0')
Public Parent As MapPoint = Nothing 'useful for backtracking at the end (and get an itinary)
'start and end has no meaning here, as both are end points for the line. The important part is that they refer to existing points
'a vertex must ALWAYS be linked to two points (or it makes no sense, you cannot have a line with only one end unless you go full moebius and we're not using enough dimensions for this to make sense
'if you feel like it, you can have a vertex looping from one point and going back to it, but it'll serve no purpose and will never be actually used except by the pathfinding algorithm (which will note it as a bad move every time)
Private _startPoint As MapPoint
Private _endPoint As MapPoint
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
'you can play around with difficulty if you like, it'll change which path the algorithm thinks is the better
Public ReadOnly Property AdjustedLength As Decimal
Get
Return _length * _difficulty
End Get
End Property
Public Sub New(name As String, startPoint As MapPoint, endPoint As MapPoint, length As Decimal, difficulty As Decimal)
_name = name
_startPoint = startPoint
_endPoint = endPoint
_length = length
_difficulty = difficulty
'automatically adding this vertex to it's points on creation:
_startPoint.AddVertex(Me)
_endPoint.AddVertex(Me)
End Sub
'this function is so we can get the "other side" of a path from it's start
Public Function GetOtherNode(currentNode As MapPoint) As MapPoint
If _startPoint Is currentNode Then
Return _endPoint
Else
Return _startPoint
End If
End Function
Public Sub ResetPathfindingValues()
Parent = Nothing
End Sub
End Class
Public Class Map
'the Map object is a collection of points.
'those points are linked by vertex
'it could be different depending on what's your purpose
Private _points As New List(Of MapPoint)
Public Function GetPoint(name As String) As MapPoint
For Each p As MapPoint In _points
If p.Name = name Then
Return p
End If
Next
Return Nothing
End Function
Public Sub New()
'You can use this part to build a simple map with a handful of points. For the demonstration that's how we'll work, but later on you can design a mean to load maps from a specific source if you want
'Here's one I threw on the screen at random. If you have one you like better, send me a pastebin and I'll use it instead
'First I create the points:
Dim oldBarn As MapPoint = New MapPoint("Old Barn", 0, 0)
Dim home As MapPoint = New MapPoint("Home", 0, 12)
Dim forest As MapPoint = New MapPoint("Forest", 0, 21)
Dim creepyDeadEnd As MapPoint = New MapPoint("Creepy Dead End", 0, 26)
Dim groceries As MapPoint = New MapPoint("Groceries", 11, 8)
Dim girlfriendsPlace As MapPoint = New MapPoint("Girlfriend's Place", 20, 8)
Dim friendsHome As MapPoint = New MapPoint("Friend's Home", 5, 13)
Dim bar As MapPoint = New MapPoint("The Foo's Bar", 32, 14) 'hehehe
'Second I create the roads between those points (as long as 2 points exist I could create the road, I just decided I would be systematic)
Dim smallRoad As MapVertex = New MapVertex("Small Road", oldBarn, home, 12, 1)
Dim oakStreet As MapVertex = New MapVertex("Oak Street", home, forest, 9, 1)
Dim pathway As MapVertex = New MapVertex("Pathway", forest, creepyDeadEnd, 5, 1)
Dim oldRoad As MapVertex = New MapVertex("Old Road", oldBarn, friendsHome, 17, 1)
Dim arlingtonStreet As MapVertex = New MapVertex("Arlington Street", home, groceries, 7, 1)
Dim fourthStreet As MapVertex = New MapVertex("4th Street", home, girlfriendsPlace, 12, 1)
Dim placeLittlefinger As MapVertex = New MapVertex("Place Littlefinger", groceries, girlfriendsPlace, 9, 1)
Dim cedarCreek As MapVertex = New MapVertex("Cedar Creek", forest, bar, 19, 1)
Dim alley As MapVertex = New MapVertex("Alley", friendsHome, groceries, 7, 1)
Dim mainStreet As MapVertex = New MapVertex("Main Street", groceries, bar, 22, 1)
Dim durnhamRoad As MapVertex = New MapVertex("Durnham Road", friendsHome, bar, 27, 1)
Dim secretRoad As MapVertex = New MapVertex("Secret Road", oldBarn, bar, 61, 1)
'Adding the points to the Map
_points.AddRange({oldBarn, home, forest, creepyDeadEnd, groceries, girlfriendsPlace, friendsHome, bar})
End Sub
'This is an implementation of the A* algorithm, which is a very popular pathfinding algorithm for simple grids/node networks
'You could use Dijkstra's algorithm if you like it better or are a Sapkowsky's fan, but I think A* will do a great job here
Public Function FindTheShortestPath(startingPoint As MapPoint, endPoint As MapPoint) As String
Dim openList As New List(Of MapPoint) 'nodes that are going to be analyzed soon
Dim closedList As New List(Of MapPoint) 'nodes that have been analyzed
'we always start the analysis... from the starting point of course!
openList.Add(startingPoint)
startingPoint.CalculateH(startingPoint, endPoint)
'as long as we haven't found the path to the end point, the algorithm will continue looking
'there are 2 ways to exit this function:
' #1 is finding the endPoint
' #2 is having nowhere left to go and still not finding the end point (which means that it's impossible)
While (openList.Count > 0)
'look for the lowest f in the openList
'this is our current node for the analysis
Dim currentNode As MapPoint = Nothing
For Each p As MapPoint In openList
If currentNode Is Nothing OrElse p.f < currentNode.f Then
currentNode = p
End If
Next
'remove the currentNode from the open list (it's being analyzed) and add to the closedList (no need to come back)
openList.Remove(currentNode)
closedList.Add(currentNode)
'check if we've reached the end node
If currentNode Is endPoint Then
'yay!
'now let's backtrack to get an itinary:
Dim path As String = BackTrack(endPoint)
ResetAllPathfindingVariables()
Return path
End If
'finding which nodes are connected to the Current node
'then analyzing it
For Each vertex As MapVertex In currentNode.VertexList
Dim nextNode As MapPoint = vertex.GetOtherNode(currentNode)
'only work on a node if it's out of the closedList
If Not closedList.Contains(nextNode) Then
'I'm tracking parents to make an itinary when this is finished
nextNode.CalculateH(currentNode, endPoint)
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
'if it's not yet on the openList, now's time to add it there!
'(I know that a negative check with a 'Else' clause is stupid, but it's easier to read in this context)
If Not openList.Contains(nextNode) Then
openList.Add(nextNode)
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
nextNode.Parent = vertex
vertex.Parent = currentNode
Else
'if this is a known node but we found a faster path to reach it, update it's parent
If currentNode.g + vertex.AdjustedLength < nextNode.g Then
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
nextNode.Parent = vertex
vertex.Parent = currentNode
End If
End If
End If
Next
End While
ResetAllPathfindingVariables()
Return "No path was found."
End Function
Private Sub ResetAllPathfindingVariables()
For Each p As MapPoint In _points
p.ResetPathfindingValues()
Next
End Sub
'recursive function to show the path found by the algorithm
Private Function BackTrack(location As Object, Optional path As String = "") As String
If path <> "" Then path = " => " & path
Select Case True
Case TypeOf location Is MapPoint
Dim currentPoint As MapPoint = DirectCast(location, MapPoint)
path = currentPoint.Name & path
If currentPoint.Parent Is Nothing Then
Return path
Else
Return BackTrack(currentPoint.Parent, path)
End If
Case TypeOf location Is MapVertex
Dim currentVertex As MapVertex = DirectCast(location, MapVertex)
path = currentVertex.Name & path
If currentVertex.Parent Is Nothing Then
Return path
Else
Return BackTrack(currentVertex.Parent, path)
End If
End Select
Return ""
End Function
End Class
Private Sub TestMyMap()
_map = New Map()
Dim path As String = _map.FindTheShortestPath(_map.GetPoint("Home"), _map.GetPoint("The Foo's Bar"))
Console.WriteLine(path)
End Sub
#End Region
Of course I'll be there to help you understand this part. It's heavy, I know. It's still a lot of fun, especially once it's finished and you get to use it!

Related

unable to add items to a list in VB.NET

Good morning,
so i have received this homework for the summer where i have to create a program to store a list of movies and display them, but the problem is that there isn't a defined number of movie so i can't use the constant method i've always used, so i tried doing that with variables instead, but whenever i press the input button twice the app crashes and i get the error "Index over the matrix limits"
Here's the code in the module
Module Module1
Public Structure Film
Public Titolo As String
Public Autore As String
Public Incasso As Integer
Public Nazionalita As String
End Structure
Public i As Integer = 0
Public Flm(i) As Film
End Module
And here's the input part
Public Class frmInput
Private Sub btnInserisci_Click(sender As Object, e As EventArgs) Handles btnInserisci.Click
If IsNumeric(txtIncasso.Text) = False Then
MsgBox("L'incasso deve essere un valore numerico", MsgBoxStyle.Exclamation, "Attenzione")
ElseIf txtTitolo.Text = "" Or txtAutore.Text = "" Or txtNazionalita.Text = "" Then
MsgBox("Uno o piĆ¹ valori sono vuoti", MsgBoxStyle.Exclamation, "Attenzione")
Else
Flm(i).Titolo = txtTitolo.Text
Flm(i).Autore = txtAutore.Text
Flm(i).Incasso = txtIncasso.Text
Flm(i).Nazionalita = txtNazionalita.Text
i += 1
End If
End Sub
End Class
You should use a List(Of Film) to store the inputs received.
A generic List like that has no practical limits and can grow while you add elements to it
Public Flm As List(Of Film) = new List(Of Film)
....
Else
Dim f as Film = new Film()
f.Titolo = txtTitolo.Text
f.Autore = txtAutore.Text
f.Incasso = txtIncasso.Text
f.Nazionalita = txtNazionalita.Text
Flm.Add(f)
End If
A List(Of Film) could be used like it was an array
For x As Integer = 0 To Flm.Count -1 Step 1
Console.WriteLine("Film #" & x+1)
Console.WriteLine("Titolo = " & Flm(x).Titolo)
.....
Next
And of course you can iterate over it using a simpler foreach
For Each Film f in Flm
Console.WriteLine("Film #" & x+1)
Console.WriteLine("Titolo = " & f.Titolo)
.....
Next
Although others have mentioned using List, which would probably be appropriate, you also mentioned it was a homework task, so maybe you need, or have to, use the more traditional arrays as you have shown. Bearing this in mind, and also to let you know what your problem is. You are incrementing i but not the array.
Public i As Integer = 0
Public Flm(i) As Film
Thus, Flm is 0 to 0, one element.
You add to this, all is OK.
You increment i, good, i += 1
However, you don't then increment the array, Flm(). Incrementing i doesn't automatically increment the array, Flm().
You need to use: ReDim Preserve
Thus... Change:
Else
Flm(i).Titolo = txtTitolo.Text
to:
Else
ReDim Preserve Flm(i)
Flm(i).Titolo = txtTitolo.Text
Lastly, IsNumeric and MsgBox are remnants of the VB6 days, there are vb.net equivalents. Also, using i as a global/public variable is really not good. It's very common, standard, to use i in all local subroutines and functions for little loops etc, it gets used and lost. If you look at almost all examples of code, you'll see i being used as the integer counter.

Looping Class Property with Do While Loops

I have a code like below to find a category property with named "Model" and after that i will get the Model's name.
But as you can see "parent" property shows the upper level of parameter. My parameters in parameter groups and its like cascaded. And i don't know in which level they are currently i'm using below code but it's not sufficient because if i have a parameter very in lower levels i had to write this elseif conditions.
Is there any quick solution to make it easier and wise way?
Public Class ParameterInfoClass
Public Shared Sub GetSubvar(ByVal ParameterGroups As IScrNamedObjectList)
Dim ParameterGroup As IScrParameterGroup
Dim nParameterGroup As Integer
Dim ParameterClass As String
nParameterGroup = ParameterGroups.count
For i As Integer = 0 To nParameterGroup - 1
ParameterGroup = ParameterGroups.item(i)
If ParameterGroup.parent.category.name = "Model" Then
ParameterClass = ParameterGroup.parent.name
ElseIf ParameterGroup.parent.parent.category.name = "Model" Then
ParameterClass = ParameterGroup.parent.parent.name
ElseIf ParameterGroup.parent.parent.parent.category.name = "Model" Then
ParameterClass = ParameterGroup.parent.parent.parent.name
'...
'This should be continue like this because i don't know in which level i will find the category name as "Model"
'.
End If
DataGridView1.Rows.Add(ParameterClass, ParameterGroup.name)
Next
End Sub
End Class
It would be great to make this section with correct solution. I thought like do-while loops can be one option but i dont know how to apply because focus is in here to look upper levels of parameter to find "Model" category after that i'm writing that Model's name.
For i As Integer = 0 To nParameterGroup - 1
ParameterGroup = ParameterGroups.item(i)
If ParameterGroup.parent.category.name = "Model" Then
ParameterClass = ParameterGroup.parent.name
ElseIf ParameterGroup.parent.parent.category.name = "Model" Then
ParameterClass = ParameterGroup.parent.parent.name
ElseIf ParameterGroup.parent.parent.parent.category.name = "Model" Then
ParameterClass = ParameterGroup.parent.parent.parent.name
'...
'This should be continue like this because i don't know in which level i will find the category name as "Model"
'.
End If
I don't have a lot of time to dig into the details, but recursion is something I love so I'm giving you a hint (I would help more but that's the time I have right now).
Instead of iterating through every possible parent level, you should create a simple recursive function which will look if it finds the "Model", then either return it or else look for it's parent by calling itself to look for it.
You would have to use this new function instead of your If ElseIf ElseIf... potentially infinite function.
I drafted something which kinda looks like what I mean:
Private Function GetParameterClass(rootClassName As rootClass) As String
If ParameterGroup.category.name = "Model" Then
Return ParameterGroup.category.name
End If
If ParameterGroup.parent IsNot Nothing Then
Return GetParameterClass(ParameterGroup.parent)
End If
Return ""
End Function
By calling a similar function, you will iterate recursively through every parent until it finds none, and the first time it finds "Model", it'll stop the recursion and return it.
Sorry for not being more precise, as I have to get back to work myself! I'll look on your thread this evening when I can, just in case. Have fun!
EDIT:
I'm not familiar with the class you're working with, so there's a good amount of guesswork in this edit. Here's how I would try to solve your issue:
Public Class ParameterInfoClass
Public Shared Sub GetSubvar(ByVal ParameterGroups As IScrNamedObjectList)
For Each parameterGroup As IScrParameterGroup In ParameterGroups
Dim parameterClass As String = GetParameterClassName(parameterGroup)
If parameterName <> "" Then
DataGridView1.Rows.Add(parameterClass, parameterGroup.Name)
End If
Next
End Sub
Private Shared Function GetParameterClassName(parameterGroup As IScrParameterGroup) As String
If parameterGroup.category.name = "Model" Then
Return parameterGroup.name
End If
If parameterGroup.parent IsNot Nothing Then
Return GetParameterClass(parameterGroup.parent)
End If
Return ""
End Function
End Class
The main idea behind GetParameterClassName is that it'll either find the parameterGroup.category.name = "Model", or else it'll return an empty string. I replaced the way you were planning to iterate with a For Each loop, which should work well with most lists, but you might need to ajust that part is IScrNamedObjectList is not or doesn't contains a list or array or something.
Whenever a GetParameterClassName is found, then the parameterClass is not empty, so we can add these informations to the DataGridView1.
You can ask your questions in the comments if you have any, and I'll be happy to oblige. I love recursion!

Returning values from functions in structures in Visual Basic

I hope the title of the post isn't too much of a mess. I'm reviewing some course material from last week, and there is just one thing I don't understand in regard to this particular structure and the add and subtract functions in it:
Structure ComNum
Dim Re As Double
Dim Im As Double
Function add(ByVal br As ComNum) As ComNum
add.Re = br.Re + Re
add.Im = br.Im + Im
End Function
Function subt(ByVal br As ComNum) As ComNum
subt.Re = br.Re - Re
subt.Im = br.Im - Im
End Function
End Structure
Sub Main()
Dim a, b, c As ComNum
a.Re = 2
a.Im = 3
b.Re = 4
b.Im = 5
c = a.add(b).add(b).subt(b)
Console.WriteLine("The second number added twice and subtracted once from the first number gives {0}+{1}i", c.Re, c.Im)
End Sub
Now, the way I understand functions is that once anything is returned from it, execution of the function stops at that exact line where the value is returned and nothing after it gets executed. According to that, it should add the real part and exit the function.
I know I'm missing a key thing here and I'd appreciate it if someone could explain this to me.
The way you have this setup those functions are creating a new, empty ComNum structure each time you call them (named either add or subt based on the function name). Unless you manually return them early it will just default to returning the function named structure.
Function add(ByVal br As ComNum) As ComNum
add.Re = br.Re + Re
add.Im = br.Im + Im
End Function
Is basically doing the equivalent of:
Dim add As New ComNum
add.Re = br.Re + Re
add.Im = br.Im + Im
Return add
Though like Lars pointed out I'm not sure why you'd want this to be a function vs a sub. Using it the way you have it setup now requires you to do something like this to get the add/subtract values because you need to capture the returned ComNum object.
Dim a As New ComNum With {.Im = 1, .Re = 1}
'Im = 6, Re = 6
a = a.add(New ComNum With {.Im = 5, .Re = 5})
Doing something like this makes more sense to me.
Structure ComNum
Dim Re As Double
Dim Im As Double
Sub add(ByVal br As ComNum)
Re += br.Re
Im += br.Im
End Sub
Sub subt(ByVal br As ComNum)
Re -= br.Re
Im -= br.Im
End Sub
End Structure
Then you could just call it this way to update the struct without having to capture the returned values.
a.add(New ComNum With {.Im = 5, .Re = 5})
Edit: Knowing more now how the exercise is supposed to be performed I'd suggest something like this for the struct:
Public Overrides Function ToString() As String
Return String.Format("Re: {0} Im: {1}", Re, Im)
End Function
Then you could call the .ToString() method like this. Though, just a thought.
Console.WriteLine("The second number added twice and subtracted once from the first number gives {0}", c.ToString())

Find matches in a card hand turns up slightly off results around 10% of the time

This is my code which is supposed to compare the values in the array 'arrHands' which stores a hand of x cards (x = cardsDrawn) as singles where the integer part is the suit (1 to 4) and the decimal represents the card number ( .01 = 1 = Ace, etc).
However around 1 in 10 times it runs it returns values that are off by one or two pairs. I know that this will happen when the hand contains a three-of-a-kind, as i haven't written the code for that yet, but it still doesn't make sense. if the value returned is wrong it is always higher than i expected.
here's the code:
Dim numPairs As Integer = 0
Dim A As Integer = 1
Dim B As Integer = 1
'A and B represent the position in the array of the cards being compared
For A = 1 To cardsDrawn
For B = 1 To cardsDrawn
If (A <> B) And (A < B) And (arrHand(A) <> 0) And (arrHand(B) <> 0) Then
'The above line stops cards from being compared to each other, or to a card they have already been compared to.
If (arrHand(A) - (Int(arrHand(A))) = (arrHand(B) - (Int(arrHand(B))))) Then
'the code above extracts the card number from the single that each card is stored as
numPairs += 1
arrHand(A) = 0
arrHand(B) = 0
End If
End If
Next
Next
Thanks for any help or ideas you may have.
It is almost always a bad idea to glue 2 pieces of information into one variable. Classes make it easy to track the various datum for a card:
Public Class Card
Private Shared Faces() As String = {"Jack", "Queen", "King", "Ace"}
Private Shared Names() As String = {"Ace", "Deuce", ..."King"}
Public Property Value As Int32
Public Property Rank As Int32
Public Property Suit As String
Public Property Img As Image
Public Property Name As String
Public Overrides Function ToString() As String
Return String.Format("{0} of {1}", Names(Rank - 1), Suit)
End Function
End Class
There is a Value and a Rank because a card always has the same rank, but depending on the game, the Value may change (e.g. Euchre and Baccarat). A Deck class could use a Stack(Of Card) and a hand can be a List(Of Card) or an array depending on the game.
Given an array of 5 cards, ranking the hand for poker is simple with linq (and assuming Poker):
Dim pairs = cards.
GroupBy(Function(v) v.Value,
Function(key, values) New With {
Key .Rank = key,
Key .Count = values.Count()
}).
OrderByDescending(Function(o) o.Count).
ThenByDescending(Function(r) r.Rank).
ToArray()
If pairs.Count is 4, there is Four of a Kind; likewise 2pair when Count=2 and a pair when the count is one. If pairs(0).Count = 3 then you have trips.
If pairs.Count = 2 AndAlso pairs(0).Count = 3, then you have a FullHouse. It is pretty simple to also do a Group on the suit to determine a flush, and put them in order to see if it is a Straight.
Do be sure to test hands from high to low: you don't want to return 2 pair when it is really a Full House.

Vb console questions how to

Right I want to know how to, if possible to use code that has already been read or an effective way for doing it.
I want to be able to use the location variable without having to write it out hundreds of times.
Hopefully you understand what im talking about. I want to be able to leave the shop and the come back to this console.writeline("where would you like to go") part.
Console.WriteLine("where would you like to go")
Console.WriteLine("1 - The shop")
location = Console.ReadLine()
Loop Until location = "1"
Console.WriteLine("")
Console.WriteLine("")
Console.WriteLine("")
Console.WriteLine("***********************************The Shop***********************************")
Console.ReadLine()
Console.WriteLine("")
Console.writeline("Shopkeeper: how can I help you")
I would advise you to try a more structured approach. Use a new class called Location that contains information about each location (example has a name and a list of possible destinations). This can of course be further advanced with possible interactions and such things.
Public Class Location
Public Property Name As String
Public Property Destinations As List(Of String)
Public Sub New(Name As String, Destinations As String())
Me.Name = Name
Me.Destinations = New List(Of String)
Me.Destinations.AddRange(Destinations)
End Sub
End Class
You first make a list of locations in your game. I made three, the street, the shop and the shop's back room (mysterious!).
On each iterations you display a list with the locations from the objects you made and let the user choose one. You then change the location based on the name.
That way you can easily add locations and interconnections.
You don't really want to hardcode every step the user can take.
Module Module1
Sub Main()
'Create locations
Dim Locations As New List(Of Location)
Locations.Add(New Location("Shop", {"Street", "Back Room"}))
Locations.Add(New Location("Street", {"Shop"}))
Locations.Add(New Location("Back Room", {"Shop"}))
'Define a starting location
Dim CurrentLocation As String = "Street"
Do
Console.WriteLine("You are at: " & CurrentLocation)
Console.WriteLine("Destinations: ")
'Bit of Linq to select the location by name from your defined locations
Dim ThisLocation As Location = (From l As Location In Locations Where l.Name = CurrentLocation Select l).First
'Display the possible destinations from here
For i = 0 To ThisLocation.Destinations.Count - 1
Console.WriteLine(String.Format("-{0}- {1}", (i + 1).ToString, ThisLocation.Destinations(i)))
Next
'Read user input for a the destination he wants to travel to
Dim NewLocation As Integer = -1
Do
Console.Write(" Go to: ")
Integer.TryParse(Console.ReadLine, NewLocation)
Loop Until NewLocation >= 1 AndAlso NewLocation <= ThisLocation.Destinations.Count
'Change the current location
CurrentLocation = ThisLocation.Destinations(NewLocation - 1)
Loop
End Sub
End Module