import java.io.StreamTokenizer; class Host { // You should not have to modify class Host at all. // Moreover, if we modified Host() methods to use a graphics // output (instead of just using println's), // but kept the names of its methods and their arguments the same, // then you shouldn't have to change your Judge code *at all*. // Some variables for the Host. // (declared private since no other objects have the right to know these // variables; you don't need to worry about this subtlety in your code.) // private StringList aList; // List of answers. private Judge judge; private String rightMsg = "Got it!"; // Message when player guesses right, private String wrongMsg = "Nope."; // or guesses wrong, private String byebyeMsg = "seeya"; // or finishes. private int stopVal = -1; // What the player uses to abort. private StreamTokenizer in; // Object to get our input from. /* Host constructor * Expects a judge and list of answers (Strings) */ public Host( Judge j ) { judge = j; aList = j.getAnswerList(); in = new StreamTokenizer( System.in ); } /* An alternate constructor */ public Host( Judge j, StringList as ) { aList = as; judge = j; in = new StreamTokenizer( System.in ); } /* play() * Actually play the game, * until the judge tells us we've run out of questions (by returning "") * or the user enters stopVal as an answer. */ public void play() { int aIndex; String question; boolean correct; while (true) { question = judge.nextQuestion(); if (question.equals( "" )) break; System.out.println( question ); showList( aList ); System.out.print( "Enter number of choice (" + stopVal + " to exit): " ); System.out.flush(); aIndex = getInt( 1, aList.length(), stopVal ); if (aIndex == stopVal) break; correct = judge.rightAnswer( Host.nth( aList, aIndex) ); respond( correct ); System.out.println( "" ); } System.out.println( byebyeMsg ); } /* getInt * Read an integer between low and high (or stopVal) */ public int getInt( int low, int high, int stopVal ) { int v; boolean outOfRange; do { try { in.nextToken(); } catch (java.io.IOException e) { throw new RuntimeException( "Judge.ask: IOException " + e ); } v = (int)in.nval; outOfRange = ((in.ttype != StreamTokenizer.TT_NUMBER) || (((v < low) || (v > high)) && (v != stopVal))); if (outOfRange) { System.out.println( "Please enter a choice from " + low + " through " + high + ", or " + stopVal + " to quit." ); } } while ( outOfRange ); return v; } /* replaceQuestions * If the Judge wants, they can replace the list of questions and answers. */ public void replaceAnswers( StringList as ) { aList = as; } /* respond * inform the user whether their last answer was right or wrong. */ private void respond( boolean correct ) { if (correct) System.out.println( rightMsg ); else System.out.println( wrongMsg ); System.out.println(); } /* printSpaces */ public void printSpaces( int n ) { while (n > 0) { System.out.print( ' ' ); n--; } System.out.flush(); } /* showList * print the list of asnwers, numbered 1..length. */ private void showList( StringList as ) { int n = 1; int spaceBetween; String a; while (as instanceof StringCons) { a = ((StringCons)as).car.toString(); // Presumably car was already String, but for flexibility we won't assume // that, and use toString() on whatever car happens to be. System.out.println( " " + n + ". " + a ); // set up for next loop iteration: as = ((StringCons) as).cdr; n++; } } /* nth * We'd like to use (non-static) StringList.nth, * except that it's not guaranteed that they use * the same numbering we do, when we display the list. * (I.e., StringList.nth may have 0 refer to first element.) */ static String nth( StringList l, int indx ) { if (! (l instanceof StringCons)) throw new RuntimeException( "Host.nth: Given empty list " + l ); if (indx == 1) return ((StringCons) l).car; else return nth( ((StringCons) l).cdr, indx-1 ); } }