/** File is: Ani.java 5-11-06 Version 1.0 Author Clark Elliott. Status: throw-away code to illustrate connectionless browser-based animal game. WEB CLIENT Just a standard web browser. Start by pointing to http://localhost:4001. Pedagogy question: What happens if the user presses the back button on the browser? Note that only a portion of the state is indexed on the client. CurrentAnimalNode is based on the *presumed* browser path: always forward. One solution is to use the following constructs: node nodeArray = new node[4000]; // max of 4000 animals. int nodeCounter; [In every new node]: this.nodeID = nodeCounter++; nodeArray[this.nodeID] = this; Then, when sending any node to the browser, send the ID of the node. Whenever that state is returned from the browser (back button or not) CurrentAnimalNode can be set based on the ID. In this way the full state of the game is contained in every page. The key element is that an integer value, which can be marshalled back and forth to the browser, is sent in place of a node pointer, which cannot be marshalled. ----------------------------------------------------------------------*/ import java.io.*; // Get the Input Output libraries import java.net.*; // Get the Java networking libraries class AnimalWorker extends Thread { // Class definition Socket sock; // Class member, socket, local to Worker. AnimalTree ani; // Constructor: assign args s, a, to local values. AnimalWorker (Socket s, AnimalTree a) {sock = s; ani = a;} public void run(){ PrintStream out = null; BufferedReader in = null; String NewHost = "localhost"; String buf = ""; int newPort; Socket clientSock; try { out = new PrintStream(sock.getOutputStream()); in = new BufferedReader (new InputStreamReader(sock.getInputStream())); String inLine = in.readLine(); System.out.println("Just got: " + inLine); // START OF GAME: if (inLine.indexOf("state-start-game-yn") > -1){ if (inLine.indexOf("response-no") > -1){ System.out.println("EXIT from game."); out.println("

Game Over

"); } else{ System.out.println("Starting the game"); sendHTMLheader(out); sendHTMLQuestion(out, ani.CurrentAnimalNode.stringdata); sendHTMLNodeState(out); sendHTMLRadio(out); } } // INTERNAL NODE: else if (inLine.indexOf("state-node-question-yn") > -1){ System.out.println("Got internal node."); if (inLine.indexOf("response-yes") > -1){ ani.CurrentAnimalNode = ani.CurrentAnimalNode.left; } else{ ani.CurrentAnimalNode = ani.CurrentAnimalNode.right; } if (ani.IsLeaf(ani.CurrentAnimalNode)){ // reached an animal, so guess: System.out.println("Now guessing the Animal"); sendHTMLheader(out); out.println("

Is the animal" + ani.aORn(ani.CurrentAnimalNode.stringdata) + ani.CurrentAnimalNode.stringdata + "?

"); sendHTMLGuessState(out); sendHTMLRadio(out); }else{ // just another internal node: sendHTMLheader(out); out.println("

" + ani.CurrentAnimalNode.stringdata + "

"); sendHTMLNodeState(out); sendHTMLRadio(out); } } // LEAF NODE: else if (inLine.indexOf("state-guess-question-yn") > -1){ if (inLine.indexOf("response-yes") > -1){ ani.CurrentAnimalNode = ani.TreeHead; sendHTMLheader(out); sendHTMLGloatAndStart(out); //sendHTMLStartGame(out); sendHTMLRadio(out); } else{ sendHTMLheader(out); sendHTMLAskWhat(out); sendHTMLAnimalTextState(out); sendHTMLInputBoxAnimal(out); } } // GOT NEW ANIMAL as TEXT: else if (inLine.indexOf("state-animal-text") > -1){ sendHTMLheader(out); int i1 = inLine.indexOf("inbox") + 6; int i2 = inLine.indexOf(" ", i1) + 1; String newAnimal = new String(inLine.substring(i1, i2)); System.out.println("New Animal is: " + newAnimal); ani.newAnimal = newAnimal; // save for later processing out.println("

Enter a question that is YES for" + ani.aORn(newAnimal) + newAnimal + " but NO for" + ani.aORn(ani.CurrentAnimalNode.stringdata) + ani.CurrentAnimalNode.stringdata + "

"); sendHTMLAnimalQuestionState(out); sendHTMLInputBoxQuestion(out); } // GOT NEW QUESTION as TEXT: else if (inLine.indexOf("state-input-question-text") > -1){ int i3 = inLine.indexOf("inbox") + 6; int i4 = inLine.indexOf(" ", i3) + 1; String q = new String(inLine.substring(i3, i4)); String q2 = q.replace('+', ' '); // Clean up from query string... q = q2.replaceAll("%3F", "?"); ani.MakeInternalNode(ani.CurrentAnimalNode, q); ani.CurrentAnimalNode = ani.TreeHead; sendHTMLheader(out); sendHTMLStartGame(out); sendHTMLRadio(out); } else{ // DEFAULT is to just start the game: System.out.println("REACHED DEFAULT STATE"); sendHTMLheader(out); ani.CurrentAnimalNode = ani.TreeHead; sendHTMLStartGame(out); sendHTMLRadio(out); } out.flush(); sock.close(); } catch (IOException ioe) {System.out.println(ioe);} } static void sendHTMLheader (PrintStream out){ out.println("HTTP/1.1 200 OK"); out.println("Content-Length: 700"); // who knows how long, faking it. out.println("Content-Type: text/html"); out.println(""); out.println(" "); out.println("

Animal Game

"); out.println("
"); } static void sendHTMLGloatAndStart(PrintStream out){ out.println("

Hah! I thought so! "); out.println("Would you like to play animal again?

"); out.println("

"); } static void sendHTMLAskWhat(PrintStream out){ out.println("

Oh well. What animal was it?

"); } static void sendHTMLStartGame(PrintStream out){ out.println("

Would you like to play animal? (If so, think of an animal.)

"); out.println("

"); } static void sendHTMLQuestion(PrintStream out, String q){ out.println("

" + q + "

"); } static void sendHTMLNodeState(PrintStream out){ out.println("

"); } static void sendHTMLGuessState(PrintStream out){ out.println("

"); } static void sendHTMLAnimalTextState(PrintStream out){ out.println("

"); } static void sendHTMLAnimalQuestionState(PrintStream out){ out.println("

"); } static void sendHTMLRadio (PrintStream out){ out.println(" Yes"); out.println(" No"); out.println(""); out.println("

"); } static void sendHTMLInputBoxAnimal (PrintStream out){ out.println(""); out.println(""); out.println(""); } static void sendHTMLInputBoxQuestion (PrintStream out){ out.println(""); out.println(""); out.println(""); } static void sendHTMLsubmit (PrintStream out){ out.println(""); out.println(""); } } class node { int uid; // not used here public node left, right; String stringdata; // question or animal node(){this.left = null; this.right = null; } node(String s){ this.left = null; this.right = null; this.stringdata = s; } } class AnimalTree { node TreeHead = null; // Class variables for bookkeeping node CurrentAnimalNode = null; String newAnimal = null; AnimalTree(String Animal){ // Constructor TreeHead = new node(Animal); } boolean IsLeaf(node N){if (N.left == null) return true; else return false;} void MakeInternalNode(node N, String Question){ N.left = new node(newAnimal); // Q is true for new ani, goes left N.right = new node(N.stringdata); // Q false for existing ani, goes right N.stringdata = Question; } void makeStartTree (){ this.CurrentAnimalNode = this.TreeHead; this.CurrentAnimalNode.left = new node("Elephant"); this.CurrentAnimalNode.right = new node("Canary"); System.out.println(this.TreeHead.stringdata); } String aORn(String s){ // match preposition with noun: if ("aeiouAEIOU".indexOf(s.substring(0,1)) > -1){ return new String(" an "); }else{return new String(" a ");} } } public class Ani { public static boolean controlSwitch = true; public static void main(String a[]) throws IOException { int q_len = 6; /* Number of requests for OpSys to queue */ int port = 4001; Socket sock; ServerSocket servsock = new ServerSocket(port, q_len); AnimalTree ani = new AnimalTree("Is the animal bigger than a chair?"); ani.makeStartTree(); System.out.println("Animal server started at 4001.\n"); while (controlSwitch) { sock = servsock.accept(); new AnimalWorker (sock, ani).start(); } } }