Skip to content

Instantly share code, notes, and snippets.

@gigamonkey
Created October 5, 2025 20:02
Show Gist options
  • Save gigamonkey/b3f92d3336a6660b71f75638aacfbbc2 to your computer and use it in GitHub Desktop.
Save gigamonkey/b3f92d3336a6660b71f75638aacfbbc2 to your computer and use it in GitHub Desktop.
TwentQuestions that reads questions and guesses from file
import java.util.*;
import java.io.*;
import java.nio.file.*;
/**
* Twenty questions that parses from a file that looks like:
*
* Is it a mammal? {
* Does it live in the water? {
* Does it get caught in tuna nets? {
* a dolphin;
* a whale;
* }
* Is it a pet? {
* a dog;
* an elephant;
* }
* }
* Does it live in the water? {
* Does it have claws? {
* a lobster;
* a fish;
* }
* Can it lick it's own eyeball? {
* a gecko;
* a snake;
* }
* }
* }
*
*/
public class TwentyQuestions {
private static final Scanner scanner = new Scanner(System.in);
/*
* Common interface for nodes and leaves of our tree of questions.
*/
private static interface Tree {
public void play();
}
/*
* A yes/no question that leads to one of two paths deeper in the tree.
*/
private static Tree question(String question, Tree ifYes, Tree ifNo) {
return () -> {
System.out.print(question + " ");
if (scanner.nextLine().startsWith("y")) {
ifYes.play();
} else {
ifNo.play();
}
};
}
/*
* A final guess.
*/
private static Tree guess(String guess) {
return () -> {
System.out.print("I guess " + guess + ". Is that right? ");
if (scanner.nextLine().startsWith("y")) {
System.out.println("Yay! I win.");
} else {
System.out.println("Darn! I was sure that was it.");
}
};
}
/*
* Read a tree of questions from a given file.
*/
private static Tree read(Path file) throws IOException {
var i = Files.lines(file).map(String::trim).iterator();
var tree = parse(i);
if (!i.hasNext()) {
return tree;
} else {
throw new RuntimeException("Syntax error. Extra lines");
}
}
/*
* Recursive parser that consumes an iterator of the lines in the file.
*/
private static Tree parse(Iterator<String> lines) {
if (lines.hasNext()){
var line = lines.next();
if (line.endsWith(" {")) {
var q = upTo(line, " {");
var y = parse(lines);
var n = parse(lines);
if (lines.hasNext() && lines.next().endsWith("}")) {
return question(q, y, n);
} else {
throw new RuntimeException("Syntax error in queston '" + q + "'. Expected }");
}
} else if (line.endsWith(";")) {
return guess(upTo(line, ";"));
} else {
throw new RuntimeException("Syntax error. Malformed line: '" + line + "'. Expected ;");
}
} else {
throw new RuntimeException("Syntax error. Ran out of lines");
}
}
/*
* Helper method to extract text up to ending puncuatin.
*/
private static String upTo(String s, String end) {
return s.substring(0, s.indexOf(end));
}
/*
* Run game based on contents of file named in the first argument.
*/
public static void main(String[] args) throws IOException {
read(Path.of(args[0])).play();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment