Programming Gambas from Zip/TextFiles

The Game of Animal edit

The Animal Game, in which the computer tries to guess the animal you are thinking of by asking you questions, was around well before people had their own computers. It dates to at least the early 1970s. The author of website http://www.animalgame.com/ says that he/she first saw it in "101 BASIC Computer Games" (ed. by David H. Ahl - Maynard, Mass., Digital Equipment, 1973.) I remember that book. The game was originally developed by Arthur Luehrmann at Dartmouth College. http://www.smalltime.com/Dictator has an online version where you guess the dictator instead of an animal.

The computer starts by knowing only two animals, BIRD and FISH and only one question that can tell the two apart, “Does it swim?”. Questions can be answered YES or NO. If your animal is neither of these, you are asked for a question that would identify your animal. Gradually a list of animals and questions is built up, and the computer becomes smarter and smarter. It is a simple form of Artificial Intelligence (AI). Some wit once said, “Natural stupidity beats artificial intelligence every time”.

To someone starting computing, it may be too complicated. However, there might be bits here and there—saving and loading text from a text file, or the managing of big programs by breaking them into small, meaningful subs, for example—that would be useful. Let it wash over you and get a general feel of things. Practise debugging when you have made a typing error and the program does not run. I was intrigued by it back in the ‘70’s, and it is too good not to include.

Here is a typical dialogue:

  • Are you thinking of an animal? Yes (No ends the program.)
  • It is a fish. No.
  • The animal you were thinking of was a …? Dog
  • Please type in a question that would distinguish a dog from a fish. Does it have legs?
  • For a dog the answer would be… Yes
  • Are you thinking of an animal? Yes
  • Can it swim? Yes
  • Does it have legs? Yes
  • It is a dog. Yes

Here is a data file. It is text only. At the end of every question is the line to go next for yes or no.

  • 0. Can it swim?/1/2
  • 1. Does it have legs?/3/4
  • 2. Does it have 2 big ears?/5/6
  • 3. dog
  • 4. Does it blow air?/9/10
  • 5. rabbit
  • 6. It is little and does it bite you?/7/8
  • 7. mosquito
  • 8. Is it small?/11/12
  • 9. whale
  • 10. fish
  • 11. fly
  • 12. bird

 

The code refers to these objects by the following names. Here goes. The coloured text at the top is TextLabel1. The “Are you thinking of an animal?” line has label LabPrompt and buttons bYes and bNo. The “The animal you were thinking of was a ...” has label LabPromptForAnimal and textbox tbNewAnimal. The “Please type in a question...” line has label LabQuestionPrompt. That is followed by the long textbox tbQuestion. Under it is another label LabQuestion. The last line, “For a 1111 the answer would be...” has label LabPrompt2 and buttons bYes2 and bNo2. The bottom line of buttons are named, from the left, bShowData, bReset, bSave, bOpen and bQuit.

Next is another form that allows you to look at the data. It shows by clicking the Data… button.

 

The form is called FData. It will automatically adjust the positions of objects on it when it is resized by dragging its corner handles. To do this, set its Arrangement property to Vertical. This makes its objects stack from top to bottom. The textarea, taData, has its expand property set to True so that its size will expand to fill the space available.

The three buttons, bSave, bCopy and bClose, are in a red rectangle the is a HBox. HBoxes spread their contents horizontally. This one is called HBox1. There are a couple of panels called Panel1 and Panel2. One is above the hbox and one is between the Copy and Close buttons, to separate them. There is a neat little spring called Spring1 that pushes the Save button to the left and the Copy button, tiny separator panel and Close button to the right.

 

When the game starts, these are the only visible objects. All others have their visible property set to False. The program sets their visibility to true later. There are four areas. Depending on the stage of the game you are up to, one by one they are made visible and the others are hidden.

Look again at the sample data file:

  • 0. Can it swim?/1/2
  • 1. Does it have legs?/3/4
  • 2. Does it have 2 big ears?/5/6
  • 3. dog
  • 4. Does it blow air?/9/10
  • 5. rabbit
  • 6. It is little and does it bite you?/7/8
  • 7. mosquito
  • 8. Is it small?/11/12
  • 9. whale
  • 10. fish
  • 11. fly
  • 12. bird

If the line counter L arrives at a line with an animal name and that name is rejected, the program replaces that line by the new question you give it and the new animal and the wrong animal are added to the end of the list.

The variables declared as Public and Private right at the start are there so that they can be accessed by several different subs. They don’t just last for the duration of the sub. They belong to the form rather than any particular sub. Z[ ] needs to be accessed by the other form, too, so it is Public.

Public z As New String[] 'database
Private Right As Integer 'line to go to if Yes is clicked
Private Wrong As Integer 'line to go to if No is clicked
Private QuestionPrompt As String
Private AnimalPrompt As String
Private NewAnimal As String
Private AskedAQuestion As Boolean 'true if we've just said, "Is it a...?"
Private NewQuestion As String
Private L As Integer 'which line in database?
Private FromYesLink As Boolean

Public Sub bQuit_Click()
  Quit
End

Public Sub bShowData_Click()
  FData.ShowModal
  FMain.SetFocus
End

Public Sub Form_Open()
  'Make sure the NoTabFocus property is set to true for all buttons, otherwise one will be highlighted when you start.
  QuestionPrompt = "Please type in a question that would distinguish a<br><b>1111</b> from a <b>2222.</b> <br><br>(e.g. Does it have...?  Can it...?  Is it...? ):"
  AnimalPrompt = "For a <b>1111</b> the answer would be..."
  StartGame(True) 'clears data too
End

Public Sub bSave_Click()
  SaveData
End

Public Sub SaveData()

  Dialog.Filter = ["*.txt", "Text Files"]
  If Dialog.SaveFile() Then Return
  File.Name = File.BaseName & ".txt"
  File.Save(Dialog.Path, z.Join(Chr(13)))
  FMain.SetFocus
Catch
  Message.Info(Error.Text)

End

Public Sub bOpen_Click()

  Dialog.Filter = ["*.txt", "Text Files"]
  If Dialog.OpenFile() Then Return
  Dim s As String = File.Load(Dialog.Path)
  z = Split(s, Chr(13))
  FMain.SetFocus
Catch
  Message.Info(Error.Text)

End

Public Sub ShowStep(Stage As Integer) '1, 2, 3 or 4

  labPrompt.Visible = (Stage = 1)
  bYes.Visible = (Stage = 1)
  bNo.Visible = (Stage = 1)

  labPromptForAnimal.Visible = (Stage = 2)
  tbNewAnimal.Visible = (Stage = 2)

  labQuestionPrompt.visible = (Stage = 3)
  tbQuestion.Visible = (Stage = 3)

  labQuestion.Visible = (Stage = 4)
  labPrompt2.Visible = (Stage = 4)
  bYes2.Visible = (Stage = 4)
  bNo2.Visible = (Stage = 4)
  Select Case Stage
    Case 2
      tbNewAnimal.SetFocus
    Case 3
      tbQuestion.SetFocus
    Case Else
      FMain.SetFocus 'a futile attempt to stop buttons being highlighted
  End Select

End

Public Sub bReset_Click()
  StartGame(True) 'clear all data too
  FMain.SetFocus
End

Public Sub StartGame(ClearDataToo As Boolean)

  If ClearDataToo Then
    z.Clear
    z.add("Can it swim?/1/2")
    z.add("fish")
    z.Add("bird")
  Endif
  L = 0
  Right = 0
  Wrong = 0
  AskedAQuestion = True
  labPrompt.text = "Are you thinking of an animal?"
  tbQuestion.Text = ""
  tbNewAnimal.Text = ""
  ShowStep(1)

End

Public Sub tbNewAnimal_KeyPress() 'Enter should cause the LostFocus event
  If Key.Code = Key.Enter Or Key.Code = Key.Return Then FMain.SetFocus
End

Public Sub tbNewAnimal_LostFocus() 'by pressing Enter or clicking elsewhere

  NewAnimal = LCase(tbNewAnimal.text)
  If IsNull(NewAnimal) Then Return 'user pressed enter without typing anything; don't proceed.
  Dim s As String = Replace(QuestionPrompt, "1111", NewAnimal) 'Please type in a question...
  s = Replace(s, "2222", z[L])
  labQuestionPrompt.text = s
  ShowStep(3)

End

Public Sub tbQuestion_KeyPress()
  If Key.Code = Key.Enter Or Key.Code = Key.Return Then FMain.SetFocus
End

Public Sub tbQuestion_LostFocus()

  NewQuestion = tbQuestion.Text
  If IsNull(NewQuestion) Then Return 'user pressed enter without typing anything; don't proceed.
  NewQuestion = UCase(NewQuestion[0]) & Right(NewQuestion, -1) 'capitalise first letter
  If Right(NewQuestion, 1) <> "?" Then NewQuestion &= "?"
  labQuestion.Text = NewQuestion
  labPrompt2.Text = Replace(AnimalPrompt, "1111", NewAnimal) 'For a gorilla the answer would be...
  ShowStep(4)

End

Public Sub AskQuestion()

  Dim k As New String[]
  k = Split(z[L], "/")
  labPrompt.text = k[0]
  Right = Val(k[1])
  Wrong = Val(k[2])
  AskedAQuestion = True
  tbNewAnimal.SetFocus
  
End

Public Sub MakeGuess()
  labPrompt.Text = "It is " & If(InStr(Left(z[L], 1), "aeiou") > 0, "an ", "a ") & z[L] & "."
  AskedAQuestion = False
End

Public Sub bYes_Click() 'Yes has been clicked

  If AskedAQuestion Then
    L = Right 'take the right fork
    If InStr(z[L], "/") > 0 Then AskQuestion Else MakeGuess
  Else 'made a guess...
    StartGame(False)
  Endif
  FMain.SetFocus
  
End

Public Sub bNo_Click() 'No has been clicked

  If labPrompt.text = "Are you thinking of an animal?" Then Quit 'If you won't play, I quit!
  If AskedAQuestion Then
    L = Wrong 'take the left fork
    If InStr(z[L], "/") > 0 Then AskQuestion Else MakeGuess
  Else 'made a wrong guess, so add an animal
    ShowStep(2)
  Endif

End

Public Sub bYes2_Click()

  Dim s As String = NewQuestion & "/" & Str(z.max + 1) & "/" & Str(z.max + 2)

  z.Add(NewAnimal) 'the right animal
  z.Add(z[L]) 'the wrong animal
  z[L] = s 'replace the earlier wrong animal with the new question
  StartGame(False)

End

Public Sub bNo2_Click()

  Dim s As String = NewQuestion & "/" & Str(z.max + 1) & "/" & Str(z.max + 2)
  z.Add(z[Wrong]) 'the wrong animal
  z.Add(NewAnimal) 'the right animal
  z[Wrong] = s 'replace the earlier wrong animal with the new question
  StartGame(False)

End

The code for the FData form is:

Public Sub Form_Open()
  taData.Text = FMain.z.Join(Chr(13)) 'Chr(13) is Return
End

Public Sub bClose_Click()
  Me.close
End

Public Sub bCopy_Click()
  Clipboard.Copy(taData.text)
End

Public Sub bSave_Click()
  FMain.SaveData
End

Notes:

Fmain.SetFocus When you click a button it highlights. To make the highlight go away at the end of doing whatever it does, set the focus on the form. It seems to be needed.
Dim z as new string[]

z = split( "a/b/c" , "/" )

z will get three rows. z[0] = “a”, z[1] = “b”, z[2] = “c”

You can specify the separator, and it may be more than one character long.

Dim s as string

s= z.join(" ")

Joins the array z into one string with spaces in between
IsNull(s) This is true if the string s is empty (no characters in it)
Chr(13) Every character has a code number. 13 is the number for Return. If you are interested, A is chr(65) and a is char(97). The code is called ASCII.
Public Sub ShowStep(Stage As Integer)

labPrompt.Visible = (Stage = 1)


This sub needs a number when it gets called. So you might say

ShowStep(1) or ShowStep(2).


If LabPrompt.Visible is true the label will be visible. If false, it is invisible.

LabPrompt’s visibility depends on the number you supply being 1.

if InStr(z[L], "/") > 0 Then If the string z[L] has a slash in it, then do something. InStr(LookInThis, ForThis) gives the position of the second string in the first.
Programming Gambas from Zip
 ← Arrays TextFiles FormArranging →