Randomizing an array - arrays

I wish to implement the Dr.D.E.Knuth's Subtractive RANDOM number generation algorithm. I wish to implement an ATM panel on which when very time user log-in the buttons will be scrambled. every button will change its position.
Here is my code:
Public Sub addbutton()
Dim n As Integer = 0
For i As Integer = 0 To 10
' Initialize one variable
btnArray(i) = New System.Windows.Forms.Button
Next i
While (n < 10)
With (btnArray(n))
.Tag = n + 1 ' Tag of button
.Width = 40 ' Width of button
.Height = 40
FlowLayoutPanel1.Controls.Add(btnArray(n))
.Text = Chr(n + 48)
AddHandler .Click, AddressOf Me.ClickButton
n += 1
End With
End While
End Sub
Then, for sending information to button Text, I used:
Dim btn As Button = sender
TextBox1.Text += btn.Text
Now the major task is to shuffle the btnArray() with Random() function.. But I've failed to do this. I managed to get some code for shuffling the array like follows:
Imports System.Security.Cryptography
Public Class ArrayUtilities
Private Random As RNGCryptoServiceProvider = New RNGCryptoServiceProvider
Private Bytes(4) As Byte
Public Function ShuffleArray(ByVal argArr As Array) As Array
Dim FirstArray As New ArrayList(argArr)
Dim SecoundArray As Array = Array.CreateInstance(GetType(Object), FirstArray.Count)
Dim intIndex As Integer
For i As Integer = 0 To FirstArray.Count - 1
intIndex = RandomNumber(FirstArray.Count)
SecoundArray(i) = FirstArray(intIndex)
FirstArray.RemoveAt(intIndex)
Next
FirstArray = Nothing
Return SecoundArray
End Function
Private Function RandomNumber(ByVal argMax As Integer) As Integer
If argMax <= 0 Then Throw New Exception
Random.GetBytes(Bytes)
Dim intValue As Integer = (BitConverter.ToInt32(Bytes, 0)) Mod argMax
If intValue < 0 Then intValue = -intValue
Return intValue
End Function
End Class
Module Module1
Sub Main()
Dim AU As ArrayUtilities
AU = New ArrayUtilities
Dim GivenArray As Integer() = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Dim NewArray As Array = AU.ShuffleArray(GivenArray)
Dim i As Integer
Dim stb As New System.Text.StringBuilder
stb.Append("GivenArray = {0,1,2,3,4,5,6,7,8,9}")
stb.Append(vbCrLf)
stb.Append("NewArray = {")
For i = 0 To NewArray.Length - 2
stb.Append(NewArray(i).ToString)
stb.Append(", ")
Next
stb.Append(NewArray(NewArray.Length - 1).ToString)
stb.Append("}")
Console.Write(stb.ToString)
Console.Read()
End Sub
End Module
Yet, when we debug this code we get RANDOMNESS for the array. In the same way, I want randomness for my buttons on form.
Thank you sir. sir i tried the code that u suggested.
I was missing the incremental character "n".
Tthe debug-able code is
flowlayoutpannel.controls.add(out(n)).
but it is not working as i wanted and ABOVE code is just to show the way i want 2 shuffle the BUTTONS.
Is there any simpler way to jst create an button array and randomize them with RANDOM() and adding to form.
My buddies says you are so stupid that u are working on this topic from last 20-25DAYS

There are quite some "shuffle" algorithms (search Fisher-Yates for example) and they are usually not difficult to implement. The EASIEST (imho) way, ist to use LINQ:
Dim r As New Random
Dim out = (From b In btnArray Order By r.Next Select b).ToArray
Maybe the question is not clear: Do you want to shuffle the POSITIONS of the buttons or do you want to shuffle the CONTENT (buttons) of the Array?

To set the position of the buttons randomly in the panel, instead of using n from 0 to 9 in the loop, you can use a random value from 0 to 9. Be sure you don't use the same value twice.

You don't need to use a cryptographically secure random number generator for that, nor do you need a separate class.
Private Shared rng As New Random()
Private Shared Function ShuffleArray(Of T)(arr() As T) As T()
Dim left = Enumerable.Range(0, arr.Length).ToList()
Dim result(arr.Length - 1) As T
For i = 0 To arr.Length - 1
Dim nextIndex = rng.Next(left.Count)
result(i) = arr(left(nextIndex))
left.RemoveAt(nextIndex)
Next
Return result
End Function

Related

VB.net Splitting a 1D array down into a 2D array

I am currently writing a (multiple choice) quiz program using VB.net I have read the answer options in from a .txt file into a single dimension temporary array however I would like to split this down into each question and the answer options for each questions into a 2D array so that (0,0) would be option A for question one and then (0,1) would be Option B for question 1 etc and then (1,0) would be option A for question 2. Below is the method I have tried however I get the error: "Object reference not set to an instance of an object" when adding 1 to a variable when I try and run this section of the code optnum = optnum + 1 Any help would be greatly appreciated, either fixing my code below or suggesting another method.
Dim optnum As Integer
Dim tempq As Integer = 0
Gameload(Phase_3.sounds)
Questionnum = 0
L_start.Hide()
optnum = 0
'splits the temp array down into options for each question
For i = 0 To 39
questions(tempq, optnum) = temparray(i)
optnum = optnum + 1
'there are 4 options for each question
'moves on to the next question when there is 4 options in the question
If optnum = 3 Then
tempq = tempq + 1
optnum = 0
End If
Next
For i = 0 To 3
L_option1.Text = questions(0, i)
Next
question_set()
Edit:
Here is the new full code I am still getting the error: Object reference not set to an instance of an object but now at the next in this section of code.
'''
For optnum = 0 To 3
questions(i, optnum) = temparray(i * 4 + optnum)
Next
'''
Thank you for all the help so far
'''
Public Class Game
Dim submission As Integer
Dim Correct_ans As Integer
Dim temparray() As String
Dim questions(,) As String
Dim Questionnum As Integer
Dim rs As New Resizer
Private Sub Game_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'finds all components on the screen in preperation if the screen resizes
rs.FindAllControls(Me)
L_start.Show()
End Sub
Private Sub Game_Resize(sender As Object, e As EventArgs) Handles Me.Resize
'resizes all components on the screen to same proportions
rs.ResizeAllControls(Me)
End Sub
Sub Gameload(ByVal sounds As String)
Dim pack As String
'reads in the sound pack
pack = My.Resources.ResourceManager.GetString(sounds)
Phase_3.Close()
'splits the pack into an array so that it can be broken down into questions
temparray = pack.Split(","c)
End Sub
Sub L_start_Click(sender As Object, e As EventArgs) Handles L_start.Click
Dim optnum As Integer
Dim tempq As Integer = 0
Gameload(Phase_3.sounds)
Questionnum = 0
L_start.Hide()
optnum = 0
'splits the temp array down into options for each question
For i = 0 To temparray.Count / 4
For optnum = 0 To 3
questions(i, optnum) = temparray(i * 4 + optnum)
Next
Next
For i = 0 To 3
L_option1.Text = questions(0, i)
Next
End Sub
'''
This is just my opinion but I think your aproach would be hard to maintain. I never saw the value of a class until I actually tried one. Maybe this is your chance.
Public Class Quiz
Public Property QuestionNumber As Integer
Public Property Question As String
Public Property AnswerA As String
Public Property AnswerB As String
Public Property AnswerC As String
Public Property AnswerD As String
Public Property CorrectAnswer As String
Public Overrides Function ToString() As String
Return $"Question: {QuestionNumber}.{Question} Answer Choices: {AnswerA}, {AnswerB}, {AnswerC}, {AnswerD} Correct Answer - {CorrectAnswer}"
End Function
End Class
To use your class...
Private QuestionList As New List(Of Quiz)
Private Sub OPCode2()
Dim temparray = File.ReadAllLines("answers.txt")
Dim temparraylocation As Integer
Dim questions = File.ReadAllLines("questions.txt")
Dim correctAnswers = File.ReadAllLines("correct.txt")
For i = 0 To questions.Length - 1
Dim qu As New Quiz
qu.QuestionNumber = i + 1
qu.Question = questions(i)
qu.CorrectAnswer = correctAnswers(i)
qu.AnswerA = temparray(temparraylocation)
temparraylocation += 1
qu.AnswerB = temparray(temparraylocation)
temparraylocation += 1
qu.AnswerC = temparray(temparraylocation)
temparraylocation += 1
qu.AnswerD = temparray(temparraylocation)
temparraylocation += 1
QuestionList.Add(qu)
Next
For Each q In QuestionList
Debug.Print(q.ToString)
Next
End Sub
Where's your declaration for temparray and questions. Will the quiz always have 4 choices and 10 questions?
It might be easier for you to have a nested loop so that i is temparray.count/4 and optnum is 0-3, then you can populate questions(i, optnum) = temparray(i*4+optnum)
Looking at your new code, you haven't initialised the questions variable. Only declared it.
Personally I would change questions to a list(of question), then use Mary's answer.

Duplicate X Axis for Graph (VB.net)

I am having some issues with my VB.net database, I am trying to present a chart which shows a composition of customers who are members or not from a graph. The graph works, however; there are duplicates (as there are 8 bars instead of 2 bars):
For my database, I've used lists rather than conventional methods such as SQL. However, I'm uncertain if I've made a mistake or I'm missing something, here's the code:
Dim a As Integer
Dim b As Integer
Dim status As String
Dim countList As New List(Of Integer)
Dim statusList As New List(Of String)
Dim yesList As New List(Of String)
Dim count As Integer = 0
For a = 0 To memberList.Count - 1
status = memberList.Item(a).memberStatus
count = 0
For b = 0 To memberList.Count - 1
If status = memberList.Item(b).memberStatus Then
count = count + 1
End If
Next
statusList.Add(memberList.Item(a).memberStatus)
countList.Add(count)
Next
For i = 0 To countList.Count - 1
Debug.Print(memberList(i).memberStatus & countList(i).ToString)
Next
Chart_MemMostPopularTown.ChartAreas("ChartArea1").AxisX.MinorTickMark.Enabled = True
Chart_MemMostPopularTown.ChartAreas("ChartArea1").AxisX.Interval = 1
Chart_MemMostPopularTown.ChartAreas("ChartArea1").AxisX.IsLabelAutoFit = True
Chart_MemMostPopularTown.ChartAreas("ChartArea1").AxisX.LabelAutoFitStyle = DataVisualization.Charting.LabelAutoFitStyles.DecreaseFont
Chart_MemMostPopularTown.Series(0).Points.DataBindXY(statusList, countList)
If there is anything I've missed out, or if I've been too vague; please do let me know. I'm new to this site BTW so apologise for mistakes or lack of clarity.
Kind Regards

A practically irrelevant just mildly interesting algorithm and how do I get the logic to work?

I was in the shower yesterday, and an idea hit me. It's a mathematical pattern or set of rules to find a list of integers.
The practical application of this pattern or whatever you could call it is up to the super mathematicians, I just wanted to see if I could make a program that could find it.
At the moment I'm using VB.net as it's what I HAVE to use for college right now, but im open to C++ as well.
So, the rules of this pattern are:
You get an Integer as your "factor", and multiply it by itself as many times as you like. This creates a list of numbers that you use as namespaces or what I'd call "containers".
If the factor was say, 2, the list would look like this - 4, 8, 16, 32, 64 etc. (excluding the base factor).
Now under each item of the list you place all integers that could fit inside it. If the number of the container is 8 for example, every number from 1 to 7 would be listed.
However the rules go further than that.
A number inside the container cannot be listed if;
it's = 1 or 2
it's = any number in the container before
it's = the factor before
or is divisible by any number in the container before.
For example
[4]-[8]-[16]-[32]
3 7 13 31
5 12 29
11 26
9 25
6 23
4 19
3 17
14
10
7
5
As you can see the numbers you get are always different. So I was working on a form in VS 2015, that allowed you to enter the factor, and the number of iterations (how long the list went) in the list.
The issue is, as you might of guessed by the fact that I'm actually doing this in the first place, is that my logic isn't all that great. As a programer I am a begginer, and as a logical thinker I am not the best.
See below what I've tried out so far. It's just what was in between the button sub:
Dim iteration As Integer = EtrIterationCount.Text
Dim factor As Integer = EtrNumericFactor.Text
Dim Container()() As Integer = New Integer(iteration)() {}
ReDim Container(iteration)(1)
Dim Contents() As Integer = New Integer() {}
Dim Base As Integer = factor
For X = 1 To iteration - 1
Container(X)(1) = New Integer()
Base = Base * factor
Container(X)(0) = Base
Next
Container(0)(0) = factor
For X = 0 To iteration - 1
Dim Test As Integer = Container(X)(0)
Dim Num = Test
For Num = Num To 0 Step -1
If X = 0 Then
For W = Num To 0 Step -1
If Not Test = 1 Then
Contents(W) = Test
End If
Next
Array.ConstrainedCopy(Contents, Contents.Length, Container, Container(X)(1), Contents.Length)
ElseIf X >= 1 Then
For W = Num To 0 Step -1
For J = 0 To Contents.Length - 1
If Not Contents(J) Mod Container(X - 1)(1) = 0 Then
If Not Test = 1 And Test = Container(X)(0) And Contents.Contains(Test) Then
Contents(W) = Test
End If
End If
Next
Next
Array.ConstrainedCopy(Contents, Contents.Length, Container, Container(X)(1), Contents.Length)
End If
Test = Test - 1
MsgBox(Container(X)(1))
Next
Next
What I have basically tried to do, is something I've not done before, and create a jagged/nested array, the first array acting as the container listing all the iterations and its first row containing the factored numbers, the second row containing the array with the list of values.
It was suggested by a first that I use Vectors, or a class of vectors to sort out this problem, but I haven't got the foggiest how to do that.
If anything I would like this to be practice on how to deal with arrays and maybe teach me some logic that I'm missing.
There are probably several ways to do this, many of them better than what I came up with, but a Dictionary(Of Integer, List(Of Integer)) will suffice to hold the data:
Option Infer On
Option Strict On
Module Module1
Sub Main()
Console.Write("Factor: ")
Dim factor = CInt(Console.ReadLine())
Console.Write("Iterations: ")
Dim iters = CInt(Console.ReadLine())
Dim result As New Dictionary(Of Integer, List(Of Integer))
Dim thisSection = factor
Dim prevSection = 0
For i = 2 To iters + 1
thisSection = thisSection * factor
result.Add(thisSection, New List(Of Integer))
For j = 3 To thisSection - 1
Dim isDivisible = False
If prevSection > 0 Then
If j Mod prevSection = 0 Then
isDivisible = True
End If
If Not isDivisible Then
For Each n In result(prevSection)
If j Mod n = 0 Then
isDivisible = True
Exit For
End If
Next
End If
End If
If Not isDivisible Then
result(thisSection).Add(j)
End If
Next
prevSection = thisSection
Next
For Each de In result
Console.WriteLine("[" & de.Key.ToString() & "] " & String.Join(", ", de.Value.OrderByDescending(Function(x) x)))
Next
Console.ReadLine()
End Sub
End Module
Sample output:
Factor: 2
Iterations: 4
[4] 3
[8] 7, 5
[16] 13, 12, 11, 9, 6, 4, 3
[32] 31, 29, 25, 23, 19, 17, 14, 10, 7, 5
A List is pretty much like an array, but you can add to it without knowing the number of entries in advance (it increases its capacity automatically).
The variable names I used could probably be more descriptive.
Incidentally, in your example you have 26 in the [32] column, but 13 (=26/2) is in the [16] column.
Also check this out. It uses the Chain pattern. More easy to add new rule.
Module Module1
Sub Main()
Dim results As New Dictionary(Of Integer, List(Of Integer))
Dim initialValue As Integer = 2
Dim multiplier As Integer = 4
For i As Integer = 2 To multiplier + 1
results.Add(Convert.ToInt32(initialValue ^ i), New List(Of Integer))
Next
For dictionaryIndex As Integer = 0 To results.Count - 1
Dim currentFactor As Integer = results.Keys(dictionaryIndex)
For testValue As Integer = 1 To currentFactor - 1
Dim chain As New ChainOfRules()
chain.AddRule(New NotInValuesRule(testValue, 1, 2))
If (dictionaryIndex > 0) Then
Dim previousFactor As Integer = results.Keys(dictionaryIndex - 1)
chain.AddRule(New NotInValuesRule(testValue, results(previousFactor).ToArray))
chain.AddRule(New NotInValuesRule(testValue, previousFactor))
chain.AddRule(New NotDivisibleListRule(testValue, results(previousFactor).ToArray))
End If
If (chain.Process) Then
results(currentFactor).Add(testValue)
End If
Next
Next
For Each pair As KeyValuePair(Of Integer, List(Of Integer)) In results
Console.WriteLine()
Console.WriteLine("Factor: {0}", pair.Key)
Console.WriteLine("-------------------")
For Each i As Integer In pair.Value
Console.WriteLine("Value: {0}", i)
Next
Next
Console.ReadLine()
End Sub
' Rules
Public Interface IRule
Function Apply() As Boolean
End Interface
Public Class NotInValuesRule
Implements IRule
Private Property Value As Integer
Private Property ValuesList As List(Of Integer)
Public Sub New(value As Integer, ParamArray valuesList As Integer())
Me.Value = value
Me.ValuesList = valuesList.ToList()
End Sub
Public Function Apply() As Boolean Implements IRule.Apply
Return Not ValuesList.Contains(Value)
End Function
End Class
Public Class NotDivisibleListRule
Implements IRule
Private Property Value As Integer
Private Property ValuesList As List(Of Integer)
Public Sub New(value As Integer, ParamArray valuesList As Integer())
Me.Value = value
Me.ValuesList = valuesList.ToList
End Sub
Public Function Apply() As Boolean Implements IRule.Apply
Dim result As Boolean = True
For Each previousValue As Integer In ValuesList
result = result And (Value Mod previousValue <> 0)
Next
Return result
End Function
End Class
Public Class ChainOfRules
Private Property Rules As New List(Of IRule)
Public Sub AddRule(rule As IRule)
Rules.Add(rule)
End Sub
Public Function Process() As Boolean
Dim result As Boolean = True
For Each Rule As IRule In Rules
result = result And Rule.Apply()
Next
Return result
End Function
End Class
End Module

Array of pictureboxes and resource images

Hey all i have the following code:
Dim radarStrengthImages() As PictureBox = ({imgRadar_Strength1, imgRadar_Strength2, imgRadar_Strength3, imgRadar_Strength4, imgRadar_Strength5, imgRadar_Strength6, imgRadar_Strength7, imgRadar_Strength8})
Dim radarStrengthResourcesON() As Bitmap = ({My.Resources.radarON_16, My.Resources.radarON_17, My.Resources.radarON_18, My.Resources.radarON_19, My.Resources.radarON_20, My.Resources.radarON_21, My.Resources.radarON_22, My.Resources.radarON_23})
Dim radarStrengthResourcesOFF() As Bitmap = ({My.Resources.radar_16, My.Resources.radar_17, My.Resources.radar_18, My.Resources.radar_19, My.Resources.radar_20, My.Resources.radar_21, My.Resources.radar_22, My.Resources.radar_23})
The imgRadar_StrengthX is the name of the pictureboxes on the form itself and My.Resources.radar_XX is the image for the pictureboxes.
However when i use this code:
Dim intX As Integer = 0
Do Until intX = 8
radarStrengthImages(intX).Image = radarStrengthResourcesON(intX)
intX += 1
Loop
I get an error of:
Object reference not set to an instance of an object
and that happens on this like:
radarStrengthImages(intX).Image = radarStrengthResourcesON(intX)
This kind of code can't work, initialization order is always an important detail. The variables you use don't get a value until after the InitializeComponent() method runs. But the arrays are initialized before that happens. So you just initialize them with Nothing, nada, zippo. "Object reference not set" is the zippo exception you'll get.
You'll have to do it later, that requires moving the initializer for the array into the constructor. Generic syntax for a sample form with textboxes:
Public Class Form1
Dim boxes As TextBox()
Public Sub New()
InitializeComponent()
boxes = New TextBox() {TextBox1, TextBox2, TextBox3}
End Sub
End Class
issue is this array start at index 0 and you have 8 items
change the loop to
Do Until intX = 7
and it should now work
or if the array will change in time, use a variable to handle the max
Module Module1
Sub Main()
Dim intX As Integer = 0
Dim test(7) As Integer '8 item
Dim max = test.Length - 1
Do Until intX = max
intX += 1
Loop
Console.WriteLine("intX: " & intX)
Console.ReadKey()
End Sub
End Module

Converting a System.Array to Double() in VB.NET 2012

I want to convert an array of type System.Array to Double() or Double(,) (I already know which one to convert to). The problematic lines of code follow
Dim kernel As Double() = CType(Array.CreateInstance(GetType(Double), _
{2 * limit + 1}, {-limit}), Double())
Where limit is predefined as a valid, positive Integer. I get the InvalidCastException. How do I go about doing this? Or another way of creating a Double array with < 0 starting index?
You can use the Enumerable.Range method to create a single-dimension array like so:
Dim start = 0
Dim count = 10
Dim singleArray = Enumerable.Range(start, count).ToArray()
To create a multidimensional array you will have to create your own extension method to modify the collection as I have done below
Public Module Extensions
<Runtime.CompilerServices.Extension()>
Function SelectMultiDimension(Of T)(collection As IEnumerable(Of T), rows As Integer, cols As Integer) As T(,)
Dim multiDimArray(rows - 1, cols - 1) As T
Dim i As Integer = 0
For Each item In collection
If i >= multiDimArray.Length Then Exit For
multiDimArray(i \ cols, i Mod cols) = item
i += 1
Next
Return multiDimArray
End Function
End Module
Then you can use it this way:
Dim mArray = Enumerable.Range(start, count).SelectMultiDimension(3, 4)

Resources