add 20 questions assignment from WCC CS 145 Spring 2019.
This commit is contained in:
parent
8018490bbd
commit
ff64a51210
|
@ -0,0 +1,117 @@
|
|||
// CSE 145 Lab 6: 20 Questions
|
||||
//
|
||||
// To use the jGRASP debugger with this program, set a breakpoint
|
||||
// and once the execution breaks, open 'this' or 'tq' on the left,
|
||||
// then look at its variable 'tree'. That's your QuestionTree.
|
||||
// Drag your 'tree' over to the right to see a visualization of it.
|
||||
//
|
||||
// (Your QuestionTree is constructed by this file on line 30.
|
||||
// The overall loop to play games is around line 68.)
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Scanner;
|
||||
|
||||
/** A basic text user interface for the 20 questions game. */
|
||||
public class QuestionMain implements UserInterface {
|
||||
public static void main(String[] args) {
|
||||
QuestionMain tq = new QuestionMain();
|
||||
tq.run();
|
||||
}
|
||||
|
||||
|
||||
// fields
|
||||
private Scanner console;
|
||||
private QuestionTree tree;
|
||||
|
||||
/** Constructs a text user interface and its question tree. */
|
||||
public QuestionMain() {
|
||||
console = new Scanner(System.in);
|
||||
tree = new QuestionTree(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's response as a String.
|
||||
*/
|
||||
public String nextLine() {
|
||||
return console.nextLine();
|
||||
}
|
||||
|
||||
/** Prints the given string to the console. */
|
||||
public void print(String message) {
|
||||
System.out.print(message);
|
||||
System.out.print(" ");
|
||||
}
|
||||
|
||||
/** Prints the given string to the console. */
|
||||
public void println(String message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
/** Prints a blank line to the console. */
|
||||
public void println() {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the user to answer a yes/no question on the console and returns the
|
||||
* user's response as a boolean (true for anything that starts with "y" or "Y").
|
||||
*/
|
||||
public boolean nextBoolean() {
|
||||
String answer = console.nextLine();
|
||||
return answer.trim().toLowerCase().startsWith("y");
|
||||
}
|
||||
|
||||
// private helper for overall game(s) loop
|
||||
private void run() {
|
||||
println("Welcome to the game of 20 Questions!");
|
||||
load();
|
||||
|
||||
// "Think of an item, and I will guess it in N tries."
|
||||
println("\n" + BANNER_MESSAGE);
|
||||
|
||||
do {
|
||||
// play one complete game
|
||||
println(); // blank line between games
|
||||
tree.play();
|
||||
print(PLAY_AGAIN_MESSAGE);
|
||||
} while (nextBoolean()); // prompt to play again
|
||||
|
||||
// print overall stats
|
||||
// Games played: N ... I have won: M
|
||||
println("\n" + String.format(STATUS_MESSAGE,
|
||||
tree.totalGames(), tree.gamesWon()));
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
// common code for asking the user whether they want to save or load
|
||||
private void load() {
|
||||
print(LOAD_MESSAGE);
|
||||
if (nextBoolean()) {
|
||||
print(SAVE_LOAD_FILENAME_MESSAGE);
|
||||
String filename = nextLine();
|
||||
try {
|
||||
Scanner in = new Scanner(new File(filename));
|
||||
tree.load(in);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// common code for asking the user whether they want to save or load
|
||||
private void save() {
|
||||
print(SAVE_MESSAGE);
|
||||
if (nextBoolean()) {
|
||||
print(SAVE_LOAD_FILENAME_MESSAGE);
|
||||
String filename = nextLine();
|
||||
try {
|
||||
PrintStream out = new PrintStream(new File(filename));
|
||||
tree.save(out);
|
||||
out.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
*
|
||||
* Matt Jensen
|
||||
* CS145 - Lab 6
|
||||
* 5/30/19
|
||||
*
|
||||
*/
|
||||
|
||||
public class QuestionNode {
|
||||
private QuestionNode yes;
|
||||
private QuestionNode no;
|
||||
private String data;
|
||||
private boolean isQuestion;
|
||||
|
||||
|
||||
public QuestionNode(String input) {
|
||||
this.data = unwrap(input);
|
||||
}
|
||||
public QuestionNode(String input, boolean isQuestion) {
|
||||
this.data = unwrap(input);
|
||||
if( isQuestion ) {
|
||||
this.markAsQuestion();
|
||||
} else {
|
||||
this.markAsAnswer();
|
||||
}
|
||||
}
|
||||
public boolean hasQuestion() {
|
||||
return ! this.isAnswer() && (this.hasYes() || this.hasNo() );
|
||||
}
|
||||
public boolean needsAnswer() {
|
||||
return ! this.isAnswer() && (! this.hasYes() || ! this.hasNo() );
|
||||
}
|
||||
public void markAsQuestion() {
|
||||
this.isQuestion = true;
|
||||
}
|
||||
public void markAsAnswer() {
|
||||
this.isQuestion = false;
|
||||
}
|
||||
public void addYes(QuestionNode yes) {
|
||||
this.yes = yes;
|
||||
}
|
||||
public void addNo(QuestionNode no) {
|
||||
this.no = no;
|
||||
}
|
||||
public void addAnswer(QuestionNode answer) {
|
||||
if( this.hasYes() ) {
|
||||
this.addNo(answer);
|
||||
} else {
|
||||
this.addYes(answer);
|
||||
}
|
||||
}
|
||||
public QuestionNode getYes() {
|
||||
return this.yes;
|
||||
}
|
||||
public QuestionNode getNo() {
|
||||
return this.no;
|
||||
}
|
||||
public String toString(boolean wrap) {
|
||||
return this.wrap(this.data);
|
||||
}
|
||||
public String toString() {
|
||||
return this.data;
|
||||
}
|
||||
public boolean isAnswer() {
|
||||
return this.isQuestion == false;
|
||||
}
|
||||
public boolean hasYes() {
|
||||
return this.yes != null;
|
||||
}
|
||||
public boolean hasNo() {
|
||||
return this.no != null;
|
||||
}
|
||||
private String unwrap(String input) {
|
||||
if( input.contains(":") ) {
|
||||
return input.split(":")[1];
|
||||
}
|
||||
return input;
|
||||
}
|
||||
private String wrap(String input) {
|
||||
String prefix = "";
|
||||
if( this.isAnswer() ) {
|
||||
prefix = "A";
|
||||
} else {
|
||||
prefix = "Q";
|
||||
}
|
||||
return prefix + ":" + input;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import org.junit.Test;
|
||||
import java.util.*;
|
||||
|
||||
public class QuestionNodeTest {
|
||||
@Test
|
||||
public void exists() {
|
||||
QuestionNode node = new QuestionNode("tail");
|
||||
assertEquals("tail", node.getQuestion());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
/**
|
||||
*
|
||||
* Matt Jensen
|
||||
* CS145 - Lab 6
|
||||
* 5/30/19
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class QuestionTree {
|
||||
|
||||
private QuestionNode root;
|
||||
private UserInterface ui;
|
||||
private Stack<QuestionNode> unanswered;
|
||||
private int totalGames;
|
||||
private int gamesWon;
|
||||
private QuestionNode lastQuestion;
|
||||
|
||||
public QuestionTree(UserInterface ui) {
|
||||
this.setUserInterface(ui);
|
||||
this.setRoot(null);
|
||||
}
|
||||
public QuestionTree(UserInterface ui, QuestionNode root) {
|
||||
this.setUserInterface(ui);
|
||||
this.setRoot(root);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Public Methods.
|
||||
*
|
||||
*/
|
||||
public void replaceYes(QuestionNode newQuestion, QuestionNode parent) {
|
||||
parent.addYes(newQuestion);
|
||||
}
|
||||
|
||||
public void save(PrintStream output) {
|
||||
this.print(output, this.getRoot());
|
||||
//output.print("hello");
|
||||
}
|
||||
private void print(PrintStream output, QuestionNode current) {
|
||||
if(current == null) {
|
||||
return;
|
||||
} else {
|
||||
output.print(current.toString(true));
|
||||
if(current.hasYes()){
|
||||
output.println();
|
||||
this.print(output, current.getYes());
|
||||
}
|
||||
if(current.hasNo()){
|
||||
output.println();
|
||||
this.print(output, current.getNo());
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
public void play() {
|
||||
this.lastQuestion = null;
|
||||
if( this.getRoot() == null ) {
|
||||
this.ui.print("First question?");
|
||||
this.setRoot(new QuestionNode(this.ui.nextLine(), true));
|
||||
this.ui.print("If yes?");
|
||||
this.getRoot().addYes(new QuestionNode(this.ui.nextLine()));
|
||||
this.ui.print("If no?");
|
||||
this.getRoot().addNo(new QuestionNode(this.ui.nextLine()));
|
||||
}
|
||||
QuestionNode guess = this.guess(this.getRoot());
|
||||
this.ui.print("Would your object happen to be " + guess.toString() + "?");
|
||||
boolean correctGuess = this.ui.nextBoolean();
|
||||
if( correctGuess ) {
|
||||
this.ui.println("I win!");
|
||||
gamesWon++;
|
||||
} else {
|
||||
this.ui.print("I lose.");
|
||||
this.addDistinction(guess);
|
||||
}
|
||||
totalGames++;
|
||||
}
|
||||
private QuestionNode getActual(QuestionNode guess) {
|
||||
this.ui.print("What is your object?");
|
||||
QuestionNode actual = new QuestionNode(this.ui.nextLine(), false);
|
||||
return actual;
|
||||
}
|
||||
private QuestionNode getNewQuestion(QuestionNode guess) {
|
||||
this.ui.println("Type a yes/no question to distinguish your item from " + guess.toString() + ":");
|
||||
QuestionNode newQuestion = new QuestionNode(this.ui.nextLine(), true);
|
||||
return newQuestion;
|
||||
}
|
||||
private boolean getReplaceYes(QuestionNode guess, QuestionNode newQuestion) {
|
||||
this.ui.println("And what is the answer for " + newQuestion + "?");
|
||||
boolean replaceYes = this.ui.nextBoolean();
|
||||
return replaceYes;
|
||||
}
|
||||
private void addDistinction(QuestionNode guess) {
|
||||
QuestionNode actual = this.getActual(guess);
|
||||
QuestionNode newQuestion = this.getNewQuestion(guess);
|
||||
boolean replaceYes = this.getReplaceYes(guess, newQuestion);
|
||||
if( replaceYes ) {
|
||||
newQuestion.addYes(actual);
|
||||
newQuestion.addNo(guess);
|
||||
} else {
|
||||
newQuestion.addNo(actual);
|
||||
newQuestion.addYes(guess);
|
||||
}
|
||||
this.replaceYes(newQuestion, this.lastQuestion);
|
||||
}
|
||||
|
||||
private QuestionNode guess(QuestionNode current) {
|
||||
if( current == null || current.isAnswer() ) {
|
||||
return current;
|
||||
} else {
|
||||
this.ui.print(current.toString());
|
||||
this.lastQuestion = current;
|
||||
if( this.ui.nextBoolean() ) {
|
||||
return this.guess(current.getYes());
|
||||
} else {
|
||||
return this.guess(current.getNo());
|
||||
}
|
||||
}
|
||||
}
|
||||
public int totalGames() {
|
||||
return this.totalGames;
|
||||
}
|
||||
public int gamesWon() {
|
||||
return this.gamesWon;
|
||||
}
|
||||
public QuestionNode getRoot() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Private Methods.
|
||||
*
|
||||
*/
|
||||
|
||||
private void setRoot(QuestionNode root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
// pre: ui not null
|
||||
private void setUserInterface(UserInterface ui) {
|
||||
if( ui == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.ui = ui;
|
||||
}
|
||||
|
||||
// pre: coming from a file.
|
||||
private boolean containsQuestion(String line) {
|
||||
return line.charAt(0) == 'Q';
|
||||
}
|
||||
|
||||
public void load(Scanner input) {
|
||||
// base case
|
||||
if( ! input.hasNextLine() ) {
|
||||
return;
|
||||
}
|
||||
Stack<QuestionNode> remaining = new Stack<QuestionNode>();
|
||||
this.build(input, remaining);
|
||||
return;
|
||||
}
|
||||
private void build(Stack<QuestionNode> remaining, QuestionNode root) {
|
||||
|
||||
}
|
||||
private void build(Scanner input, Stack<QuestionNode> remaining) {
|
||||
// base case
|
||||
if( ! input.hasNextLine() ) {
|
||||
if( ! remaining.empty() ) {
|
||||
throw new IllegalArgumentException("question unanswered");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
String line = input.nextLine();
|
||||
QuestionNode current = new QuestionNode(line, containsQuestion(line));
|
||||
if( remaining.empty() ) {
|
||||
if( this.getRoot() == null ) {
|
||||
this.setRoot(current);
|
||||
} else {
|
||||
throw new IllegalArgumentException("bad root element");
|
||||
}
|
||||
} else {
|
||||
QuestionNode last = remaining.pop();
|
||||
last.addAnswer(current);
|
||||
if(last.needsAnswer() ) {
|
||||
remaining.add(last);
|
||||
}
|
||||
}
|
||||
if( ! current.isAnswer() ) {
|
||||
remaining.add(current);
|
||||
}
|
||||
this.build(input, remaining);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import org.junit.Test;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public class QuestionTreeTest {
|
||||
@Test
|
||||
public void testExistance() {
|
||||
UserInterface ui = new QuestionMain();
|
||||
QuestionTree tree = new QuestionTree(ui);
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load() {
|
||||
UserInterface ui = new QuestionMain();
|
||||
QuestionTree tree = new QuestionTree(ui);
|
||||
String file = "Q:Is it an animal?\nA:cat\nQ:Does it go on your feet?\nA:shoe\nA:computer";
|
||||
tree.load(new Scanner(file));
|
||||
assertEquals("Is it an animal?", tree.getRoot().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replace() {
|
||||
UserInterface ui = new QuestionMain();
|
||||
QuestionTree tree = new QuestionTree(ui);
|
||||
String file = "Q:Is it an animal?\nA:cat\nA:table?";
|
||||
tree.load(new Scanner(file));
|
||||
QuestionNode newQuestion = new QuestionNode("Is it black?", true);
|
||||
tree.replaceYes(newQuestion, tree.getRoot());
|
||||
assertEquals("Is it black?", tree.getRoot().getYes().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void otherload() throws FileNotFoundException {
|
||||
UserInterface ui = new QuestionMain();
|
||||
QuestionTree tree = new QuestionTree(ui);
|
||||
tree.load(new Scanner(new File("question2.txt")));
|
||||
assertEquals("Is it an animal?", tree.getRoot().toString());
|
||||
}
|
||||
@Test
|
||||
public void save() throws FileNotFoundException, IOException {
|
||||
// setup
|
||||
UserInterface ui = new QuestionMain();
|
||||
QuestionTree tree = new QuestionTree(ui);
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
tree.load(new Scanner(new File("question1.txt")));
|
||||
PrintStream out = new PrintStream(result);
|
||||
tree.save(out);
|
||||
String expected = "Q:Is it an animal?\nA:cat\nQ:Does it go on your feet?\nA:shoe\nA:computer";
|
||||
assertEquals(expected, result.toString());
|
||||
result.close();
|
||||
}
|
||||
@Test
|
||||
public void saveLonger() throws FileNotFoundException, IOException {
|
||||
// setup
|
||||
UserInterface ui = new QuestionMain();
|
||||
QuestionTree tree = new QuestionTree(ui);
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
tree.load(new Scanner(new File("question2.txt")));
|
||||
PrintStream out = new PrintStream(result);
|
||||
tree.save(out);
|
||||
String expected = "Q:Is it an animal?\nQ:Can it fly?\nA:bird\nQ:Does it have a tail?\nA:mouse\nA:spider\nQ:Does it have wheels?\nA:bicycle\nQ:Is it nice?\nA:TA\nA:teacher";
|
||||
assertEquals(expected, result.toString());
|
||||
result.close();
|
||||
}
|
||||
public void play() throws FileNotFoundException, IOException {
|
||||
// setup
|
||||
UserInterface ui = new QuestionMain();
|
||||
QuestionTree tree = new QuestionTree(ui);
|
||||
tree.load(new Scanner(new File("question2.txt")));
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// CSE 145 Lab 6: 20 Questions
|
||||
|
||||
/**
|
||||
* Interface describing abstract user interaction operations.
|
||||
* This interface is implemented by the graphical and text UIs for the game.
|
||||
* Your QuestionTree interacts with the UI through this interface.
|
||||
* @author Marty Stepp
|
||||
* @version 2010/02/20
|
||||
*/
|
||||
public interface UserInterface {
|
||||
/**
|
||||
* Waits for the user to input a yes/no answer (by typing, clicking, etc.),
|
||||
* and returns that answer as a boolean value.
|
||||
* @return the answer typed by the user as a boolean (yes is true, no is false)
|
||||
*/
|
||||
boolean nextBoolean();
|
||||
|
||||
/**
|
||||
* Waits for the user to input a text value, and returns that answer as a String.
|
||||
* @return the answer typed by the user as a String (empty string if no answer typed)
|
||||
*/
|
||||
String nextLine();
|
||||
|
||||
/**
|
||||
* Displays the given output message to the user.
|
||||
* @param message The message to display. Assumes not null.
|
||||
*/
|
||||
void print(String message);
|
||||
|
||||
/**
|
||||
* Displays the given output message to the user.
|
||||
* If the UI is a text UI, also inserts a line break (\n).
|
||||
* @param message The message to display. Assumes not null.
|
||||
*/
|
||||
void println(String message);
|
||||
|
||||
// various messages that are output by the user interface
|
||||
// (your QuestionTree does not need to refer to these messages)
|
||||
final String PLAY_AGAIN_MESSAGE = "Challenge me again?";
|
||||
final String SAVE_MESSAGE = "Shall I remember these games?";
|
||||
final String LOAD_MESSAGE = "Shall I recall our previous games?";
|
||||
final String SAVE_LOAD_FILENAME_MESSAGE = "What is the file name?";
|
||||
final String STATUS_MESSAGE = "Games played: %d\nI won: %d";
|
||||
final String BANNER_MESSAGE = "Think of an item, and I will guess it.";
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
Welcome to the game of 20 Questions!
|
||||
Shall I recall our previous games? No
|
||||
|
||||
Think of an item, and I will guess it.
|
||||
|
||||
Would your object happen to be computer? N
|
||||
I lose. What is your object? cat
|
||||
Type a yes/no question to distinguish your item from computer: Is it an animal?
|
||||
And what is the answer for your object? Yes
|
||||
Challenge me again? y
|
||||
|
||||
Is it an animal? y
|
||||
Would your object happen to be cat? NO
|
||||
I lose. What is your object? Dog
|
||||
Type a yes/no question to distinguish your item from cat: Does it meow?
|
||||
And what is the answer for your object? no
|
||||
Challenge me again? y
|
||||
|
||||
Is it an animal? yes
|
||||
Does it meow? No
|
||||
Would your object happen to be Dog? YES
|
||||
I win!
|
||||
Challenge me again? nope
|
||||
|
||||
Games played: 3
|
||||
I won: 1
|
||||
Shall I remember these games? no
|
|
@ -0,0 +1,23 @@
|
|||
Welcome to the game of 20 Questions!
|
||||
Shall I recall our previous games? yes please
|
||||
What is the file name? question2.txt
|
||||
|
||||
Think of an item, and I will guess it.
|
||||
|
||||
Is it an animal? no
|
||||
Does it have wheels? nope
|
||||
Is it nice? nah
|
||||
Would your object happen to be teacher? yes
|
||||
I win!
|
||||
Challenge me again? y
|
||||
|
||||
Is it an animal? yes
|
||||
Can it fly? YES
|
||||
Would your object happen to be bird? yep
|
||||
I win!
|
||||
Challenge me again? n
|
||||
|
||||
Games played: 2
|
||||
I won: 2
|
||||
Shall I remember these games? y
|
||||
What is the file name? out.txt
|
|
@ -0,0 +1,5 @@
|
|||
Q:Is it an animal?
|
||||
A:cat
|
||||
Q:Does it go on your feet?
|
||||
A:shoe
|
||||
A:computer
|
|
@ -0,0 +1,11 @@
|
|||
Q:Is it an animal?
|
||||
Q:Can it fly?
|
||||
A:bird
|
||||
Q:Does it have a tail?
|
||||
A:mouse
|
||||
A:spider
|
||||
Q:Does it have wheels?
|
||||
A:bicycle
|
||||
Q:Is it nice?
|
||||
A:TA
|
||||
A:teacher
|
Binary file not shown.
Loading…
Reference in New Issue