More logical programming in Ruby: solving Einstein's riddle (Zebra puzzle)
The Zebra puzzle is a well-known logic puzzle often attributed to Albert Einstein, who is said to have invented it as a boy. The legend goes that he claimed that "only 2% of the world's population can solve this".
Here's how to solve it without leaving Ruby with this
tiny Prolog interpreter*1. There are a few variants of the riddle; the code below solves this one
(based on the code left by an anonymous reader Gordon in a comment on that page, with
little modifications to make it work):
require 'tiny_prolog_ext' def _ (@anonymous_var = (@anonymous_var ||= "S_00000").succ).intern end member[:Z, cons(_,:L)] <<= member[:Z, :L] member[:Z, cons(:Z,_)].fact #query member[:X, list(1,2,3,4,5)] next_to[:X, :Y, :List] <<= iright[:X, :Y, :List] next_to[:X, :Y, :List] <<= iright[:Y, :X, :List] iright[:L, :R, cons(:L, cons(:R , _ ))].fact iright[:L, :R, cons(_ , :Rest)] <<= iright[:L, :R, :Rest] einstein[:Houses, :Fish_Owner] <<= [ eq[:Houses, list(list('house', 'norwegian', _, _, _, _), _, list('house', _, _, _, 'milk', _), _, _)], member[list('house', 'brit', _, _, _, 'red'), :Houses], member[list('house', 'swede', 'dog', _, _, _), :Houses], member[list('house', 'dane', _, _, 'tea', _), :Houses], iright[list('house', _, _, _, _, 'green'), list('house', _, _, _, _, 'white'), :Houses], member[list('house', _, _, _, 'coffee', 'green'), :Houses], member[list('house', _, 'bird', 'pallmall', _, _), :Houses], member[list('house', _, _, 'dunhill', _, 'yellow'), :Houses], next_to[list('house', _, _, 'dunhill', _, _), list('house', _, 'horse', _, _, _), :Houses], member[list('house', _, _, _, 'milk', _), :Houses], next_to[list('house', _, _, 'marlboro', _, _), list('house', _, 'cat', _, _, _), :Houses], next_to[list('house', _, _, 'marlboro', _, _), list('house', _, _, _, 'water', _), :Houses], member[list('house', _, _, 'winfield', 'beer', _), :Houses], member[list('house', 'german', _, 'rothmans', _, _), :Houses], next_to[list('house', 'norwegian', _, _, _, _), list('house', _, _, _, _, 'blue'), :Houses], member[list('house', :Fish_Owner, 'fish', _, _, _), :Houses] ] query einstein[:Houses, :Fish_Owner]
If you run it, you'll get as expected:
$ ruby einstein.rb
1 einstein[(("house" "norwegian" "cat" "dunhill" "water" "yellow")
("house" "dane" "horse" "marlboro" "tea" "blue")
("house" "brit" "bird" "pallmall" "milk" "red")
("house" "german" "fish" "rothmans" "coffee" "green")
("house" "swede" "dog" "winfield" "beer" "white")), "german"]
(slightly reformatted for clarity)
Yes, it's fairly slow, but still interesting.
No Title - Gordon Thiesfeld (2007-02-24 (Sat) 18:12:00)
Wow! I wasn't really expecting a reply, let alone such a fast one. This does run slower (~ 1 minute on my laptop) than in swi-prolog (~2 seconds), but it is lightyears faster than anything I've come up with so far (~ never finished) :)
mfp 2007-02-25 (Sun) 11:47:21
I happened to see your comment when I needed a mental break :)
Actually, I'd have expected the performance to be worse... 1/30x against a specialized interpreter is not bad at all for a very simple, unoptimized Ruby implementation...
lv 2007-02-25 (Sun) 17:29:54
I use "zebra" to roughly gauge how fast a language is. Swi runs zebra in 90 milliseconds on my computer.
mfp 2007-02-26 (Mon) 03:28:10
I'm getting 70ms w/ swi-prolog vs. ~25s with the Ruby interpreter, 350x slower. That's more in line with my expectations.
*1 download the required tiny_prolog.rb and tiny_prolog_ext.rb from that page
- 480 http://www.dzone.com/rsslinks/more_logical_programming_in_ruby_solving_einstein.html
- 198 http://www.dzone.com
- 48 http://anarchaia.org
- 27 http://www.urubatan.com.br/2007/07/13/code-contest-valendo-uma-cortesia-para-o-just-java-2007
- 24 http://www.artima.com/forums/flat.jsp?forum=123&thread=196721
- 24 http://www.railscn.com/about3293.html
- 21 http://planet.perl.org
- 20 http://www.dzone.com/links/rss/more_logical_programming_in_ruby_solving_einstein.html
- 18 http://www.urubatan.com.br/code-contest-valendo-uma-cortesia-para-o-just-java-2007
- 16 http://planetruby.0x42.net
Keyword(s):[blog] [ruby] [frontpage] [logic] [programming] [prolog] [riddle] [einstein]
References:[Ruby interpreting Prolog' interpreting Lisp interpreting Lisp solving FizzBuzz] [Logic programming in Ruby: a tiny prolog interpreter and symbolic computation]