-
Notifications
You must be signed in to change notification settings - Fork 131
Expand file tree
/
Copy pathScrabble.java
More file actions
191 lines (158 loc) · 8.43 KB
/
Scrabble.java
File metadata and controls
191 lines (158 loc) · 8.43 KB
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
187
188
189
190
191
package com.booleanuk;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Scrabble {
private int score = 0;
private String word;
private String regexLetters;
private HashMap<Character, Integer> pointsMap = new HashMap<>();
// TODO: Check meaning of final
private final List<Character> onePoints = Arrays.asList('A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T');
private final List<Character> twoPoints = Arrays.asList('D', 'G');
private final List<Character> threePoints = Arrays.asList('B', 'C', 'M', 'P');
private final List<Character> fourPoints = Arrays.asList('F', 'H', 'V', 'W', 'Y');
private final List<Character> fivePoints = Arrays.asList('K');
private final List<Character> eightPoints = Arrays.asList('J', 'X');
private final List<Character> tenPoints = Arrays.asList('Q', 'Z');
public Scrabble(String word) {
this.word = word.toUpperCase();
// TODO: Is there a better way?
// Initialize pointsMap for the letters and the corresponding points
onePoints.forEach( letter -> pointsMap.put(letter, 1));
twoPoints.forEach( letter -> pointsMap.put(letter, 2));
threePoints.forEach( letter -> pointsMap.put(letter, 3));
fourPoints.forEach( letter -> pointsMap.put(letter, 4));
fivePoints.forEach( letter -> pointsMap.put(letter, 5));
eightPoints.forEach( letter -> pointsMap.put(letter, 8));
tenPoints.forEach( letter -> pointsMap.put(letter, 10));
// Regex expressions
this.regexLetters = "[a-zA-Z]+";
}
/**
* Outputs string after regex is applied to it.
* Most of the code is from Oracle's Java tutorial at: https://docs.oracle.com/javase/tutorial/essential/regex/test_harness.html
* It prints out information about the findings from the regex expression.
* @param word
* @param regexPattern
* @return
*/
public String extractStringWithRegex(String word, String regexPattern) {
// Reference: https://docs.oracle.com/javase/tutorial/essential/regex/test_harness.html
String output = "";
Pattern pattern = Pattern.compile(regexPattern);
Matcher matcher = pattern.matcher(word);
boolean found = false;
while (matcher.find()) {
System.out.printf("I found the text" +
" \"%s\" starting at " +
"index %d and ending at index %d.%n",
matcher.group(),
matcher.start(),
matcher.end());
found = true;
output += matcher.group();
}
if(!found){
System.out.printf("No match found.%n");
}
System.out.println("text: " + output);
return output;
}
public boolean extractStringWithRegexBoolean(String word, String regexPattern) {
// Reference: https://docs.oracle.com/javase/tutorial/essential/regex/test_harness.html
Pattern pattern = Pattern.compile(regexPattern);
Matcher matcher = pattern.matcher(word);
return matcher.find();
}
/**
* Calculate points for the given string of letters, the string should be provided with the surrounding brackets.
* After calculation, the function updates the score
* @param strLettersWithBrackets E.g. {[dog]}, [d]o{g} etc.
*/
public void calculatePoints(String strLettersWithBrackets, int pointMultiplier) {
// Extract only letters, escape brackets
strLettersWithBrackets = extractStringWithRegex(strLettersWithBrackets, this.regexLetters);
// Calculate double points
for (char letter : strLettersWithBrackets.toCharArray()) {
this.score += pointsMap.get(letter) * pointMultiplier;
}
}
public int score() {
// Regex patterns TODO: Should put this in the constructor as well
// Regex tips https://regexr.com/
String regexDouble = "\\{.*?\\}";
String regexTriple = "\\[.*?\\]";
// Can include letters, special characters, brackets
String regexWordsWithSpecialCharacters = "[^a-zA-Z]+";
// Check for single occurrence of single bracket
String regexLeftSquareBracket = "\\[{1}";
String regexRightSquareBracket = "\\]{1}";
String regexLeftCurlyBracket = "\\{{1}";
String regexRightCurlyBracket = "\\}{1}";
// A sequence of the same letter e.g. "ll" in he{ll}o
String regexDuplicationOfLetters = "(\\w)\\1+";
boolean isDouble = extractStringWithRegexBoolean(this.word, regexDouble);
boolean isTriple = extractStringWithRegexBoolean(this.word, regexTriple);
boolean isOnlyLetters = !extractStringWithRegexBoolean(this.word, regexWordsWithSpecialCharacters); // Is only letters if it is NOT a word with mixed letters, special characters and brackets
if (isDouble || isTriple || isOnlyLetters) {
if (isDouble) {
// Extract double letters, brackets included
String doubleLetters = extractStringWithRegex(this.word, regexDouble);
// Check for invalid duplication of letters inside brackets, e.g. he{ll}o
boolean invalidDuplication = extractStringWithRegexBoolean(doubleLetters, regexDuplicationOfLetters);
if (invalidDuplication) {
return 0;
}
// Check for invalid single square brackets: if one but not both appear, with XOR (exclusive or)
boolean leftBracket = extractStringWithRegexBoolean(doubleLetters, regexLeftSquareBracket);
boolean rightBracket = extractStringWithRegexBoolean(doubleLetters, regexRightSquareBracket);
if (leftBracket ^ rightBracket) {
return 0;
}
// Check if this double point sequence contains a sequence of nested triple points,
// if that is the case:
// - calculate triple points first
boolean containsTriple = extractStringWithRegexBoolean(doubleLetters, regexTriple);
if (containsTriple) {
// Calculate nested triple separately (the letters are first tripled (*3) and then doubled (*2)
String nestedTriple = extractStringWithRegex(doubleLetters, regexTriple);
calculatePoints(nestedTriple, 3*2);
// Remove it from doubleLetters to avoid duplication of points
doubleLetters = doubleLetters.replace(nestedTriple, "");
}
// Calculate double points
calculatePoints(doubleLetters, 2);
// Remove this pair of curly brackets (Double points) and its content to avoid duplicated points {...} when moving on to checking triple points in next section
String originalDoubleLetters = extractStringWithRegex(this.word, regexDouble);
this.word = this.word.replace(originalDoubleLetters, "");
}
if (isTriple) {
// Extract triple letters, brackets included
String tripleLetters = extractStringWithRegex(this.word, regexTriple);
// Check for invalid duplication of letters inside brackets, e.g. he{ll}o
boolean invalidDuplication = extractStringWithRegexBoolean(tripleLetters, regexDuplicationOfLetters);
if (invalidDuplication) {
return 0;
}
// TODO: Refactor duplicate code
// Check for invalid single curly brackets: if one but not both appear, with XOR (exclusive or)
boolean leftBracket = extractStringWithRegexBoolean(tripleLetters, regexLeftCurlyBracket);
boolean rightBracket = extractStringWithRegexBoolean(tripleLetters, regexRightCurlyBracket);
if (leftBracket ^ rightBracket) {
return 0;
}
// Calculate triple points
calculatePoints(tripleLetters, 3);
}
// Calculate ordinary/base points
String baseLetters = this.word.replaceAll(regexDouble, ""); // Remove double points
baseLetters = baseLetters.replaceAll(regexTriple, ""); // Remove triple points
for (char letter : baseLetters.toCharArray()) {
this.score += pointsMap.get(letter);
}
return this.score;
}
return 0;
}
}