「ドキドキ登山」を ruby で解いた。


問題 http://mtsmfm.github.io/2016/06/04/doukaku-e04.html
実装リンク集 http://qiita.com/mtsmfm/items/6d9112fcc568908caaba
です。

とりあえず、コード。

def amida( paths, pos )
  r=[]
  paths.each.with_index(0) do |path, ix|
    cands =  [path, (path+1)%8 ]
    if cands.include? pos
      r.push ix
      pos,=cands-[pos]
    end
  end
  r
end

def can_go( stone_path, paths, x )
  walk = amida( paths.reverse, x ).map{ |x| paths.size-x-1 }
  ( walk & stone_path ).empty?
end

def solve_impl(paths, stone)
  stone_path=amida( paths, stone )
  if stone_path.empty?
    [*0..7]-[stone]
  else
    (0..7).select{ |x|
      can_go( stone_path, paths, x )
    }
  end
end

def solve( src )
  path, stone = src.split(":")
  solve_impl( path.chars.map{|x| x.to_i-1}, stone.ord - ?A.ord ).map{ |x| (x+?A.ord).chr }.join
end

$stdout.sync=true

DATA.map{ |line|
  num, src, exp = line.scan(/(\d+).*\"([^\"]*)\".*\"([^\"]*)\"/).to_a.flatten
  act = solve(src)
  okay = act==exp
  puts( "#{num} #{okay ? "ok" : "**NG**"} #{src}->#{act} / e:#{exp}" )
  okay
}.all?.tap{ |x| puts( x ? "everything is okay" : "something wrong" ) }

__END__
/*0*/ test("2512:C", "DEFGH"
/*14*/ test("3456781:C", ""
/*30*/ test("381352782758218463842725673473:B", "A"

いつも通り、テストデータの大半は省略。

当日の説明で一番反響があったのは
pos,=cands-[pos]
の部分。
これは、
pos,_ = cands-[pos]
の「_」を省略したものなので、
pos = (cands-[pos])[0]
と同等。

  • 横方向の動きのみを記録すればだいたいOK
  • しかし、石が横方向に全く動かない場合は特別扱いする必要がある
  • 石の動きと人間の動きがほぼ同じなので、どちらも「amida」で実装

という感じの実装になっている。

大変よい問題だったと思う。
私は難しめに感じたけど、会場ではそうでもない感じだった。