diff --git a/pom.xml b/pom.xml index 04d1878..f76ad3e 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,17 @@ commons-cli 1.4 + + com.fasterxml.jackson.core + jackson-core + 2.9.1 + + + com.fasterxml.jackson.core + jackson-databind + 2.9.1 + + junit diff --git a/src/main/java/fr/pavnay/scrabble/DictionaryBuilder.java b/src/main/java/fr/pavnay/scrabble/DictionaryBuilder.java index bae9e54..083811d 100644 --- a/src/main/java/fr/pavnay/scrabble/DictionaryBuilder.java +++ b/src/main/java/fr/pavnay/scrabble/DictionaryBuilder.java @@ -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 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; } + } diff --git a/src/main/java/fr/pavnay/scrabble/Main.java b/src/main/java/fr/pavnay/scrabble/Main.java index 7d95bbb..2a43cf5 100644 --- a/src/main/java/fr/pavnay/scrabble/Main.java +++ b/src/main/java/fr/pavnay/scrabble/Main.java @@ -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")); diff --git a/src/main/java/fr/pavnay/scrabble/Node.java b/src/main/java/fr/pavnay/scrabble/Node.java index eab84a2..4d66c04 100644 --- a/src/main/java/fr/pavnay/scrabble/Node.java +++ b/src/main/java/fr/pavnay/scrabble/Node.java @@ -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 words; - private String parent; +public interface Node extends Serializable { + + public void addWord(String word); + public List 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(); - } - if (!this.words.contains(word)) { - this.words.add(word); - } - } - - public List 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(); - } } diff --git a/src/main/java/fr/pavnay/scrabble/Resolver.java b/src/main/java/fr/pavnay/scrabble/Resolver.java index 3193dd9..a95f6b9 100644 --- a/src/main/java/fr/pavnay/scrabble/Resolver.java +++ b/src/main/java/fr/pavnay/scrabble/Resolver.java @@ -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(); } diff --git a/src/main/java/fr/pavnay/scrabble/ScrabbleUtils.java b/src/main/java/fr/pavnay/scrabble/ScrabbleUtils.java index d7a7787..c26747e 100644 --- a/src/main/java/fr/pavnay/scrabble/ScrabbleUtils.java +++ b/src/main/java/fr/pavnay/scrabble/ScrabbleUtils.java @@ -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; + } + } diff --git a/src/main/java/fr/pavnay/scrabble/impl/HashNodeImpl.java b/src/main/java/fr/pavnay/scrabble/impl/HashNodeImpl.java new file mode 100644 index 0000000..f1eeec6 --- /dev/null +++ b/src/main/java/fr/pavnay/scrabble/impl/HashNodeImpl.java @@ -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 nodes = new HashMap(); + private List 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(); + } + if (!this.words.contains(word)) { + this.words.add(word); + } + } + + public List getWords() { + if (this.words == null) { + return null; + } + Collections.sort(this.words); + return this.words; + } + + public Map 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 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 node : nodes.entrySet()) { + sb.append(node.getValue()); + } + return sb.toString(); + } +} diff --git a/src/main/java/fr/pavnay/scrabble/impl/NodeImpl.java b/src/main/java/fr/pavnay/scrabble/impl/NodeImpl.java new file mode 100644 index 0000000..4351c3c --- /dev/null +++ b/src/main/java/fr/pavnay/scrabble/impl/NodeImpl.java @@ -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 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(); + } + if (!this.words.contains(word)) { + this.words.add(word); + } + } + + public List 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(); + } +} diff --git a/src/main/java/fr/pavnay/scrabble/serializer/NodeSerializer.java b/src/main/java/fr/pavnay/scrabble/serializer/NodeSerializer.java new file mode 100644 index 0000000..7d78994 --- /dev/null +++ b/src/main/java/fr/pavnay/scrabble/serializer/NodeSerializer.java @@ -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 { + private static final long serialVersionUID = -5136242177329213286L; + + public NodeSerializer() { + this(null); + } + + public NodeSerializer(Class 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(); + } +} diff --git a/src/main/resources/resolvers/english b/src/main/resources/resolvers/english index 72d1b80..68f082a 100644 Binary files a/src/main/resources/resolvers/english and b/src/main/resources/resolvers/english differ diff --git a/src/main/resources/resolvers/french b/src/main/resources/resolvers/french index a490ee0..d7771dd 100644 Binary files a/src/main/resources/resolvers/french and b/src/main/resources/resolvers/french differ