Skip to content

Instantly share code, notes, and snippets.

@MrAlexLau
Created August 10, 2013 17:37
Show Gist options
  • Save MrAlexLau/6201331 to your computer and use it in GitHub Desktop.
Save MrAlexLau/6201331 to your computer and use it in GitHub Desktop.
A simple solution to the "robots vs lasers" puzzle
#a simple solution to the "robots vs lasers" puzzle
#see http://www.puzzlenode.com/puzzles/4-robots-vs-lasers
#usage:
#simply run this program with ruby and pass the input file name as the sole argument
#example: ruby robots.rb sample-input.txt
#########################################################
#just use a structure since we only need to hold data
#could use a class but it'd be overkill for this example
FactoryLine = Struct.new :north_lasers, :conveyor_belt, :south_lasers
def read_input(filename)
factory_floor = []
factory_line = FactoryLine.new()
i = 0
#open the file and read the factory floor input
#each factory floor is made of many factory lines
#each factory line has 4 lines of text:
# 1. the north lasers
# 2. the conveyor belt
# 3. the south lasers
# 4. a blank line separating it from the next factory line
# example:
# #|#|#|##
# ---X----
# ###||###
File.open(filename).each_line{ |line|
#i mod 4 since there is a new factory line after every 4 lines of input
if (i % 4) == 0
factory_line[:north_lasers] = line.strip!
elsif (i % 4) == 1
factory_line[:conveyor_belt] = line.strip!
elsif (i % 4) == 2
factory_line[:south_lasers] = line.strip!
factory_floor << factory_line #append the line to the factory floor array
factory_line = FactoryLine.new()
end
i += 1
}
return factory_floor
end
#put this check in a function so it's easier to test
def get_position(conveyor_belt)
return conveyor_belt.index("X")
end
#calculate the total number of hits on the robot
#given a laser array (north or south), where the robot is, and if it's going east or west
def number_of_hits(laser_array, robot_position, east_west, north_south)
number_of_hits = 0
if east_west == :west
click = 0
#count from the current position down to the west-most position (aka lowest index)
for i in robot_position.downto(0)
# if the current index has a laser, check to see if it shoots
if laser_array[i] == "|"
if north_south == :north and click.even?
#the lasers shoot from the north side on even clicks
number_of_hits += 1
elsif north_south == :south and click.odd?
#the lasers shoot from the south side on odd clicks
number_of_hits += 1
end
end
click += 1
end
elsif east_west == :east
click = 0
# if the current index has a laser, check to see if it shoots
for i in robot_position.upto(laser_array.length - 1)
if laser_array[i] == "|"
if north_south == :north and click.even?
#the lasers shoot from the north side on even clicks
number_of_hits += 1
elsif north_south == :south and click.odd?
#the lasers shoot from the south side on odd clicks
number_of_hits += 1
end
end
click += 1
end
end
return number_of_hits
end
#calculate and print which directions the robot should take
#based on its current position in the factory line
def get_direction(factory_line)
robot_position = get_position(factory_line[:conveyor_belt])
hits_east = 0
hits_west = 0
#calculate the hits going east
hits_east = number_of_hits(factory_line[:north_lasers], robot_position, :east, :north) + number_of_hits(factory_line[:south_lasers], robot_position, :east, :south)
#calculate the hits going west
hits_west = number_of_hits(factory_line[:north_lasers], robot_position, :west, :north) + number_of_hits(factory_line[:south_lasers], robot_position, :west, :south)
#return EAST if number of hits going east
#is larger than the number of hits going west
if hits_east < hits_west
return "GO EAST"
end
#otherwise return WEST if hits_west is greater
#or the 2 are equal
return "GO WEST"
end
#actually run the program here
#read the input file and print the directions
factory_floor = read_input(ARGV[0])
factory_floor.each do |factory_line|
puts get_direction(factory_line)
end
#test methods
raise "get_position test 1 failed" unless (get_position("--X---") == 2)
raise "get_position test 2 failed" unless (get_position("X------") == 0)
raise "get_position test 3 failed" unless (get_position("----X") == 4)
raise "number_of_hits test 1 failed" unless (number_of_hits("#|#|#|##", 3, :west, :north) == 2)
raise "number_of_hits test 2 failed" unless (number_of_hits("###||###", 3, :west, :north) == 1)
raise "number_of_hits test 3 failed" unless (number_of_hits("#|#|#|##", 2, :east, :south) == 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment