-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSpellingBee.java
186 lines (158 loc) · 6.15 KB
/
SpellingBee.java
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package student;
import edu.willamette.cs1.spellingbee.SpellingBeeGraphics;
import java.awt.Color;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.regex.Pattern;
public class SpellingBee {
private static final String ENGLISH_DICTIONARY = "res/EnglishWords.txt";
private static final Pattern PUZZLE_VALIDATION_REGEX = Pattern.compile("[a-zA-Z]");
private static final int PUZZLE_LENGTH = 7;
private static final int WORD_BONUS = PUZZLE_LENGTH;
private static final int MIN_WORD_LENGTH = 4;
private final Map<String, Boolean> dictionary = new HashMap<>();
private final List<String> validDictionaryWords = new ArrayList<>();
private final List<String> enteredWords = new ArrayList<>();
private SpellingBeeGraphics sbg;
private Pattern currentWordValidationRegex = Pattern.compile("");
private String[] currentWordLetters = null;
private int totalScore = 0;
public SpellingBee() {
loadDictionaryFile();
}
public void run() {
sbg = new SpellingBeeGraphics();
sbg.addField("Puzzle", (s) -> puzzleAction(s));
sbg.addField("Word", (s) -> userSolveAction(s));
sbg.addButton("Solve", (s) -> solveAction());
}
private boolean validatePuzzleLength(String s) {
if (s.length() != PUZZLE_LENGTH) {
sbg.showMessage("The puzzle string must be exactly 7 characters", Color.RED);
return false;
}
return true;
}
private boolean validatePuzzleContents(String s) {
boolean isValid = PUZZLE_VALIDATION_REGEX.matcher(s).find();
if (!isValid) {
sbg.showMessage("The puzzle string must only consist of letters", Color.RED);
}
Set<String> chars = new HashSet<>();
for (String c: s.split("")) {
if (chars.contains(c)) {
sbg.showMessage("The puzzle string must consist of unique letters", Color.red);
return false;
}
chars.add(c);
}
return isValid;
}
private void puzzleAction(String s) {
if (!validatePuzzleLength(s)) {
return;
}
if (!validatePuzzleContents(s)) {
return;
}
sbg.setBeehiveLetters(s);
initDictionary();
}
private boolean wordUsesAllLetters(String word) {
return Arrays.stream(currentWordLetters).allMatch((s) -> word.toLowerCase().contains(s));
}
private int getWordScore(String word) {
boolean shouldGetBonus = wordUsesAllLetters(word);
return (word.length() == MIN_WORD_LENGTH ? 1 : word.length()) + (shouldGetBonus ? WORD_BONUS : 0);
}
private boolean wordContainsCenterLetter(String word) {
return word.toLowerCase().contains(sbg.getBeehiveLetters().substring(0, 1).toLowerCase());
}
private boolean isValidWord(String word) {
if (MIN_WORD_LENGTH > word.length()) {
return false;
}
long regexMatchCount = currentWordValidationRegex.matcher(word.toLowerCase()).results().count();
boolean matchesRegex = regexMatchCount == word.length();
boolean hasMiddleLetter = wordContainsCenterLetter(word);
return matchesRegex && hasMiddleLetter;
}
private void initState() {
currentWordValidationRegex = Pattern.compile(String.format("[%s]", sbg.getBeehiveLetters().toLowerCase()));
currentWordLetters = sbg.getBeehiveLetters().toLowerCase().split("");
totalScore = 0;
sbg.clearWordList();
enteredWords.clear();
sbg.showMessage("");
}
private void loadDictionaryFile() {
try {
File dictionaryFile = new File(ENGLISH_DICTIONARY);
Scanner dictionaryScanner = new Scanner(dictionaryFile);
while (dictionaryScanner.hasNextLine()) {
String word = dictionaryScanner.nextLine();
dictionary.put(word, false);
}
} catch (FileNotFoundException e) {
System.out.println("failed to load english dictionary");
System.exit(0);
}
}
private void initDictionary() {
validDictionaryWords.clear();
initState();
dictionary.forEach((word, valid) -> {
boolean isValid = isValidWord(word);
dictionary.put(word, isValid);
if (isValid) {
validDictionaryWords.add(word);
}
});
}
private void addWord(String word) {
int score = getWordScore(word);
totalScore += score;
boolean isBonusWord = wordUsesAllLetters(word);
sbg.addWord(String.format("%s (%d)", word, score), isBonusWord ? Color.blue : Color.black);
enteredWords.add(word);
String pluralWord = enteredWords.size() > 1 ? "s" : "";
String pluralScore = totalScore > 1 ? "s" : "";
String msg = String.format("%d word%s; %d point%s", enteredWords.size(), pluralWord, totalScore, pluralScore);
sbg.showMessage(msg);
}
private void solveAction() {
initState();
for (String word: validDictionaryWords) {
if (!enteredWords.contains(word)) {
addWord(word);
}
}
}
private void userSolveAction(String s) {
if (MIN_WORD_LENGTH > s.length()) {
sbg.showMessage("The word does not include at least four letters", Color.red);
return;
}
if (!wordContainsCenterLetter(s)) {
sbg.showMessage("The word does not include the center letter", Color.red);
return;
}
Boolean isValidWord = dictionary.get(s);
if (isValidWord == null) {
sbg.showMessage("The word is not in the dictionary", Color.red);
return;
} else if (!isValidWord) {
sbg.showMessage("The word includes letters not in the beehive", Color.red);
return;
}
if (enteredWords.contains(s)) {
sbg.showMessage("You have already found the word and is not allowed to be scored twice", Color.red);
return;
}
addWord(s);
}
public static void main(String[] args) {
new SpellingBee().run();
}
}