August 30, 2008

Guess the animal

This code implements a simple binary search for answers. The nodes all have questions, but the leaf-node has a suggestion for an answer.

The player is prompted to verify if this is correct, but if it’s not the player is requested for the right answer and a question to ask to tell the difference

Console version


/*
 *  Guess.java - main file.
 *
 */
import java.io.*;
import java.util.*;
class Node {
	Node yes = null;
	Node no = null;
	String desc = null;

	public Node(String desc) {
		this.desc = desc;
	}

}

class ConsoleIO {

	public static boolean YES = true;
	public static boolean NO = false;
	HashSet < String > positives = new HashSet < String > ();
	HashSet < String > negatives = new HashSet < String > ();


	static ConsoleIO io = null;
	private static BufferedReader br = null;

	private void populatePositives() {
		positives.add("YES");
		positives.add("Y");
		positives.add("YEAH");
	}

	private void populateNegatives() {
		negatives.add("NO");
		negatives.add("N");
		negatives.add("NOPE");
		negatives.add("FUCK");
	}

	private ConsoleIO() {
		br = new BufferedReader(new InputStreamReader(System. in ));
	}

	private static ConsoleIO checkInstance() {
		if (io == null) {
			io = new ConsoleIO();
			io.populateNegatives();
			io.populatePositives();
		}
		return io;
	}

	public static String get() {
		checkInstance();
		String r = "";
		try {
			r = br.readLine();
		} catch (IOException e) {
			System.err.println("Input error");
		}
		return r;
	}

	/**
	 * Get an input from the user, can be any string.
	 *
	 * @param prompt
	 * @return
	 */
	public static String getInput(String prompt) {
		System.out.print(prompt);
		System.out.flush();
		return ConsoleIO.get().trim();
	}

	/**
	 * Get a simple yes/no answer.
	 *
	 * @param prompt
	 * @return
	 */
	public static boolean getYesNo(String prompt) {
		String s = getInput(prompt).trim().toUpperCase();
		while (true) {
			if (io.positives.contains(s)) {
				return true;
			}
			if (io.negatives.contains(s)) {
				return false;
			}
			s = getInput(prompt).trim().toUpperCase();
		}
	}

}



/**
 *
 * @author tovare
 *
 */
public class Guess {

	Node head = null;
	Node current = null;

	void search() {
		current = head;
		// Traverse our yes/no questions until we hit a leaf node.
		while (current.no != null) {
			if (ConsoleIO.getYesNo(current.desc + "? ")) {
				current = current.yes;
			} else {
				current = current.no;
			}
		}
		if (ConsoleIO.getYesNo("Is it a " + current.desc + "? ")) {
			System.out.println("Yippee! I win! \n\n");
		} else {
			Node n = new Node(ConsoleIO.getInput("What animal is it? "));
			Node a = new Node(ConsoleIO.getInput("What seperates a " + n.desc + " from a " + current.desc + "? "));
			a.yes = n;
			a.no = current;
			head = a;
		}
	}

	public void play() {
		head = new Node("Dog");
		boolean inPlay = ConsoleIO.getYesNo("Animals, wanna play? ");
		while (inPlay) {
			search();
			inPlay = ConsoleIO.getYesNo("Wanna play again? ");
		}
	}


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Guess game = new Guess();
		game.play();
	}
}

Applet version

The applet version was written in 1997 and uses a state machine to keep track of the current state while responding to asynchronous events from the GUI.

/*
 * Requires JDK 1.1 or higher
 */
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

class Node {
	Node yes;
	Node no;
	String text;
	Node(String t) {
		yes = null;
		no = null;
		text = t;
	}
}

public class GuessTheAnimal extends Applet implements ActionListener {
	private static final long serialVersionUID = 1L;
	final int GAMESTART_REQUEST = 0;
	final int COMPUTER_GUESSES = 1;
	final int COMPUTER_GUESSES_FEATURE = 2;
	final int ANIMAL_NAME_REQUEST = 3;
	final int NEW_FEATURE_REQUEST = 4;
	Node head;
	Node current;
	int state;
	TextArea output;
	TextField input;

	public GuessTheAnimal() {
		head = new Node("DOG");
		state = GAMESTART_REQUEST;
		setLayout(new BorderLayout());
		output = new TextArea("COMPUTER: Animals, wanna play?\n");
		input = new TextField();
		add(output, "Center");
		add(input, "South");
		input.addActionListener(this);
		state = GAMESTART_REQUEST;
	}

	void askQuestion() {
		if (current.no == null) {
			output.append("Is it a " + current.text + "?\n");
		} else {
			output.append(current.text + "?\n");
		}
	}

	public void respond(String userText) {
		switch (state) {
			case GAMESTART_REQUEST:
				if (userText.startsWith("Y")) {
					current = head;
					askQuestion();
					state = COMPUTER_GUESSES;
				}
				break;
			case COMPUTER_GUESSES:
				if (current.no == null) {
					if (userText.startsWith("YES")) {
						output.append("Yippee, I win!\n");
						output.append("Wanna play again?\n");
						state = GAMESTART_REQUEST;
					} else {
						output.append("What animal is it?\n");
						state = ANIMAL_NAME_REQUEST;
					}
				} else {
					if (userText.startsWith("YES")) {
						current = current.yes;
						askQuestion();
					} else if (userText.startsWith("NO")) {
						current = current.no;
						askQuestion();
					} else {
						output.append("Answer Yes or No please.\n");
					}
				}
				break;
			case ANIMAL_NAME_REQUEST:
				current.yes = new Node(userText);
				output.append("What separates a " + userText + " from a " + current.text + "?\n");
				state = NEW_FEATURE_REQUEST;
				break;
			case NEW_FEATURE_REQUEST:
				current.no = new Node(current.text);
				current.text = userText;
				state = GAMESTART_REQUEST;
				output.append("Wanna play again?\n");
				break;
		}
	}

	public void actionPerformed(ActionEvent e) {
		output.append(input.getText() + "\n");
		respond(input.getText().toUpperCase());
		input.setText("");
	}
}

© Tov Are Jacobsen 1997-2018