So you've got an array called DiceList
and it holds the result of rolling the dice. We can sort it pretty easily using LINQ:
Dim rolls = DiceList.OrderBy(Function(x) x)
But we should also remove duplicates as it makes the problem easier to deal with:
Dim rolls = DiceList.OrderBy(Function(x) x).Distinct().ToArray()
Now a simple way to look at it might be just to collect the differences of the rolls into a string:
Dim consec = ""
For i = 1 to Ubound(rolls)
sum += (rolls(i) - rolls(i-1)).ToString()
Next i
And then ask:
If consec.Contains("1111") Then 'its a large straight
Else If consec.Contains("111") Then 'there's a small straight
Of course, you might think it simpler to just list out some combos:
Dim smallStraights = {"1234","2345","3456"}
Dim largeStraights = {"12345","23456"}
Then turn your rolls into a string:
Dim rollsStr = string.Join("", rolls.Select(Function(x) x.ToString()))
And ask if the string contains any of the straights:
If largeStraights.Any(Function(ls) rollsStr.Contains(ls)) Then '...
Else If smallStraights.Any(Function(ss) rollsStr.Contains(ss)) Then '...
Note that this last syntax is a bit odd; because our straights are in an array and we're querying to see if the rolls string contains any of the straights, we can't start out with rollsStr.Contains(...)
.
Instead we actually need to ask "for all these straights in this array, is there any array element such that the rolls string contains the array element" ?
With loops it would look like:
'smallStraights.Any(Function(ss) rollsStr.Contains(ss))
For Each ss In smallStraights
If rollsStr.Contains(ss) Return True 'stop as soon as one is found
Next ss
Return False 'none found
So how does this all work?
We have a set of rolls:
{2, 1, 4, 3, 6}
As a human, we could look for consecutives in this either by
- counting up and jumping back and forth (find the 1, go left to the 2, right three places to the 3, left to the 4, right to the 6, work out that we had 4 in a row, but not 5, call it a straight small)
- rearranging the dice so they are shown in order and see how many of them are "one more than the one to their left"
The latter approach is what I start with - I sort the array and look at the differences. Because duplicates would ruin our approach (A set of 1,2,2,3,4 is actually a small straight if you throw one of the 2s away, but if you kept it you'd have a difference chain of 1,0,1,1 and the 0 would upset things if we were looking for a difference chain of 1,1,1) I also take them out as part of the "sort the dice" step
After we implemented the approach of sorting the dice and then going through them one by one working out the difference to the previous die, we built a string up that described the differences.
Building a string makes our life easier because there are built in methods that ask if one string contains another. If our difference string was e.g. "0111", or "1112" then it does contain a "111" which means a small straight is present (remember that there are 5 dice, but only 4 differences because the algorithm is "this_dice minus previous_dice" i.e. for 5 dice A,B,C,D,E we do B-A, C-B, D-C, and E-D - 4 differences for 5 dice)
Then we might realise that it's actually easier to not do the differneces thing, but just to order the dice, remove the duplicates and look for the small combination of dice that mean a straight is present.. This means we're literally taking our {1,2,3,4,6} rolls, turning them into a string of "12346" and then looking in it to see if we can find "1234", or "2345", or "3456" - the small straights. If we do this after we look for the big straights, and only if we didn't find a big straight, then for a roll set of "12345" we wouldn't accidentally declare it a small straight (because "12345" contains "1234") when its really a big straight
Why choose one over the other? Well, looking for the limited number of small/large straights (there are only 5) is viable because there are only 5. If Yahtzee had 100 sided dice, and a straight could be 1-2-3-4, 2-3-4-5, 3-4-5-6, 4-5-6-7, 5-6-7-8 .. all the way to 97-98-99-100 then it would make sense to do the differences method, because instead of listing 98 combinations of small straight, the differences method always reduces the variety of what we're looking for to "111"; a small straight of 1-2-3-4 or 97-98-99-100 both become 1-1-1-1 if we do differences
So all that remains is for your code to turn your list of numbers into a single string and then use Contains. This is a lot easier to do than ask "does this list of numbers contain this other list of numbers" so we (ab)use string into being our data container for the numbers because it means they're no longer separate things that have to be cross coordinated; they're a single string that contains a pattern and over the time we've developed lots of ways in programming languages, of looking for patterns inside strings
You certainly could have one bunch of numbers, {1,2,3,4,6} and ask "does this set of numbers contain this other set of numbers {1,2,3,4}" but it would look a bit more like this (in programming 101 terms, not using LINQ or Sets etc)
Dim rolls = {1,2,3,4,6} 'note: these values must be unique
Dim straight = {1,2,3,4} 'note: these values must be unique
Dim numFound = 0
For Each r in rolls
For Each s in straight
If r == s Then
numFound += 1
End If
Next s
Next r
If numFound = straight.Length Then 'if we found all the numbers in the straight
Console.Write("All the numbers of the straight exist in the rolls")
End If
We still have the problem that duplicates defeat this method so we need to dedupe our rolls. We could do that by adding a bit on:
Dim numFound = 0
Dim prevR = -1
For Each r in rolls
If r = prevR Then Continue 'skip this one, it's a duplicate of the previous roll
prevR = r ' remember the current roll for next time
For Each s in straight
If r == s Then
numFound += 1
End If
Next s
Next r
We also still have the problem that the rolls need to be sorted, because we only check the previous one roll. If we are going to be working with unsorted rolls, then we need to check all the previous ones to see if the current roll occurred already:
For i = LBound(rolls) to UBound(rolls)
Dim r = rolls(i)
'Check ALL the previous rolls
Dim seenBefore = False
For p = i - 1 To LBound(rolls) Step -1
Dim prevR = rolls(p)
If prevR = r Then seenBefore = True
Next p
If seenBefore Then Continue 'skip this one, it's a duplicate of a previous roll
For Each s in straight
If r == s Then
numFound += 1
End If
Next s
Next r
You can see how the problem starts growing every time we think about it/try to solve another problem/bug with the previous iteration. All in we now have a mechanism for checking if one set of numbers exists in another set of numbers but its quite lengthy compared to our previous steps:
Dim rolls = {1,3,2,5,4}
Dim rollsString = string.Join("", rolls.OrderBy(...).Distinct()) 'turn the rolls into a string like "12345"
If rollsString.Contains("1234") Then 'rolls contains the small straight 1234
Note, these use LINQ extensively and you might not have been taught LINQ.. You might need an approach that implements the algorithm "sort, unique, look for straights" using what you know already, but equally you can probably do your own learning (getting help learning on SO is possible, though a lot of people want to just give you the answer in the shortest time possible to try and win the points) and justify your algorithm and your solution to the teacher.
If you don't want to use LINQ, you can take a look at some of the other things discussed and assemble a solution. Deduping a List can be done by something like:
Dim uniqueList as New List(Of Integer) 'must be a list, not an array
For Each i in listWithDuplicates
If Not uniqueList.Contains(i) Then uniqueList.Add(i)
Next i