Advent of Code 2016, Day 1: No Time for a Taxicab

#ruby #advent of code 2016

Part A

Day 1 we are walking around city grid in search of Easter Bunny Headquarters.

Our input specifies the list of moves we need to perform and each move consists of turning left or right and then moving forward a given number of steps.

Our input looks like this:

R5, L5, R5, R3

Our first task is to output how many blocks away we will be after performing all these moves. Below you can find my solution:

moves = File.read("1.txt").strip.split(", ")
@headings = [
  [0, 1],  # north
  [1, 0],  # east
  [0, -1], # south
  [-1, 0]  # west
]

index = 0

sum = moves.map do |move|
  direction = move[0]
  count = move[1..].to_i
  index = direction == "R" ? index + 1 : index - 1
  heading = @headings[index % 4]

  [heading[0] * count, heading[1] * count]
end.reduce do |acc, move|
  [acc[0] + move[0], acc[1] + move[1]]
end

puts sum.map(&:abs).sum

@headings array contains the offsets from current position for each direction. First index is offset when moving north, then east, south and west. If we move from index 0 to index 1, so from north to east we turn right. Similarly if we decrease index we turn left.

If we multiple the offset by number of steps we will have to full movement. In our first loop we are mapping the list of moves into the list of offsets. And in the second loop we are adding them all together.

In the end we will have all the moves represented as one offset from our initial position and we need to calculate the distance using Manhattan distance. This is just a sum of differences for both x and y.

Part B

In the second part we need to calculate the distance to the first position visited twice. So we need to actually keep track of visited positions and then stop if we visit one again. Below is my solution:

moves = File.read("1.txt").strip.split(", ")
@headings = [
  [0, 1],
  [1, 0],
  [0, -1],
  [-1, 0]
]

index = 0
position = [0, 0]
visited = {}

moves.each_with_index do |move, step|
  direction = move[0]
  count = move[1..].to_i
  index = (direction == "R" ? index + 1 : index - 1) % 4
  heading = @headings[index]

  count.times do
    position = [position[0] + heading[0], position[1] + heading[1]]

    if !visited[position]
      visited[position] = step
    else
      puts position.map(&:abs).sum
      return
    end
  end
end

Now we need to store each location visited, so we need to move in 1 unit steps to do that. At first I did the same as in Part A, I was doing hops and got incorrect results. We store all visited positions in visited hash and when we reach the same position again we need to output it’s distance from the start.