The three rules of Ruby Quiz:

1.  Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2.  Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3.  Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Hans Fugal

I am amazed whenever I see or hear about the rising generation of keypad
punchers. People that can carry on IM conversations with a 12-key phone
pad without instantly going mad; it's mind-boggling. As adaptive as the
rising generation is, the "Multitap" solution is far from efficient. For
example, I learned from Wheel of Fortune that the most common letters
are RSTLNE, only one of which (T) is the first tap on one of the keys. 

Your mission then, should you choose to accept it, is to develop a more
efficient algorithm for key entry. User interaction is simply the 12
keys (0-9, * and #) with the letters printed on them as usual[1], and
visual feedback of what they have typed so far. Simulating algorithms
thought up by other people (e.g. LetterWise[2]) is fair game.

[ Editor's Note:

Hans sent the following code to get people started with a simple testing
inteface for their algorithms:

	class TapEvent
	  attr_reader :when, :digit
	  def initialize(digit)
	    @digit = digit
	    @when = Time.now
	  end
	  def to_s
	    @digit
	  end
	end

	class PhonePad
	  attr_reader :text, :cursor
	  def set_text(text,cursor)
	    @text = text
	    @cursor = cursor
	  end
	  def register(&block)
	    @observers.push block
	  end
	  def initialize
	    @observers = []
	    @text = ''
	    @cursor = 0
	  end
	  def notify_observers(digit)
	    if digit =~ /[0-9*#]/
	      @observers.each { |block| block.call(TapEvent.new(digit)) }
	    end
	  end
	end

	class CLIPhonePad < PhonePad
	  def initialize
	    super
	    Thread.new do
	      while not $stdin.eof? do
		$stdin.readline.split('').each { |c| notify_observers(c) }
	      end
	    end
	  end
	  def set_text(text,cursor)
	    super(text,cursor)
	    puts to_s
	  end
	  def run
	  end
	  def to_s
	    @text.dup.insert(@cursor,'_')
	  end
	end

	if $0 == __FILE__
	  p = CLIPhonePad.new

	  p.register do |ev| 
	    puts "#{ev} at #{ev.when}"
	    p.set_text(p.text+ev.digit, p.cursor+1) 
	  end

	  Thread.list[0].join
	end

Hans's code is well suited to GUI adaption, if you're so inclined.  (Please post
to Ruby Talk if you do build a GUI for this.  That's not a spoiler.)

Here's another version by me, that doesn't require you press return after the
digits:

	begin
	    require "Win32API"

	    def read_char
	        Win32API.new("crtdll", "_getch", [], "L").Call
	    end
	rescue LoadError
	    def read_char
	        system "stty raw -echo"
	        STDIN.getc
	    ensure
	        system "stty -raw echo"
	    end
	end

	loop do
		char = read_char.chr
		case char
		when /^(?:\d|\*|#)$/
			### Replace the following line with your algorithm. ###
			puts "You entered #{char}."
		when /q/i
			break
		else 
			puts "'#{char}' is not a key on the keypad."
		end
	end

-JEG2 ]

This is an area of serious research for some people[2]; don't fret it if
your algorithm isn't perfect or ideal, and don't spend too long on it. ;-) 
Make your goal to be better than dumb, which is to say be better
than "Multitap".

	1. http://www.yorku.ca/mack/uist01-f1.jpg
	2. http://www.yorku.ca/mack/uist01.html