Programming Gambas from Zip/TextFiles
The Game of Animal
editThe 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)
ShowStep(1) or ShowStep(2).
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. |