herndon@umn-cs.UUCP (03/05/86)
The following is a program for computing anagrams. It should work on any system which has a dictionary & the curses package. It's a moderately quick hack, put together for a friend who wanted to find all the words which could be made out of a phrase, and adapted so that it will work with phrases. (An anagram is a word or phrase made up from the letters of another word or phrase.) To compile, cut the program out and place in "ana.c". Then compile with cc ana.c -o ana -lcurses -ltermcap To run, type ana /usr/dict/words <word> <word>... (on my system, /usr/dict/words is the dictionary). The program will display all words in the dictionary which may be made from the words on the command line. After you type in each word, the program will redisplay the screen showing only those words that may be constructed from the letters remaining. ^U will erase the phrase you've entered so far, ^W will erase the last word entered, ^F will step forward to words not shown on the display, and ^B will step backwards to words not shown on the display. ? will display a help message, and Q will cause the program to exit. Sample anagram: sheraton == rats on her | ashen rot | no hearts | the sonar | north sea | heros tan | near shot | hot snare | treason + h | ... A popular use for programs like this is to figure out words that may be constructed from people's names. If your work/school place has posted name-directories made up of individual letters, these may then be re-arranged to provide entertainment. Disclaimer: Don't blame me if you get fired. --------------------------------------------------------------Cut Here. #include <ctype.h> #include <curses.h> /* maximum number of test words */ #define NLEVELS 30 char *words[NLEVELS][20000]; int letters[NLEVELS][26]; int savelet[26]; int maxword[NLEVELS]; int wordindex[NLEVELS]; int maxwordlen = 0; char phrase[120]; char wordspace[100000]; char *nextwsp = &wordspace[0]; main(ac, av) int ac; char *av[]; { register int i; register char c; char *p; FILE *fp; char line[120]; register int status; int lets[26], testw[26]; if(ac < 3) { printf("Usage: ana dict_file word [word ...]\n"); exit(1); } for(i = 2; i < ac; i++) { printf("%s ", av[i]); p = av[i]; while(*p) { if(*p < 'a' || *p > 'z') { printf("Bad character: %c.\n", *p); } else { lets[*p - 'a']++; } p++; } } printf("\n"); for(i = 0; i < 26; i++) { if(lets[i] != 0) { printf("letter '%c': %d.\n", i+'a', lets[i]); } } if((fp = fopen(av[1], "r")) == NULL) { printf("Can't open %s.\n", av[1]); exit(1); } while(1) { for(i = 0; i < 26; i++) testw[i] = lets[i]; i = 0; status = TRUE; do { c = getc(fp); if(c >= 'A' && c <= 'Z') c += 'a' - 'A'; if(islower(c)) { if(--testw[c-'a'] < 0) status = FALSE; } else if(isdigit(c)) { status = FALSE; } line[i++] = c; } while(c != '\n' && c != EOF); line[i-1] = '\0'; if(status == TRUE) { printf("%s\n", line); words[0][maxword[0]++] = nextwsp; i = 0; do { *nextwsp++ = line[i]; } while(line[i++] != '\0'); if(i-1 > maxwordlen) maxwordlen = i-1; } nextword: if(c == EOF) { fclose(fp); wordindex[0] = 0; lcopy(lets, letters[0]); lcopy(lets, savelet); anagram(); exit(0); } } } anagram() { int i = 0; int level = 0; char c; initscr(); noecho(); crmode(); display(level); while(c = getch()) { switch(c) { case '?': printf("? - help\n"); printf("Q - quit\n"); printf("' ' - print remaining words\n"); printf("^U - erase entered words\n"); printf("^W - erase entered word\n"); printf("^F - page forward in dictionary\n"); printf("^B - page backward in dictionary\n"); printf("lower case letters print, if in remaining letters\n"); printf("-----> Hit any character to continue."); getch(); display(level); break; case 'Q': endwin(); exit(0); /* You have reached the point of no return. */ case '\n': display(level); break; case ' ': if(i > 0 && phrase[i-1] != ' ') { phrase[i++] = ' '; phrase[i] = '\0'; compute(level); level++; display(level); } break; case '\025': /* ^u */ i = 0; phrase[i] = '\0'; level = 0; lcopy(savelet, letters[0]); display(level); break; case '\b': case '\0177': if(i > 0) { if(islower(phrase[i-1])) { ++letters[level][phrase[i-1]-'a']; i--; mvaddch(LINES-1, i-1, ' '); phrase[i] = '\0'; } else if(phrase[i-1] == ' ') { level--; i--; mvaddch(LINES-1, i-1, ' '); phrase[i] = '\0'; } else { mvaddstr(LINES-1,60,"error in phrase!"); putchar('\07'); } } display(level); break; case '\023': /* ^w - erase word */ if(i > 0) { if(phrase[i-1] == ' ') { level--; i--; phrase[i]= '\0'; } while(i > 0 && (islower(phrase[i-1]))) { i--; phrase[i] = '\0'; } } display(level); break; case '\06': /* ^f - page forward */ wordindex[level] += 75; if(wordindex[level] >= maxword[level]) wordindex[level] = maxword[level]; display(level); break; case '\02': /* ^b - page back */ wordindex[level] -= 75; if(wordindex[level] < 0) wordindex[level] = 0; display(level); break; default: if(islower(c)) { if(--letters[level][c-'a'] >= 0) { mvaddch(LINES-1, i, c); phrase[i++] = c; phrase[i] = '\0'; } else { ++letters[level][c-'a']; putchar('\07'); } refresh(); } else { putchar('\07'); } } } } lcopy(from, to) int from[], to[]; { int i; for(i = 0; i < 26; i++) to[i] = from[i]; } display(level) int level; { int i, row, col; clear(); row = col = 0; for(i = wordindex[level]; i < maxword[level]; i++) { mvaddstr(row, col, words[level][i]); if(++row >= LINES-3) { row = 0; col += maxwordlen + 6; if(col+maxwordlen >= COLS-4) break; } } mvaddstr(LINES-1, 0, phrase); refresh(); } compute(level) int level; { int testw[26]; int i, gw, nextsave; char *p; int j; for(nextsave = i = 0; i < maxword[level]; i++) { lcopy(letters[level], testw); gw = TRUE; for(p = words[level][i]; *p != '\0'; p++) { if(islower(*p)) { if(--testw[*p-'a'] < 0) { gw = FALSE; break; } } } if(gw == TRUE) words[level+1][nextsave++] = words[level][i]; } lcopy(letters[level], letters[level+1]); wordindex[level+1] = 0; maxword[level+1] = nextsave; }