Back to Code List
c++

Simple 20 Questions

This is a simple game of 20 questions that learns the more you play using a binary tree structure. Currently, it only remembers the content in memory, but it is more in place for a binary tree concept.

   Main.cpp

#include "BinaryTree.cpp"
#include <string>
#include <iostream>

void play(BinaryTreeNode<std::string>* current_ptr);
void learn(BinaryTreeNode<std::string>*& leaf_ptr);

int main() {
	bool playGame = true;
	std::string startAnswer = "Elephant";
	BinaryTreeNode<std::string> *root_node = create_node(startAnswer);

	while(playGame) {
		play(root_node);
		std::string input;
		std::cout << "Play again? (y or n)";
		std::cin >> input;
		std::cin.ignore();
		playGame = (input == "y" || input == "Y");
	}
	
	return 0;
}

void play(BinaryTreeNode<std::string>* current_ptr)
{
	std::cout << "Think of an animal. Press enter when ready." << std::endl;
	while (std::cin.get() != '\n');
	
	std::string input;

	while (!is_leaf(*current_ptr))
	{
		std::cout << current_ptr->data << " ";
		std::cin >> input;
		std::cin.ignore();
		if (input == "y" || input == "Y" || input == "yes" || input == "Yes")
			current_ptr = current_ptr->left;
		else
			current_ptr = current_ptr->right;
	}

	std::cout << "Is it a(n) " << current_ptr->data << "? ";
	std::cin >> input;
	std::cin.ignore();
	if (input == "y" || input == "Y" || input == "yes" || input == "Yes")
		std::cout << "Ha! Knew it!" << std::endl;
	else
		learn(current_ptr);
} 

void learn(BinaryTreeNode<std::string>*& leaf_ptr)
{                                            
	std::string guess_animal;
	std::string correct_animal;
	std::string new_question;

	guess_animal = leaf_ptr->data;
	std::cout << "I give up. What are you? A(n) ";
	std::getline(std::cin, correct_animal);

	/* //save the correct animal to a file? will need to read it somehow
	ofstream animal_file;
	animal_file.open("Animals.txt", ios::app);
	if(!animal_file.is_open())
		cout << "Error opening animal file!";
	else if (animal_file.is_open())
		animal_file << correct_animal << endl;
	animal_file.close();*/

	std::cout << "Please type a yes/no question that will distinguish a(n) "
			<< correct_animal << " from a(n) " << guess_animal << "." << std::endl;
	std::getline(std::cin, new_question);

	/* //save the new question to a file? will need to read it somehow
	ofstream question_file;
	question_file.open("Questions.txt", ios::app);
	if(!question_file.is_open())
		cout << "Error opening question file!";
	else if (question_file.is_open())
		question_file << new_question << endl;
	question_file.close();*/

	leaf_ptr->data = new_question;
	std::cout << "As a(n) " << correct_animal << ", " << new_question << std::endl;

	std::string input;
	std::cin >> input;
	std::cin.ignore();
	if (input == "y" || input == "Y" || input == "yes" || input == "Yes")
	{                          
		leaf_ptr->left = create_node(correct_animal);
		leaf_ptr->right = create_node(guess_animal);
	}
	else 
	{
		leaf_ptr->left = create_node(guess_animal);
		leaf_ptr->right = create_node(correct_animal);
	}
}    

   BinaryTree.h

// standard binary tree implementation

#ifndef BINTREE_H
#define BINTREE_H

template <class T>
struct BinaryTreeNode
{
	T data;
	BinaryTreeNode *left;
	BinaryTreeNode *right;

};

template <class T>
BinaryTreeNode<T>* create_node(T& entry, BinaryTreeNode<T>* l_ptr=nullptr, BinaryTreeNode<T>* r_ptr=nullptr);

template <class T>
bool is_leaf(const BinaryTreeNode<T>&);

template <class T>
void tree_clear(BinaryTreeNode<T>*&);

template <class T>
BinaryTreeNode<T>* tree_copy(BinaryTreeNode<T>*);

#endif
    

   BinaryTree.cpp

// standard binary tree implementation

#include "BinaryTree.h"

template <class T>
BinaryTreeNode<T>* create_node(T& entry, BinaryTreeNode<T>* l_ptr, BinaryTreeNode<T>* r_ptr)
{
	BinaryTreeNode<T> *result_ptr;

	result_ptr = new BinaryTreeNode<T>;
	result_ptr->data    = entry;
	result_ptr->left    = l_ptr;
	result_ptr->right   = r_ptr;

	return result_ptr;
};

template <class T>
bool is_leaf(const BinaryTreeNode<T>& node)
{
	return (node.left == nullptr) && (node.right == nullptr);
};

template <class T>
void tree_clear(BinaryTreeNode<T>*& root_ptr)
{
	if (root_ptr != nullptr)
	{
		tree_clear(root_ptr->left);
		tree_clear(root_ptr->right);
		delete root_ptr;
		root_ptr = nullptr;
	}
};

template <class T>
BinaryTreeNode<T>* tree_copy(BinaryTreeNode<T>* root_ptr)
{
	BinaryTreeNode<T> *l_ptr;
	BinaryTreeNode<T> *r_ptr;
	if (root_ptr == nullptr)
		return nullptr;
	else
	{
		l_ptr = tree_copy(root_ptr->left);
		r_ptr = tree_copy(root_ptr->right);
		return create_node(root_ptr->data, l_ptr, r_ptr);
	}
};