さて、3 日目。今日は 12/5 だが・・・ サンタを乗せた宇宙船はスイングバイに無事成功し、一路金星へ向かっているようだ。 ただ、あわてんぼうのサンタクロースさんはとても慌てていたようで、燃料管理システムが完全にはインストールされていなかったようだ。 そんなわけで、そいつをやる。

https://adventofcode.com/2019/day/2

3 日目: Crossed Wires

1 問目: パネルを開けたら、そこは、ワイヤーの天国でした。

制御ボードを開けてみるとごちゃごちゃしたワイヤーが見える。 これらのワイヤーは片方は必ず中央ポートに、もう片方はグリッドの外へと繋がっている。 また、ワイヤーは折れ曲がって繋がっている。 例えば、下記のようにワイヤーのパスが定義されているとすると

R8,U5,L5,D3

これは、ワイヤーが中央ポートから始まって右へ 8 、上へ 5 、左へ 5 、下へ 3 進み、そこからグリッドの外へと繋がっている。

こんな風に複数のワイヤーが制御ボード上へ配置されているわけだが、これらのワイヤーは時たま交差する。

燃料管理システムを完璧なものにするためには、中央ポートから最も近い交差地点を見つけ、中央ポートとの マンハッタン距離 を 算出する必要がある。

まず、テスト用のファイルを用意する。

R75,D30,R83,U83,L12,D49,R71,U7,L72
U62,R66,U55,R34,D71,R55,D58,R83

移動用の数字をパースするプログラムを書いて行こう。 まずはいつも通り、標準入力から定義を読み込む部分を作る。

#! /usr/bin/env ruby

def cordinates(directions)
  directions
end

while l = gets
  directions = l.strip.split(",")
  p cordinates(directions)
end

次に、cordinates メソッドを実装していく。 こいつは入力を基に、ワイヤーが通過する座標を列挙した配列を返すメソッドにする予定だ。

まずは、方向指示をパースしよう。こんな風にできる。

direction, magnitude = d[0], d[1,d.length()-1].to_i

後は、方向を考慮して、ただひたすら、座標を記録していくだけだ。 実装はこんな感じになる。

#! /usr/bin/env ruby

def cordinates(directions)
  cordinates = []
  current = [0, 0]
  directions.each do |d|
    direction, magnitude = d[0], d[1,d.length()-1].to_i
    case direction
    when "U"
      magnitude.times do
        current[1] += 1
        cordinates << current.dup
      end
    when "R"
      magnitude.times do
        current[0] += 1
        cordinates << current.dup
      end
    when "D"
      magnitude.times do
        current[1] -= 1
        cordinates << current.dup
      end
    when "L"
      magnitude.times do
        current[0] -= 1
        cordinates << current.dup
      end
    else
      STDERR.puts = "UNKNOWN DIRECTION :" + d
    end
  end
  cordinates
end

while l = gets
  directions = l.strip.split(",")
  p cordinates(directions)
end

動かしてみると、まぁいい感じになっている。

% cat test1.tsv| ./ans1.rb
[[1, 0], [2, 0], ...(中略)..., [74, 0], [75, 0], [75, -1] ...(後略)

後は、2つのワイヤーから、共通する座標を抜き出せばそれで良い。

ruby の場合、2つの配列で & をとればすぐに抜き出せる。

共通する座標の原点とのマンハッタン距離の最小値を出すとこんな感じになる。

paths = []

while l = gets
  directions = l.strip.split(",")
  paths << cordinates(directions)
end

cross = paths[0] & paths[1]

p cross.map{|c| c[0].abs + c[1].abs }.min

試してみよう。

% cat test1.tsv| ./ans1.rb
159

いい感じ。

これで制御ボード上で、最も中央ポートに近い交差地点がわかった。

2 問目: アラートの原因はなんだったのか。

さて、次は交差地点へのステップ数を求めなきゃいけないらしい。

ここまで出来てればほとんど出来上がったようなもんです。

crosses = paths[0] & paths[1]

steps = corsses.map{|c| paths[0].index(c) + paths[1].index(c) + 2 }

p steps.min

こいつも動きを試してみると・・・

% cat test1.tsv| ./ans1.rb
610

うん。出来た。