Thursday, November 22, 2007

I have ended world hunger

I'm a computer programmer by trade and more importantly I'm a problem solver by nature. When I am presented with a problem, however minor, I can't help but try to think of ways to solve it.

Two weeks ago I posted an entry called "You are the paramount computer technician without letup!", wherein I wrote a program, called PamFRI, to solve a problem that my friend, Pam, was having with her keyboard. I got a lot of comments from people claiming that the program was "useless". The program solved a problem that only one person had and she wouldn't even have the problem the on following day. Furthermore, it didn't even actually solve the problem since it's impossible to use the program if you have the problem. Alright, to be fair it was me that said all those things but I just can't handle criticism, regardless of how self-inflicted it may be.

Feeling like my reputation as a computer programmer was on the line I knew I had to rewrite the program. This time I decided to be a little more ambitious and end world hunger.

(require
(planet "csv.ss" ("neil" "csv.plt" 1 1))
(planet "sxml.ss" ("lizorkin" "sxml.plt" 1 4))
(planet "htmlprag.ss" ("neil" "htmlprag.plt" 1 3))
(planet "aif.ss" ("schematics" "macro.plt" 1 0))
(only (lib "1.ss" "srfi") list-index)
(lib "uri-codec.ss" "net")
(lib "url.ss" "net")
(lib "etc.ss")
(lib "list.ss")
(lib "string.ss"))

(define thesaurus
(let ([table (make-hash-table 'equal)]
[get-line
(make-csv-reader
(open-input-file "mobythes.aur")
'((separator-chars . (#\,))
(strip-leading-whitespace? . #t)
(strip-trailing-whitespace? . #t)))])
(let loop ([line (get-line)])
(unless (empty? line)
(let ([word (first line)])
(string-lowercase! word)
(hash-table-put! table word (rest line))
(loop (get-line)))))
table))

(define (post url data)
(html->sxml
(post-pure-port
(string->url url)
(string->bytes/utf-8 (alist->form-urlencoded data)))))

(define (check word options)
(foldl
(lambda (synonym ans)
(if (member synonym options) synonym ans))
false
(hash-table-get thesaurus word (lambda () empty))))

(define ((sxpath/f path) sxml)
(first ((sxpath path) sxml)))

(define (answer page)
(let* ([words ((sxpath "//div/div/ol/li") page)]
[word ((sxpath/f "strong/text()") (first words))]
[choices (map (sxpath/f "a/text()") (rest words))]
[answer
(number->string
(add1
(aif ans identity (check word choices)
(list-index (lambda (e) (string=? e ans))
choices)
(random 4))))])
(cons
(cons 'SELECTED answer)
(map (lambda (tag)
(cons (string->symbol
((sxpath/f "@name/text()") tag))
((sxpath/f "@value/text()") tag)))
((sxpath
"//input[@type='hidden' and @name!='SELECTED']")
page)))))

(let loop ([data empty])
(let ([p (post "http://freerice.com/index.php" data)])
(write ((sxpath "//p[@class='vocabLevel']/text()") p))
(newline)
(sleep 10)
(loop (answer p))))


Inspiration for this program came last week, right after I wrote PamFRI. One of my coworkers, Fred Henle, sent out a nice, little time waster know as Free Rice to the developers' mailing list. Free Rice is a non-profit web site where users are given a vocabulary quiz. For every answer the user gets right, the organization donates ten grains of rice to third-world countries through the UN.

Moments after Fred's email, Ben Mathes responded with his solution to end world hunger: a link to dictionary.com. As soon as I got Ben's mail it was pretty obvious to me what I had to do. "I can automate that!" I thought to myself. I had just written PamFRI, which uses a machine-readable thesaurus and PLT Scheme has a really nice web-scraping module on Planet. With only a few more lines of code I could modify my original program to grab the web page, read and answer the question, and then post it back. Calling such a program in a loop ought donate a lot of rice and would, at least in theory, end world hunger.

It's probably not advisable for me to encourage my readers to run this program since it generates a page hit to Free Rice once every ten seconds. If everyone one of my readers ran this program at the same time it could generate up to five page hits to Free Rice every ten seconds. On second thought, maybe that's not so bad. My friend, Trevor, points out that the real danger is when the OLPC project really takes off. We'll have ourselves a veritable DDoS attack if this program were to get into the hands of the kids who actually benefit from the rice donations.

On a serious note, the real reason I wrote this entry is to let people know about Free Rice and encourage them to play for real. I also wanted to show how darn cool the webscrape functionality is in PLT Scheme in case anyone has any need for it.

Monday, November 19, 2007

Six Degrees of Wikipedia is On Line

Last month I posted an entry called Six Degrees of Wikipedia, where in I started playing a game in which people try to find the shortest path between two given Wikipedia pages. My friend Colin made a random node generation script and yesterday we created a new web site where we will administer the game. Periodically a new challenge to connect two Wikipedia pages (by Wikipedia-internal links) will be issued. The first one is already up, so get cracking. The winners will be announced when the next challenge is release. Enjoy! Oh and hey, no editing the pages so that your path works.

Extra credit for people who write solvers or know how to use Google to find such things. :) I mean the Kevin Bacon game is still fun despite the existence of solvers, right?

Go to: http://sixdegreesofwikipedia.blogspot.com/ to play.

Friday, November 9, 2007

"You are the paramount computer technician without letup!"

Have you ever you spilled water on your keyboard? Have you ever shorted out the F, R, and I keys on your iBook all at once? Have you ever had to chat under such circumstances because you couldn't get an appointment at the Apple Store until tomorrow? Is your name Pamela Worth? Are you chatting with me right now on instant messenger? Maybe it's time you tried the latest in useless technology. That's right, maybe PamFRI is perfect for you!

Earlier today I was talking to my friend, Pam, on line and she seemed to be speaking rather funny.

me: How are you?
Pamela: well, apart from not hav1ng some very important letters not working...
me: You're 'i' key is broken?
Pamela: 3 keys
f, r, i
Pam has app't 2moro to see Mac "gen1uses"
me: How did it break? Mysteriously?
Pamela: not so Mysteriously.
1 sp1lled a small amount of H20


Intermittently a few of her keys would not work so she was resorting to l33t speak, cutting and pasting my own words back to me, using chemical formula abbreviations, or simply referring to herself in the third person. So I did what any good, overly nerdy friend would do in that situation.


grep -vi "[fri]" /usr/dict/words | mutt -s "Here's a list of words that don't use F, R, or I" [Pam's email address]


But as you can probably imagine, a list of all of the words in the English language that don't use the letters F, R, or I isn't all that useful. For starters one would have to search the entire list of words and the definitions aren't even there.

I simply had to do more to help the poor girl, so I helped how any good, super geeky friend would help. I made a small program that uses a machine readable thesaurus from the Moby project to accept a sentence that you want to type, as well as a list of keys that are broken. The program searches the sentence for any uses of the broken keys and swaps them out for suitable synonyms that don't also use the broken keys. In the event there are no suitable synonmys, the word gets printed out with square brackets. I call it PamFRI.

If you're wondering what the above paragraph looks like without the letter's F, R, or I:

Ego absolutely had to do on and on to help the debased dame, so psyche helped how any good, hot geeky bosom buddy would help. Monad made a small agenda that uses a jalopy plumbable cache ex the Moby lay plans to accept a sentence that you want to type, as well as a levy about jolty keys. The keynote speech looks down the sentence so as to any uses about the wobbly keys and swaps them out because plenty good enough synonyms that don't also use the quelled keys. Gangplank the event no seasonable synonmys can be etch, the vow gets typeset out amongst yes-man [brackets]. One and only call the goods [PamFRI].

(require
(planet "csv.ss" ("neil" "csv.plt" 1 1))
(lib "list.ss")
(lib "string.ss"))

(define thesaurus
(let ([table (make-hash-table 'equal)]
[get-line
(make-csv-reader
(open-input-file "mobythes.aur")
'((separator-chars . (#\,))
(strip-leading-whitespace? . #t)
(strip-trailing-whitespace? . #t)))])
(let loop ([line (get-line)])
(unless (empty? line)
(let ([word (first line)])
(string-lowercase! word)
(hash-table-put! table word (rest line))
(loop (get-line)))))
table))

(define (suggest badchars sentence)
(regexp-replace*
"[a-zA-Z'\\-]+"
sentence
(lambda (aword)
(string-lowercase! aword)
(if ((typeable? badchars) aword)
aword
(replacement badchars aword)))))

(define ((typeable? badchars) aword)
(not (regexp-match
(regexp
(string-append
"(?i:[" (list->string badchars) "])"))
aword)))

(define (replacement badchars aword)
(let* ([synonyms
(hash-table-get
thesaurus aword (lambda () empty))]
[replacements
(filter (typeable? badchars) synonyms)])
(if (empty? replacements)
(string-append "[" aword "]")
(list-ref replacements
(random (length replacements))))))


You call the program like this:

> (suggest '(#\h) "hello my name is")
"salutation my name is"
> (suggest '(#\h #\n) "hello my name is")
"kiss my itemize is"
> (suggest '(#\i) "I like the program very much")
"superego respect the program very much"


So if you're a clumsy, water drinking, Apple computing, debased dame, fear not. Help is on the way. You can download the program here in a zip format complete with the thesaurus. The program requires Dr. Scheme to be opened which is availible for Linux, Mac, and Windows.

By the way, I fully intend to continue calling them 'yes-man brackets'.

Thursday, November 8, 2007

I'm a grown-up now

A little more than a year ago Randall Munroe, author of XKCD, posted a comic, called Grownups, about a girl filling her apartment with playpen balls. The girl in the comic offers no explanation as to why she's done this, other than the fact that she's a grow-up now and it's her turn to decide what being a grown-up means. The whimsical web comic has often portrayed a state of mind that hits very close to home for me and this strip wasn't an exception.

I'm impulsive so I started looking on line for playpen balls the following weekend and quickly learned the same thing Randall did. Filling one's apartment with playpen balls, for any reasonably sized apartment, or even a tiny dorm room, would cost well over a few thousand dollars. Determined to have a ball pit, I decided I would cordon off the bottom of my lofted bed and make a ball-pit underneath. The lofted bed is a nice big queen-sized bed so the pit would be about 5'x7' with about 5' head clearance.

Using an on-line playpen ball volume calculator (inspired by the XKCD comic itself) I found that making a 5'x7' ball pit 2' deep was a pretty tractable goal. With a little help from my friend Sue I was able to find two ebay auctions for 700 and 800 balls from the same seller. The orders totaled about $160 counting shipping, which by the way made up more than 40% of the cost.

I placed a bid and week or so later I received the largest delivery I'd ever received as well as an endearingly spastic but uninformative voice from my roommate attempting to describe exactly what had happened to our front porch while I was gone. "Hey! Mike! Oh my god there's, like... the porch is totally gone. They're huge. These all have your name... I can't... do want me to... Holy crap." Remembering my order from a week ago I figured that was probably what she was talking about so I went home to bring them in.

On the Saturday after the delivery arrived, Sue and I went to Home Depot, the toy store for grown-ups who think the word grown-up has been ill defined. After some careful consideration we decided to pick up a reel of plastic garden fencing, zip ties, and you guessed it, some PVC pipe.

The lofted bed was already up against two walls so I just needed to gate off the other two. One wall, the short one, I decided to completely cover with the garden fence. The long wall I made the entry way, so it has a short wall made of a PVC frame and garden fence which is easy to step over.

That Saturday night Sarah came over and Sue, Sarah, and I sat in the ball pit for nearly five hours talking and laughing uncontrollably while throwing balls at each others faces. It really is quite amazing how long throwing balls at your friends' faces can last without getting boring. When it did we just lounged around and chatted until someone decided it was again time to throw balls at each other's faces. As the night winded down Sarah took great joy in completely burying herself and Sue made sure that both of us had heard every possibly innuendo involving the word balls.

Later in the week my improv troupe came over to practice and we ended the night with a really loud and rowdy ball pit fight where in most people just threw balls at Tony while Tony scrambled to bury his face and anything else fragile under a thick enough covering of playpen balls. My more obsessive compulsive friends came over the following weekend and we shorted the ball pit in spectrum order. To be fair this project also started with throwing balls at each others faces when I decided that Mike could only throw blue balls and Trevor could only throw red. This created a really nice visual effect so we ran with it and Lisa took some pictures.

I guess what I've learned from all this is simply that if you are going to go through the trouble of making a ball pit in your apartment just realize that all your friends are going to want to do is throw plastic balls at your face. Recently I moved and decided to make a video of the reconstruction of the ball pit.