17 March 2013

Hamlet's Monkey - Part 2


OK so a while back I started work on my oh so awesome Hamlet's Monkey project. Anyway, I figured if the loop is too large, it'll just choke my CF instance, so this might be better handled as a java project.

I'm going to focus on the red light method as the green light method is just pretty simple. Basically, loop for a specified number of times grab a random letter and then check it against the Hamlet string. If we're successful add a new letter, if not, the monkey has to start again!
So here's the crux of it all:


private static char generateRandomLetter(){
 Random rnd = new Random();
 char strChar = lstAlphabet.charAt(rnd.nextInt(lstAlphabet.length()));
 return strChar;
}

public static void main(String[] args) {
    int            intCount                 = 0;
    String        strSubString            = "";
    String        strShakespeare            = Shakespeare.replaceAll("[^a-zA-Z]", ""); //Shakespeare without spaces etc
    String        strMonkeyString            = "";
    String        strBestSoFar            = "";
    
    while (intCount < intNumLoops) {
        intCount++;
        
        //generate the random guess, one keystroke at a time
        strMonkeyString    = strMonkeyString + Character.toString(generateRandomLetter());
        
        strSubString    =    strShakespeare.substring(0,strMonkeyString.length());
        
        System.out.print(strMonkeyString + "==" + strSubString);

        //check if we're done
        if(strMonkeyString.equalsIgnoreCase(strSubString)){
            System.out.println(" ** Nice guess, move along please.");
            if(strSubString.length() > strBestSoFar.length()){
                strBestSoFar    =    strSubString;
            }
        }else{
            System.out.println("");
            strMonkeyString    = "";
        }
    }
    
    trackProgress(intCount,strBestSoFar);
    
}


What was more interesting was how to store the results. What I decided to do was to write to a file using a JSON struct. This file could then store the results which could be read in every time the class was run and we'll know its all time success rate.
So again, not a complicated couple of functions. trackProgress gets called from the main function. It just reads the results from the file, and tries to decode the two JSON variables into local variables. If the current best guess is better than the one on file, we use the new one. Otherwise we just add a running total of the number of loops we've done. The read and write functions should be pretty self explanatory.

        @SuppressWarnings("unchecked")
        private static void writeResultsToFile(long intKeyStrokes, String strBestGuess){
            
            //create json object
            JSONObject obj = new JSONObject();
            obj.put("intKeyStrokes", intKeyStrokes);
            obj.put("strBestGuess", strBestGuess);
            
            //write it to file
            try {
                FileWriter file = new FileWriter(strFileName);
                file.write(obj.toJSONString());
                file.flush();
                file.close();
         
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        private static JSONObject readResultsFromFile(){
            JSONParser parser = new JSONParser();
            JSONObject jsonObject = new JSONObject();
            
            try {
                //read from file
                Object obj = parser.parse(new FileReader(strFileName));
                jsonObject = (JSONObject) obj;
         
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return jsonObject;
        }
        
        
        private static void trackProgress(int intKeyStrokes, String strBestGuess){
            JSONObject    jsonObject                = readResultsFromFile();
            String        strBestGuessFromFile    = "";
            long        intKeyStrokesFromFile    = 0;
            String        strNewBestGuess            = "";
            long        intNewStrokes            = 0;
            
            if(jsonObject.get("intKeyStrokes") != null && jsonObject.get("strBestGuess") != null){
                strBestGuessFromFile    = (String) jsonObject.get("strBestGuess");
                intKeyStrokesFromFile    = (long) jsonObject.get("intKeyStrokes");
            }
     
            //whichever string is longer, this is the new best guess
            if(strBestGuess.length() > strBestGuessFromFile.length()){
                strNewBestGuess        = strBestGuess;
            }else{
                strNewBestGuess        = strBestGuessFromFile;
            }
            
            //number of key strokes is cumulative
            intNewStrokes            = intKeyStrokes + intKeyStrokesFromFile;
            
            writeResultsToFile(intNewStrokes,strNewBestGuess);
            System.out.println("Finishing - " + intNewStrokes + " keystrokes-" + strNewBestGuess);
        }
Oh yea, there's one thing. You'll need the the json simple project to use all this json goodness. https://code.google.com/p/json-simple/

To import this library into your project in eclipse, simply right click on the project go down to "Build Path" -> "Add External Archives..." then add the json-simple.1.1.1.jar Simple :)

Here's the full code: http://pastebin.com/h29t3bD7 Have fun!

No comments: