Programming Gambas from Zip/Arrays
Arrays, Lists, Sorting and Shuffling
[edit | edit source]There are times when you need not just separated memories with individual names like Speed, Distance, Time but a list of memories, a collection of variables, that can be numbered. So you might have Speed[0], Speed[1], Speed[2] and so on, all storing different speeds, or a list of several times that have names like Time[0], Time[1], Time[2] etc. This is called an array.
The elements (items) in the array are numbered, starting from zero, and you use square brackets. Teachers might have an array of student names, Student[0], Student[1] … Student[Student.Max]. Arrays have a count (e.g. Student.Count) and a max (Student.Max). Don’t go past Max or you will be out of bounds. And that means detention after school for sure.
You can have arrays of just about anything. However, you need to create them with the NEW operator when you want them.
An array of strings:
Dim Names As New String[]
Names = ["John", "Mary", "Lucy", "Owen", "Peter", "Clare", "Thomas"]
An array of integers, using the array’s Add method:
Dim Numbers As New Integer[]
'put the numbers 8 to 28 into an array; Numbers[0] is 8; Numbers[20] is 28
For i as integer = 8 to 28
Numbers.add(i)
Next
Arrays have Sort and Shuffle methods. You can write any of these. gb.descent and its mate are constants in the gb component.
Names.sort
Numbers.sort
Names.sort(gb.descent)
Numbers.sort(gb.descent)
Names.shuffle
Numbers.shuffle
To see your array, put a listbox on your form then put your array into its list. The array on the right goes into the listbox’s list on the left. The code will look something like this. More detailed instructions follow.
Listbox1.List = Names
Listbox1.List = Numbers
The buttons are called bShuffle and bSort.
Public s As New String[]
Public Sub Form_Open()
s = ["Apple", "Banana", "Carrot", "Dragonfruit", "Elderberry", "Fig", "Grape", "Honeydew", "Imbe", "Jackfruit", "Kiwi", "Lime"]
ListBox1.List = s
End
Public Sub bSort_Click()
s = ListBox1.List 'copy the list into array s[]
ListBox1.List = s.Sort() 'put the sorted s[] into the listbox's list
End
Public Sub bShuffle_Click()
s = ListBox1.List 'copy the list into array s[]
s.Shuffle 'shuffle the array s[]
ListBox1.List = s 'put s into the listbox's list
End
Notice that you cannot say ListBox1.List.Shuffle, even though ListBox1’s List property acts like an array. Yes, it is an array. No, it doesn’t come with the Shuffle method.
The shuffle button has an extra line in its Click handler compared with the sort button. s.Sort() is a thing, a function. s.Shuffle is a method. It is not a thing but a process, a procedure. It is a sub that does not return any value when it is done. You cannot put it into something. If you tried ListBox1.List = s.shuffle() you would get an error message. The Gambas help shows how they are different:
Sorting alphabetically and Sorting Numerically
[edit | edit source]A listbox with numbers needs to be sorted numerically. Sorting number 1 to 12 alphabetically will give you 1, 10, 11, 12, 2, 3, 4, 5, 6, 7, 8, 9 because alphabetically “10” comes before “2”. Copy the list into an integer array and sort that:
Public Sub bSort_Click()
Dim x As New Integer[]
x = ListBox1.List
x.Sort
ListBox1.List = x
End
You can see this in action:
Public z As New Integer[]
Public s As New String[]
Public Sub Form_Open()
For i As Integer = 1 To 12
z.Add(i)
Next
z.Shuffle
ListBox1.List = z
End
Public Sub Button1_Click()
s = ListBox1.List
ListBox1.List = s.Sort()
End
Public Sub Button2_Click()
z = ListBox1.List
ListBox1.List = z.Sort()
End
Strings
[edit | edit source]Strings can be treated as arrays of characters. So, if Nm = "Gerard" then Nm[0] is G, Nm[1] is e, Nm[2] is r and so on.
However, you cannot change letters like Nm[2]="x" to make Gerard become Gexard. You can get the letter, but you can’t put something into it. You would have to use some of the wonderful functions that strings have. You can do many things with strings. You could use any of these:
Nm = Left(Nm,1) & “x” & Mid(Nm,3)
Nm = Left(Nm,1) & “x” & Right(Nm,4)
Nm = Replace(Nm, “e”, “x”)
Public FirstName As String = "Gerard"
Public Sub b1_Click()
Label1.Text = Left(FirstName, 1) & "x" & Mid(FirstName, 3)
End
Public Sub b2_Click()
Label1.Text = Left(FirstName, 1) & "y" & Right(FirstName, 4)
End
Public Sub b3_Click()
Label1.Text = Replace(FirstName, "e", "z")
End
Arrays of Arrays
[edit | edit source]You can have memories arranged in a list. They would all have the same name, but be numbered like X[0], X[1], X[2] etc:
You can have memories arranged in a grid (square or rectangle) and refer to them by row and column. This is also how the cells are numbered in a GridView or TableView:
You can have them arranged in a cube or prism, so that there are like layers of rectangles. The third number in brackets tells which layer. [Row, Column, Layer]
You can have arrays of them, too, but even though you can have multi-dimensional arrays, simple list arrays are the ones most often used.
Table of Squares, Square Roots and Calculations
[edit | edit source]This program fills a grid with calculations for the numbers one to ten. It also shows how to adjust properties of a gridview—its columns, rows and cells.
Public Sub Form_Open()
Me.Show
With gv1
.Header = GridView.Horizontal
.Columns.Count = 4
.Columns[0].Width = 50
.Columns[1].Width = 60
.Columns[2].Width = 60
.Columns[3].Width = 50
.Columns[0].Text = ("Number")
.Columns[1].Text = ("Square")
.Columns[2].Text = ("Root")
.Columns[3].Text = ("*3+5")
For i As Integer = 0 To 3
.Columns[i].Alignment = Align.Right
Next
.Padding = 5
End With
End
Public Sub b1_Click()
gv1.Rows.Count = 10
End
Public Sub bQuit_Click()
Quit
End
Public Sub gv1_Data(Row As Integer, Column As Integer)
Dim x As Integer = Row + 1
Select Case Column
Case 0
gv1.Data.Text = x
Case 1
gv1.Data.Text = x ^ 2
Case 2
gv1.Data.Text = Format(Sqr(x), "##.000")
Case 3
gv1.Data.Text = x * 3 + 5
End Select
If Row Mod 2 = 0 Then gv1.Data.Background = &HBFFFBF
End
Things to notice are the With … End With lines, setting up the gridview when the form opens, and the _Data() event to fill each cell. gv1.Rows.Count = 10 is enough to trigger the Data() event for every cell in those ten rows.
The _Data() event occurs when the cell has to be painted. The filling of the cells could be done when the Fill button is clicked, but then we would have to use nested For statements to count down the rows and across the columns. Gambas already has to do this, because it has to paint each cell. The _Data() event happens for each cell in each row, so why not put the text into the cells then?
If Row Mod 2 = 0 Then gv1.Data.Background = &HBFFFBF sets the background of the cell to peppermint green if the row number has a remainder of zero when divided by 2. Mod means “the remainder when you divide by ...”. For example 3 Mod 2 is 1, so row 3 has a white background. 4 Mod 2 is 0 because four divided by two equals two remainder zero, so row 4 has a green background.
We could alternate two colours, pink and green, with
gv1.Data.Background = If(Row Mod 2 = 0, &HBFFFBF, &HFFCFCF)
To colour the columns, try this in the tv1_Data() event:
gv1.Data.Background = Choose(Column + 1, &FFAAFF, &FFFFAA, &AAFFFF, &AAAAFF)
Format(Sqr(x), "##.000") is an interesting expression. The Format function takes a floating point number like 1.41421356237 and formats it according to the pattern supplied. "##.000" means two digits if you need them, a dot, and three decimal places using zeros. What number to format? Sqr(x). This is the square root of the number x. The square root of two appears as 1.414.
Format Function
[edit | edit source]+ | Print the sign of the number. |
- | Print the sign of the number only if it is negative. |
# | Print a digit only if necessary. |
0 | Always print a digit, padding with a zero if necessary. |
. | Print the decimal separator. |
, | Print the thousand separators. |
% | Multiply the number by 100 and print a per-cent sign. |
E | Introduces the exponential part of a Float number. The sign of the exponent is always printed. |
There are many more symbols for formatting dates and currency.
The Game of Moo
[edit | edit source]To play the game of Moo, also called Bulls and Cows, one person (the computer!) chooses a mystery number. It has 4 digits, and all digits are different. Wikipedia says, “The modern game with pegs was invented in 1970 by Mordecai Meirowitz, an Israeli postmaster and telecommunications expert. It resembles an earlier pencil and paper game called Bulls and Cows that may date back a century or more.” “Moo was written in 1970 by J. M. Grochow at MIT in the PL/I computer language.”
After each guess the computer tells you how many bulls you scored and how many cows. A bull is a digit in your number that is in its correct place in the mystery number. A cow is a digit that is present in the mystery number but is in its wrong place. Thus you are aiming for BBBB, all four digits in their correct places. CCCC means you have the correct digits but they are not in their right places. BBC means two digits are correctly placed, one of the other digits is in the number but in the wrong place, and another digit is not in the number at all. Some people play by the rule that you win if you guess it in ten or fewer turns. Bulls are listed first and cows second. You are not told which digits are the bulls or which are cows.
You need 2 textboxes, a gridview called gvHistory, and a button called bNewGame with the text property “New Game”.
The New Game button is initially invisible.
Public MyNumber As String
Public Count As Integer
Public Sub Form_Open()
gvHistory.Columns.Count = 2
ChooseNumber
End
Public Sub ChooseNumber()
Dim Digits As New String[]
Dim i, p1, p2 As Integer
Dim d As String
For i = 0 To 9
Digits.Add(Str(i))
Next
Digits.Shuffle
MyNumber = Digits[0] & Digits[1] & Digits[2] & Digits[3]
End
Public Sub EvaluateGuess()
Dim s As String
Dim i, j As Integer
Dim YourGuess As String = tbGuess.text
Count += 1
For i = 0 To 3 'look for bulls
If YourGuess[i] = MyNumber[i] Then s &= "B"
Next
For i = 0 To 3 'look for cows
For j = 0 To 3
If i <> j And YourGuess[i] = MyNumber[j] Then s &= "C"
Next
Next
tbReply.Text = s
gvHistory.Rows.Count += 1
gvHistory[gvHistory.Rows.max, 0].text = YourGuess
gvHistory[gvHistory.Rows.max, 1].text = s
If s = "BBBB" Then Congratulate
tbGuess.SelectAll
End
Public Sub Congratulate()
Message("<b>Congratulations!</b><br><br>Got it in " & count)
FMain.Background = Color.Yellow '&FFFF00
bNewGame.Visible = True
End
Public Sub bNewGame_Click()
FMain.Background = Color.Default
bNewGame.Visible = False
gvHistory.Rows.Count = 0
Count = 0
ChooseNumber
tbReply.text = ""
tbGuess.text = ""
tbGuess.SetFocus
End
Public Sub tbGuess_Change()
If Len(tbGuess.text) = 4 Then EvaluateGuess
End
Now for the post-mortem:
There are two public variables. MyNumber is the computer’s secret number. Count keeps count of how many guesses.
Form_Open() On startup, set gridview to 2 columns and choose the secret number.
Public Sub ChooseNumber() Put digits 0 to 9 in a 10-item array called Digits and shuffle. The secret number is the first four digits. They will be random and none is repeated.
Public Sub EvaluateGuess() When you evaluate a guess, it is one more guess so add 1 to Count. Look for Bulls: Is the first character in your guess the same as the first character in the number? Check second, third and fourth characters too. Each time two characters match, take what s was and add a B to the end of it using s &= "B".
In looking for cows, i goes through 0, 1, 2, 3, looking through your number each time. For each one of those digits in your number, check all the digits in the secret number looking for a match, but disregard where the position numbers are the same (like the third digit in the secret number and the third digit in my guess), for that is a bull and has already been found.
S is a variable that contains BBBB or BBCC or B or whatever.
Add a row to the history gridview and put the guess in the first column and its evaluation into the second column.
Public Sub Congratulate() Show a message saying “Congratulations! You got it in 8” or whatever. Change the form’s colour to yellow. Make the New Game button visible.
Public Sub bNewGame_Click() To start a new game, remove the yellow colour, hide the New Game button, remove everything from the history gridview, set the count of guesses back to zero, choose another number, blank out the two textboxes, and set the focus to the textbox where you type in a guess so you are ready to start typing.
Public Sub tbGuess_Change() When the text in the Guess textbox changes because you have typed another digit, check the length of what is typed and if it is 4 characters long, evaluate the guess.
Adding an “I Give Up” Feature
[edit | edit source]Let us make it that typing a question mark means “I give up—tell me the answer”. We need as new event, tbGuess_KeyPress(). As soon as a question mark is typed, this handler will check the static class, Key, to see if the character typed was “?”. If so, message us the correct answer and start a new game.
Starting a new game is exactly what we have in the _Click handler for the New Game button. This code needs to be taken out of the _Click handler and put in a sub of its own. We can call on this NewGame sub when the button is clicked or when the user gives up by typing “?”. Here is the rearranged and extra code:
Public Sub bNewGame_Click()
NewGame
End
Public Sub NewGame()
FMain.Background = Color.Default
bNewGame.Visible = False
gvHistory.Rows.Count = 0
Count = 0
ChooseNumber
tbReply.text = ""
tbGuess.text = ""
tbGuess.SetFocus
End
Public Sub tbGuess_KeyPress()
If Key.Text = "?" Then
Message("My number was " & MyNumber)
NewGame
Stop Event
Endif
End
Stop Event is there to prevent the question mark appearing in the tbGuess textbox. It is not necessary.
The important principle is (and you can memorise this or take this to the bank) if you want to refer to the same lines of code in two or more places, put them in their own sub and call on them by name.
Assignment Operators
[edit | edit source]x = x+2 | Add 2 to whatever x used to be, then put the answer back into x. |
x += 2 | The same thing: x becomes whatever it was (=), plus (+) 2. |
x = x * 4 | Multiply x by 4, and put the answer back into x. |
x *= 4 | The same thing: x becomes whatever it was (=), times (*) 4. |
s = s & "abc" | s becomes whatever s was and (&) “abc” tacked onto the end of it. |
s &= "abc" | The same thing: s becomes whatever it was (=) and (&) “abc” onto the end of it. |
There are numeric operators including ^ to mean “raised to the power of”. Boolean operators are AND, OR and NOT. There are others but these are the most used and useful.