require 'set'

module Graph
	def add_node(data = nil)
		Node.new(data)
	end

	def add_edge(u, v, label = nil)
		e = Edge.new(u, v, label)
		u.outgoings << e
		v.incomings << e
		e
	end
	
	def del_edge(e)
		u, v = e.from, e.to
		u.outgoings.delete(e)
		v.incomings.delete(e)
		e
	end

	class Node
		def initialize(data)
			@data = data
			@outgoings = Set.new
			@incomings = Set.new
		end

		def to_nodes
			@outgoings.map(&:to)
		end

		def from_nodes
			@incomings.map(&:from)
		end
		
		def to_s
			@label
		end

		attr_accessor :incomings, :outgoings
		attr_reader :data
	end

	class Edge
		def initialize(u, v, label = nil)
			@from = u	
			@to = v
			@label = label
		end
		attr_reader :from, :to, :label
	end

	def get_path_bfs(s, t)
		return [s] if s == t
		path_edge = {}
		reached = Set[s]
		queue = [s]
		while !queue.empty? 
			u = queue.shift
			u.outgoings.each{|e|
				v = e.to
				next if reached.include?(v)	
				reached << v
				queue << v
				path_edge[v] = e

				if v == t
					path = []
					while e = path_edge[v]
						path.unshift e
						v = e.from
					end
					return path
				end
			}
		end	
		return nil
	end

	def get_path_dfs(s, t, reached = Set.new)
		return [s] if s == t
		reached << s	
		s.outgoings.each{|e|
			v = e.to
			next if reached.include?(v)
			return [e] if v == t
			
			path = get_path_dfs(v, t, reached) 
			return [e] + path if path
		}
		nil
	end

	def layers_from(start)
		reached = Set[*start]
		layers = [start]

		loop {
			layers << []
			layers[-2].each{|u|
				u.to_nodes.each{|v|
					next if reached.include?(v)
					reached << v
					layers[-1] << v
				}
			}	

			if layers[-1].empty?
				layers.pop
				return layers
			end
		}
	end

	def reachable_from(s, reached = Set.new, root = true)
		reached << s	
		s.outgoings.each{|e|
			v = e.to
			next if reached.include?(v)
			reachable_from(v, reached, false) 
		}
		root ? reached : nil
	end
end

extend Graph

loop {
	w, h = gets.split.map(&:to_i)
	break if w == 0
	a = (1..h).map{ gets.split.map(&:to_i) }
	nodes = (0..h-1).map{|i| (0..w-1).map{|j| add_node([i, j])} }

	(0..h-1).each{|i|
		(0..w-1).each{|j|
			next if a[i][j] == 1
			u = nodes[i][j]
			if j < w-1 && a[i][j+1] != 1
				v = nodes[i][j+1]
				add_edge(u, v, :right)
				add_edge(v, u, :left)
			end
			if i < h-1 && a[i+1][j] != 1
				v = nodes[i+1][j]
				add_edge(u, v, :down)
				add_edge(v, u, :up)
			end
		}
	}

	goal_node = cargo_node = pusher_node = nil
	(0..h-1).each{|i|
		(0..w-1).each{|j|
			goal_node = nodes[i][j] if a[i][j] == 3
			cargo_node = nodes[i][j] if a[i][j] == 2
			pusher_node = nodes[i][j] if a[i][j] == 4
		}
	}
	
	
	movable_dir = []
	cargo_node.outgoings.each{|e1|
		e2 = cargo_node.incomings.find{|e| e.label == e1.label}
		next unless e2
		tmp = cargo_node.outgoings
		cargo_node.outgoings = []
		movable_dir << e1.label if get_path_dfs(pusher_node, e2.from)
		cargo_node.outgoings = tmp
	}
	movable_dir

	state = [cargo_node.data, movable_dir.sort]
	queue = [state]
	push = 0
	reached = Set[state]

	success = false
	loop {
		next_queue = []
		until queue.empty?
			state = queue.pop
			i, j = state[0]
			u = nodes[i][j]
			if u == goal_node
				success = true
				break
			end
			state[1].each{|dir|
				e = u.outgoings.find{|e| e.label == dir}
				v = e.to
				movable_dir = []
				v.outgoings.each{|e1|
					e2 = v.incomings.find{|e| e.label == e1.label}
					next unless e2
					tmp = v.outgoings
					v.outgoings = []
					movable_dir << e1.label if get_path_bfs(u,e2.from)
					v.outgoings = tmp
				}
				state = [v.data, movable_dir.sort]
				next if reached.include?(state)
				reached << state
				next_queue << state
			}
		end

		break if success
		if next_queue.empty?
			push = -1
			break
		end

		queue = next_queue
		push += 1
	}
	p push
}

Measured memory_bytes: 6948