add 20 questions assignment from WCC CS 145 Spring 2019.

This commit is contained in:
Matthew Jensen 2019-12-14 18:28:46 -08:00
parent 8018490bbd
commit ff64a51210
12 changed files with 20487 additions and 0 deletions

View File

@ -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());
}
}
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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.";
}

19883
20-questions/animals.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,5 @@
Q:Is it an animal?
A:cat
Q:Does it go on your feet?
A:shoe
A:computer

View File

@ -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

BIN
20-questions/spec.pdf Normal file

Binary file not shown.