Skip to content

Instantly share code, notes, and snippets.

@silverjam
Created August 13, 2010 04:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save silverjam/522307 to your computer and use it in GitHub Desktop.
Save silverjam/522307 to your computer and use it in GitHub Desktop.
abstract class Classification {
double frequency()
boolean isComplete()
boolean isPartial()
...
class Complete extends Classification ...
class Partial extends Classification ...
class Partialish extends Classification ...
class Nothing extends Classification ...
class WordSet {
void populate(String filename)
Classification classify(String word)
...
class SwipeState
{
Keyboard _keyboard;
WordSet _wordset;
KeyHitCollector _keyCollector;
...
void mouseDragged() { ... }
void mouseReleased() { ... }
void draw() { ... }
}
ArrayList<String> words() {
HashMap<String, Double> complete = new HashMap();
ArrayList<String> prefixes = new ArrayList();
ArrayList<String> ls = new ArrayList();
if ( _keys.isEmpty() )
return ls;
prefixes.add(_keys.get(0));
Classification klass = _wordset.classify(prefixes.get(0));
if ( klass.isComplete() )
complete.put(prefixes.get(0), klass.frequency());
for (int i = 1; i < _keys.size(); i++)
{
String ch = _keys.get(i);
ArrayList<String> newPrefixes = new ArrayList();
for (int j = 0; j < prefixes.size(); j++) {
String prefix = prefixes.get(j) + ch;
klass = _wordset.classify(prefix);
if ( klass.isComplete() )
complete.put(prefix, klass.frequency());
if ( klass.isPartial() )
newPrefixes.add(prefix);
}
prefixes.addAll(newPrefixes);
}
ls = new ArrayList(complete.keySet());
Collections.sort(ls, new Comparator() { /* Sort by length */ });
while ( ls.size() > MAX_WORD_COUNT )
ls.remove(ls.size() - 1);
Collections.sort(ls, new FreqCmp(complete));
return ls;
}
// Data: http://drop.io/vnb0bwj
PFont font;
SwipeState state;
void setup()
{
fill(#ffffff);
stroke(#ffffff);
size(450, 400);
frameRate(60);
state = new SwipeState();
font = loadFont("AharoniBold-20.vlw");
textFont(font);
background(0);
state.draw();
}
void mouseReleased()
{
state.mouseReleased();
}
void mouseDragged()
{
state.mouseDragged();
}
void draw() { }
class SwipeState
{
Keyboard _keyboard;
WordSet _wordset;
KeyHitCollector _keyCollector;
int _prevMouseX = -1;
int _prevMouseY = -1;
SwipeState()
{
_keyboard = new Keyboard(30, 330);
_wordset = new WordSet();
_wordset.populate("words.txt");
_wordset.populate("freq.txt");
_keyCollector = new KeyHitCollector(_keyboard, _wordset);
}
void mouseDragged()
{
pushStyle();
fill(#ff0000);
stroke(#ff0000);
strokeWeight(3);
if ( _prevMouseX == -1 )
point(mouseX, mouseY);
else
line(_prevMouseX, _prevMouseY, mouseX, mouseY);
_prevMouseX = mouseX;
_prevMouseY = mouseY;
popStyle();
_keyCollector.detect(mouseX, mouseY);
}
void mouseReleased()
{
background(0);
fill(#ffffff);
stroke(#ffffff);
_prevMouseX = -1;
_prevMouseY = -1;
_keyboard.draw();
int y = 30;
for ( String word : _keyCollector.words() )
{
text(word, 170, y); y += 20;
}
_keyCollector.reset();
}
void draw()
{
_keyboard.draw();
}
}
final int MAX_WORD_COUNT = 12;
abstract class Classification
{
double _freq;
Classification() { _freq = 0; }
Classification(double freq) {
//print(Double.toString(freq)); print(" ");
_freq = freq;
}
double frequency() {
//print(Double.toString(_freq)); print(" ");
return _freq;
}
boolean isComplete() { return false; }
boolean isPartial() { return false; }
}
class Complete extends Classification {
Complete(double freq) { super(freq); }
boolean isComplete() { return true; }
}
class Partial extends Classification {
boolean isPartial() { return true; }
}
class Partialish extends Classification {
Partialish(double freq) { super(freq); }
boolean isPartial() { return true; }
boolean isComplete() { return true; }
}
class Nothing extends Classification {
boolean isNothing() { return true; }
}
class WordSet
{
HashMap<String, Classification> _map;
Partial _partial;
Nothing _nothing;
WordSet()
{
_map = new HashMap();
_partial = new Partial();
_nothing = new Nothing();
}
Classification exists(String s, Classification klass)
{
Classification existing = _map.get(s);
if ( existing != null && existing.isComplete() )
klass = new Partialish(existing.frequency());
return klass;
}
void populate(String filename)
{
String words[] = loadStrings(filename);
for(int i=0; i < words.length; i++)
{
String word;
double freq = 0.0;
String[] parts = words[i].split(" ", 2);
word = parts[0].toUpperCase();
if ( parts.length == 2 )
{
freq = Double.parseDouble(parts[0]);
word = parts[1].toUpperCase();
}
for(int j=1; j < word.length(); j++)
{
String partial = word.substring(0, j);
_map.put(partial, exists(partial, _partial));
}
_map.put(word, new Complete(freq));
}
}
Classification classify(String word)
{
Classification klass = _map.get(word);
if ( klass == null )
klass = _nothing;
//print(Double.toString(klass.frequency())); print(" ");
return klass;
}
}
class Key
{
static final int _dx = 4, _dy = 16;
static final int _boxDx = 28, _boxDy = 20;
String _c; int _x, _y;
Key(String c, int x, int y) { _c = c; _x = x; _y = y; }
void draw()
{
text(_c, _x, _y);
noFill();
bezierRect(_x - _dx, _y - _dy, _boxDx, _boxDy, -2, -2);
}
int left() { return _x - _dx; }
int top() { return _y - _dy; }
int right() { return left() + _boxDx; }
int bottom() { return top() + _boxDy; }
String c() { return _c; }
boolean hit(int x, int y)
{
return x > left() && x < right() && y > top() && y < bottom();
}
}
class Keyboard
{
static final String _row1 = "QWERTYUIOP[]\\";
static final String _row2 = "ASDFGHJKL;'";
static final String _row3 = "ZXCVBNM,./";
static final int _keySpacing = 30, _rowSpacing = 25,
_2ndOffset = 15, _3rdOffset = _2ndOffset+10;
ArrayList<Key> _row1Keys;
ArrayList<Key> _row2Keys;
ArrayList<Key> _row3Keys;
int _x, _y;
void populate(String row, ArrayList ls, int x, int y)
{
for (int i = 0; i < row.length(); i++) {
ls.add(new Key(row.substring(i, i+1), x, y));
x += _keySpacing;
}
}
void drawRow(ArrayList<Key> row)
{
for (int i = 0; i < row.size(); i++) {
Key k = row.get(i);
k.draw();
}
}
Keyboard(int x, int y)
{
_x = x; _y = y;
_row1Keys = new ArrayList();
_row2Keys = new ArrayList();
_row3Keys = new ArrayList();
populate(_row1, _row1Keys, x, y);
populate(_row2, _row2Keys, x + _2ndOffset, y + _rowSpacing);
populate(_row3, _row3Keys, x + _3rdOffset, y + 2 * _rowSpacing);
}
Key rowHit(ArrayList<Key> row, int x, int y)
{
for (int i = 0; i < row.size(); i++) {
Key k = row.get(i);
if ( k.hit(x, y) )
return k;
}
return null;
}
Key hit(int x, int y)
{
Key c = null;
c = rowHit(_row1Keys, x, y);
if ( c != null ) return c;
c = rowHit(_row2Keys, x, y);
if ( c != null ) return c;
c = rowHit(_row3Keys, x, y);
if ( c != null ) return c;
return null;
}
void draw()
{
drawRow(_row1Keys);
drawRow(_row2Keys);
drawRow(_row3Keys);
}
}
class KeyHitCollector
{
Key _lastKey;
Keyboard _keyboard;
WordSet _wordset;
ArrayList<String> _keys;
KeyHitCollector(Keyboard k, WordSet w)
{
_keys = new ArrayList();
_keyboard = k;
_wordset = w;
}
void reset() { _keys.clear(); }
void detect(int x, int y)
{
Key k = _keyboard.hit(mouseX, mouseY);
if ( k != null && k != _lastKey ) {
_keys.add(k.c());
}
_lastKey = k;
}
ArrayList<String> words()
{
HashMap<String, Double> complete = new HashMap();
ArrayList<String> prefixes = new ArrayList();
ArrayList<String> ls = new ArrayList();
if ( _keys.isEmpty() )
return ls;
prefixes.add(_keys.get(0));
Classification klass = _wordset.classify(prefixes.get(0));
if ( klass.isComplete() )
complete.put(prefixes.get(0), klass.frequency());
for (int i = 1; i < _keys.size(); i++)
{
String ch = _keys.get(i);
ArrayList<String> newPrefixes = new ArrayList();
for (int j = 0; j < prefixes.size(); j++)
{
String prefix = prefixes.get(j) + ch;
klass = _wordset.classify(prefix);
if ( klass.isComplete() )
complete.put(prefix, klass.frequency());
if ( klass.isPartial() )
newPrefixes.add(prefix);
}
prefixes.addAll(newPrefixes);
}
ls = new ArrayList(complete.keySet());
Collections.sort(ls, new Comparator() {
public int compare(Object o1, Object o2)
{ return -(((String)o1).length() - ((String)o2).length()); }
public boolean equals(Object o) { return false; }
});
while ( ls.size() > MAX_WORD_COUNT )
ls.remove(ls.size() - 1);
Collections.sort(ls, new FreqCmp(complete));
return ls;
}
}
class FreqCmp implements Comparator
{
HashMap<String, Double> _freqs;
FreqCmp(HashMap<String, Double> freqs) { _freqs = freqs; }
public int compare(Object o1, Object o2)
{
double d = _freqs.get((String)o1) - _freqs.get((String)o2);
if ( d < 0 ) return 1; else if ( d > 0 ) return -1;
return 0;
}
public boolean equals(Object o)
{ return false; }
}
void bezierRect(float x, float y, float w, float h, float xr, float yr)
{
float w2=w/2f, h2=h/2f, cx=x+w2, cy=y+h2;
beginShape();
vertex(cx,cy-h2);
bezierVertex(cx+w2-xr, cy-h2, cx+w2, cy-h2+yr, cx+w2, cy);
bezierVertex(cx+w2, cy+h2-yr, cx+w2-xr, cy+h2, cx, cy+h2);
bezierVertex(cx-w2+xr, cy+h2, cx-w2, cy+h2-yr, cx-w2, cy);
bezierVertex(cx-w2, cy-h2+yr, cx-w2+xr, cy-h2, cx, cy-h2);
endShape();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment