```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
protected   :x, :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...8) === @x and (0...8) === @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 8)[@y] if valid?
end

def ==(c)
@x == c.x and @y == c.y
end

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 / 8) }

# 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

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

```