Created
October 5, 2025 20:02
-
-
Save gigamonkey/b3f92d3336a6660b71f75638aacfbbc2 to your computer and use it in GitHub Desktop.
TwentQuestions that reads questions and guesses from file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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