Introduction
I have been writing about games quite often, and the major undertone of each of those games (I will provide links to a few games at the end of this article) have been that: as long as you can figure out the logic behind the game, you are more than halfway there; some games are different, though. With a few games, you need more than logic.
Today, I will cover a game which seems simple enough, but is actually pretty complicated! In this article, you will learn how to create a game which can think for itself, and the beauty is that there is no real Artificial Intelligence involved.
What Is a Guess the Animal Game?
A Guess the Animal game, or Guess the Object game, is a game that asks you questions. Based on your answers, either yes or no for example, the game knows what question to ask next. The game thinks for itself and records your answers as your play; this then assists in the game in knowing what to ask next.
Say, for example, the game asks you: “Is it an animal?” and you say: “yes,” the game will proceed in asking if the animal has a trunk. If you provide “no” as an answer, the game might ask another question to determine the correct animal. If you said “yes” to the previous question, the game would respond in saying that the animal is an Elephant.
This ability is beginner level A.I. and is known as a Binary Tree.
Binary Trees
A Binary Tree is a hierarchical data structure in which each node (parent) has children. The topmost node is called the root. Elements with no children are called leaves.
Our Project
Open Visual Studio and create a Console Application in either VB.NET or C#. You may name your project anything you desire. Once the project has been loaded, add the BinaryTree class.
C#
class BinaryTree { BinaryTreeNode btnRoot; public BinaryTree(string strQuestion, string strYes, string strNo) { btnRoot = new BinaryTreeNode(strQuestion); btnRoot.StoreYes(new BinaryTreeNode(strYes)); btnRoot.StoreNo(new BinaryTreeNode(strNo)); } public void Play() { btnRoot.Guess(); } }
VB.NET
Private btnRoot As BinaryTreeNode Public Sub New(ByVal strQuestion As String, ByVal strYes As _ String, ByVal strNo As String) btnRoot = New BinaryTreeNode(strQuestion) btnRoot.StoreYes(New BinaryTreeNode(strYes)) btnRoot.StoreNo(New BinaryTreeNode(strNo)) End Sub Public Sub Play() btnRoot.Guess() End Sub
The BinaryTree class instantiates a BinaryTreeNode object. You will create the BinaryTreeNode class next. Inside the BinaryTree class’ initialization, the seeding values for the game get stored. Without these values, there is no game and no intelligence. Let’s add the BinaryTreeNode class now.
C#
[Serializable] class BinaryTreeNode { string strMess; BinaryTreeNode btnYes; BinaryTreeNode btnNo; public BinaryTreeNode(string strMessage) { strMess = strMessage; btnNo = null; btnYes = null; } public void Guess() { if (ValidQuestion()) { Console.WriteLine(strMess); Console.Write("Enter 'Y' for YES and 'N' for NO: "); char chrInput = Answer(); if (chrInput == 'y' || chrInput == 'Y') btnYes.Guess(); else if (chrInput == 'n' || chrInput == 'N') btnNo.Guess(); } else Query(); } public void Query() { Console.WriteLine("Are you thinking of a(n) " + strMess + "?"); Console.Write("Enter 'Y' for YES and 'N' for NO: "); char chrInput = Answer(); if (chrInput == 'y' || chrInput == 'Y') Console.Write("Computer Wins!"); else if (chrInput == 'n' || chrInput == 'N') PlayerWin(); } private void PlayerWin() { Console.Write("You win! What Animal were you thinking of?"); string strUserAnimal = Console.ReadLine(); Console.Write("Please enter a question to distinguish a(n) " + strMess + " from " + strUserAnimal + ": "); string strQuestion = Console.ReadLine(); Console.Write("If you were thinking of a(n) " + strUserAnimal + ", what would have been the answer to that question?"); char chrInput = Answer(); if (chrInput == 'y' || chrInput == 'Y') { btnNo = new BinaryTreeNode(strMess); btnYes = new BinaryTreeNode(strUserAnimal); } else if (chrInput == 'n' || chrInput == 'N') { btnYes = new BinaryTreeNode(strMess); btnNo = new BinaryTreeNode(strUserAnimal); } Console.Write("Knowledge Increased"); StoreMessage(strQuestion); } public bool ValidQuestion() { if (btnNo == null && btnYes == null) return false; else return true; } private char Answer() { char chrInput = ' '; while (chrInput != 'y' && chrInput != 'Y' && chrInput != 'n' && chrInput != 'N') { chrInput = Console.ReadLine().ElementAt(0); chrInput = Char.ToLower(chrInput); } return chrInput; } public void StoreMessage(string strMessage) { strMess = strMessage; } public string GetMessage() { return strMess; } public void StoreNo(BinaryTreeNode btnNode) { btnNo = btnNode; } public BinaryTreeNode GetNo() { return btnNo; } public void StoreYes(BinaryTreeNode btnNode) { btnYes = btnNode; } public BinaryTreeNode GetYes() { return btnYes; } }
VB.NET
<Serializable> Class BinaryTreeNode Private strMess As String Private btnYes As BinaryTreeNode Private btnNo As BinaryTreeNode Public Sub New(ByVal strMessage As String) strMess = strMessage btnNo = Nothing btnYes = Nothing End Sub Public Sub Guess() If ValidQuestion() Then Console.WriteLine(strMess) Console.Write("Enter 'Y' for YES and 'N' for NO: ") Dim chrInput As Char = Answer() If chrInput = "y"c OrElse chrInput = "Y"c Then btnYes.Guess() ElseIf chrInput = "n"c OrElse chrInput = "N"c Then btnNo.Guess() End If Else Query() End If End Sub Public Sub Query() Console.WriteLine("Are you thinking of a(n) " & strMess _ & "?") Console.Write("Enter 'Y' for YES and 'N' for NO: ") Dim chrInput As Char = Answer() If chrInput = "y"c OrElse chrInput = "Y"c Then Console.Write("Computer Wins!") ElseIf chrInput = "n"c OrElse chrInput = "N"c Then PlayerWin() End If End Sub Private Sub PlayerWin() Console.Write("You win! What Animal were you thinking of?") Dim strUserAnimal As String = Console.ReadLine() Console.Write("Please enter a question to distinguish a(n) " _ & strMess & " from " & strUserAnimal & ": ") Dim strQuestion As String = Console.ReadLine() Console.Write("If you were thinking of a(n) " & _ strUserAnimal & ", what would have been the answer _ to that question?") Dim chrInput As Char = Answer() If chrInput = "y"c OrElse chrInput = "Y"c Then btnNo = New BinaryTreeNode(strMess) btnYes = New BinaryTreeNode(strUserAnimal) ElseIf chrInput = "n"c OrElse chrInput = "N"c Then btnYes = New BinaryTreeNode(strMess) btnNo = New BinaryTreeNode(strUserAnimal) End If Console.Write("Knowledge Increased") StoreMessage(strQuestion) End Sub Public Function ValidQuestion() As Boolean If btnNo Is Nothing AndAlso btnYes Is Nothing Then _ Return False Else Return True End Function Private Function Answer() As Char Dim chrInput As Char = " "c While chrInput <> "y"c AndAlso chrInput <> "Y"c _ AndAlso chrInput <> "n"c AndAlso chrInput <> "N"c chrInput = Console.ReadLine().ElementAt(0) chrInput = Char.ToLower(chrInput) End While Return chrInput End Function Public Sub StoreMessage(ByVal strMessage As String) strMess = strMessage End Sub Public Function GetMessage() As String Return strMess End Function Public Sub StoreNo(ByVal btnNode As BinaryTreeNode) btnNo = btnNode End Sub Public Function GetNo() As BinaryTreeNode Return btnNo End Function Public Sub StoreYes(ByVal btnNode As BinaryTreeNode) btnYes = btnNode End Sub Public Function GetYes() As BinaryTreeNode Return btnYes End Function End Class
The btnYes and btnNo fields are BinaryTreeNode objects themselves, making them recursive by using them. The Guess Sub procedure allows you to enter your responses and calls the Query sub procedure. The Query sub interrogates the user and calls the PlayerWin sub, where most of the action happens. In the IF statement, after a question was asked, the game’s logic determines what was answered and how to proceed further with the game. Finally, add the Main sub’s code inside the Program file or Module file.
C#
class Program { static BinaryTree btAnimals; static void Main(string[] args) { NewGame(); Console.WriteLine("Let's Start!"); btAnimals.Play(); } static void NewGame() { Console.WriteLine("Initializing."); Console.WriteLine("Enter a question about an Animal: "); string strQuestion = Console.ReadLine(); Console.Write("Enter a guess for Yes: "); string strYesSeed = Console.ReadLine(); Console.Write("Enter a guess for No: "); string strNoSeed = Console.ReadLine(); btAnimals = new BinaryTree(strQuestion, strYesSeed, strNoSeed); } }
VB.NET
Module Module1 Public btAnimals As BinaryTree Public Sub Main() NewGame() Console.WriteLine("Let's Start!") btAnimals.Play() End Sub Private Sub NewGame() Console.WriteLine("Initializing.") Console.WriteLine("Enter a question about an Animal: ") Dim strQuestion As String = Console.ReadLine() Console.Write("Enter a guess for Yes: ") Dim strYesSeed As String = Console.ReadLine() Console.Write("Enter a guess for No: ") Dim strNoSeed As String = Console.ReadLine() btAnimals = New BinaryTree(strQuestion, strYesSeed, _ strNoSeed) End Sub End Module
When you run the program, you will get a screen with the output shown in Figure 1.
Figure 1: Running
Previous Games
As promised, here are links to a few games I have written about in the past:
- “Creating a Memory Game in Visual Basic“
- “Creating a Tile Slide Puzzle Game in VB.NET“
- “Adding Sizzle to a Video Slot Game with VB.NET“
- “Creating your Own Hidden Object Game with VB.NET“
Conclusion
Some games are more complicated than others; even I am amazed how complicated this little project has become. Hopefully, I can think of another game idea for you soon. Until then, play nice!