オフラインリアルタイムどう書くE04 の yancya の解答


Ruby で解きました

問題

方針

  • 全体の横道の数だけステップがある
  • 各ステップで、どの横道に入るかという情報のリストが石側、登山家側の両方で作れる
  • いずれかのステップで石の通る横道と被ってしまう登山家はアウト(意味深)
  • 石が全く横道に入らない場合、最初に石が落ち始めた方角にいる登山家はアウト(意味深)

コード

# coding: utf-8
LABELS = ("A".."H").to_a

def hoge(code)
  # code #=> "2512:C"

  sideways, start = code.split(":").tap { |a, b|
    break [
      a.chars.map(&:to_i).
        map { |n| [LABELS[n-1], LABELS[n % 8]].join },
      b
    ]
  }

  # sideways #=> ["BC", "EF", "AB", "BC"]
  # start    #=> "C"

  router = -> ((d, log), way) {
    if way.match(d)
      [way.gsub(d, ""), log + [way]]
    else
      [d, log + [nil]]
    end
  }

  routes = LABELS.map { |l| sideways.reverse.reduce([l, []], &router) }.to_h

  # 麓から登ったときのゴールが key、経路が value
  # routes #=> {
  #              "C" => [ nil, "AB",  nil, "BC"],
  #              "B" => ["BC",  nil,  nil, "BC"],
  #              "A" => ["BC", "AB",  nil,  nil],
  #              "D" => [ nil,  nil,  nil,  nil],
  #              "F" => [ nil,  nil, "EF",  nil],
  #              "E" => [ nil,  nil, "EF",  nil],
  #              "G" => [ nil,  nil,  nil,  nil],
  #              "H" => [ nil,  nil,  nil,  nil]
  #            }

  # 石のスタート方向がゴールになっている経路の逆順が石の経路
  danger_route = routes[start].reverse

  # danger_route #=> ["BC", nil, "AB", nil]

  routes.values.map { |route|
    route.
      zip(danger_route.reverse).
      map { |(a, b)| a && a == b ? "死" : "セーフ" }.
      index("死") ? "死" : "生"
  }.map.with_index { |judge, i| #=> ["死", "死", "死", "生", "生", "生", "生", "生"]
    LABELS[i] if judge == "生"
  }.         #=> [nil, nil, nil, "D", "E", "F", "G", "H"]
    compact. #=> ["D", "E", "F", "G", "H"]
    join.    #=> "DEFGH"
    gsub(danger_route.none? ? start : "", "") #=> "DEFGH"
end

require 'test-unit'
class MainTest < Test::Unit::TestCase
  data(
    "/*00*/" => ["2512:C", "DEFGH"],
    "/*01*/" => ["1:A", "CDEFGH"],
    "/*02*/" => [":C", "ABDEFGH"],
    "/*03*/" => ["2345:B", "AGH"],
    "/*04*/" => ["1256:E", "ABCDH"],
    "/*05*/" => ["1228:A", "ADEFG"],
    "/*06*/" => ["5623:B", "AEFGH"],
    "/*07*/" => ["8157:C", "ABDEFGH"],
    "/*08*/" => ["74767:E", "ABCFGH"],
    "/*09*/" => ["88717:D", "ABCEFGH"],
    "/*10*/" => ["148647:A", "ACDEFH"],
    "/*11*/" => ["374258:H", "BCDEFH"],
    "/*12*/" => ["6647768:F", "ABCDEH"],
    "/*13*/" => ["4786317:E", "ABFGH"],
    "/*14*/" => ["3456781:C", ""],
    "/*15*/" => ["225721686547123:C", "CEF"],
    "/*16*/" => ["2765356148824666:F", "ABCDEH"],
    "/*17*/" => ["42318287535641783:F", "BDE"],
    "/*18*/" => ["584423584751745261:D", "FGH"],
    "/*19*/" => ["8811873415472513884:D", "CFG"],
    "/*20*/" => ["74817442725737422451:H", "BCDEF"],
    "/*21*/" => ["223188865746766511566:C", "ABGH"],
    "/*22*/" => ["2763666483242552567747:F", "ABCG"],
    "/*23*/" => ["76724442325377753577138:E", "EG"],
    "/*24*/" => ["327328486656448784712618:B", ""],
    "/*25*/" => ["4884637666662548114774288:D", "DGH"],
    "/*26*/" => ["84226765313786654637511248:H", "DEF"],
    "/*27*/" => ["486142154163288126476238756:A", "CDF"],
    "/*28*/" => ["1836275732415226326155464567:F", "BCD"],
    "/*29*/" => ["62544434452376661746517374245:G", "G"],
    "/*30*/" => ["381352782758218463842725673473:B", "A"],
  )
  test "hoge" do |(actual, expected)|
    assert { hoge(actual) == expected }
  end
end