module Graphical
	require 'set'

	def reachable_from(s, max_depth = nil)
		reached = Set[s]
		queue = [s]
		depth = 0
		loop {
			break if max_depth && depth >= max_depth
			next_queue = []
			until queue.empty?
				u = queue.shift
				each_out_connection_of(u){|v, _|
					next if reached.include?(v)
					reached << v
					next_queue << v
				}
			end
			break if next_queue.empty?
			queue = next_queue
			depth += 1
		}
		return reached
	end

	def bfs(start)
		raise "start must be Enumerable" if !start.kind_of?(Enumerable)
		reached = Set[*start.to_a]
		queue = []
		start.each{|s| queue << s}
		dist = {}
		loop.with_index {|_, depth|
			next_queue = []
			until queue.empty?
				u = queue.shift
				dist[u] = depth
				each_out_connection_of(u){|v, _|
					next if reached.include?(v)
					reached << v
					next_queue << v
				}
			end
			break if next_queue.empty?
			queue = next_queue
		}
		return dist
	end
	
	def dijkstra(start)
		raise "start must be Enumerable" if !start.kind_of?(Enumerable)
		h = Heap.new
		reached = Set[*start.to_a]
		start.each{|s| h.add(s, 0)}

		dist = {}
		until h.empty?
			u, key = h.del_min
			return key if block_given? && yield(u, key)
			dist[u] = key
			each_out_connection_of(u){|v, l|
				d = dist[u] + l
				if reached.include?(v)
					h.update_key(v, d)
				else
					h.add(v, d)
					reached << v
				end
			}
		end
		block_given? ? nil : dist
	end

	def bidir_dijkstra(s, t)
		f_dist = {}
		b_dist = {}

		f_heap = Heap.new
		b_heap = Heap.new

		f_heap.add(s, 0)
		b_heap.add(t, 0)

		f_reached = Set[s]
		b_reached = Set[t]

		f_current_dist = b_current_dist = 0
		best = Float::INFINITY

		loop {
			if !f_heap.empty?
				u, key = f_heap.del_min
				f_dist[u] = key
				f_current_dist = key
				each_out_connection_of(u){|v, l|
					d = f_dist[u] + l
					if b_dist[v]
						path_len = d + b_dist[v]
						best = path_len if path_len < best
					end
					if f_reached.include?(v)
						f_heap.update_key(v, d)
					else
						f_heap.add(v, d)
						f_reached << v
					end
				}
			end

			if !b_heap.empty?
				u, key = b_heap.del_min
				b_dist[u] = key
				b_current_dist = key
				each_in_connection_of(u){|v, l|
					d = b_dist[u] + l
					if f_dist[v]
						path_len = d + f_dist[v]
						best = path_len if path_len < best
					end
					if b_reached.include?(v)
						b_heap.update_key(v, d)
					else
						b_heap.add(v, d)
						b_reached << v
					end
				}
			end

			return best if f_current_dist + b_current_dist >= best
			return nil if f_heap.empty? && b_heap.empty?
		}
	end

	def a_star(start)
		raise "a_star need termination condition" unless block_given?
		h = Heap.new
		reached = Set[start]
		h.add(start, [a_star_heuristic(start), 0])

		dist = {}
		until h.empty?
			u, (e, d) = h.del_min
			return d if yield(u, dist)
			dist[u] = d
			each_out_connection_of(u){|v, l|
				d = dist[u] + l
				e = d + a_star_heuristic(v)
				if reached.include?(v)
					h.update_key(v, [e, d])
				else
					h.add(v, [e, d])
					reached << v
				end
			}
		end
		block_given? ? nil : dist
	end

	#make_variations :bidir_dijkstra

	def prim(start)
		h = Heap.new
		h.add(start, 0)
		reached = Set[start]
		tree_len = 0

		until h.empty?
			u, key = h.del_min
			tree_len += key

			each_connection_of(u){|v, d|
				if reached.include?(v)
					h.update_key(v, d)
				else
					h.add(v, d)
					reached << v
				end
			}
		end
		tree_len
	end
end

extend Graphical

w, h = gets.split.map &:to_i
$a = (1..h).map{ gets.chomp.split("") }

def each_out_connection_of(u)
	i, j = u
	[[-1,0],[1,0],[0,-1],[0,1]].each{|dy, dx|
		y, x = i+dy, j+dx
		yield [[y, x], 1] if (0..$a.size-1) === y && (0..$a[0].size-1) === x && $a[y][x] !~ /[#*]/
	}
end

start = goal = nil

tiles = []
(1..h-2).each{|i|
	(1..w-2).each{|j|
		start = [i,j] if $a[i][j] == ?s
		goal = [i,j] if $a[i][j] == ?g
		tiles << [i,j] if $a[i][j] !~ /[#*g]/
	}
}

dist = bfs([goal])

springs = Set.new 
(1..h-2).each{|i|
	(1..w-2).each{|j|
		next if $a[i][j] == ?#
		springs << [i,j] if $a[i][j] == ?*
	}
}

def each_out_connection_of(u)
	i, j = u
	[[-1,0],[1,0],[0,-1],[0,1]].each{|dy, dx|
		y, x = i+dy, j+dx
		yield [[y, x], 1] if (0..$a.size-1) === y && (0..$a[0].size-1) === x && $a[y][x] != ?#
	}
end

to_spring = bfs(springs)

if !to_spring[start]
	puts dist[start]
	exit
end

tiles.select!{|v| dist[v] || to_spring[v]}
tiles1, tiles2 = tiles.partition{|v| dist[v]}

s2 = tiles2.map{|v| to_spring[v]}.inject(0, :+)

e_min = 0
e_max = 1e20

loop.with_index {|_, itr|
	e_center = (e_min + e_max) / 2.0

	tiles1, tiles3 = tiles1.partition{|v|
		!to_spring[v] || dist[v] < to_spring[v] + e_max
	}
	s2 += tiles3.map{|v| to_spring[v]}.inject(0, :+)
	tiles2 += tiles3

	s1 = 0
	tiles1.each{|v|
		if !to_spring[v]
			s1 += dist[v]
		else 
			x = dist[v]
			y = to_spring[v] + e_center
			s1 += (x < y ? x : y)
		end
	}
	exp = (s1 + s2 + tiles2.size * e_center) / tiles.size.to_f

	break if (e_center - exp).abs / exp < 1e-15
	if e_center < exp
		e_min = exp
	else
		e_max = exp
	end
}

printf("%.11f\n", 
	[
		dist[start] || Float::INFINITY,
		(to_spring[start] || Float::INFINITY) + e_min
	].min)

Measured memory_bytes: 228084