Generic rage.

This commit is contained in:
asofold 2012-09-03 05:03:28 +02:00
parent 167717609c
commit 8534cf91e2
3 changed files with 83 additions and 40 deletions

View File

@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.LookupEntry;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.Node; import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.Node;
@ -14,7 +15,7 @@ import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.Node;
* @author mc_dev * @author mc_dev
* *
*/ */
public class PrefixTree<K, N extends Node<K>>{ public class PrefixTree<K, N extends Node<K>, L extends LookupEntry<K, N>>{
public static class Node<K>{ public static class Node<K>{
public boolean isEnd = false; public boolean isEnd = false;
@ -33,7 +34,7 @@ public class PrefixTree<K, N extends Node<K>>{
if (node != null) return node; if (node != null) return node;
else if (factory == null) return null; else if (factory == null) return null;
else{ else{
node = factory.getNewNode(); node = factory.newNode();
children.put(key, node); children.put(key, node);
return node; return node;
} }
@ -41,7 +42,7 @@ public class PrefixTree<K, N extends Node<K>>{
} }
public static interface NodeFactory<K, N extends Node<K>>{ public static interface NodeFactory<K, N extends Node<K>>{
public N getNewNode(); public N newNode();
} }
public static class LookupEntry<K, N extends Node<K>>{ public static class LookupEntry<K, N extends Node<K>>{
@ -62,28 +63,20 @@ public class PrefixTree<K, N extends Node<K>>{
} }
} }
protected final NodeFactory<K, N> factory; public static interface LookupEntryFactory<K, N extends Node<K>, L extends LookupEntry<K, N>>{
public L newLookupEntry(N node , N insertion, int depth, boolean hasPrefix);
}
protected final NodeFactory<K, N> nodeFactory;
protected final LookupEntryFactory<K, N, L> resultFactory;
protected N root; protected N root;
public PrefixTree(final Class<N> clazz){ public PrefixTree(NodeFactory<K, N> nodeFactory, LookupEntryFactory<K, N, L> resultFactory){
this(new NodeFactory<K, N>() { this.nodeFactory = nodeFactory;
@Override this.root = nodeFactory.newNode();
public N getNewNode() { this.resultFactory = resultFactory;
try {
return clazz.newInstance();
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
return null;
}
}
});
}
public PrefixTree(NodeFactory<K, N> factory){
this.factory = factory;
this.root = factory.getNewNode();
} }
public LookupEntry<K, N> lookup(K[] keys, final boolean create){ public LookupEntry<K, N> lookup(K[] keys, final boolean create){
@ -91,13 +84,12 @@ public class PrefixTree<K, N extends Node<K>>{
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public LookupEntry<K, N> lookup(final List<K> keys, final boolean create){ public L lookup(final List<K> keys, final boolean create){
N insertion = root; N insertion = root;
N node = null;
int depth = 0; int depth = 0;
N current = root; N current = root;
boolean hasPrefix = false; boolean hasPrefix = false;
final NodeFactory<K, N> factory = (NodeFactory<K, N>) (create ? this.factory : null); final NodeFactory<K, N> factory = (NodeFactory<K, N>) (create ? this.nodeFactory : null);
for (final K key : keys){ for (final K key : keys){
final N child = (N) current.getChild(key, null); final N child = (N) current.getChild(key, null);
if (child == null){ if (child == null){
@ -108,12 +100,13 @@ public class PrefixTree<K, N extends Node<K>>{
} }
} }
else{ else{
// Node already exists, set as insertion point. // A node already exists, set as insertion point.
insertion = current = child; insertion = current = child;
depth ++; depth ++;
if (child.isEnd) hasPrefix = true; if (child.isEnd) hasPrefix = true;
} }
} }
N node = null;
if (create){ if (create){
node = current; node = current;
current.isEnd = true; current.isEnd = true;
@ -121,11 +114,30 @@ public class PrefixTree<K, N extends Node<K>>{
else if (depth == keys.size()){ else if (depth == keys.size()){
node = current; node = current;
} }
return new LookupEntry<K, N>(node, insertion, depth, hasPrefix); return resultFactory.newLookupEntry(node, insertion, depth, hasPrefix);
} }
public void clear() { public void clear() {
root = factory.getNewNode(); root = nodeFactory.newNode();
// TODO: maybe more unlinking ? // TODO: maybe more unlinking ?
} }
/**
* Factory method for a simple tree.
* @param keyType
* @return
*/
public static <K> PrefixTree<K, Node<K>, LookupEntry<K, Node<K>>> newPrefixTree(){
return new PrefixTree<K, Node<K>, LookupEntry<K, Node<K>>>(new NodeFactory<K, Node<K>>(){
@Override
public final Node<K> newNode() {
return new Node<K>();
}
}, new LookupEntryFactory<K, Node<K>, LookupEntry<K,Node<K>>>() {
@Override
public LookupEntry<K, Node<K>> newLookupEntry(Node<K> node, Node<K> insertion, int depth, boolean hasPrefix) {
return new LookupEntry<K, PrefixTree.Node<K>>(node, insertion, depth, hasPrefix);
}
});
}
} }

View File

@ -0,0 +1,39 @@
package fr.neatmonster.nocheatplus.checks.chat.analysis.ds;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.LookupEntry;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.Node;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.SimplePrefixTree.SimpleLookupEntry;
/**
* Simple prefix tree, for one given key type.
* <hr>
* Interesting: ctrl-shift-o (eclipse) is not idempotent.
* @author mc_dev
*
* @param <K>
*/
public class SimplePrefixTree<K> extends PrefixTree<K, Node<K>, SimpleLookupEntry<K>> {
public static class SimpleLookupEntry<K> extends LookupEntry<K, Node<K>>{
public SimpleLookupEntry(Node<K> node, Node<K> insertion, int depth, boolean hasPrefix) {
super(node, insertion, depth, hasPrefix);
}
}
public SimplePrefixTree() {
super(new NodeFactory<K, Node<K>>(){
@Override
public Node<K> newNode() {
return new Node<K>();
}
}, new LookupEntryFactory<K, Node<K>, SimpleLookupEntry<K>>(){
@Override
public SimpleLookupEntry<K> newLookupEntry(
Node<K> node, Node<K> insertion,
int depth, boolean hasPrefix) {
return new SimpleLookupEntry<K>(node, insertion, depth, hasPrefix);
}
});
}
}

View File

@ -6,20 +6,12 @@ import java.util.List;
import fr.neatmonster.nocheatplus.checks.chat.analysis.MessageLetterCount; import fr.neatmonster.nocheatplus.checks.chat.analysis.MessageLetterCount;
import fr.neatmonster.nocheatplus.checks.chat.analysis.WordLetterCount; import fr.neatmonster.nocheatplus.checks.chat.analysis.WordLetterCount;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree; import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.SimplePrefixTree;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.LookupEntry; import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.SimplePrefixTree.SimpleLookupEntry;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.Node;
import fr.neatmonster.nocheatplus.checks.chat.analysis.ds.PrefixTree.NodeFactory;
public class CompressedChars extends AbstractWordProcessor{ public class CompressedChars extends AbstractWordProcessor{
protected final PrefixTree<Character, Node<Character>> tree = new PrefixTree<Character, Node<Character>>( protected final SimplePrefixTree<Character> tree = new SimplePrefixTree<Character>();
new NodeFactory<Character, Node<Character>>() {
@Override
public Node<Character> getNewNode() {
return new Node<Character>();
}
});
protected final int maxAdd; protected final int maxAdd;
@ -72,7 +64,7 @@ public class CompressedChars extends AbstractWordProcessor{
private float getScore(List<Character> chars) { private float getScore(List<Character> chars) {
final int len = chars.size(); final int len = chars.size();
LookupEntry<Character, Node<Character>> entry = tree.lookup(chars, true); SimpleLookupEntry<Character> entry = tree.lookup(chars, true);
float score = (float) (entry.depth*entry.depth) / (float) (len*len) ; float score = (float) (entry.depth*entry.depth) / (float) (len*len) ;
if (entry.depth == chars.size()){ if (entry.depth == chars.size()){
score += 0.2; score += 0.2;