Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

# Natural Language Toolkit: Word Finder 

# 

# Copyright (C) 2001-2012 NLTK Project 

# Author: Steven Bird <sb@csse.unimelb.edu.au> 

# URL: <http://www.nltk.org/> 

# For license information, see LICENSE.TXT 

 

# Simplified from PHP version by Robert Klein <brathna@gmail.com> 

# http://fswordfinder.sourceforge.net/ 

from __future__ import print_function 

 

import random 

 

 

# reverse a word with probability 0.5 

def revword(word): 

    if random.randint(1,2) == 1: 

        return word[::-1] 

    return word 

 

# try to insert word at position x,y; direction encoded in xf,yf 

def step(word, x, xf, y, yf, grid): 

    for i in range(len(word)): 

        if grid[xf(i)][yf(i)] != "" and grid[xf(i)][yf(i)] != word[i]: 

            return False 

    for i in range(len(word)): 

        grid[xf(i)][yf(i)] = word[i] 

    return True 

 

# try to insert word at position x,y, in direction dir 

def check(word, dir, x, y, grid, rows, cols): 

    if dir==1: 

        if x-len(word)<0 or y-len(word)<0: 

            return False 

        return step(word, x, lambda i:x-i, y, lambda i:y-i, grid) 

    elif dir==2: 

        if x-len(word)<0: 

            return False 

        return step(word, x, lambda i:x-i, y, lambda i:y, grid) 

    elif dir==3: 

        if x-len(word)<0 or y+(len(word)-1)>=cols: 

            return False 

        return step(word, x, lambda i:x-i, y, lambda i:y+i, grid) 

    elif dir==4: 

        if y-len(word)<0: 

            return False 

        return step(word, x, lambda i:x, y, lambda i:y-i, grid) 

 

def wordfinder(words, rows=20, cols=20, attempts=50, 

               alph='ABCDEFGHIJKLMNOPQRSTUVWXYZ'): 

    """ 

    Attempt to arrange words into a letter-grid with the specified 

    number of rows and columns.  Try each word in several positions 

    and directions, until it can be fitted into the grid, or the 

    maximum number of allowable attempts is exceeded.  Returns a tuple 

    consisting of the grid and the words that were successfully 

    placed. 

 

    :param words: the list of words to be put into the grid 

    :type words: list 

    :param rows: the number of rows in the grid 

    :type rows: int 

    :param cols: the number of columns in the grid 

    :type cols: int 

    :param attempts: the number of times to attempt placing a word 

    :type attempts: int 

    :param alph: the alphabet, to be used for filling blank cells 

    :type alph: list 

    :rtype: tuple 

    """ 

 

    # place longer words first 

    words.sort(cmp=lambda x,y:cmp(len(x),len(y)), reverse=True) 

 

    grid = []  # the letter grid 

    used = []  # the words we used 

 

    # initialize the grid 

    for i in range(rows): 

        grid.append([""] * cols) 

 

    # try to place each word 

    for word in words: 

        word = word.strip().upper()  # normalize 

        save = word                  # keep a record of the word 

        word = revword(word) 

        for attempt in range(attempts): 

            r = random.randint(0, len(word)) 

            dir = random.choice([1,2,3,4]) 

            x = random.randint(0,rows) 

            y = random.randint(0,cols) 

            if   dir==1: x+=r; y+=r 

            elif dir==2: x+=r 

            elif dir==3: x+=r; y-=r 

            elif dir==4: y+=r 

            if 0<=x<rows and 0<=y<cols: 

                if check(word, dir, x, y, grid, rows, cols): 

#                   used.append((save, dir, x, y, word)) 

                    used.append(save) 

                    break 

 

    # Fill up the remaining spaces 

    for i in range(rows): 

        for j in range(cols): 

            if grid[i][j] == '': 

                grid[i][j] = random.choice(alph) 

 

    return grid, used 

 

def word_finder(): 

    from nltk.corpus import words 

    wordlist = words.words() 

    random.shuffle(wordlist) 

    wordlist = wordlist[:200] 

    wordlist = [w for w in wordlist if 3 <= len(w) <= 12] 

    grid, used = wordfinder(wordlist) 

 

    print("Word Finder\n") 

    for i in range(len(grid)): 

        for j in range(len(grid[i])): 

            print(grid[i][j], end=' ') 

        print() 

    print() 

 

    for i in range(len(used)): 

        print("%d:" % (i+1), used[i]) 

 

if __name__ == '__main__': 

    word_finder()