21 Commits
Author SHA1 Message Date
cblanken bc70b88bf7 Bump version 2.0.0 2022-09-26 11:44:51 -04:00
cblanken 21aab46b96 Refactor board_randomizer
- Make file read separate and return "dice" or a list of strings from
  dice handling functions for use in downstream programs
2022-09-26 11:40:36 -04:00
cblanken f18c30cb60 Rename Super Big Boggle dice file 2022-09-23 10:20:48 -04:00
cblanken da915b723c Update wordlist splitting script
- Force lowercase on split
- Only match single (non compound) words
- Don't match punctuation
- Sort and uniquify
2022-09-23 10:20:48 -04:00
cblanken d5a102713d Fix die letters for 'New Boggle' dice 2022-09-23 10:20:38 -04:00
cblanken c488263eea Bump version and update license 2022-09-21 10:15:14 -04:00
cblanken fe1f1c2b97 Fix MAX_WORD_LENGTH parsing 2022-09-21 10:04:02 -04:00
cblanken d2584686a3 Fix max word length
- Previously the max word length parameter was checking the tree depths
  instead of the length of the word
- This fix acounts for multi-letter blocks like 'Qu', 'Tr' etc.
2022-09-21 09:45:09 -04:00
cblanken 8f75604d15 Handle blocks with empty strings and non-existant wordlists 2022-09-20 22:45:57 -04:00
cblanken 96da732dd9 Update board_randomizer module
- Fix typo: randimizer to randomizer
- Add module function to get direct 2d array of board values
2022-09-20 15:58:26 -04:00
cblanken ec53042d18 Update and move word splitting script 2022-09-20 13:21:57 -04:00
cblankenandGitHub 5c18a4aebf Update README.md 2022-09-15 14:06:55 -04:00
cblanken b197253d86 Add 9x9 dice file 2022-09-15 13:44:14 -04:00
cblanken 67f8c439b0 Update release version 2022-09-15 13:44:14 -04:00
cblanken 8c41ad212d Add missing __init__.py for PyPI package 2022-09-15 13:44:14 -04:00
cblanken 94800909b4 Update project version number 2022-09-15 13:44:14 -04:00
cblanken f24b996411 Update README.md 2022-09-15 13:44:14 -04:00
cblanken e4df95cd08 Update .gitignore 2022-09-15 13:44:14 -04:00
cblanken 0e9b120e94 Reorganize files into PyPI package format 2022-09-15 13:44:14 -04:00
cblanken 276c27f1ce Add pyproject.toml for PyPI 2022-09-15 13:44:13 -04:00
cblanken d30c44af3c Add MIT LICENSE 2022-09-15 13:43:55 -04:00
86 changed files with 264 additions and 110 deletions
+8 -1
View File
@@ -1,2 +1,9 @@
# Byte-compiled / optimized
__pycache__/
*.py[cod]
# Distribution / packaging
dist/
# Env
.vscode
__pycache__
+8
View File
@@ -0,0 +1,8 @@
The MIT License (MIT)
Copyright © 2022 Cameron Blankenbuehler
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+15 -8
View File
@@ -2,8 +2,12 @@
A solver for the popular word game Boggle.
# Install
```bash
$ git clone https://github.com/cblanken/boggler.git
```console
pip install boggler
```
OR
```console
git clone https://github.com/cblanken/boggler.git
```
To use the script to solve a particular Boggle board configuration, you'll need to do a few things
@@ -11,11 +15,11 @@ To use the script to solve a particular Boggle board configuration, you'll need
Here is an example `board.csv`. Note the orientation of the board does not matter.
```console
$ cat boards/b1.csv
s,a,i,p
l,qu,a,y
u,l,l,s
o,w,h,a
$ cat board.csv
y,e,o,s
r,e,o,v
d,f,e,y
n,m,e,qu
```
2. Find a dictionary wordlist file or create your own
@@ -393,4 +397,7 @@ que : [(3, 3), (3, 2)]
quey : [(3, 3), (3, 2), (2, 3)]
quem : [(3, 3), (3, 2), (3, 1)]
queme : [(3, 3), (3, 2), (3, 1), (2, 2)]
```
```
# License
The included [wordlists](src/boggler/wordlists) are covered by their respective licenses. All other files MIT © Cameron Blankenbuehler
-31
View File
@@ -1,31 +0,0 @@
'''Module to generate random Boggle boards for testing'''
from sys import argv
from random import randint, shuffle
from math import sqrt
def read_dice_file(path):
# TODO: Factor in 'qu' die face
'''Return list of die strings from file ignoring all comments (#)'''
with open(path, 'r+', encoding="utf-8") as file:
return [line.rstrip().split(',') for line in file.readlines() if line[0] != "#"]
def roll_die(die: str):
'''Return a face of the given die string to simulate rolling a die'''
return str(die[randint(0, len(die) - 1)])
def roll_dice(dice: list[str]):
'''Return a random roll for each die'''
return [ roll_die(die) for die in dice ]
if __name__ == '__main__':
if len(argv) != 2:
print('Usage: python3 board_randomizer.py <dice_file>')
else:
dice_strings = read_dice_file(argv[1])
shuffle(dice_strings)
rolls = roll_dice(dice_strings)
# Format dice rolls for boards file
board_size = int(sqrt(len(rolls)))
for i in range(0, len(dice_strings), board_size):
print(",".join(rolls[i:i+board_size]))
+23
View File
@@ -0,0 +1,23 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "boggler"
version = "2.0.0"
authors = [
{ name="Cameron Blankenbuehler", email="cameron.blankenbuehler@gmail.com" },
]
description = "Utilities for solving the Boggle word game."
readme="README.md"
license = { file="LICENSE" }
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: POSIX :: Linux",
]
[project.urls]
"Homepage" = "https://github.com/cblanken/boggler"
"Bug Tracker" = "https://github.com/cblanken/boggler/issues"
-35
View File
@@ -1,35 +0,0 @@
#!/bin/sh
if [ -z $1 ] || [ -z $2 ]; then
echo "Usage: ./filter_prefix.sh WORDLIST OUT_DIR"
exit 0
else
grep -P "^a" $1 > "$2/words_a.txt"
grep -P "^b" $1 > "$2/words_b.txt"
grep -P "^c" $1 > "$2/words_c.txt"
grep -P "^d" $1 > "$2/words_d.txt"
grep -P "^e" $1 > "$2/words_e.txt"
grep -P "^f" $1 > "$2/words_f.txt"
grep -P "^g" $1 > "$2/words_g.txt"
grep -P "^h" $1 > "$2/words_h.txt"
grep -P "^i" $1 > "$2/words_i.txt"
grep -P "^j" $1 > "$2/words_j.txt"
grep -P "^k" $1 > "$2/words_k.txt"
grep -P "^l" $1 > "$2/words_l.txt"
grep -P "^m" $1 > "$2/words_m.txt"
grep -P "^n" $1 > "$2/words_n.txt"
grep -P "^o" $1 > "$2/words_o.txt"
grep -P "^p" $1 > "$2/words_p.txt"
grep -P "^q" $1 > "$2/words_q.txt"
grep -P "^r" $1 > "$2/words_r.txt"
grep -P "^s" $1 > "$2/words_s.txt"
grep -P "^t" $1 > "$2/words_t.txt"
grep -P "^u" $1 > "$2/words_u.txt"
grep -P "^v" $1 > "$2/words_v.txt"
grep -P "^w" $1 > "$2/words_w.txt"
grep -P "^x" $1 > "$2/words_x.txt"
grep -P "^y" $1 > "$2/words_y.txt"
grep -P "^z" $1 > "$2/words_z.txt"
grep -P "^_" $1 > "$2/words__.txt"
exit 0
fi
+48
View File
@@ -0,0 +1,48 @@
'''Module to generate random Boggle boards for testing'''
from sys import argv, stderr
from random import randint, shuffle
from math import sqrt
from os import path
def read_dice_file(dice_path: str):
'''Return list of die strings from file ignoring all comments (#)'''
with open(path.abspath(dice_path), 'r+', encoding="utf-8") as file:
return [line.rstrip().split(',') for line in file.readlines() if line[0] != "#"]
def roll_die(die: str):
'''Return a face of the given die string to simulate rolling a die'''
return str(die[randint(0, len(die) - 1)])
def roll_dice(dice: list[str]):
'''Return a random roll for each die'''
return [ roll_die(die) for die in dice ]
def get_random_board(dice: list[str]):
shuffle(dice)
rolls = roll_dice(dice)
# Format dice rolls for boards file
board_size = int(sqrt(len(rolls)))
board = []
for i in range(0, len(dice), board_size):
board.append(rolls[i:i+board_size])
return board
def get_random_board_csv(dice: list[str]):
board = get_random_board(dice)
board = [",".join(row) for row in board]
return board
if __name__ == '__main__':
if len(argv) != 2:
print('Usage: python3 board_randomizer.py <dice_file>')
else:
try:
dice = read_dice_file(path.abspath(argv[1]))
board = get_random_board_csv(dice)
for row in board:
print(row)
except Exception as e:
print("Argument must be a valid file path!", file=stderr)
+18 -16
View File
@@ -11,22 +11,24 @@ if __name__ == '__main__':
board = read_boggle_file(Path(sys.argv[1]))
if len(sys.argv) == 3:
boggle_board = BoggleBoard(board)
print(boggle_board)
boggle_tree = build_full_boggle_tree(boggle_board, Path(sys.argv[2]))
elif len(sys.argv) == 4:
try :
try:
boggle_board = BoggleBoard(board, int(sys.argv[3]))
boggle_tree = build_full_boggle_tree(boggle_board, Path(sys.argv[2]))
print("\nBOARD")
print(boggle_board)
for start_pos, tree in boggle_tree.items():
print(f"\nStarting @ {start_pos}...")
for word in tree.word_paths:
print(f"{word[0]: <{boggle_board.max_word_len}}: {word[1]}")
except ValueError as e:
print("The [MAX_WORD_LENGTH] argument must be an integer.")
print("Please try again.")
except ValueError:
print("Invalid MAX_WORD_LENGTH. Please try again with a valid integer.")
sys.exit(1)
try:
boggle_tree = build_full_boggle_tree(boggle_board, Path(sys.argv[2]))
print("\nBOARD")
print(boggle_board)
for start_pos, tree in boggle_tree.items():
print(f"\nStarting @ {start_pos}...")
for word in tree.word_paths:
print(f"{word[0]: <{boggle_board.max_word_len}}: {word[1]}")
except ValueError as e:
print("The [MAX_WORD_LENGTH] argument must be an integer.")
print("Please try again.")
sys.exit(1)
+26 -18
View File
@@ -197,9 +197,9 @@ class WordNode:
class WordTree:
'''A tree populated by WordNode(s) to complete words from a given root letter and wordlist'''
def __init__(self, alphabet: str, root: WordNode, words: list[str] = None,
def __init__(self, alphabet: list, root: WordNode, words: list[str] = None,
max_word_len = 16) -> WordTree:
self.__alphabet: str = alphabet
self.__alphabet: list = alphabet
self.__wordlist: list[str] = words
self.__root: WordNode = root
self.__max_word_len: int = max_word_len
@@ -216,7 +216,7 @@ class WordTree:
self.__insert_word(word)
@property
def alphabet(self) -> str:
def alphabet(self) -> list:
'''Getter for alphabet property'''
return self.__alphabet
@@ -278,7 +278,7 @@ class WordTree:
continue
try:
alpha_index = [x[0] for x in self.alphabet].index(letter)
alpha_index = self.alphabet.index(letter)
except ValueError: # letters not in given alphabet
return False
@@ -324,7 +324,7 @@ class WordTree:
# TODO: return all possible paths, maybe create minature WordTree? Or just of list of paths.
return curr_node
def build_boggle_tree(self, board: BoggleBoard, board_cell: BoardCell, subtree: WordTree, depth: int = 1) -> WordTree:
def build_boggle_tree(self, board: BoggleBoard, board_cell: BoardCell, subtree: WordTree, word_len: int = 0) -> WordTree:
'''Return subtree of board given a particular root (first letter).
Keyword arguments:
@@ -334,6 +334,12 @@ class WordTree:
subtree -- the partial tree passed to the next recursive step for generating branches
'''
if word_len > self.max_word_len or word_len >= board.max_word_len:
#print(f"MAX DEPTH REACHED! Depth = {depth}")
subtree.active_node = subtree.active_node.parent
self.active_node = self.active_node.parent
return
# TODO rework active_node refs for recursion so don't have to be reset to parent at every point of return
if self.active_node.is_word and len(self.active_node.children) == 0:
word_path = subtree.active_node.path[::-1]
@@ -347,12 +353,6 @@ class WordTree:
subtree.word_paths.append((subtree.active_node.get_word(board), word_path))
#print("2: WORD FOUND:", "".join([board.board[x].letters for x in word_path]), word_path)
if depth >= self.max_word_len or depth >= board.max_word_len:
#print(f"MAX DEPTH REACHED! Depth = {depth}")
subtree.active_node = subtree.active_node.parent
self.active_node = self.active_node.parent
return
# Branch for each adjacent board cell
for cell in board_cell.adjacent_cells:
# Check dictionary and exclude nodes already in path
@@ -361,7 +361,7 @@ class WordTree:
subtree.active_node.add_child_node(new_node)
subtree.active_node = subtree.active_node.children[cell.letters] # update subtree pointer
self.active_node = self.active_node.children[cell.letters] # update dictionary tree pointer
self.build_boggle_tree(board, board.board[cell.pos], subtree, depth=depth+1)
self.build_boggle_tree(board, board.board[cell.pos], subtree, word_len=word_len+len(board_cell.letters))
self.active_node = self.active_node.parent
subtree.active_node = subtree.active_node.parent
@@ -383,17 +383,25 @@ def build_full_boggle_tree(board: BoggleBoard, wordlist_path: str) -> dict[str,
print("Reading in wordlists...")
for letters in alphabet:
if letters[0] in index:
if letters == "":
# Skip wordlist read for blocks with empty string
index[""] = {}
continue
elif letters[0] in index:
index[letters] = index[letters[0]]
continue
filename = "words_" + letters[0] + ".txt"
print(f">> {letters}: {filename}")
wordlist = read_wordlist(path.join(path.abspath(wordlist_path), filename))
index[letters] = wordlist
try:
wordlist = read_wordlist(path.join(path.abspath(wordlist_path), filename))
index[letters] = wordlist
print(f">> {letters}: {filename}")
except FileNotFoundError:
print(f">> {letters}: -- Skipping -- no wordlist found for {letters}")
index[letters] = {}
print("Generating WordTrees...")
params = [ [alphabet, board, cell, index[cell.letters] ] for cell in board.board.values()]
params = [ [alphabet, board, cell, index[cell.letters] ] for cell in board.board.values()]
with Pool(processes=len(board.board)) as pool:
for i, res in enumerate(pool.map(build_boggle_tree, params)):
print(f">> {params[i][2]}")
@@ -409,4 +417,4 @@ def read_wordlist(file):
def read_boggle_file(file):
'''Return list of rows from Boggle board csv file'''
with open(file, 'r', encoding='utf-8') as file:
return [x.rstrip().split(',') for x in file.readlines()]
return [x.rstrip().split(',') for x in file.readlines()]
@@ -1,5 +1,5 @@
# Listed alphabetically
a,a,a,e,e,g
a,a,e,e,g,n
a,b,b,j,o,o
a,c,h,o,p,s
a,f,f,k,p,s
1 # Listed alphabetically
2 a,a,a,e,e,g a,a,e,e,g,n
3 a,b,b,j,o,o
4 a,c,h,o,p,s
5 a,f,f,k,p,s
+82
View File
@@ -0,0 +1,82 @@
# Made from 6x6 dice repeated to reach 9x9 (81) dice rolls
_,_,_,e,i,o
a,a,a,f,r,s
a,a,e,e,e,e
a,a,e,e,o,o
a,a,f,i,r,s
a,b,d,e,i,o
a,d,e,n,n,n
a,e,e,e,e,m
a,e,e,g,m,u
a,e,g,m,n,n
a,e,i,l,m,n
a,e,i,n,o,u
a,f,i,r,s,y
an,er,he,in,qu,th
b,b,b,j,j,z
c,c,e,n,s,t
c,d,d,l,n,n
c,e,e,i,t,t
c,e,i,p,s,t
c,f,g,n,u,w
d,d,h,n,o,t
d,h,h,l,o,r
d,h,h,n,o,w
d,h,l,n,o,r
e,h,i,l,r,s
e,i,i,l,s,t
e,i,l,p,s,t
e,m,o,t,t,t
e,n,s,s,s,u
g,o,r,r,v,w
h,i,r,s,t,v
h,o,p,r,s,t
i,p,r,s,y,y
j,k,qu,w,x,z
n,o,o,t,u,w
o,o,o,t,t,u
_,_,_,e,i,o
a,a,a,f,r,s
a,a,e,e,e,e
a,a,e,e,o,o
a,a,f,i,r,s
a,b,d,e,i,o
a,d,e,n,n,n
a,e,e,e,e,m
a,e,e,g,m,u
a,e,g,m,n,n
a,e,i,l,m,n
a,e,i,n,o,u
a,f,i,r,s,y
an,er,he,in,qu,th
b,b,b,j,j,z
c,c,e,n,s,t
c,d,d,l,n,n
c,e,e,i,t,t
c,e,i,p,s,t
c,f,g,n,u,w
d,d,h,n,o,t
d,h,h,l,o,r
d,h,h,n,o,w
d,h,l,n,o,r
e,h,i,l,r,s
e,i,i,l,s,t
e,i,l,p,s,t
e,m,o,t,t,t
e,n,s,s,s,u
g,o,r,r,v,w
h,i,r,s,t,v
h,o,p,r,s,t
i,p,r,s,y,y
j,k,qu,w,x,z
n,o,o,t,u,w
o,o,o,t,t,u
e,m,o,t,t,t
e,n,s,s,s,u
g,o,r,r,v,w
h,i,r,s,t,v
h,o,p,r,s,t
i,p,r,s,y,y
j,k,qu,w,x,z
n,o,o,t,u,w
o,o,o,t,t,u
1 # Made from 6x6 dice repeated to reach 9x9 (81) dice rolls
2 _,_,_,e,i,o
3 a,a,a,f,r,s
4 a,a,e,e,e,e
5 a,a,e,e,o,o
6 a,a,f,i,r,s
7 a,b,d,e,i,o
8 a,d,e,n,n,n
9 a,e,e,e,e,m
10 a,e,e,g,m,u
11 a,e,g,m,n,n
12 a,e,i,l,m,n
13 a,e,i,n,o,u
14 a,f,i,r,s,y
15 an,er,he,in,qu,th
16 b,b,b,j,j,z
17 c,c,e,n,s,t
18 c,d,d,l,n,n
19 c,e,e,i,t,t
20 c,e,i,p,s,t
21 c,f,g,n,u,w
22 d,d,h,n,o,t
23 d,h,h,l,o,r
24 d,h,h,n,o,w
25 d,h,l,n,o,r
26 e,h,i,l,r,s
27 e,i,i,l,s,t
28 e,i,l,p,s,t
29 e,m,o,t,t,t
30 e,n,s,s,s,u
31 g,o,r,r,v,w
32 h,i,r,s,t,v
33 h,o,p,r,s,t
34 i,p,r,s,y,y
35 j,k,qu,w,x,z
36 n,o,o,t,u,w
37 o,o,o,t,t,u
38 _,_,_,e,i,o
39 a,a,a,f,r,s
40 a,a,e,e,e,e
41 a,a,e,e,o,o
42 a,a,f,i,r,s
43 a,b,d,e,i,o
44 a,d,e,n,n,n
45 a,e,e,e,e,m
46 a,e,e,g,m,u
47 a,e,g,m,n,n
48 a,e,i,l,m,n
49 a,e,i,n,o,u
50 a,f,i,r,s,y
51 an,er,he,in,qu,th
52 b,b,b,j,j,z
53 c,c,e,n,s,t
54 c,d,d,l,n,n
55 c,e,e,i,t,t
56 c,e,i,p,s,t
57 c,f,g,n,u,w
58 d,d,h,n,o,t
59 d,h,h,l,o,r
60 d,h,h,n,o,w
61 d,h,l,n,o,r
62 e,h,i,l,r,s
63 e,i,i,l,s,t
64 e,i,l,p,s,t
65 e,m,o,t,t,t
66 e,n,s,s,s,u
67 g,o,r,r,v,w
68 h,i,r,s,t,v
69 h,o,p,r,s,t
70 i,p,r,s,y,y
71 j,k,qu,w,x,z
72 n,o,o,t,u,w
73 o,o,o,t,t,u
74 e,m,o,t,t,t
75 e,n,s,s,s,u
76 g,o,r,r,v,w
77 h,i,r,s,t,v
78 h,o,p,r,s,t
79 i,p,r,s,y,y
80 j,k,qu,w,x,z
81 n,o,o,t,u,w
82 o,o,o,t,t,u
+35
View File
@@ -0,0 +1,35 @@
#!/bin/sh
if [ -z $1 ] || [ -z $2 ]; then
echo "Usage: WORDLIST OUT_DIR"
exit 0
else
grep -ioP "^a[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_a.txt"
grep -ioP "^b[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_b.txt"
grep -ioP "^c[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_c.txt"
grep -ioP "^d[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_d.txt"
grep -ioP "^e[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_e.txt"
grep -ioP "^f[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_f.txt"
grep -ioP "^g[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_g.txt"
grep -ioP "^h[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_h.txt"
grep -ioP "^i[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_i.txt"
grep -ioP "^j[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_j.txt"
grep -ioP "^k[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_k.txt"
grep -ioP "^l[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_l.txt"
grep -ioP "^m[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_m.txt"
grep -ioP "^n[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_n.txt"
grep -ioP "^o[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_o.txt"
grep -ioP "^p[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_p.txt"
grep -ioP "^q[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_q.txt"
grep -ioP "^r[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_r.txt"
grep -ioP "^s[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_s.txt"
grep -ioP "^t[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_t.txt"
grep -ioP "^u[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_u.txt"
grep -ioP "^v[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_v.txt"
grep -ioP "^w[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_w.txt"
grep -ioP "^x[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_x.txt"
grep -ioP "^y[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_y.txt"
grep -ioP "^z[a-z]+" $1 | tr [A-Z] [a-z] | sort | uniq > "$2/words_z.txt"
touch "$2/words__.txt"
exit 0
fi