Skip to content

Instantly share code, notes, and snippets.

@chadbrewbaker
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chadbrewbaker/372a8075362b81c1adbf to your computer and use it in GitHub Desktop.
Save chadbrewbaker/372a8075362b81c1adbf to your computer and use it in GitHub Desktop.
Laser maze problem
#Chad Brewbaker May 10, 2014
#Laser maze problem
def get_coords(s)
return s.gsub(/[vVlLrR]/, ' ').strip.split(',').map {|i| i.to_i}.dup
end
get_coords("1,7V") != [1,7] ? abort("ERROR in get_coords") : nil
def laser_paths(line = "")
if(line =~ /RL/)
return {"N" => "W", "S"=>"N", "E" => "W", "W"=> "N"}
end
if(line =~ /RR/)
return {"N" => "S", "S"=>"E", "E" => "S", "W"=> "E"}
end
if(line =~ /LR/)
return {"N" => "E", "S"=>"N", "E" => "N", "W"=> "E"}
end
if(line =~ /LL/)
return {"N" => "S", "S"=>"W", "E" => "W", "W"=> "S"}
end
if(line =~ /L/)
return {"N" => "E", "S"=>"W", "E" => "N", "W"=> "S"}
end
if(line =~ /R/)
return {"N" => "W", "S"=>"E", "E" => "S", "W"=> "N"}
end
return {"N" => "S", "S"=>"N", "E" => "W", "W"=> "E"}
end
def consume_line(l,maze)
if(l =~ /-/ ) # SPAM
return maze
end
coords = get_coords(l)
if(l =~ /[HV]/ ) #laser
maze["Lasers"] = maze["Lasers"].push( [coords,l.dup])
return maze
end
if( l =~ /[LR]/) #mirror
maze[coords] = laser_paths(l)
return maze
end
maze["Boundary"] = coords
return maze
end
def get_laser_vectors(maze)
lasers = []
boundary = maze["Boundary"]
maze["Lasers"].each{ |l|
coords = l[0]
if(l[1] =~ /H/ )
if(boundary[0]-1 == coords[0])
lasers.push([coords.dup, "E"])
end
if(coords[0]==0)
lasers.push([coords.dup, "W"])
end
end
if(l[1] =~ /V/)
if(boundary[1]-1 == coords[0])
lasers.push([coords.dup, "N"])
end
if(coords[1]==0)
lasers.push([coords.dup, "S"])
end
end
}
return lasers
end
def opposite(direction)
h = {"N" => "S", "S"=>"N", "E" => "W", "W"=> "E"}
return h[direction]
end
opposite("N") != "S" ? abort("ERROR in opposite") : nil
def next_cell(vec,path)
h = {"N" =>[0,1] , "E" => [1,0] , "W" => [-1,0], "S" => [0,-1]}
direction = h[path[vec[1]]]
new_coord = vec[0].zip(direction).map{ |x,y| x + y }
return [ new_coord, opposite(path[vec[1]]) ]
end
next_cell([[1,1],"N"], {"N" => "S", "S"=>"N", "E" => "W", "W"=> "E"}) != [[1,0],"N"] ? abort("ERROR in next_cell") : nil
next_cell([[1,1],"E"], {"N" => "S", "S"=>"N", "E" => "W", "W"=> "E"}) != [[0,1],"E"] ? abort("ERROR in next_cell") : nil
def in_maze(coords, boundary)
if(coords[0] < 0 || coords[0] >= boundary[0])
return false
end
if(coords[1] < 0 || coords[1] >= boundary[1])
return false
end
return true
end
in_maze([0,0],[1,1]) == false ? abort("ERROR in in_maze") : nil
in_maze([1,0],[1,1]) == true ? abort("ERROR in in_maze") : nil
in_maze([0,1],[1,1]) == true ? abort("ERROR in in_maze") : nil
in_maze([-1,0],[1,1]) == true ? abort("ERROR in in_maze") : nil
in_maze([0,-1],[1,1]) == true ? abort("ERROR in in_maze") : nil
def to_hv(str)
if str =~ /[EW]/
return "H"
else
return "V"
end
end
to_hv("E") != "H" ? abort("ERROR in to_hv") : nil
to_hv("N") != "V" ? abort("ERROR in to_hv") : nil
def print_laserpos(lasers)
lasers.each{|l|
suffix = (l[1] =~ /H/ )? " Horizontal": " Vertical"
puts "Laser Start: "+ l[0][0].to_s + ", " + l[0][1].to_s + suffix
}
end
def print_laser_outputs(laser_outputs)
laser_outputs.each{|l|
suffix = (l =~ /H/ )? " Horizontal": " Vertical"
coords = get_coords(l)
puts "Exit Point: "+ coords[0].to_s + ", " + coords[1].to_s + suffix
}
end
#-- Main driver code --#
#Default to cells with no mirrors
maze = Hash.new({"N" => "S", "S"=>"N", "E" => "W", "W"=> "E"})
maze["Lasers"] = []
maze["Boundary"] = [1,1]
STDIN.read.split("\n").each do |line|
maze = consume_line(line,maze)
end
laser_vectors = get_laser_vectors(maze)
seen_vectors = {}
outputs = {}
while(laser_vectors.size > 0)
vec = laser_vectors.pop
if(maze[vec[0]])
if(seen_vectors[vec.to_s].nil?)
#only need to persist mirror paths to avoid cycles
seen_vectors[vec.to_s] = true
else
next
end
end
path = maze[vec[0]]
new_vec = next_cell(vec,path)
if(!in_maze(new_vec[0],maze["Boundary"]))
outputs[ vec[0][0].to_s + "," + vec[0][1].to_s + to_hv(new_vec[1]) ] = true
else
laser_vectors.push(new_vec)
end
end
puts "Dimensions: "+ maze["Boundary"][0].to_s + ", "+maze["Boundary"][1].to_s
print_laserpos(maze["Lasers"])
print_laser_outputs(outputs.keys.to_a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment