Loading...
Logo
Processing Forum
Hi there.... I'm making a Boggle solver... (just for fun - there's plenty of them around already).

The first step was to write a program where you could just enter the word in a text field and the program would check to see if it is in the dictionary. The dictionary I am using is the SOWPODS official scrabble dictionary which I have as a text file. I decided to use a binary search algorithm - found one on the net and adapted it. I am using G4P for the text field and buttons. The program will just not find any words though. I even replaced the binary search algorithm with a simple sequential one (both are in the program) - still indicates the word is not found. I set up a printwriter to print the word read from the textfield to a file to check nothing weird was happening to it - seemed fine. Well, I'm stumped....

To run this you will need to create a textfile with some words in it, called "sowpods.txt". You will also need the G4P library installed. If you can spot anything obvious that would be great!

Copy code
  1. import guicomponents.*;

    GTextField wordfield;
    GButton findbutton;
    PFont arial12;
    String[] dictionary;
    //PrintWriter output;

    void setup()
    {
    size(500, 200);
    background(255);
    fill(0);
    //output = createWriter("test.txt");
    GComponent.globalFont = GFont.getFont(this, "Arial", 13);
    dictionary = loadStrings("sowpods.txt");
    wordfield = new GTextField(this,"", 10, 26, 200, 30, true);
    findbutton = new GButton(this, "Go", 15, 70, 40, 20);
    arial12 = loadFont("ArialMT-12.vlw");
    textFont(arial12, 12);
    }


    void draw()
    {

    }


    boolean wordsearch(String word) //the original binary search method
    {
    int first = 0;
    int upto = dictionary.length;

    while (first < upto) {
    int mid = (first + upto) / 2; // Compute mid point.
    if (word.compareTo(dictionary[mid].toLowerCase()) < 0) {
    upto = mid; // repeat search in bottom half.
    } else if (word.compareTo(dictionary[mid].toLowerCase()) > 0) {
    first = mid + 1; // Repeat search in top half.
    } else {
    return true; // Found it. return true
    }
    }
    return false; // Failed to find key
    }

    void handleButtonEvents(GButton button)
    {
    background(255);
    if(seqwordsearch(wordfield.viewText().toLowerCase())) text("found", 200, 150);
    else text("not found", 200, 150);
    text(wordfield.viewText().toLowerCase(),200,175);
    //output.println(wordfield.viewText().toLowerCase());
    }


    void handleTextFieldEvents(GTextField textfield) {}

    boolean seqwordsearch(String word) //a slow search method
    {
    println("word is: " + word);
    for(int i=0; i<dictionary.length; i++)
    {
    println(dictionary[i]);
    if(word.equalsIgnoreCase(dictionary[i])) return true;
    }
    return false;
    }

    /*
    void keyPressed()
    {
    if(key=='Q')
    {
    output.flush(); // Writes the remaining data to the file
    output.close(); // Finishes the file
    exit(); // Stops the program
    }
    }
    */


Replies(9)

For some reason the text received from the textfield has a trailing newline (\n). This is why the string comparison fails.
You can use String.trim() to remove leading and trailing whitespace, and then it should work.
Copy code
  1. void handleButtonEvents(GButton button) 
  2. {
  3.   background(255);
  4.   String trimmed = wordfield.viewText().toLowerCase().trim();
  5.   if(seqwordsearch(trimmed)) text("found", 200, 150);
  6.     else text("not found", 200, 150);
  7.   text(trimmed,200,175);
  8.   //output.println(wordfield.viewText().toLowerCase());
  9. }

Ah... thanks a lot for your reply. You're right.... How did you know?

I printed out the length of the input text - and I noticed it was one more than what I expected
Note: better than binary search, for a dictionary (a collection that rarely or never change), you can use a TreeSet or a HashSet.
Try and dimension them appropriately in the constructor to avoid several re-dimensioning in the construction phase.
If I understand the problem the G4P textfield is used to hold a single word. In which modify the line
  1. wordfield = new GTextField(this,"", 10, 26, 200, 30, true);
by changing the true to false and use viewText() instead of getText() to get the word from wordfield.

If the textfield is only being used to hold a single line of text then this is a better solution.

In the current version of G4P the GTextField component can be used either as a single line or multi line input field. Using true in the constructor makes it multi line and the enter key will move the cursor to the next line scrolling up the text if necessary. Also viewText was designed for use in multi line mode so appends '\n' to the end of each line including the last one which explains the problem you encountered.

Thanks..... I assume you meant use getText() instead of viewText()? 

I did this, and changed true to false, and I was able to get rid of the trim() which I was using. So it's looking good now.

Philho: I'll have a look at that, thanks. Just out of curiosity, I compared the binary search to a sequential one.... I expected the sequential one to take a noticeable amount of time (there are 275,000 entries in the dictionary), but they both appeared to work "instantly". Just shows you how fast modern computers are. But, if you did 1000 searches I'm sure you would notice the difference.

How would I get the words from the textfile into a TreeSet? Would you read them into a string array first, and then add them one by one using a for loop?
How would I get the words from the textfile into a TreeSet?
Yes, the loadString() will do the loading to an array.
But you are right, for a program with user interaction (ie. no searches repeated in a loop), perhaps optimal data structures are not so useful.
Here's the dictionary search program as it stands, now that it works. It might be useful to someone else so I will just post it here.

Copy code
  1. import guicomponents.*;

    GTextField wordfield;
    GButton findbutton;
    PFont arial12;
    String[] dictionary;

    void setup()
    {
    size(500, 200);
    background(255);
    fill(0);
    GComponent.globalFont = GFont.getFont(this, "Arial", 13);
    dictionary = loadStrings("sowpods.txt"); //dictionary text file
    wordfield = new GTextField(this,"", 10, 26, 200, 30, false);
    findbutton = new GButton(this, "Go", 15, 70, 40, 20);
    arial12 = loadFont("ArialMT-12.vlw");
    textFont(arial12, 12);
    }

    void draw()
    {

    }

    boolean wordsearch(String word) //the original binary search method
    {
    int first = 0;
    int upto = dictionary.length;

    while (first < upto) {
    int mid = (first + upto) / 2; // Compute mid point.
    if (word.compareTo(dictionary[mid].toLowerCase()) < 0) {
    upto = mid; // repeat search in bottom half.
    } else if (word.compareTo(dictionary[mid].toLowerCase()) > 0) {
    first = mid + 1; // Repeat search in top half.
    } else {
    return true; // Found it. return true
    }
    }
    return false; // Failed to find key
    }

    void handleButtonEvents(GButton button)
    {
    background(255);
    if(wordsearch(wordfield.getText().toLowerCase())) text("found", 200, 150);
    else text("not found", 200, 150);
    text(wordfield.viewText().toLowerCase(),200,175);
    }

    void handleTextFieldEvents(GTextField textfield) {}
I will be using this in a Boggle solver so it will be called many times in a row to find out which of the "words" are valid. I'll see how it runs with the binary search and implement the TreeSet if it seems slow. Cheers.