mirror of
https://github.com/Febbweiss/scrabble-resolver.git
synced 2026-03-04 22:25:36 +00:00
Initial commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
22
pom.xml
Normal file
22
pom.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>fr.pavnay</groupId>
|
||||||
|
<artifactId>scrabble-resolver</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<dependencies>
|
||||||
|
<!-- Tools -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-cli</groupId>
|
||||||
|
<artifactId>commons-cli</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Unit testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
116
src/main/java/fr/pavnay/scrabble/DictionaryBuilder.java
Normal file
116
src/main/java/fr/pavnay/scrabble/DictionaryBuilder.java
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package fr.pavnay.scrabble;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DictionaryBuilder {
|
||||||
|
private static Map<String, Resolver> resolvers = new HashMap<String, Resolver>();
|
||||||
|
|
||||||
|
public static Resolver generateResolver(Resolver resolver, File dictionary, int minimalSize, int maximalSize)
|
||||||
|
throws IOException {
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(dictionary), "UTF-8"));
|
||||||
|
String line = null;
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
int valid = 0;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
int size = line.length();
|
||||||
|
total++;
|
||||||
|
if ((size >= minimalSize) && (size <= maximalSize) && (!line.contains("-")) && (!line.contains("."))
|
||||||
|
&& (!line.contains("'"))) {
|
||||||
|
String cleaned = StringUtils.toLowerCaseASCII(line);
|
||||||
|
if (cleaned != null) {
|
||||||
|
valid++;
|
||||||
|
|
||||||
|
char[] sortedLetters = StringUtils.sortLetters(cleaned);
|
||||||
|
|
||||||
|
char currentLetter = sortedLetters[0];
|
||||||
|
|
||||||
|
Node currentNode = resolver.getNode(currentLetter);
|
||||||
|
for (int i = 1; i < size; i++) {
|
||||||
|
currentLetter = sortedLetters[i];
|
||||||
|
resolver.updateStatistics(currentLetter);
|
||||||
|
if (i == size - 1) {
|
||||||
|
currentNode.getNode(currentLetter).addWord(cleaned);
|
||||||
|
} else {
|
||||||
|
currentNode = currentNode.getNode(currentLetter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
|
||||||
|
System.out.println("Total words in file : " + total + " - Valid words : " + valid);
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Enigma generateEnigma(String language, int minLength, int maxLength) {
|
||||||
|
Resolver resolver;
|
||||||
|
try {
|
||||||
|
resolver = loadResolver(language);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return resolver.generateEnigma(minLength, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateResolver(String language) throws IOException {
|
||||||
|
File file = new File(
|
||||||
|
"C:/Users/viaduc105.smallbusiness/Documents/workspace-sts/SocialArena/resources/" + language);
|
||||||
|
if (!file.exists()) {
|
||||||
|
System.out.println("No dictionary for " + language);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Resolver resolver = generateResolver(new Resolver(), file, 3, 7);
|
||||||
|
resolver.computeStatistics();
|
||||||
|
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
|
||||||
|
new File("C:/Users/viaduc105.smallbusiness/Documents/workspace-sts/SocialArena/resources/resolver/"
|
||||||
|
+ language)));
|
||||||
|
oos.writeObject(resolver);
|
||||||
|
oos.flush();
|
||||||
|
oos.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadResolvers() throws IOException, ClassNotFoundException {
|
||||||
|
List<String> languages = ScrabbleUtils.loadLanguages();
|
||||||
|
for (String language : languages) {
|
||||||
|
long t1 = System.currentTimeMillis();
|
||||||
|
loadResolver(language);
|
||||||
|
System.out.println("Resolver in " + language + " loaded in " + (System.currentTimeMillis() - t1) + "ms.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Resolver loadResolver(String language)
|
||||||
|
throws FileNotFoundException, IOException, ClassNotFoundException {
|
||||||
|
Resolver resolver = (Resolver) resolvers.get(language);
|
||||||
|
if (resolver == null) {
|
||||||
|
long t1 = System.currentTimeMillis();
|
||||||
|
String path = DictionaryBuilder.class.getResource("/resolvers/" + language).getPath();
|
||||||
|
File file = new File(path);
|
||||||
|
if (!file.exists()) {
|
||||||
|
System.out.println("No resolver for " + language);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
|
||||||
|
resolver = (Resolver) ois.readObject();
|
||||||
|
ois.close();
|
||||||
|
|
||||||
|
resolvers.put(language, resolver);
|
||||||
|
System.out.println("Resolver in " + language + " loaded in " + (System.currentTimeMillis() - t1) + "ms.");
|
||||||
|
}
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/main/java/fr/pavnay/scrabble/Enigma.java
Normal file
61
src/main/java/fr/pavnay/scrabble/Enigma.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package fr.pavnay.scrabble;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Enigma implements Serializable {
|
||||||
|
private static final long serialVersionUID = 7542854436817730656L;
|
||||||
|
private int min;
|
||||||
|
private int max;
|
||||||
|
private char[] letters;
|
||||||
|
private Map<Integer, List<String>> words;
|
||||||
|
|
||||||
|
public Enigma(char[] letters, Map<Integer, List<String>> words, int min, int max) {
|
||||||
|
this.letters = letters;
|
||||||
|
this.words = words;
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getLetters() {
|
||||||
|
List<String> lLetters = new ArrayList<String>();
|
||||||
|
if (this.letters == null) {
|
||||||
|
return lLetters;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < this.letters.length; i++) {
|
||||||
|
lLetters.add(Character.toString(this.letters[i]));
|
||||||
|
}
|
||||||
|
return lLetters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, List<String>> getWords() {
|
||||||
|
return this.words;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid(String word) {
|
||||||
|
if (StringUtils.isBlank(word)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<String> lWords = this.words.get(Integer.valueOf(word.length()));
|
||||||
|
return lWords.contains(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder("Letters : ");
|
||||||
|
if (this.letters != null) {
|
||||||
|
sb.append(new String(this.letters));
|
||||||
|
} else {
|
||||||
|
sb.append("-");
|
||||||
|
}
|
||||||
|
sb.append("\nWords between ").append(this.min).append(" and ").append(this.max).append(" letters : \n");
|
||||||
|
for (int i = this.max; i > this.min - 1; i--) {
|
||||||
|
List<String> lWords = this.words.get(Integer.valueOf(i));
|
||||||
|
if (lWords != null) {
|
||||||
|
sb.append("\twith ").append(i).append(" letters (" + lWords.size() + "): ").append(lWords).append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
167
src/main/java/fr/pavnay/scrabble/Main.java
Normal file
167
src/main/java/fr/pavnay/scrabble/Main.java
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
package fr.pavnay.scrabble;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.cli.CommandLine;
|
||||||
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
|
import org.apache.commons.cli.DefaultParser;
|
||||||
|
import org.apache.commons.cli.HelpFormatter;
|
||||||
|
import org.apache.commons.cli.Option;
|
||||||
|
import org.apache.commons.cli.Options;
|
||||||
|
import org.apache.commons.cli.ParseException;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
private final static List<String> availableLanguages = ScrabbleUtils.loadLanguages();
|
||||||
|
private final static Options helpOptions = configHelpParameter();
|
||||||
|
private final static Options options = configParameters();
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
final CommandLineParser parser = new DefaultParser();
|
||||||
|
CommandLine firstLine = null;
|
||||||
|
try {
|
||||||
|
firstLine = parser.parse(helpOptions, args, true);
|
||||||
|
} catch (ParseException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean helpMode = firstLine.hasOption("help");
|
||||||
|
if (helpMode) {
|
||||||
|
final HelpFormatter formatter = new HelpFormatter();
|
||||||
|
formatter.printHelp("Main", options, true);
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
CommandLine line = parser.parse(options, args);
|
||||||
|
if( line.hasOption( "build" ) ) {
|
||||||
|
generate(line);
|
||||||
|
} else {
|
||||||
|
getEnigma(line);
|
||||||
|
}
|
||||||
|
} catch (ParseException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void generate(CommandLine line) {
|
||||||
|
final String source = line.getOptionValue("build", "");
|
||||||
|
final String language = line.getOptionValue("lang", "");
|
||||||
|
final int min = Integer.parseInt(line.getOptionValue("min", "3"));
|
||||||
|
final int max = Integer.parseInt(line.getOptionValue("max", "7"));
|
||||||
|
|
||||||
|
System.out.println(String.format("Generating %s resolver from %s.\nWords size: [%d, %d]", language, source, min, max ));
|
||||||
|
|
||||||
|
File file = new File(source);
|
||||||
|
if (!file.exists())
|
||||||
|
{
|
||||||
|
System.err.println("Source file not found " + source);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Resolver resolver = DictionaryBuilder.generateResolver(new Resolver(), file, min, max);
|
||||||
|
resolver.computeStatistics();
|
||||||
|
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("src/main/resources/resolvers/" + language)));
|
||||||
|
oos.writeObject(resolver);
|
||||||
|
oos.flush();
|
||||||
|
oos.close();
|
||||||
|
} catch( IOException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void getEnigma(CommandLine line) {
|
||||||
|
final String language = line.getOptionValue("lang", "");
|
||||||
|
final int min = Integer.parseInt(line.getOptionValue("min", "3"));
|
||||||
|
final int max = Integer.parseInt(line.getOptionValue("max", "7"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
manageLanguage(language);
|
||||||
|
Enigma enigma = DictionaryBuilder.generateEnigma(language, min, max);
|
||||||
|
System.out.println(enigma);
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Options configHelpParameter() {
|
||||||
|
final Option helpFileOption = Option.builder("h")
|
||||||
|
.longOpt("help")
|
||||||
|
.desc("Display help message").build();
|
||||||
|
|
||||||
|
final Options firstOptions = new Options();
|
||||||
|
|
||||||
|
firstOptions.addOption(helpFileOption);
|
||||||
|
|
||||||
|
return firstOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Options configParameters() {
|
||||||
|
|
||||||
|
final Option buildOption = Option.builder("b")
|
||||||
|
.longOpt("build") //
|
||||||
|
.desc("Build a new dictionary from the source file (a Linux words file)")
|
||||||
|
.hasArg(true)
|
||||||
|
.argName("source")
|
||||||
|
.required(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final Option languageOption = Option.builder("l")
|
||||||
|
.longOpt("lang")
|
||||||
|
.desc("Language (in " + availableLanguages + ")")
|
||||||
|
.hasArg(true)
|
||||||
|
.argName("language")
|
||||||
|
.required(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final Option helpFileOption = Option.builder("h")
|
||||||
|
.longOpt("help")
|
||||||
|
.desc("Display help message").build();
|
||||||
|
|
||||||
|
final Option minOption = Option.builder("min")
|
||||||
|
.longOpt("min")
|
||||||
|
.desc("Minimum word length (default : 3)")
|
||||||
|
.hasArg(true)
|
||||||
|
.argName("min")
|
||||||
|
.required(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final Option maxOption = Option.builder("max")
|
||||||
|
.longOpt("max")
|
||||||
|
.desc("Maximum word length (default : 7)")
|
||||||
|
.hasArg(true)
|
||||||
|
.argName("max")
|
||||||
|
.required(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final Options options = new Options();
|
||||||
|
|
||||||
|
options.addOption(buildOption);
|
||||||
|
options.addOption(helpFileOption);
|
||||||
|
options.addOption(languageOption);
|
||||||
|
options.addOption(minOption);
|
||||||
|
options.addOption(maxOption);
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void manageLanguage(String language) {
|
||||||
|
if( StringUtils.isBlank(language) ) {
|
||||||
|
throw new IllegalArgumentException("No language provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !availableLanguages.contains(language.toLowerCase()) ) {
|
||||||
|
throw new IllegalArgumentException(String.format("Unknown %s language. Available languages : %s", language, availableLanguages.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/main/java/fr/pavnay/scrabble/Node.java
Normal file
73
src/main/java/fr/pavnay/scrabble/Node.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package fr.pavnay.scrabble;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Node implements Serializable {
|
||||||
|
private static final long serialVersionUID = 3539215265338287172L;
|
||||||
|
private Node[] nodes = new Node[26];
|
||||||
|
private List<String> words;
|
||||||
|
private String parent;
|
||||||
|
|
||||||
|
public Node(String parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addWord(String word) {
|
||||||
|
if (this.words == null) {
|
||||||
|
this.words = new ArrayList<String>();
|
||||||
|
}
|
||||||
|
if (!this.words.contains(word)) {
|
||||||
|
this.words.add(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getWords() {
|
||||||
|
if (this.words == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collections.sort(this.words);
|
||||||
|
return this.words;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNode(char character) {
|
||||||
|
Node node = this.nodes[(character - 'a')];
|
||||||
|
if (node == null) {
|
||||||
|
node = new Node(this.parent + character);
|
||||||
|
this.nodes[(character - 'a')] = node;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWordsCount() {
|
||||||
|
int total = 0;
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
Node current = this.nodes[i];
|
||||||
|
if (current != null) {
|
||||||
|
total += current.getWordsCount();
|
||||||
|
}
|
||||||
|
if (this.words != null) {
|
||||||
|
total += this.words.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder("Parent " + this.parent);
|
||||||
|
if (this.words != null) {
|
||||||
|
sb.append(this.words.toString());
|
||||||
|
} else {
|
||||||
|
sb.append('-');
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
Node current = this.nodes[i];
|
||||||
|
if (current != null) {
|
||||||
|
sb.append(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
185
src/main/java/fr/pavnay/scrabble/Resolver.java
Normal file
185
src/main/java/fr/pavnay/scrabble/Resolver.java
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
package fr.pavnay.scrabble;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class Resolver implements Serializable {
|
||||||
|
private static final long serialVersionUID = 8267126995323709570L;
|
||||||
|
private Node[] nodes = new Node[26];
|
||||||
|
private float[] statistics = new float[26];
|
||||||
|
private float totalCharacter = 0.0F;
|
||||||
|
|
||||||
|
public Node getNode(char character) {
|
||||||
|
Node node = this.nodes[(character - 'a')];
|
||||||
|
this.statistics[(character - 'a')] += 1.0F;
|
||||||
|
this.totalCharacter += 1.0F;
|
||||||
|
if (node == null) {
|
||||||
|
node = new Node(Character.toString(character));
|
||||||
|
this.nodes[(character - 'a')] = node;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateStatistics(char character) {
|
||||||
|
this.statistics[(character - 'a')] += 1.0F;
|
||||||
|
this.totalCharacter += 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeStatistics() {
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
this.statistics[i] = (this.statistics[i] * 100.0F / this.totalCharacter);
|
||||||
|
System.out.println((char) (i + 97) + "=" + this.statistics[i] + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayStatistics() {
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
System.out.println((char) (i + 97) + "=" + this.statistics[i] + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getStatistics() {
|
||||||
|
return this.statistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Enigma generateEnigma(int minimalLettersCount, int maximalLettersCount) {
|
||||||
|
boolean mustRun = false;
|
||||||
|
char[] letters;
|
||||||
|
Map<Integer, List<String>> allWords;
|
||||||
|
do {
|
||||||
|
letters = getRandomSet(maximalLettersCount);
|
||||||
|
allWords = getWords(letters, minimalLettersCount);
|
||||||
|
|
||||||
|
int wordsCount = 0;
|
||||||
|
for (int i = minimalLettersCount; i < maximalLettersCount + 1; i++) {
|
||||||
|
List<String> words = allWords.get(Integer.valueOf(i));
|
||||||
|
if (words != null) {
|
||||||
|
wordsCount += words.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mustRun = wordsCount < (maximalLettersCount + minimalLettersCount) * 0.7D;
|
||||||
|
} while (mustRun);
|
||||||
|
return new Enigma(letters, allWords, minimalLettersCount, maximalLettersCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char[] getRandomSet(int maxLetter) {
|
||||||
|
float[] statistics = getStatistics();
|
||||||
|
float max = 0.0F;
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
max += statistics[i];
|
||||||
|
}
|
||||||
|
Random randomizer = new Random();
|
||||||
|
char[] letters = new char[maxLetter];
|
||||||
|
for (int i = 0; i < maxLetter; i++) {
|
||||||
|
letters[i] = getRandomLetter(randomizer, max, statistics);
|
||||||
|
}
|
||||||
|
return letters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char getRandomLetter(Random randomizer, float max, float[] statistics) {
|
||||||
|
float r = randomizer.nextFloat() * (int) max;
|
||||||
|
max = 0.0F;
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
max += statistics[i];
|
||||||
|
if (r < max) {
|
||||||
|
return (char) (i + 97);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'z';
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Integer, List<String>> getWords(char[] letters, int minimum) {
|
||||||
|
List<String> words = new ArrayList<String>();
|
||||||
|
for (int i = letters.length; i > 2; i--) {
|
||||||
|
List<String> newWords = getWords(letters, minimum, i);
|
||||||
|
if (newWords != null) {
|
||||||
|
for (String word : newWords) {
|
||||||
|
if (!words.contains(word)) {
|
||||||
|
words.add(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<Integer, List<String>> lists = new HashMap<Integer, List<String>>();
|
||||||
|
for (String word : words) {
|
||||||
|
List<String> list = lists.get(Integer.valueOf(word.length()));
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<String>();
|
||||||
|
lists.put(Integer.valueOf(word.length()), list);
|
||||||
|
}
|
||||||
|
list.add(word);
|
||||||
|
}
|
||||||
|
for (int i = letters.length; i > 2; i--) {
|
||||||
|
List<String> list = lists.get(Integer.valueOf(i));
|
||||||
|
if (list != null) {
|
||||||
|
Collections.sort(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getWords(char[] letters, int minimum, int size) {
|
||||||
|
if (size < minimum) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String set = new String(letters);
|
||||||
|
char[] sortLetters = StringUtils.sortLetters(set);
|
||||||
|
|
||||||
|
int setSize = letters.length;
|
||||||
|
if (size == setSize) {
|
||||||
|
Node currentNode = this.nodes[(sortLetters[0] - 'a')];
|
||||||
|
if (currentNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int i = 1; i < setSize; i++) {
|
||||||
|
currentNode = currentNode.getNode(sortLetters[i]);
|
||||||
|
if (currentNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (i == setSize - 1) {
|
||||||
|
return currentNode.getWords();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String nString = new String(sortLetters);
|
||||||
|
List<String> results = null;
|
||||||
|
for (int i = 0; i < setSize - size; i++) {
|
||||||
|
for (int j = 0; j < setSize; j++) {
|
||||||
|
List<String> words = getWords(
|
||||||
|
(nString.substring(0, j) + nString.subSequence(j + 1, setSize)).toCharArray(), minimum,
|
||||||
|
size - i);
|
||||||
|
if (words != null) {
|
||||||
|
if (results == null) {
|
||||||
|
results = new ArrayList<String>();
|
||||||
|
}
|
||||||
|
for (String word : words) {
|
||||||
|
if (!results.contains(word)) {
|
||||||
|
results.add(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (results != null) {
|
||||||
|
Collections.sort(results);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countWords() {
|
||||||
|
int total = 0;
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
Node current = this.nodes[i];
|
||||||
|
if (current != null) {
|
||||||
|
total += current.getWordsCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/fr/pavnay/scrabble/ScrabbleUtils.java
Normal file
17
src/main/java/fr/pavnay/scrabble/ScrabbleUtils.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package fr.pavnay.scrabble;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ScrabbleUtils {
|
||||||
|
|
||||||
|
public static List<String> loadLanguages() {
|
||||||
|
URL url = Main.class.getClassLoader().getResource("resolvers");
|
||||||
|
File resolver = new File(url.getPath());
|
||||||
|
String[] files = resolver.list();
|
||||||
|
return Arrays.asList(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
37
src/main/java/fr/pavnay/scrabble/StringUtils.java
Normal file
37
src/main/java/fr/pavnay/scrabble/StringUtils.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package fr.pavnay.scrabble;
|
||||||
|
|
||||||
|
import java.text.Normalizer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public final class StringUtils {
|
||||||
|
|
||||||
|
public static String toLowerCaseASCII(String s) {
|
||||||
|
if (isBlank(s)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return stripAccents(s).trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBlank(String s) {
|
||||||
|
return (s == null) || (s.trim().length() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static char[] sortLetters(String s) {
|
||||||
|
if (s == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (isBlank(s)) {
|
||||||
|
return s.toCharArray();
|
||||||
|
}
|
||||||
|
char[] sortedLetters = s.toCharArray();
|
||||||
|
Arrays.sort(sortedLetters);
|
||||||
|
|
||||||
|
return sortedLetters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String stripAccents(String s) {
|
||||||
|
s = Normalizer.normalize(s, Normalizer.Form.NFD);
|
||||||
|
s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}]", "").replaceAll("[^\\p{ASCII}]", "");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/main/resources/resolvers/english
Normal file
BIN
src/main/resources/resolvers/english
Normal file
Binary file not shown.
BIN
src/main/resources/resolvers/french
Normal file
BIN
src/main/resources/resolvers/french
Normal file
Binary file not shown.
5
target/classes/META-INF/MANIFEST.MF
Normal file
5
target/classes/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Built-By: FECAILLE
|
||||||
|
Build-Jdk: 1.8.0_77
|
||||||
|
Created-By: Maven Integration for Eclipse
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#Generated by Maven Integration for Eclipse
|
||||||
|
#Fri Sep 22 09:55:44 CEST 2017
|
||||||
|
version=0.0.1-SNAPSHOT
|
||||||
|
groupId=fr.pavnay
|
||||||
|
m2e.projectName=scrabble-resolver
|
||||||
|
m2e.projectLocation=D\:\\Workspace_JADE\\scrabble-resolver
|
||||||
|
artifactId=scrabble-resolver
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>fr.pavnay</groupId>
|
||||||
|
<artifactId>scrabble-resolver</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<dependencies>
|
||||||
|
<!-- Tools -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-cli</groupId>
|
||||||
|
<artifactId>commons-cli</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Unit testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
BIN
target/classes/fr/pavnay/scrabble/DictionaryBuilder.class
Normal file
BIN
target/classes/fr/pavnay/scrabble/DictionaryBuilder.class
Normal file
Binary file not shown.
BIN
target/classes/fr/pavnay/scrabble/Enigma.class
Normal file
BIN
target/classes/fr/pavnay/scrabble/Enigma.class
Normal file
Binary file not shown.
BIN
target/classes/fr/pavnay/scrabble/Main.class
Normal file
BIN
target/classes/fr/pavnay/scrabble/Main.class
Normal file
Binary file not shown.
BIN
target/classes/fr/pavnay/scrabble/Node.class
Normal file
BIN
target/classes/fr/pavnay/scrabble/Node.class
Normal file
Binary file not shown.
BIN
target/classes/fr/pavnay/scrabble/Resolver.class
Normal file
BIN
target/classes/fr/pavnay/scrabble/Resolver.class
Normal file
Binary file not shown.
BIN
target/classes/fr/pavnay/scrabble/ScrabbleUtils.class
Normal file
BIN
target/classes/fr/pavnay/scrabble/ScrabbleUtils.class
Normal file
Binary file not shown.
BIN
target/classes/fr/pavnay/scrabble/StringUtils.class
Normal file
BIN
target/classes/fr/pavnay/scrabble/StringUtils.class
Normal file
Binary file not shown.
BIN
target/classes/resolvers/english
Normal file
BIN
target/classes/resolvers/english
Normal file
Binary file not shown.
BIN
target/classes/resolvers/french
Normal file
BIN
target/classes/resolvers/french
Normal file
Binary file not shown.
Reference in New Issue
Block a user