mirror of
https://github.com/Febbweiss/scrabble-resolver.git
synced 2026-03-04 14:15:37 +00:00
Optim: compressed resolver
This commit is contained in:
11
pom.xml
11
pom.xml
@@ -11,6 +11,17 @@
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.9.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.9.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Unit testing -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
||||
@@ -3,14 +3,9 @@ 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 {
|
||||
@@ -58,7 +53,7 @@ public class DictionaryBuilder {
|
||||
public static Enigma generateEnigma(String language, int minLength, int maxLength) {
|
||||
Resolver resolver;
|
||||
try {
|
||||
resolver = loadResolver(language);
|
||||
resolver = ScrabbleUtils.loadResolver(language);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
@@ -66,51 +61,19 @@ public class DictionaryBuilder {
|
||||
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;
|
||||
public static void main(String[] args) throws Exception {
|
||||
for( String language : new String[] {"english", "french"} ) {
|
||||
long avg = 0;
|
||||
for( int i = 0; i < 100; i++) {
|
||||
resolvers.clear();
|
||||
long t1 = System.currentTimeMillis();
|
||||
ScrabbleUtils.loadResolver(language);
|
||||
long t2 = System.currentTimeMillis() - t1;
|
||||
avg += t2;
|
||||
}
|
||||
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.");
|
||||
System.out.println(language + " : " + (avg/100));
|
||||
}
|
||||
return resolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
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;
|
||||
@@ -70,16 +68,15 @@ public class Main {
|
||||
try {
|
||||
Resolver resolver = DictionaryBuilder.generateResolver(new Resolver(), file, min, max);
|
||||
resolver.computeStatistics();
|
||||
resolver.displayStatistics();
|
||||
|
||||
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("src/main/resources/resolvers/" + language)));
|
||||
oos.writeObject(resolver);
|
||||
oos.flush();
|
||||
oos.close();
|
||||
ScrabbleUtils.writeResolver(resolver, language);
|
||||
} 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"));
|
||||
|
||||
@@ -1,73 +1,14 @@
|
||||
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 interface Node extends Serializable {
|
||||
|
||||
public void addWord(String word);
|
||||
public List<String> getWords();
|
||||
public Node getNode(char character);
|
||||
public Object getNodes();
|
||||
public int getWordsCount();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,20 +8,20 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import fr.pavnay.scrabble.impl.HashNodeImpl;
|
||||
|
||||
public class Resolver implements Serializable {
|
||||
private static final long serialVersionUID = 8267126995323709570L;
|
||||
private Node[] nodes = new Node[26];
|
||||
|
||||
private static final long serialVersionUID = 3424195161013074975L;
|
||||
|
||||
public Node nodes = new HashNodeImpl();
|
||||
private float[] statistics = new float[26];
|
||||
private float totalCharacter = 0.0F;
|
||||
|
||||
public Node getNode(char character) {
|
||||
Node node = this.nodes[(character - 'a')];
|
||||
Node node = nodes.getNode(character);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ public class Resolver implements Serializable {
|
||||
|
||||
int setSize = letters.length;
|
||||
if (size == setSize) {
|
||||
Node currentNode = this.nodes[(sortLetters[0] - 'a')];
|
||||
Node currentNode = nodes.getNode(sortLetters[0]);
|
||||
if (currentNode == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -175,7 +175,8 @@ public class Resolver implements Serializable {
|
||||
public int countWords() {
|
||||
int total = 0;
|
||||
for (int i = 0; i < 26; i++) {
|
||||
Node current = this.nodes[i];
|
||||
// Node current = this.nodes[i];
|
||||
Node current = nodes.getNode((char)(i + 'a'));
|
||||
if (current != null) {
|
||||
total += current.getWordsCount();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
package fr.pavnay.scrabble;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleAbstractTypeResolver;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
||||
import fr.pavnay.scrabble.impl.HashNodeImpl;
|
||||
import fr.pavnay.scrabble.serializer.NodeSerializer;
|
||||
|
||||
public class ScrabbleUtils {
|
||||
|
||||
@@ -14,4 +29,82 @@ public class ScrabbleUtils {
|
||||
return Arrays.asList(files);
|
||||
}
|
||||
|
||||
public static Resolver loadResolver(String language) {
|
||||
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;
|
||||
}
|
||||
|
||||
Resolver resolver = null;
|
||||
|
||||
try {
|
||||
ObjectMapper mapper = getObjectMapper();
|
||||
resolver = mapper.readerFor(Resolver.class).readValue(loadFile(file) );
|
||||
} catch(IOException ioe) {
|
||||
|
||||
}
|
||||
System.out.println("Resolver in " + language + " loaded in " + (System.currentTimeMillis() - t1) + "ms.");
|
||||
return resolver;
|
||||
}
|
||||
|
||||
public static boolean writeResolver(Resolver resolver, String language) {
|
||||
ObjectMapper mapper = getObjectMapper();
|
||||
|
||||
try {
|
||||
String serialized = mapper.writeValueAsString(resolver);
|
||||
writeFile(serialized.getBytes(), language);
|
||||
}catch(IOException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void writeFile(byte[] content, String language) throws IOException {
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
|
||||
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
|
||||
gzipOutputStream.write(content);
|
||||
gzipOutputStream.close();
|
||||
|
||||
FileOutputStream out = new FileOutputStream( "src/main/resources/resolvers/" + language );
|
||||
out.write(byteArrayOutputStream.toByteArray());
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
private static InputStream loadFile(File file) throws IOException {
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int count = 0;
|
||||
while ((count = fis.read(buffer))!=-1){
|
||||
out.write(buffer, 0, count);
|
||||
}
|
||||
byte[] b = out.toByteArray();
|
||||
fis.close();
|
||||
|
||||
return new GZIPInputStream(new ByteArrayInputStream(b));
|
||||
}
|
||||
|
||||
private static ObjectMapper getObjectMapper() {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
SimpleModule module = new SimpleModule();
|
||||
|
||||
SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver();
|
||||
resolver.addMapping(Node.class, HashNodeImpl.class);
|
||||
|
||||
module.setAbstractTypes(resolver);
|
||||
module.addSerializer(Node.class, new NodeSerializer());
|
||||
mapper.registerModule(module);
|
||||
|
||||
return mapper;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
81
src/main/java/fr/pavnay/scrabble/impl/HashNodeImpl.java
Normal file
81
src/main/java/fr/pavnay/scrabble/impl/HashNodeImpl.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package fr.pavnay.scrabble.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.pavnay.scrabble.Node;
|
||||
|
||||
public class HashNodeImpl implements Node {
|
||||
|
||||
private static final long serialVersionUID = 4221818951064573126L;
|
||||
|
||||
private Map<Character,Node> nodes = new HashMap<Character, Node>();
|
||||
private List<String> words;
|
||||
private String parent;
|
||||
|
||||
public HashNodeImpl() {
|
||||
}
|
||||
|
||||
public HashNodeImpl(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 Map<Character, Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public Node getNode(char character) {
|
||||
Node node = this.nodes.get(character);
|
||||
if (node == null) {
|
||||
node = new HashNodeImpl(this.parent + character);
|
||||
nodes.put(character, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public int getWordsCount() {
|
||||
int total = 0;
|
||||
|
||||
for(Map.Entry<Character, Node> node : nodes.entrySet()) {
|
||||
total += node.getValue().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(Map.Entry<Character, Node> node : nodes.entrySet()) {
|
||||
sb.append(node.getValue());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
81
src/main/java/fr/pavnay/scrabble/impl/NodeImpl.java
Normal file
81
src/main/java/fr/pavnay/scrabble/impl/NodeImpl.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package fr.pavnay.scrabble.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import fr.pavnay.scrabble.Node;
|
||||
|
||||
public class NodeImpl implements Node {
|
||||
private static final long serialVersionUID = 6637351994367583747L;
|
||||
|
||||
public Node[] nodes = new Node[26];
|
||||
public List<String> words;
|
||||
private String parent;
|
||||
|
||||
public NodeImpl() {}
|
||||
|
||||
public NodeImpl(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[] getNodes() {
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
public Node getNode(char character) {
|
||||
Node node = this.nodes[(character - 'a')];
|
||||
if (node == null) {
|
||||
node = new NodeImpl(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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package fr.pavnay.scrabble.serializer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
|
||||
import fr.pavnay.scrabble.Node;
|
||||
|
||||
public class NodeSerializer extends StdSerializer<Node> {
|
||||
private static final long serialVersionUID = -5136242177329213286L;
|
||||
|
||||
public NodeSerializer() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public NodeSerializer(Class<Node> t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Node node, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
||||
generator.writeStartObject();
|
||||
generator.writeObjectField("nodes", node.getNodes());
|
||||
generator.writeObjectField("words", node.getWords());
|
||||
generator.writeEndObject();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user