/* Word Finder Finds words (based on a word list) in an array of letters, or from an anagram Copyright (C) 2002-2007 Dmitry Brant http://dmitrybrant.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ //--------------------------------------------------------------------------- #include #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; const int MAX_WORDS = 100000; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { words = new myWordRec[MAX_WORDS]; wordCount = 0; int iFileHandle; int iFileLength; int iBytesRead; char *pszBuffer; try{ iFileHandle = FileOpen("wordlist.txt", fmOpenRead); iFileLength = FileSeek(iFileHandle,0,2); FileSeek(iFileHandle,0,0); pszBuffer = new char[iFileLength+1]; iBytesRead = FileRead(iFileHandle, pszBuffer, iFileLength); FileClose(iFileHandle); int ptr=0, wordptr; char c; while((iFileLength - ptr) > 4){ //read a word while(pszBuffer[ptr] < 'A') ptr++; words[wordCount].word = new char[12]; wordptr=0; do{ words[wordCount].word[wordptr] = pszBuffer[ptr]; ptr++; wordptr++; }while(pszBuffer[ptr] >= 'A'); for(int k=wordptr; k<12; k++) words[wordCount].word[k] = 0; words[wordCount].length = strlen(words[wordCount].word); wordCount++; if(wordCount >= MAX_WORDS) break; } delete [] pszBuffer; for(int i=wordCount; iEnabled = true; }catch(...){ Application->MessageBox("Error while reading file", "File Error", MB_ICONEXCLAMATION); return; } } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action){ for(int i=0; i<100000; i++){ if(words[i].length){ delete [] words[i].word; } } delete [] words; } //--------------------------------------------------------------------------- void __fastcall TForm1::cmdGoClick(TObject *Sender){ lstResults->Items->Clear(); Screen->Cursor = crHourGlass; //initialize array of nodes for(int i=0; i<8; i++) for(int j=0; j<8; j++) Nodes[i][j].taken = true; //populate the array of nodes Nodes[0][0].letter = txt11->Text.c_str()[0]; if(Nodes[0][0].letter >= 'A') Nodes[0][0].taken = false; Nodes[0][1].letter = txt12->Text.c_str()[0]; if(Nodes[0][1].letter >= 'A') Nodes[0][1].taken = false; Nodes[0][2].letter = txt13->Text.c_str()[0]; if(Nodes[0][2].letter >= 'A') Nodes[0][2].taken = false; Nodes[0][3].letter = txt14->Text.c_str()[0]; if(Nodes[0][3].letter >= 'A') Nodes[0][3].taken = false; Nodes[0][4].letter = txt15->Text.c_str()[0]; if(Nodes[0][4].letter >= 'A') Nodes[0][4].taken = false; Nodes[0][5].letter = txt16->Text.c_str()[0]; if(Nodes[0][5].letter >= 'A') Nodes[0][5].taken = false; Nodes[0][6].letter = txt17->Text.c_str()[0]; if(Nodes[0][6].letter >= 'A') Nodes[0][6].taken = false; Nodes[0][7].letter = txt18->Text.c_str()[0]; if(Nodes[0][7].letter >= 'A') Nodes[0][7].taken = false; Nodes[1][0].letter = txt21->Text.c_str()[0]; if(Nodes[1][0].letter >= 'A') Nodes[1][0].taken = false; Nodes[1][1].letter = txt22->Text.c_str()[0]; if(Nodes[1][1].letter >= 'A') Nodes[1][1].taken = false; Nodes[1][2].letter = txt23->Text.c_str()[0]; if(Nodes[1][2].letter >= 'A') Nodes[1][2].taken = false; Nodes[1][3].letter = txt24->Text.c_str()[0]; if(Nodes[1][3].letter >= 'A') Nodes[1][3].taken = false; Nodes[1][4].letter = txt25->Text.c_str()[0]; if(Nodes[1][4].letter >= 'A') Nodes[1][4].taken = false; Nodes[1][5].letter = txt26->Text.c_str()[0]; if(Nodes[1][5].letter >= 'A') Nodes[1][5].taken = false; Nodes[1][6].letter = txt27->Text.c_str()[0]; if(Nodes[1][6].letter >= 'A') Nodes[1][6].taken = false; Nodes[1][7].letter = txt28->Text.c_str()[0]; if(Nodes[1][7].letter >= 'A') Nodes[1][7].taken = false; Nodes[2][0].letter = txt31->Text.c_str()[0]; if(Nodes[2][0].letter >= 'A') Nodes[2][0].taken = false; Nodes[2][1].letter = txt32->Text.c_str()[0]; if(Nodes[2][1].letter >= 'A') Nodes[2][1].taken = false; Nodes[2][2].letter = txt33->Text.c_str()[0]; if(Nodes[2][2].letter >= 'A') Nodes[2][2].taken = false; Nodes[2][3].letter = txt34->Text.c_str()[0]; if(Nodes[2][3].letter >= 'A') Nodes[2][3].taken = false; Nodes[2][4].letter = txt35->Text.c_str()[0]; if(Nodes[2][4].letter >= 'A') Nodes[2][4].taken = false; Nodes[2][5].letter = txt36->Text.c_str()[0]; if(Nodes[2][5].letter >= 'A') Nodes[2][5].taken = false; Nodes[2][6].letter = txt37->Text.c_str()[0]; if(Nodes[2][6].letter >= 'A') Nodes[2][6].taken = false; Nodes[2][7].letter = txt38->Text.c_str()[0]; if(Nodes[2][7].letter >= 'A') Nodes[2][7].taken = false; Nodes[3][0].letter = txt41->Text.c_str()[0]; if(Nodes[3][0].letter >= 'A') Nodes[3][0].taken = false; Nodes[3][1].letter = txt42->Text.c_str()[0]; if(Nodes[3][1].letter >= 'A') Nodes[3][1].taken = false; Nodes[3][2].letter = txt43->Text.c_str()[0]; if(Nodes[3][2].letter >= 'A') Nodes[3][2].taken = false; Nodes[3][3].letter = txt44->Text.c_str()[0]; if(Nodes[3][3].letter >= 'A') Nodes[3][3].taken = false; Nodes[3][4].letter = txt45->Text.c_str()[0]; if(Nodes[3][4].letter >= 'A') Nodes[3][4].taken = false; Nodes[3][5].letter = txt46->Text.c_str()[0]; if(Nodes[3][5].letter >= 'A') Nodes[3][5].taken = false; Nodes[3][6].letter = txt47->Text.c_str()[0]; if(Nodes[3][6].letter >= 'A') Nodes[3][6].taken = false; Nodes[3][7].letter = txt48->Text.c_str()[0]; if(Nodes[3][7].letter >= 'A') Nodes[3][7].taken = false; Nodes[4][0].letter = txt51->Text.c_str()[0]; if(Nodes[4][0].letter >= 'A') Nodes[4][0].taken = false; Nodes[4][1].letter = txt52->Text.c_str()[0]; if(Nodes[4][1].letter >= 'A') Nodes[4][1].taken = false; Nodes[4][2].letter = txt53->Text.c_str()[0]; if(Nodes[4][2].letter >= 'A') Nodes[4][2].taken = false; Nodes[4][3].letter = txt54->Text.c_str()[0]; if(Nodes[4][3].letter >= 'A') Nodes[4][3].taken = false; Nodes[4][4].letter = txt55->Text.c_str()[0]; if(Nodes[4][4].letter >= 'A') Nodes[4][4].taken = false; Nodes[4][5].letter = txt56->Text.c_str()[0]; if(Nodes[4][5].letter >= 'A') Nodes[4][5].taken = false; Nodes[4][6].letter = txt57->Text.c_str()[0]; if(Nodes[4][6].letter >= 'A') Nodes[4][6].taken = false; Nodes[4][7].letter = txt58->Text.c_str()[0]; if(Nodes[4][7].letter >= 'A') Nodes[4][7].taken = false; Nodes[5][0].letter = txt61->Text.c_str()[0]; if(Nodes[5][0].letter >= 'A') Nodes[5][0].taken = false; Nodes[5][1].letter = txt62->Text.c_str()[0]; if(Nodes[5][1].letter >= 'A') Nodes[5][1].taken = false; Nodes[5][2].letter = txt63->Text.c_str()[0]; if(Nodes[5][2].letter >= 'A') Nodes[5][2].taken = false; Nodes[5][3].letter = txt64->Text.c_str()[0]; if(Nodes[5][3].letter >= 'A') Nodes[5][3].taken = false; Nodes[5][4].letter = txt65->Text.c_str()[0]; if(Nodes[5][4].letter >= 'A') Nodes[5][4].taken = false; Nodes[5][5].letter = txt66->Text.c_str()[0]; if(Nodes[5][5].letter >= 'A') Nodes[5][5].taken = false; Nodes[5][6].letter = txt67->Text.c_str()[0]; if(Nodes[5][6].letter >= 'A') Nodes[5][6].taken = false; Nodes[5][7].letter = txt68->Text.c_str()[0]; if(Nodes[5][7].letter >= 'A') Nodes[5][7].taken = false; Nodes[6][0].letter = txt71->Text.c_str()[0]; if(Nodes[6][0].letter >= 'A') Nodes[6][0].taken = false; Nodes[6][1].letter = txt72->Text.c_str()[0]; if(Nodes[6][1].letter >= 'A') Nodes[6][1].taken = false; Nodes[6][2].letter = txt73->Text.c_str()[0]; if(Nodes[6][2].letter >= 'A') Nodes[6][2].taken = false; Nodes[6][3].letter = txt74->Text.c_str()[0]; if(Nodes[6][3].letter >= 'A') Nodes[6][3].taken = false; Nodes[6][4].letter = txt75->Text.c_str()[0]; if(Nodes[6][4].letter >= 'A') Nodes[6][4].taken = false; Nodes[6][5].letter = txt76->Text.c_str()[0]; if(Nodes[6][5].letter >= 'A') Nodes[6][5].taken = false; Nodes[6][6].letter = txt77->Text.c_str()[0]; if(Nodes[6][6].letter >= 'A') Nodes[6][6].taken = false; Nodes[6][7].letter = txt78->Text.c_str()[0]; if(Nodes[6][7].letter >= 'A') Nodes[6][7].taken = false; Nodes[7][0].letter = txt81->Text.c_str()[0]; if(Nodes[7][0].letter >= 'A') Nodes[7][0].taken = false; Nodes[7][1].letter = txt82->Text.c_str()[0]; if(Nodes[7][1].letter >= 'A') Nodes[7][1].taken = false; Nodes[7][2].letter = txt83->Text.c_str()[0]; if(Nodes[7][2].letter >= 'A') Nodes[7][2].taken = false; Nodes[7][3].letter = txt84->Text.c_str()[0]; if(Nodes[7][3].letter >= 'A') Nodes[7][3].taken = false; Nodes[7][4].letter = txt85->Text.c_str()[0]; if(Nodes[7][4].letter >= 'A') Nodes[7][4].taken = false; Nodes[7][5].letter = txt86->Text.c_str()[0]; if(Nodes[7][5].letter >= 'A') Nodes[7][5].taken = false; Nodes[7][6].letter = txt87->Text.c_str()[0]; if(Nodes[7][6].letter >= 'A') Nodes[7][6].taken = false; Nodes[7][7].letter = txt88->Text.c_str()[0]; if(Nodes[7][7].letter >= 'A') Nodes[7][7].taken = false; //calculate adjacents // i=leftness, j=topness for(int i=0; i<8; i++){ for(int j=0; j<8; j++){ int numAdjacent=0; //top-left if((i>0) && (j>0)){ if(!Nodes[i-1][j-1].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i-1][j-1]; } } //top if(j>0){ if(!Nodes[i][j-1].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i][j-1]; } } //top-right if((i<7) && (j>0)){ if(!Nodes[i+1][j-1].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i+1][j-1]; } } //left if(i>0){ if(!Nodes[i-1][j].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i-1][j]; } } //right if(i<7){ if(!Nodes[i+1][j].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i+1][j]; } } //bottom-left if((i>0) && (j<7)){ if(!Nodes[i-1][j+1].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i-1][j+1]; } } //bottom if(j<7){ if(!Nodes[i][j+1].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i][j+1]; } } //bottom-right if((i<7) && (j<7)){ if(!Nodes[i+1][j+1].taken){ Nodes[i][j].adjacent[numAdjacent++] = &Nodes[i+1][j+1]; } } for(int k=numAdjacent; k<32; k++) Nodes[i][j].adjacent[k] = NULL; } } //do the search! minLength = atoi(txtMinLen->Text.c_str()); searchStringLen = 0; for(int i=0; i<16; i++) searchString[i] = 0; int* matches = new int[wordCount]; for(int k=0; kCursor = crDefault; } //--------------------------------------------------------------------------- void TForm1::SearchNode(NodeRec* Node, int* matchList, int numMatches){ //if the node is already taken, don't bother if(Node->taken) return; //acquire the node Node->taken = true; //add our letter to the search string searchString[searchStringLen++] = Node->letter; //build match list int* matches = new int[wordCount]; int numMatch=0; //try to match our letter for(int i=0; iletter){ //we have a letter match if(searchStringLen == words[matchList[i]].length){ //whoa! we have a word match! if(!words[matchList[i]].found){ words[matchList[i]].found = true; if(searchStringLen >= minLength) lstResults->Items->Add(String(words[matchList[i]].word)); } }else{ //add it to the list matches[numMatch++] = matchList[i]; } } } if(numMatch){ //call our adjacents for(int i=0; i<32; i++){ if(Node->adjacent[i]){ if(!Node->adjacent[i]->taken) SearchNode(Node->adjacent[i], matches, numMatch); } } } delete [] matches; //remove our letter from the search string searchString[searchStringLen - 1] = 0; searchStringLen--; //release the node Node->taken = false; } //--------------------------------------------------------------------------- void __fastcall TForm1::txtKeyPress(TObject *Sender, char &Key){ if((Key == 7) || (Key == 8)){ ((TEdit*)Sender)->Text = " "; FindNextControl((TEdit*)Sender, false, true, false)->SetFocus(); }else if((Key == 10) || (Key == 13)){ TWinControl* c = (TWinControl*)Sender; for(int i=0; i<8-((TEdit*)Sender)->Tag; i++){ c = FindNextControl(c, true, true, false); } c->SetFocus(); }else{ ((TEdit*)Sender)->Text = String(Key); FindNextControl((TEdit*)Sender, true, true, false)->SetFocus(); } Key = 0; } //--------------------------------------------------------------------------- void __fastcall TForm1::cmdAnagramClick(TObject *Sender){ String str = txtAnagram->Text; int strLen = str.Length(); if(!strLen) return; lstResults->Items->Clear(); Screen->Cursor = crHourGlass; //initialize array of nodes NodeRec* nodes = new NodeRec[strLen]; //calculate adjacents for(int i=0; i= 'A') nodes[i].taken = false; else nodes[i].taken = true; int numAdjacent=0; for(int j=0; jText.c_str()); searchStringLen = 0; for(int i=0; i<16; i++) searchString[i] = 0; int* matches = new int[wordCount]; for(int k=0; kCursor = crDefault; } //--------------------------------------------------------------------------- void __fastcall TForm1::txtAnagramKeyPress(TObject *Sender, char &Key){ if((Key == 10) || (Key == 13)){ Key = 0; cmdAnagramClick(Sender); return; } } //--------------------------------------------------------------------------- void __fastcall TForm1::txtMinLenKeyPress(TObject *Sender, char &Key){ if((Key == 7) || (Key == 8)){ return; } if((Key < '0') || (Key > '9')){ Key = 0; } } //---------------------------------------------------------------------------