Visual Basic (.NET) > randomize listbox picks (unique) - vb.net

I just want to make randomizer program. It will be used to pick tournament pairs (like f.e. UEFA Champions League quaterfinal pairs)
GUI Screen: http://i.imgur.com/jqBMJjt.png
I have trouble with this.. When I tried to make picker, it works well > from listbox 1 (left side) to listbox2 (50% of listbox1 items), listbox3 (50% of listbox1 items).. (left side) but these picks aren't unique. There are some duplicates as you can see on image (2nd listbox 2x noob).
Part of my code:
Private Sub RandomiseListBox()
Dim count As Integer = CarbonFiberListBox1.Items.Count
Dim countt As Integer
'countt = count / 2
Dim item As String
Dim itemz As New List(Of String)()
Dim repeat As New List(Of String)()
Dim aa, bb As Integer
If Not count = 0 And ((count Mod 2) = 0) Then
CarbonFiberListBox2.Items.Clear()
CarbonFiberListBox3.Items.Clear()
For index As Integer = 0 To countt - 1 Step 1
item = Me.CarbonFiberListBox1.Items(Me.randomiser.Next(index, count))
itemz.Add(item)
'Me.CarbonFiberListBox1.Items.Remove(item)
'Me.CarbonFiberListBox1.Items.Insert(index, item)
Me.CarbonFiberListBox2.Items.Insert(index, item)
Next index
For index As Integer = 0 To countt - 1 Step 1
For aa = 0 To bb = 999
item = Me.CarbonFiberListBox1.Items(Me.randomiser.Next(index, count))
If Not (itemz.Contains(item)) And Not (repeat.Contains(item)) Then
repeat.Add(item)
'Me.CarbonFiberListBox1.Items.Remove(item)
'Me.CarbonFiberListBox1.Items.Insert(index, item)
Me.CarbonFiberListBox3.Items.Insert(index, item)
End If
Next
Next index
'For index As Integer = 0 To countt - 1 Step 1
'Next index
ElseIf count > 0 Then
'CarbonFiberButton4.Text = "ODD PARTICIPANTS!"
Else
End If
End Sub
Can I get help? I think it is so easy.

Maybe this little example will give you an idea. It works by getting a list, in random order, from one listbox. Note how the list is depleted as items are added to the other listboxes which stops duplicates.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'some sample data
ListBox1.DataSource = {"one", "two", "three", "four", "five", "six", "seven"}
DoRandom()
End Sub
Private Shared prng As New Random
Private Sub DoRandom()
ListBox2.Items.Clear()
ListBox3.Items.Clear()
Dim l As New List(Of String)
'random order of items in ListBox1
l.AddRange(ListBox1.Items.Cast(Of String).OrderBy(Function(s) prng.Next))
'add half to lb2
For x As Integer = 0 To l.Count \ 2
ListBox2.Items.Add(l(0))
l.RemoveAt(0)
Next
'remainder to lb3
For x As Integer = 0 To l.Count - 1
ListBox3.Items.Add(l(0))
l.RemoveAt(0)
Next
End Sub

Related

Fill in missing numbers in different lists twice. ArgumentOutOfRangeException

I need your help to prepare data. I am reading a byte array. I make bytes to unsigned integers. I read in different blocks of that array and write the UInt32s in 5 lists in total. The data has been stored compressed; that is, some spaces are missing and I need to fill them up. To make it clear, I made a compilable test project for you and wrote the data into an excel file.
This is the original data. From the left to the right: Sizes, Addresses, Indexes, Number_of_items, Description
You can see that in column C the 2, 3, and 4 are missing. So I select columns C through E, and move them down 3 rows. I fill the gaps with 2, 3, 4 in column C and 1, 1, 1 in the other two columns.
I do this until I reach the end of column B. Columns B, C, D, and E must have the same length.
Where I have a little problem
I fail because a While or For loop evaluates the List.Count property only once. That is, if I add something to a list within the loop, the loop doesn't run often enough. I've provisionally worked around this by writing While True and catching an OutOfRangeException. Maybe someone has a better idea; or even an idea that completely replaces my approach :D
Step № 2
If a row has a 2 in column D, I select columns B through E below the 2, and move the contents down one row (only one, because the difference is 1).
I want to do this until I get to the bottom of the table. This will make all columns the same length.
Again, I have the problem that I use While True and go out using an exception. Does anyone have a better idea?
FormMain.vb
Public NotInheritable Class FormMain
Private Sizes As New List(Of UInt32) From {
58_355UI,
20_270UI,
4_830UI,
4_443UI,
25_177UI,
8_844UI,
4_101UI,
4_200UI,
14_991UI,
12_639UI,
12_894UI,
14_165UI,
12_954UI,
26_670UI,
7_388UI}
Private Addresses As New List(Of UInt32) From {4_323UI, 62_706UI, 83_646UI, 88_935UI, 93_883UI, 128_259UI, 132_718UI,
137_254UI, 152_590UI, 178_485UI, 193_022UI, 206_718UI}
Private Indexes As New List(Of UInt32) From {1UI, 5UI, 6UI, 9UI, 10UI, 12UI}
Private NumberOfItems As New List(Of UInt32) From {1UI, 2UI, 1UI, 2UI, 1UI, 2UI}
Private Description As New List(Of UInt32) From {1UI, 1UI, 1UI, 1UI, 1UI, 1UI}
Private Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
Dim RopD As New Reprocessing_of_parsed_data(Sizes, Addresses, Indexes, NumberOfItems, Description)
RopD.Fill_gaps()
End Sub
End Class
Reprocessing_of_parsed_data.vb
Public NotInheritable Class Reprocessing_of_parsed_data
Public Property Sizes As New List(Of UInteger)
Public Property Addresses As New List(Of UInteger)
Public Property Indexes As New List(Of UInteger)
Public Property Number_of_items As New List(Of UInteger)
Public Property Description As New List(Of UInteger)
Public Sub New(sizes As List(Of UInt32), addresses As List(Of UInt32), indexes As List(Of UInt32), number_of_items As List(Of UInt32), description As List(Of UInt32))
Me.Sizes = sizes
Me.Addresses = addresses
Me.Indexes = indexes
Me.Number_of_items = number_of_items
Me.Description = description
End Sub
Public Sub Fill_gaps()
Dim counterForAddressesList As Integer = 0
'Dim ListCount As Integer = Indexes.Count - 2
Dim i As Integer = 0
While True 'i < ListCount - 2
Try
Dim delta As Integer = CInt(Indexes(i + 1) - Indexes(i)) - 1
Dim number As UInt32 = Indexes(i)
While delta > 0
number += 1UI
counterForAddressesList += 1
Indexes.Insert(CInt(number) - 1, number)
Number_of_items.Insert(CInt(number) - 1, 1UI)
Description.Insert(CInt(number) - 1, 1UI)
delta -= 1
'ListCount += 1
End While
counterForAddressesList += 1
i += 1
Catch ex As ArgumentOutOfRangeException
Exit While
End Try
End While
' Step 2
Dim j As Integer = 0
While True
Try
If Number_of_items(j) > 1UI Then
Dim delta As Integer = CInt(Number_of_items(j)) - 1
While delta > 0
Addresses.Insert(j + 1, UInteger.MaxValue)
Indexes.Insert(j + 1, UInteger.MaxValue)
Number_of_items.Insert(j + 1, UInteger.MaxValue)
Description.Insert(j + 1, UInteger.MaxValue)
delta -= 1
j += 1
End While
End If
j += 1
Catch ex As ArgumentOutOfRangeException
Exit While
End Try
End While
End Sub
End Class
It is never a good idea to catch an index out of bounds exception in a Try-Catch-statement. Only conditions you are not in control of (often I/O errors) should be handled at runtime. An index being out of bounds is a design error and must be fixed at design time.
I extracted the two steps from Sub Fill_gaps into two new methods to make the code easier to read and test.
Public Sub Fill_gaps() ' A better name would be "Decompress"
PrintTable() 'For testing
FillGaps()
PrintTable() 'For testing
AddMissingNumberOfItems()
PrintTable() 'For testing
End Sub
I also added a method PrintTable for testing
Private Sub PrintTable()
Console.WriteLine()
Console.WriteLine($" A B C D E")
For i = 0 To Sizes.Count - 1
Dim A = Sizes(i)
Dim B = If(i < Addresses.Count, Addresses(i), 0UI)
Dim C = If(i < Indexes.Count, Indexes(i), 0UI)
Dim D = If(i < NumberOfItems.Count, NumberOfItems(i), 0UI)
Dim E = If(i < Description.Count, Description(i), 0UI)
Console.WriteLine($"{A,10}{B,10}{C,10}{D,10}{E,10}")
Next
End Sub
Step 1: fill the gaps (the method is self-explanatory):
Private Sub FillGaps()
' Fill gaps in columns C, D and E.
' The number of Addresses B indicates the total number of indexes.
' Append empty items to C, D and E until the list counts matches the
' expected total number of indexes.
Dim originalIndexCount = Indexes.Count 'Save original count
Do While Indexes.Count < Addresses.Count
Indexes.Add(CUInt(Indexes.Count + 1)) ' Make index 1-based
NumberOfItems.Add(1)
Description.Add(1)
Loop
'Move the rows to where the index indicates.
'We do it backwards to not overwrite existing items.
For i As Integer = originalIndexCount - 1 To 0 Step -1
Dim targetIndex = CInt(Indexes(i)) - 1 ' Subtract 1, indexes are 0-based
If targetIndex <> i Then
' Copy to target position
Indexes(targetIndex) = Indexes(i)
NumberOfItems(targetIndex) = NumberOfItems(i)
Description(targetIndex) = Description(i)
'Clear resp. initialize old row
Indexes(i) = CUInt(i + 1) ' Make index 1-based
NumberOfItems(i) = 1
Description(i) = 1
End If
Next
End Sub
Step 2:
Private Sub AddMissingNumberOfItems()
' Insert empty rows after items with NumberOfItems > 1.
' We do it backwards to not mess up our indexes.
For i As Integer = Indexes.Count - 1 To 0 Step -1
For k As UInteger = 2 To NumberOfItems(i)
Addresses.Insert(i + 1, 0)
Indexes.Insert(i + 1, 0)
NumberOfItems.Insert(i + 1, 0)
Description.Insert(i + 1, 0)
Next
Next
End Sub
If you use the following test list for the descriptions, you will better see which rows have been moved or added
Private Description As New List(Of UInt32) From {2UI, 3UI, 4UI, 5UI, 6UI, 7UI}

Display line says index was out of range

There is a button that displays an item from an array by searching an input in another array. In this instance, I want to display an item from animalArray.
To do this, a user needs to input a certain name from the nameArray. Binary search, will compare the input and nameArray(middle). But when all that is done, when displaying the array using listbox it crashes and says "index was out of bounds of the array". Even though all items in all arrays has 9 items including 0.
binarySearch(nameArray, animalArray, InputBox("Enter Owner name", "Owner name"))
How to solve this?
Sub binarySearch(ByVal array1, ByVal array2, ByVal item)
Sort()
Dim low = 0
Dim high = 9
Dim middle As String
Dim subfindindex = -1
Do While low <= high And subfindindex = -1
middle = (low + high) \ 2
If array1(middle) = item Then
subfindindex = middle
Exit Do
End If
If middle > item Then
high = middle - 1
Else
low = middle + 1
End If
Loop
ListBox1.Items.Add(array2(subfindindex)) '<--- index was out of bounds of array
End Sub
Your main problem is that you're comparing a number to a name, and attempting to determine which is greater:
If middle > item Then
Instead, you'll want to compare the number (the value of the middle variable) to the index of the name in the name array.
That said, you'll get more mileage with this by using lists instead of arrays, and by descriptively naming and strongly typing your parameter variables. Here's the working code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Animals As New List(Of String)
Dim Names As New List(Of String)
Animals.Add("Dog")
Animals.Add("Cat")
Animals.Add("Sheep")
Animals.Add("Goat")
Animals.Add("Chicken")
Animals.Add("Fish")
Animals.Add("Cow")
Animals.Add("Snake")
Animals.Add("Rabbit")
Animals.Add("Squirrel")
Names.Add("Jim")
Names.Add("Betty")
Names.Add("Frank")
Names.Add("Paul")
Names.Add("Susan")
Names.Add("Debbie")
Names.Add("Bob")
Names.Add("Tina")
Names.Add("Fred")
Names.Add("Bill")
Me.BinarySearch(Names, Animals, InputBox("Enter Owner name", "Owner name"))
End Sub
Sub BinarySearch(Names As List(Of String), Animals As List(Of String), Name As String)
Dim SubFindIndex As Integer
Dim Middle As Integer
Dim High As Integer
Dim Low As Integer
SubFindIndex = -1
High = 9
Low = 0
Do While Low <= High And SubFindIndex = -1
Middle = (Low + High) \ 2
If Names(Middle) = Name Then
SubFindIndex = Middle
Exit Do
End If
If Middle > Names.IndexOf(Name) Then
High = Middle - 1
Else
Low = Middle + 1
End If
Loop
Me.ListBox1.Items.Add(Animals(SubFindIndex))
End Sub
End Class
But there's a lot simpler way of accomplishing the same goal:
Sub BinarySearch2(Names As List(Of String), Animals As List(Of String), Name As String)
Dim Animal As String
Dim Index As Integer
Index = Names.IndexOf(Name)
Animal = Animals(Index)
Me.ListBox1.Items.Add(Animal)
End Sub
--EDIT--
Here's what you should see after entering a name from the list in the InputBox:

how do i change the colour of a button based on a string input

For my computing project I am creating a game of risk this requires me to randomly generate the initial countries of the players (I have started with 2 players for simplicity), for this I am going to have the buttons (which represent the countries) to change colour to denote which of the players country it is.
I have tried to assign each player a string value of their colour then set the button back colour to that value. The problem with that at the moment is with the line of "b.Tag.BackColor = Players_Colours(N)" as the value that Players_Colours(N) gives is "S"c for some reason.
Any ideas why that is the case or anything would be appreciated.
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
Public Function Random_country_picker(ByVal players)
Dim County_List = {"Oxfordshire", "Buckinhamshire", "Berkshire", "London", "Hampshire", "Surrey", "West_Sussex", "East_Sussex", "Kent", "Bedfordshire", "Cambridgeshire", "Hertfordshire", "Essex", "Cornwall", "Devon", "Gloucestershire", "Whiltshire", "Lancashire", "Cumbria", "Cheshire", "Manchester", "Merseyside", "Lincolnshire", "Staffordshire", "Herefordshire", "County_Durham", "North_Yorkshire", "South_Yorkshire", "Warwickshire", "Northumberland", "West_Yorkshire", "East_Yorkshire", "Shropshire", "Northamptonshire", "Derbyshire", "Nottinghamshire", "Worcestershire", "Somerset", "Dorset", "Isle_Of_White", "Norfolk", "Suffolk"}
Dim value As String
Dim num = 0
Dim nump = 42 / players
Dim N As Integer
Dim Players_Colours As String
Dim z As String
Players_Colours = {"Pink", "Red"}.ToString
N = 0
Randomize()
Dim rnd As New Random()
Dim index As Integer
While nump > num
If N > Players_Colours.Length Then
N = 0
End If
index = rnd.Next(0, County_List.Length)
value = County_List(index)
For Each b As Windows.Forms.Button In Me.Controls
If b.Tag = index Then
b.Tag.BackColor = Players_Colours(N)
End If
Next
Array.Clear(County_List, index, 1)
num += 1
N += 1
End While
Return 0
End Function
Random_country_picker(2)

Visual Basic: How can i display the prime numbers between 1 and the inputted number

Hello everyone so i'm trying to find the prime numbers of any input. I want them to be in a listbox and the input in a text box. I would like to use two arguments but i don't know how to. this is the code i have i need dire help. I am not the best at visual basic i just need some guidance. My code isn't working but display a drop down box when i press display.
Public Class Form1
Private Sub Button3_Click_1(sender As Object, e As EventArgs) Handles Button3.Click
Dim prim As Integer
Dim test As Integer
Dim imPrime As Boolean = False
prim = CInt(txtNum.Text)
test = prim
If prim = 1 Then
imPrime = False
MessageBox.Show("Enter a number greater than one please")
Else
Do While prim >= 2
For i As Integer = 2 To prim
If prim Mod i = 0 Then
imPrime = False
Exit For
Else
imPrime = True
lstPrime.Items.Add(prim)
End If
Next
Loop
End If
If imPrime = True Then
lstPrime.Items.Add(prim)
End If
End Sub
End Class
This is my fastest VBA code to generate prime numbers between two numbers.
The generated prime numbers are put in clipboard. You will need to open
your ms office word and type Ctrl+V to view all the generated prime numbers.
Sub generateprimenumbersbetween()
Dim starting_number As Long
Dim last_number As Long
Dim primenumbers As Variant
Dim a As Long
Dim b As Long
Dim c As Long
starting_number = 1 'input value here
last_number = 1000000 'input value here
primenumbers = ""
For a = starting_number To last_number
c = Round(Sqr(a)) + 1
For b = 2 To c
If a = 1 Or (a Mod b = 0 And c <> b) Then
Exit For
Else
If b = c Then
primenumbers = primenumbers & " " & a
Exit For
End If
End If
Next b
Next a
Dim answer As DataObject
Set answer = New DataObject
answer.SetText primenumbers
answer.PutInClipboard
End Sub
I think the while loop is not working as you intend. You need two loops, the first one counting up to the possible prime, and an inner one counting up to the counter in the outer loop.
You can find examples everywhere... here's one implemented in C#, but since your question was specifically about a listbox, I've translated it to VB.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
calculatePrimes()
End Sub
Private Sub calculatePrimes()
Dim prim As Integer
Dim count As Integer = 0
prim = CInt(Me.TextBox1.Text)
If prim < 3 Then
MsgBox("Please enter a bigger number")
Return
End If
Me.ListBox1.Items.Clear()
For i As Integer = 1 To prim
Dim isPrime As Boolean = True
For j As Integer = 2 To i
If (i Mod j <> 0) Then count = count + 1
Next
If count = (i - 2) Then Me.ListBox1.Items.Add(i)
count = 0
Next
End Sub
End Class
(This assumes you have a textbox for input called TextBox1 and a listbox for display called ListBox1)

Bubble Sort logical error VB.NET

This program suppose to sort records(in arySort) in ascending order by last name(index 1 in aryTemp and aryTemp2) and place the result in the list box over the old, preloaded, unsorted records.
It sorts them strangely, I have to click multiple times the Ascending button to get the actual sort result that I suppose to get from clicking the button once.
Why doesn't it sort items with a single mouse click?
The source:
Public Class Form1
Dim FILE_NAME As String = "Students.txt"
Dim numberOfRecords As Integer 'total number of records
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If System.IO.File.Exists(FILE_NAME) = True Then
Dim objReader As New System.IO.StreamReader(FILE_NAME)
Do While objReader.Peek() <> -1
lstBox.Items.Add(objReader.ReadLine)
numberOfRecords += 1
Loop
objReader.Close()
End If
End Sub
Private Sub btnAscending_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAscending.Click
'load all students into array
Dim arySort(numberOfRecords - 1) As String
Dim aryTemp() As String 'holds first record's last name
Dim aryTemp2() As String 'holds second record's last name
For i = 0 To numberOfRecords - 1
arySort(i) = lstBox.Items(i)
Next
Dim temp As String 'holds temporary record
Dim k As Integer
For i = 0 To arySort.Length - 2
aryTemp = Split(arySort(i), " ")
For k = i + 1 To arySort.Length - 1
aryTemp2 = Split(arySort(k), " ")
If aryTemp(1) < aryTemp2(1) Then
temp = arySort(k)
arySort(k) = arySort(i)
arySort(i) = temp
End If
Next
Next
lstBox.Items.Clear()
numberOfRecords = 0
For i = 0 To arySort.Length - 1
lstBox.Items.Add(arySort(i))
numberOfRecords += 1
Next
End Sub
End Class
If you just need to sort your list (as you say in the comment), don't implement your own sort mechanism but use the one of .NET:
' Define how we want to compare items '
Function compareByLastName(ByVal item1 As String, ByVal item2 As String) As Integer
Return String.Compare(item1.Split(" ")(1), item2.Split(" ")(1))
End Function
Private Sub btnAscending_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAscending.Click
' load all students into array '
Dim arySort(numberOfRecords - 1) As String
For i = 0 To numberOfRecords - 1
arySort(i) = lstBox.Items(i)
Next
' Use built-in .NET magic '
Array.Sort(arySort, AddressOf compareByLastName)
' Write the values back into your list box '
lstBox.Items.Clear()
numberOfRecords = 0
For i = 0 To arySort.Length - 1
lstBox.Items.Add(arySort(i))
numberOfRecords += 1
Next
End Sub
This uses the built-in quicksort algorithm of the .NET class library. Here's the documentation of the method we are using: Array.Sort(T(), Comparison(Of T)).
compare with my working bubble sort:
Public Sub BubbleSort(ByVal arr() As Integer)
Dim flag As Boolean = False
For i As Integer = 0 To arr.Length - 1
For j As Integer = 0 To arr.Length - 2 - i
If arr(j + 1) < arr(j) Then
flag = True
Dim temp As Integer = arr(j)
arr(j) = arr(j + 1)
arr(j + 1) = temp
End If
Next
If flag = False Then Return ' no swaps =>already sorted
Next
End Sub
I see a two major issues with your algorithm:
It's not bubble sort. Bubble sort swaps adjacent elements, i.e., it swaps i with i+1. You, on the other hand, swap some element i with the first j > i where name(i) < name(j). Maybe you should show us, in pseudo code, which algorithm you are actually trying to implement?
aryTemp contains element i and aryTemp2 contains some element j > i. Why do you swap the elements if aryTemp(1) < aryTemp2(1)? Isn't that already the correct order if you want your elements to be sorted ascending?