Here's my solution... This actually turned out to be relatively easy
for me, both in algorithm and programming. Simple but fun problem.
#!/usr/bin/env ruby
# Helper class
class Tile
attr_reader

, :y
protected

, :y
def initialize(x, y)
@x, @y = x, y
end
def Tile.named(s)
Tile.new(s.downcase[0] - 'a'[0], s.downcase[1] - '1'[0])
end
def valid?
(0...

=== @x and (0...

=== @y
end
def to_s
to_str
end
def to_str
%w(a b c d e f g h)[@x] + %w(1 2 3 4 5 6 7

[@y] if valid?
end
def ==(c)
@x == c.x and @y == c.y
end
def adjacent?(c)
dx = (@x - c.x).abs
dy = (@y - c.y).abs
valid? and c.valid? and (dx == 1 && dy == 2 or dx == 2 && dy == 1)
end
end
def knights_trip(start, finish, *forbidden)
# First, build big bucket o' tiles.
board = (0...64).collect { |n| Tile.new(n % 8, n /

}
# Second, pull out forbidden tiles.
board.reject! { |t| forbidden.include?(t) }
# Third, prepare a hash, where layer 0 is just the start.
# Remove start from the board.
x = 0
flood = { x => [start] }
board.delete(start)
# Fourth, perform a "flood fill" step, finding all board tiles
# adjacent to the previous step.
until flood[x].empty? or flood[x].include?(finish) do
x += 1
flood[x] = flood[x-1].inject([]) do |mem, obj|
mem.concat(board.find_all { |t| t.adjacent?(obj) })
end
# Remove those found from the board.
board.reject! { |t| flood[x].include?(t) }
end
# Finally, determine if we found a way to the finish and, if so,
# build a path.
if not flood[x].empty?
# We found a way. Time to build the path. This is built
# backwards, so finish goes in first.
path = [finish]
# Since we got to finish in X steps, we know there must be
# at least one adjancent to finish at X-1 steps, and so on.
until x == 0
x -= 1
# Find in flood[x] a tile adjacent to the head of our
# path. Doesn't matter which one. Make it the new head
# of our path.
jumps = flood[x].find_all { |t| t.adjacent?(path.first) }
path[0,0] = jumps.sort_by { rand }.first
end
# Tada!
path
end
end
# main
args = ARGV.collect { |arg| Tile.named(arg) }
if args.any? { |c| not c.valid? }
puts "Invalid argument(s)!"
else
trip = knights_trip(*args)
if trip
puts "Knight's trip: " + trip.join(", ")
else
puts "No route available!"
end
end