Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
move = function (n, x, y, z)
    if n == 1 then
      return n..x..y
    else
      return move(n-1, x, z, y) ..
             n..x..y ..
             move(n-1, z, y, x)
    end
  end

disco = function (pos, n) return string.sub(pos, n, n) end
valido_h = function (pos, n, x, y)
    return disco(pos, n) == x
  end
valido_v = function (pos, n, x, y)
    for i=1,n-1 do
      if disco(pos, i) == x or disco(pos, i) == y then
        return false
      end
    end
    return true
  end
splitmovs = function (movs) return split(movs, "(...)") end
splitmov = function (mov)
    local n = tonumber(string.sub(mov, 1, 1))
    local x = string.sub(mov, 2, 2)
    local y = string.sub(mov, 3, 3)
    return n, x, y
  end
aplica1 = function (pos, n, x, y)
    return string.sub(pos, 1, n-1) .. y .. string.sub(pos, n+1)
  end
aplica = function (pos, movs, pr)
    for i,mov in ipairs(splitmovs(movs)) do
      if not valido_h(pos, splitmov(mov)) then error(pos.." "..mov..": bad h") end
      if not valido_v(pos, splitmov(mov)) then error(pos.." "..mov..": bad v") end
      if pr then print(pos, mov) end
      pos = aplica1(pos, splitmov(mov))
    end
    if pr then print(pos) end
    return pos
  end

--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "hanoi.lua"
= move(4, "a", "b", "c")
= disco("aaaaaa", 1)
= aplica("aaaaaa", move(4, "a", "b", "c"))

--]]