Programming Gambas from Zip/Arrays

Arrays, Lists, Sorting and Shuffling

edit

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

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

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

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

   

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
+ 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
 
Mastermind board game

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

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
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.

Programming Gambas from Zip
 ← ThreeThings Arrays TextFiles →