BloomFilter bf; String beingEntered; color textColor; void setup() { size(500, 550); colorMode(RGB, 255, 255, 255, 1.0); smooth(); ellipseMode(CENTER); frameRate(25); noLoop(); strokeWeight(5); PFont helvetica = loadFont("Helvetica-24.vlw"); textFont(helvetica, 24); beingEntered = ""; textColor = #0000FF; bf = new DrawingBloomFilter(25, 25, 10); bf.initialize(); } void keyPressed() { if (beingEntered.length() > 0) { if (keyCode == 8) { beingEntered = beingEntered.substring(0, beingEntered.length() - 1); handleInput(beingEntered); } else if (keyCode == 10 || keyCode == 13) { addString(beingEntered); beingEntered = ""; } } if (key == CODED) { return; } if (keyCode != 8 && keyCode != 10 && keyCode != 13) { beingEntered += key; handleInput(beingEntered); } } void addString(String s) { bf.add(s); redraw(); } void handleInput(String s) { if (s.length() > 0) { textColor = bf.contains(s) ? #FF0000 : #0000FF; } redraw(); } void draw() { background(255); bf.display(); fill(textColor); text(beingEntered, 20, 510, 460, 25); } class BloomFilter { int _numBits; int _numHashes; Bit[] _bits; BloomFilter(int m, int k) { _numBits = m; _numHashes = k; } void initialize() { _bits = new Bit[_numBits]; for (int i = 0; i < _numBits; i++) { _bits[i] = new Bit(); } } void add(String s) { for (int i = 0; i < _numHashes; i++) { int bit = doubleHash(s, i, _numBits); _bits[bit].on(); } } boolean contains(String s) { boolean isIn = true; for (int i = 0; i < _numHashes; i++) { int bit = doubleHash(s, i, _numBits); if (!_bits[bit].get()) { isIn = false; } } return isIn; } int doubleHash(String s, int i, int m) { return abs(djb2(s) + i * sdbm(s)) % m; } int sdbm(String s) { int hash = 0; for (int i = 0; i < s.length(); i++) { hash = s.charAt(i) + (hash << 6) + (hash << 16) - hash; } return hash; } int djb2(String s) { int hash = 5381; for (int i = 0; i < s.length(); i++) { hash = ((hash << 5) + hash) ^ s.charAt(i); } return hash; } void display() {} } class DrawingBloomFilter extends BloomFilter { int _x; int _y; // Not guaranteed to be exactly k bits... DrawingBloomFilter(int m, int k) { super(int(sq(int(sqrt(m)))), k); _x = int(sqrt(m)); _y = _x; } DrawingBloomFilter(int x, int y, int k) { super(x * y, k); _x = x; _y = y; } void initialize() { _bits = new DrawingBit[_numBits]; int i = 0; for (int x = 0; x < _x; x++) { for (int y = 0; y < _y; y++) { _bits[i++] = new DrawingBit(x, y); } } } void display() { loop(); boolean stopLoop = true; for (int i = 0; i < _bits.length; i++) { _bits[i].display(); if (stopLoop && _bits[i].inFade()) { stopLoop = false; } } if (stopLoop) { noLoop(); } } } int BIT_BUFFER = 20; // Pixels between each DrawingBit int BIT_SIZE = 6; int BIT_FADE_SIZE = BIT_BUFFER; class Bit { boolean _state; Bit() { _state = false; } void on() { _state = true; } boolean get() { return _state; } boolean inFade() { return false; } void display() {} } class DrawingBit extends Bit { int _x; int _y; boolean _inFade; float _fadePercentage; DrawingBit(int x, int y) { super(); _x = x * BIT_BUFFER + BIT_BUFFER / 2; _y = y * BIT_BUFFER + BIT_BUFFER / 2; _inFade = false; } void on() { _state = true; initFade(); } boolean get() { initFade(); return super.get(); } boolean inFade() { return _inFade; } void initFade() { _inFade = true; _fadePercentage = 0.0; } void display() { if (_inFade) { fade(); color strokeColor = _state ? color(255, 0, 0, 0.5) : color(0, 0, 255, 0.5); stroke(strokeColor); } else { noStroke(); } color fillColor = _state ? #FF0000 : #0000FF; fill(fillColor); ellipse(_x, _y, BIT_SIZE, BIT_SIZE); } void fade() { _fadePercentage += .1; int fadeSize = int(_fadePercentage * BIT_FADE_SIZE); color fadeColor = _state ? color(255, 0, 0, 1.0 - _fadePercentage) : color(0, 0, 255, 1.0 - _fadePercentage); fill(fadeColor); ellipse(_x, _y, fadeSize, fadeSize); if (_fadePercentage >= 1.0) { _inFade = false; } } }