CVGalleryGamesPreviewRandomJavaSiteWeb
Site updates
Testing New System now...

Knowledge Base

Introduction

What this does

This program provides a fully-featured knowledge base. Through asking the user a series of questions, it can work out which item the user was thinking of. For example, you can teach it all about animals, and then impress people as the computer works out which one they were thinking of. If they think of one that isn't there, they can teach it a new question to add the new animal (so you don't get caught out twice). Unlike most programs of this type, this is not limited to simple yes/no questions - it can provide you with a wide range of options.

Using it

The first thing you need to do, if you haven't already, is install the optional XML package called Java API for XML Processing (JAXP). This has been fully tested with version 1.1 only. You can get it from the Java XML site. Remember to add it to your classpath, so javac can find it.

Once you're in the program, it's fully menu driven, and has plenty of idiot-proofing, so it shouldn't be too hard to use. Try loading MAME.xml and playing around with that first - press 1, return, MAME.xml, return, 3 to get started.

The "none of these" option at the end of each set of questions allows you to add another option if none apply - this is how the program gets round the yes / no limit.

Download:

KnowledgeBase.java - command line
KnowledgeBase.class - command line
base.dtd - defines the documents
mt.xml - template used to make new documents
MAME.xml - sample file
import java.io.*; Used for loading, saving, inputting files
import java.net.*;
import java.util.*; Used for Vector
import javax.xml.parsers.*; Used for XML
import org.w3c.dom.*; Used for XML - provides similar interface to JavaScript
import org.xml.sax.*; Used for XML

public class KnowledgeBase
{
    private static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    private static Document theBase; the Document class is similar to the document in javascript
    private static Vector linkids;
    private static Vector links;
    
    private static int idno;

    private static int status;

    private static final int NOTHING_LOADED = 0; These are used to prevent quit without saving
    private static final int FILE_LOADED = 1;
    private static final int UNSAVED_CHANGES =2;
    
    public static void main(String[] args)
    {
	status = NOTHING_LOADED;

	while(true)
	    {
		System.out.println("1) Load file");
		System.out.println("2) Save file");
		System.out.println("3) Run query");
		System.out.println("4) New file");
		System.out.println("5) Quit");

		int i = getMenuOption(5);
		
		if(i==1)
		    load();
		
		if(i==2)
		    save();

		if(i==3)
		    query();		       		   

		if(i==4)
		    newBase();
		    
		if(i==5)
		    quit();
	    }
    }

    private static void quit()
    {
	if(status==UNSAVED_CHANGES)
	    {
		System.out.println("Changes not saved. Really quit?");
		System.out.println("1) Yes");
		System.out.println("2) No");

		if(getMenuOption(2) == 1)
		    System.exit(0);
	    }
	else
	    {
		System.exit(0);
	    }
    }

    private static void query()
    {
	if(status == NOTHING_LOADED)
	    {
		System.out.println("No file loaded");
		return;
	    }
	else
	    {
		System.out.println(theBase.getDocumentElement().getAttribute("opening"));
		ask("q1");
	    }
    }

    private static void newBase()
    {
	try
	    {
		if(status == UNSAVED_CHANGES)
		    {
			System.out.println("Discard changes?");
			System.out.println("1) Yes");
			System.out.println("2) No");

			if(getMenuOption(2) == 2)
			    return;
		    }


		DocumentBuilderFactory dbf =              A DocumentBuilderFactory
		    DocumentBuilderFactory.newInstance(); makes DocumentBuilders

		dbf.setValidating(true);
		
		DocumentBuilder db = dbf.newDocumentBuilder();

		theBase = db.parse("mt.xml"); And the DocumentBuilders make Documents

 This part of the program inputs information about a new knowledge base

		System.out.println("What is this knowledge base about?");
		String inp = input.readLine();
		theBase.getDocumentElement().setAttribute("about" , inp);

getDocumentElement gives the highest level element in a document, like <HTML>. 
In this program, <base> is that element, and it stores some general info. about the knowledgebase.
Although the "about" attribute is not currently used, it might be in future versions with alternative interfaces.

		System.out.println("Enter opening, e.g. Think of an animal");
		inp = input.readLine();
		theBase.getDocumentElement().setAttribute("opening" , inp);

		System.out.println("Enter first question");
		inp = input.readLine();
		theBase.getElementById("q1").setAttribute("value" , inp);
		
This is used to find some elements - not all document nodes are elements. For example, in HTML,
when there is a paragraph like this : <p>hello</p> , the element node <p> contains a text node.
		
		Vector links = new Vector();
		NodeList nl = theBase.getElementById("q1").getChildNodes();
	
		for(int i=0; i<nl.getLength(); i++)
		    {
			if(nl.item(i).getNodeType() == Node.ELEMENT_NODE)
			    {		
				links.add((Element)nl.item(i));
			    }
			
		    }

		System.out.println("Enter first reply");
		inp = input.readLine();
		((Element)links.get(0)).setAttribute("content" , inp);
The 0 can be assumed to be the correct index here because mt.xml has a
known structure - the item can be used without checking it's there.

		System.out.println("Enter item for this reply");
		inp = input.readLine();
		theBase.getElementById("a1").setAttribute("content" , inp);

		System.out.println("Enter second reply");
		inp = input.readLine();
		((Element)links.get(1)).setAttribute("content" , inp);

		System.out.println("Enter item for this reply");
		inp = input.readLine();
		theBase.getElementById("a2").setAttribute("content" , inp);

		status = UNSAVED_CHANGES;
		
		
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
	catch(ParserConfigurationException p)
	    {
		System.out.println(p);
	    }
	catch(SAXException s)
	    {
		System.out.println(s);
	    }
    }

    private static void save()
    {
	if(status == NOTHING_LOADED)
	    {
		System.out.println("No file loaded");
		return;
	    }

	try
	    {
		System.out.println("Enter filename:");
		String s = input.readLine();

		FileWriter fw = new FileWriter(s);
		fw.write("<?xml version='1.0'?>");
		fw.write("<!DOCTYPE base SYSTEM 'base.dtd'>");
		fw.write("\n " + theBase.getDocumentElement());
		fw.flush();
		fw.close();

		status = FILE_LOADED;
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
    }

This is needed because the XML parser does not recognise new IDs until the document is reloaded
    private static void fudge()
    {
	try
	    {
		FileWriter fw = new FileWriter("temp.xml");
		fw.write("<?xml version='1.0'?>");
		fw.write("<!DOCTYPE base SYSTEM 'base.dtd'>");
		fw.write("\n " + theBase.getDocumentElement());
		fw.flush();
		fw.close();

		DocumentBuilderFactory dbf = 
		    DocumentBuilderFactory.newInstance();

		dbf.setValidating(true);

		DocumentBuilder db = dbf.newDocumentBuilder();

		theBase = db.parse("temp.xml");

	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
	catch(ParserConfigurationException p)
	    {
		System.out.println(p);
	    }
	catch(SAXException s)
	    {
		System.out.println(s);
	    }
    }

    private static void load()
    {
	try
	    {
		if(status == UNSAVED_CHANGES)
		    {
			System.out.println("Discard changes?");
			System.out.println("1) Yes");
			System.out.println("2) No");

			if(getMenuOption(2) == 2)
			    return;
		    }
		
		System.out.println("Enter filename");
		System.out.print("?");

		DocumentBuilderFactory dbf = 
		    DocumentBuilderFactory.newInstance();
		
		dbf.setValidating(true);

		DocumentBuilder db = dbf.newDocumentBuilder();
	
		theBase = db.parse(input.readLine());

		idno = Integer.parseInt(((Element)(theBase.getElementsByTagName("base").item(0))).getAttribute("idno"));

		status = FILE_LOADED;
		
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
	catch(ParserConfigurationException p)
	    {
		System.out.println(p);
	    }
	catch(SAXException s)
	    {
		System.out.println(s);
	    }
    }

    private static void ask(String id)
    {
	Vector linkids = new Vector();
	Vector links = new Vector();

	Element e = theBase.getElementById(id);

	
	System.out.println(e.getAttribute("value"));
	
	int items = 0;
	
	NodeList nl = e.getChildNodes();
	
	for(int i=0; i<nl.getLength(); i++)
	    {
		if(nl.item(i).getNodeType() == Node.ELEMENT_NODE)
		    {
			items++;
			System.out.print(items + ") ");
			System.out.println(((Element)nl.item(i)).getAttribute("content") );
			linkids.add(((Element)nl.item(i)).getAttribute("link"));
			links.add((Element)nl.item(i));
		    }
		
	    }
	
	System.out.println((items+1) + ") None of these" );
	System.out.println();
	
	int choice =  getMenuOption(items + 1);
	
	if(choice == items+1)
	    {
		newoption(id);
	    }
	else
	    {
		e = theBase.getElementById((String)linkids.get(choice -1));
		
		if(e.getTagName().equals("answer"))
		    guess((Element)links.get(choice -1));
		else
		    ask((String)linkids.get(choice -1));
	    }
	
    }

    private static void newoption(String id)
    {

	try
	    {
		Element e = theBase.getElementById(id);
		idno++;
		((Element)(theBase.getElementsByTagName("base").item(0))).setAttribute("idno" , "" + idno);

		System.out.println("What item were you thinking of?");
		System.out.print("?");
		String itemname = input.readLine();
	
		Element newans = theBase.createElement("answer");
		newans.setAttribute("id" , "a" + idno);
		newans.setAttribute("content" , itemname);

		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode(" "));
		theBase.getElementsByTagName("answers").item(0).appendChild(newans);
		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode("\n"));

		System.out.println("What is the answer for this item?");
		System.out.print("?");
		String itemvalue = input.readLine();

		Element newrep = theBase.createElement("reply");
		newrep.setAttribute("content" , itemvalue);
		newrep.setAttribute("link" , "a" + idno);

		e.appendChild(theBase.createTextNode("   "));
		e.appendChild(newrep);
                e.appendChild(theBase.createTextNode("\n"));

		fudge();
		status = UNSAVED_CHANGES;
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
    }

    private static void guess(Element oldReply)
    {
	Element e = theBase.getElementById(oldReply.getAttribute("link"));

	System.out.println("It is :");
	System.out.println(e.getAttribute("content"));

	System.out.println();
	System.out.println("1)OK ");
	System.out.println("2)Wrong");
	int i = getMenuOption(2);

	if(i==2)
	    addItem(oldReply);
    }

    private static void addItem(Element oldReply)
    {
	Element f = theBase.getElementById(oldReply.getAttribute("link"));
	idno++;
	((Element)(theBase.getElementsByTagName("base").item(0))).setAttribute("idno" , "" + idno);
	
	try
	    {
		System.out.println("What item were you thinking of?");
		System.out.print("?");
		String itemname = input.readLine();
	
		Element newans = theBase.createElement("answer");
		newans.setAttribute("id" , "a" + idno);
		newans.setAttribute("content" , itemname);


		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode(" "));
		theBase.getElementsByTagName("answers").item(0).appendChild(newans);
		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode("\n"));

		System.out.println("Enter a question to tell the two apart");
		String theq = input.readLine();

		Element newq = theBase.createElement("question");
		newq.setAttribute("id" , "q" + idno);
		newq.setAttribute("value" , theq);
		newq.setAttribute("media" , "text");

		theBase.getElementsByTagName("questions").item(0).appendChild(theBase.createTextNode("\n"));
		theBase.getElementsByTagName("questions").item(0).appendChild(newq);
		theBase.getElementsByTagName("questions").item(0).appendChild(theBase.createTextNode("\n"));

		System.out.println("The answer for " + itemname + "?");
		String replycnew = input.readLine();

		Element replynewitem = theBase.createElement("reply");
		replynewitem.setAttribute("content" , replycnew);
		replynewitem.setAttribute("link" , "a" + idno);

		newq.appendChild(theBase.createTextNode("\n   "));
		newq.appendChild(replynewitem);
		newq.appendChild(theBase.createTextNode("\n"));
		
		
		System.out.println("The answer for " + f.getAttribute("content") + "?");
		String replycold = input.readLine();

		Element replyolditem = theBase.createElement("reply");
		replyolditem.setAttribute("content" , replycold);
		replyolditem.setAttribute("link" , oldReply.getAttribute("link"));

		newq.appendChild(theBase.createTextNode("   "));
		newq.appendChild(replyolditem);
		newq.appendChild(theBase.createTextNode("\n"));
		

		oldReply.setAttribute("link" , "q" + idno);

		fudge();
		status = UNSAVED_CHANGES;
		
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
    }

    This should look familiar if you're reading these in order :) - code reuse is good!
    private static int getMenuOption(int numoptions)
    {       
	boolean notyet = true;
	while(notyet)
	    {
		System.out.print("?");
		String s = new String("");
		
		try
		    {
			s = input.readLine();
		    }
		catch(IOException e)
		    {
			System.out.println(e);
		    }
		
		int i;
		
		try
		    {
			i = Integer.parseInt(s);
			
			if(i<=numoptions && i>0)
			    {
				return i;
			    }
			else
			    {
				System.out.println("Not an option");
			    }
		    }
		catch(NumberFormatException e)
		    {
			System.out.println("Not an option");
		    }
		
		
	    }
	//never here;
	return -128;
	
    }
    
}
	 
	 
NOTE: The Java section is mostly in maintenence mode. I don't have time to work on it right now. Errors will be corrected if pointed out, but they are not actively being searched for. Newer site features, like alternate stylesheets, may cause problems with these pages.