import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import pl.shockah.StringTools; import pl.shockah.shocky.Module; import pl.shockah.shocky.Utils; import pl.shockah.shocky.cmds.Command; import pl.shockah.shocky.cmds.CommandCallback; import pl.shockah.shocky.cmds.Parameters; public class ModuleDFWords extends Module { public static final Pattern tag = Pattern.compile("\\[(.+?)\\]"); public static final Pattern split = Pattern.compile(":"); public static final Pattern space = Pattern.compile("\\s"); public Map<String, List<Word>> symbols; public Map<String, Word> words; public Map<String, Map<Word,String>> translations; protected Command cmd; @Override public String name() { return "dfwords"; } @Override public void onEnable(File dir) { try { words = new HashMap<String, Word>(); symbols = new HashMap<String, List<Word>>(); translations = new HashMap<String, Map<Word,String>>(); processFile(new File("modules/df/language_words.txt")); processFile(new File("modules/df/language_SYM.txt")); processFile(new File("modules/df/language_DWARF.txt")); processFile(new File("modules/df/language_ELF.txt")); processFile(new File("modules/df/language_GOBLIN.txt")); processFile(new File("modules/df/language_HUMAN.txt")); Command.addCommands(this, cmd = new CmdDFWords()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onDisable() { Command.removeCommands(cmd); symbols = null; words = null; translations = null; } public void processFile(File file) throws IOException { if (!file.exists() || !file.isFile()) return; String content; boolean valid = false; FileInputStream stream = new FileInputStream(file); try { FileChannel fc = stream.getChannel(); MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); content = Charset.forName("cp437").decode(bb).toString(); } finally { stream.close(); } Matcher matcher = tag.matcher(content); String[] symbol = null; String translation = null; Word word = null; Noun noun = null; Adj adj = null; Verb verb = null; Prefix prefix = null; while (matcher.find()) { String[] parts = split.split(matcher.group(1)); String type = parts[0]; if (type.contentEquals("OBJECT")) { valid = parts[1].contentEquals("LANGUAGE"); continue; } if (!valid) continue; if (type.contentEquals("WORD")) { word = new Word(parts[1]); words.put(parts[1], word); translation = null; symbol = null; } else if (type.contentEquals("SYMBOL")) { symbol = parts[1].split("_"); translation = null; word = null; } else if (type.contentEquals("TRANSLATION")) { translation = parts[1]; translations.put(translation, new HashMap<Word,String>()); symbol = null; word = null; } if (word == null && symbol == null && translation == null) continue; if (noun != null) { if (type.contentEquals("THE_NOUN_SING")) { noun.flags |= Noun.THE_NOUN_SING; continue; } else if (type.contentEquals("THE_NOUN_PLUR")) { noun.flags |= Noun.THE_NOUN_PLUR; continue; } else if (type.contentEquals("THE_COMPOUND_NOUN_SING")) { noun.flags |= Noun.THE_COMPOUND_NOUN_SING; continue; } else if (type.contentEquals("THE_COMPOUND_NOUN_PLUR")) { noun.flags |= Noun.THE_COMPOUND_NOUN_PLUR; continue; } else if (type.contentEquals("OF_NOUN_SING")) { noun.flags |= Noun.OF_NOUN_SING; continue; } else if (type.contentEquals("OF_NOUN_PLUR")) { noun.flags |= Noun.OF_NOUN_PLUR; continue; } else if (type.contentEquals("FRONT_COMPOUND_NOUN_SING")) { noun.flags |= Noun.FRONT_COMPOUND_NOUN_SING; continue; } else if (type.contentEquals("FRONT_COMPOUND_NOUN_PLUR")) { noun.flags |= Noun.FRONT_COMPOUND_NOUN_PLUR; continue; } else if (type.contentEquals("REAR_COMPOUND_NOUN_SING")) { noun.flags |= Noun.REAR_COMPOUND_NOUN_SING; continue; } else if (type.contentEquals("REAR_COMPOUND_NOUN_PLUR")) { noun.flags |= Noun.REAR_COMPOUND_NOUN_PLUR; continue; } else { noun = null; } } else if (adj != null) { if (type.contentEquals("ADJ_DIST")) { adj.dist = Byte.parseByte(parts[1]); continue; } else if (type.contentEquals("THE_COMPOUND_ADJ")) { adj.flags |= Adj.THE_COMPOUND_ADJ; continue; } else if (type.contentEquals("FRONT_COMPOUND_ADJ")) { adj.flags |= Adj.FRONT_COMPOUND_ADJ; continue; } else if (type.contentEquals("REAR_COMPOUND_ADJ")) { adj.flags |= Adj.REAR_COMPOUND_ADJ; continue; } else { adj = null; } } else if (verb != null) { if (type.contentEquals("STANDARD_VERB")) { verb.flags |= Verb.STANDARD_VERB; continue; } else { verb = null; } } else if (prefix != null) { if (type.contentEquals("FRONT_COMPOUND_PREFIX")) { prefix.flags |= Prefix.FRONT_COMPOUND_PREFIX; continue; } else if (type.contentEquals("THE_COMPOUND_PREFIX")) { prefix.flags |= Prefix.THE_COMPOUND_PREFIX; continue; } else { prefix = null; } } if (type.contentEquals("NOUN")) { noun = new Noun(parts); if (word.nouns == null) word.nouns = new ArrayList<Noun>(); word.nouns.add(noun); word.all.add(noun); } else if (type.contentEquals("ADJ")) { adj = new Adj(parts[1]); if (word.adjs == null) word.adjs = new ArrayList<Adj>(); word.adjs.add(adj); word.all.add(adj); } else if (type.contentEquals("VERB")) { verb = new Verb(parts); if (word.verbs == null) word.verbs = new ArrayList<Verb>(); word.verbs.add(verb); word.all.add(verb); } else if (type.contentEquals("PREFIX")) { prefix = new Prefix(parts[1]); if (word.prefixes == null) word.prefixes = new ArrayList<Prefix>(); word.prefixes.add(prefix); word.all.add(prefix); } else if (symbol != null && type.contentEquals("S_WORD")) { for (int i = 0; i < symbol.length; i++) { if (!symbols.containsKey(symbol[i])) symbols.put(symbol[i], new ArrayList<Word>()); symbols.get(symbol[i]).add(words.get(parts[1])); } } else if (translation != null && type.contentEquals("T_WORD")) { Word keyword = words.get(parts[1]); if (keyword != null) translations.get(translation).put(keyword, parts[2]); } } } public static <T> void put(Map<Short, List<T>> map, short key, T value) { if (!map.containsKey(key)) map.put(key, new ArrayList<T>()); map.get(key).add(value); } public static class Word { public Set<Part> all = new HashSet<Part>(); public List<Noun> nouns; public List<Adj> adjs; public List<Verb> verbs; public List<Prefix> prefixes; public final String name; public Word(String name) { this.name = name; } public Set<Part> getParts(short flags) { HashSet<Part> set = new HashSet<Part>(); for (Part p : all) { if ((p.getFlags() & flags) != 0) set.add(p); } if (set.isEmpty()) return null; return set; } public Part getPart(Random rnd, short flags) { return Utils.rndCollection(getParts(flags), rnd); } public String getString(Random rnd, short flags, Map<Word,String> tranmap) { if (tranmap != null && tranmap.containsKey(this)) return tranmap.get(this); Part part = getPart(rnd, flags); if (part == null) return null; return part.getString(flags); } } public Word get(Random rnd, short flags, String symbol) { if (symbol != null && !symbols.containsKey(symbol)) return null; Collection<Word> iter = symbol != null ? symbols.get(symbol) : words.values(); List<Word> list; if (flags == 0) list = new ArrayList<Word>(iter); else { list = new ArrayList<Word>(); for (Word w : iter) { Set<Part> parts = w.getParts(flags); if (parts != null && !parts.isEmpty()) list.add(w); } } if (list.isEmpty()) return null; return list.get(rnd.nextInt(list.size())); } public String parse(CharSequence cs) { Random rnd = new Random(); Map<Word,String> tranmap = null; String[] args = space.split(cs); int the = -1; int of = -1; for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.equalsIgnoreCase("the")) { the = i; continue; } else if (arg.equalsIgnoreCase("of")) { of = i; continue; } short flags = 0; if (the != -1 && the == i - 1) flags |= THE; if (of != -1 && of == i - 1) flags |= OF; Matcher m = tag.matcher(arg); StringBuffer sb = new StringBuffer(); while (m.find()) { String[] parts = split.split(m.group(1)); if (parts.length==2 && parts[0].contentEquals("TR")) { String trans = parts[1]; if (translations.containsKey(trans)) tranmap = translations.get(trans); m.appendReplacement(sb,""); continue; } char[] chars = parts[0].toCharArray(); byte verbmode = 0; boolean matched = false; for (int o = 0; !matched && o < chars.length; o++) { char c = chars[o]; switch (c) { case 's': flags |= SING; verbmode = 1; break; case 'p': flags |= PLUR; verbmode = 2; break; case 'r': verbmode = 3; break; case 't': verbmode = 4; break; case 'n': flags |= NOUN; String symbol = null; if (parts.length==2) symbol = parts[1]; Word w = get(rnd, flags, symbol); m.appendReplacement(sb,w != null ? w.getString(rnd, flags,tranmap) : ""); matched = true; break; case 'c': flags |= COMPOUND; short flags1 = (short) ((flags | FRONT) & ~PLUR); short flags2 = (short) (flags | REAR); String symbol1 = null; String symbol2 = null; if (parts.length==2) { symbol1 = symbol2 = parts[1]; } else if (parts.length==3) { symbol1 = parts[1]; symbol2 = parts[2]; } Word w1 = get(rnd, flags1, symbol1); Word w2 = get(rnd, flags2, symbol2); if (w1 != null && w2 != null) m.appendReplacement(sb,w1.getString(rnd, flags1,tranmap)+ '-'+ w2.getString(rnd,flags2,tranmap)); else m.appendReplacement(sb,""); matched = true; break; case 'v': flags = VERB; symbol = null; if (parts.length==2) symbol = parts[1]; w = get(rnd, flags, symbol); if (w != null) { if (tranmap != null && tranmap.containsKey(w)) { m.appendReplacement(sb, tranmap.get(w)); } else { Verb v = ((Verb) w.getPart(rnd, flags)); switch (verbmode) { case 0: m.appendReplacement(sb, v.base); break; case 1: m.appendReplacement(sb, v.presentSimple); break; case 2: m.appendReplacement(sb, v.pastTense); break; case 3: m.appendReplacement(sb, v.presentParticiple); break; case 4: m.appendReplacement(sb, v.pastParticiple); break; } } } else { m.appendReplacement(sb,""); } matched = true; break; case 'a': flags |= ADJ; w = null; symbol = null; if (parts.length==2) symbol = parts[1]; w = get(rnd, flags, symbol); if (w != null) m.appendReplacement(sb,w.getString(rnd, flags,tranmap)); else m.appendReplacement(sb,""); matched = true; break; } } } m.appendTail(sb); args[i] = sb.toString(); } return StringTools.implode(args, " "); } public static final short NOUN = 0x0001; public static final short ADJ = 0x0002; public static final short VERB = 0x0004; public static final short PREFIX = 0x0008; public static final short SING = 0x0010; public static final short PLUR = 0x0020; public static final short THE = 0x0040; public static final short OF = 0x0080; public static final short COMPOUND = 0x0100; public static final short FRONT = 0x0200; public static final short REAR = 0x0400; public static interface Part { short getFlags(); String getString(short flags); } public static class Noun implements Part { public static final short THE_NOUN_SING = THE | NOUN | SING; public static final short THE_NOUN_PLUR = THE | NOUN | PLUR; public static final short OF_NOUN_SING = OF | NOUN | SING; public static final short OF_NOUN_PLUR = OF | NOUN | PLUR; public static final short THE_COMPOUND_NOUN_SING = THE | COMPOUND | NOUN | SING; public static final short THE_COMPOUND_NOUN_PLUR = THE | COMPOUND | NOUN | PLUR; public static final short FRONT_COMPOUND_NOUN_SING = FRONT | COMPOUND | NOUN | SING; public static final short FRONT_COMPOUND_NOUN_PLUR = FRONT | COMPOUND | NOUN | PLUR; public static final short REAR_COMPOUND_NOUN_SING = REAR | COMPOUND | NOUN | SING; public static final short REAR_COMPOUND_NOUN_PLUR = REAR | COMPOUND | NOUN | PLUR; public final String singular; public final String plural; public short flags; public Noun(String[] words) { singular = words[1]; plural = words.length == 3 ? words[2] : words[1]; } @Override public short getFlags() { return flags; } @Override public String getString(short flags) { if ((flags & PLUR) != 0) return plural; return singular; } } public static class Adj implements Part { public static final short THE_COMPOUND_ADJ = THE | COMPOUND | ADJ; public static final short FRONT_COMPOUND_ADJ = FRONT | COMPOUND | ADJ; public static final short REAR_COMPOUND_ADJ = REAR | COMPOUND | ADJ; public final String adjective; public byte dist = 1; public short flags; public Adj(String word) { adjective = word; } @Override public short getFlags() { return flags; } @Override public String getString(short flags) { return adjective; } } public static class Verb implements Part { public static final short STANDARD_VERB = VERB; public final String base; public final String presentSimple; public final String pastTense; public final String pastParticiple; public final String presentParticiple; public short flags; public Verb(String[] words) { base = words[1]; presentSimple = words[2]; pastTense = words[3]; pastParticiple = words[4]; presentParticiple = words[5]; } @Override public short getFlags() { return flags; } @Override public String getString(short flags) { return base; } } public static class Prefix implements Part { public static final short FRONT_COMPOUND_PREFIX = FRONT | COMPOUND | PREFIX; public static final short THE_COMPOUND_PREFIX = THE | COMPOUND | PREFIX; public final String word; public short flags; public Prefix(String word) { this.word = word; } @Override public short getFlags() { return flags; } @Override public String getString(short flags) { return word; } } public class CmdDFWords extends Command { public String command() { return "dfwords"; } public String help(Parameters params) { StringBuilder sb = new StringBuilder(); sb.append("dfwords/g"); sb.append("\ndfwords {query} - returns a random line using given tags"); return sb.toString(); } @Override public void doCommand(Parameters params, CommandCallback callback) { if (params.tokenCount == 0) { callback.type = EType.Notice; callback.append(help(params)); return; } callback.append(parse(params.input)); } } }