Programming in Go

When I start learning a new programming language I often write the program to play the “Guess the Animal” game to get a feel for the language. Below is a simple version of this game written in Go. ┬áThe program starts “knowing” only about two animals, but as you play it it “learns” more, by asking you to provide new animals and new questions.

Here is the code. Enjoy!


package main

import (
	"bufio"
	"fmt"
	"os"
)

type Question struct {
	text      string
	yesAnswer *Question
	noAnswer  *Question
}

func yesOrNo(prompt string) (answer string) {
	fmt.Printf("%s [y/n]? ", prompt)
	fmt.Scanln(&answer)
	return answer
}

func (q *Question) isLeaf() bool {
	return q.yesAnswer == nil && q.noAnswer == nil
}

func (q *Question) ask() (result *Question, answer string) {
	answer = yesOrNo(q.text)
	if answer == "y" {
		result = q.yesAnswer
	} else {
		result = q.noAnswer
	}
	return result, answer
}

var root *Question

func initialize() *Question {
	shark := Question{"shark", nil, nil}
	cat := Question{"cat", nil, nil}
	return &Question{"Is it a mamal", &cat, &shark}
}

func addAnimal(q *Question) {
	var animal, question string
	fmt.Printf("Ok. I give up. What animal is it? ")
	fmt.Scanln(&animal)
	fmt.Printf(
		"Enter a question to tell a difference between %s and %s: ",
		animal, q.text)
	reader := bufio.NewReader(os.Stdin)
	line, _, _ := reader.ReadLine()
	question = string(line)
	answer := yesOrNo(fmt.Sprintf("And for %s the answer is", 
		animal))
	oldAnimal := Question{q.text, nil, nil}
	q.text = question
	newAnimal := Question{animal, nil, nil}
	if answer == "y" {
		q.yesAnswer = &newAnimal
		q.noAnswer = &oldAnimal
	} else {
		q.yesAnswer = &oldAnimal
		q.noAnswer = &newAnimal
	}
}

func play() {
	var answer string
	currentQuestion := root
	for !currentQuestion.isLeaf() {
		currentQuestion, answer = currentQuestion.ask()
	}
	answer = yesOrNo(fmt.Sprintf("Is it a %s", 
		currentQuestion.text))
	if answer == "y" {
		fmt.Printf("OK!!! Got it!!\n")
	} else {
		addAnimal(currentQuestion)
	}
}

func main() {
	root = initialize()
	quit := "n"
	for quit == "n" {
		play()
		quit = yesOrNo("Quit ")
	}
}