ESM オフラインリアルタイムどう書くの問題を解いてみた


ESM オフラインリアルタイムどう書くで出題された「行列のできるラーメン屋」という問題を解いてみた。

問題 : https://gist.github.com/mtsmfm/4b8ffb53ffac055f5843
記事 : http://mtsmfm.github.io/2015/10/22/esm-doukaku.html

このページ以外の実装例(気づいた順)は下表のとおり。

言語 URL
Ruby https://gist.github.com/mtsmfm/4f11795ad0d1bccc9d75
JavaScript https://esa-pages.io/p/sharing/1699/posts/292/fa8d0bd9f7189b9e8a3b.html
Ruby http://qiita.com/cielavenir/items/fa6e7b4e79e1673bbe05
Java https://gist.github.com/fossamagna/ab2208f767b26c301415
Haskell http://qiita.com/narinari/items/204996ac13f7d84e858b
Ruby, C++ http://qiita.com/emattsan/items/c5be573586df510eb5b7

私の実装はだいぶスクロールした下の方に書きましたよ。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

ruby2.2.3

def try_sit( chairs, cus )
  n=cus[0]
  pos = 8.times.find{ |x| (x...(x+n)).all?{ |y| chairs[y%8]==0 } }
  if pos
    (pos...(pos+n)).each{ |x| chairs[x%8]=1 }
    cus.shift
  end
end

def progress( chairs )
  chairs.size.times do |ix|
    chairs[ix] = (chairs[ix]+1) % 4 if chairs[ix]!=0
  end
end

def solve_impl( chairs, cus )
  loop do
    try_sit( chairs, cus )
    return chairs if cus.empty?
    progress(chairs)
  end
end

def solve(s)
  ch=solve_impl( [0]*8, s.chars.map( &:to_i ) )
  ch.map{ |x| x==0 ? 0 : 1 }.join
end

DATA.map do |line|
  num, src, expected = line.split( /\s+/ )
  actual = solve( src )
  ok = actual == expected
  puts [num, (ok ? "ok" : "***NG***"), src, expected, actual].join(" ")
  ok
end.all?{ |x| puts( x ? "all okay!" : "some failed" ) }

__END__
1 3316  11111110
2 3342153 11111111

テストデータの大半は省略。

30分ぐらいだったと思う。計るの忘れてましたすいません。
副作用のあるメソッドばかりで汚い感じ。これならクラスにしたほうがよかったか。

ソースコード内に 8 とか平気で書いていてすいません。マジカルな感じで。

chars と chairs が見間違えやすくて混乱するかも。

実装としては順当なつもりだけど、どうかなぁ。

C/C++ では当たり前にできる true/false を 1/0 に変換する計算が、ruby だと expr ? 1 : 0 になってしまうのが不満なんだけど、もっといい方法があるのかなぁ。

出力が2進数っぽかったので、ビット演算をして欲しいのかなと思ったんだけど、気にせず普通に計算してみた。

try_sit の中の計算がやや DRY じゃない感じ。検査のためのループと代入のためのループが同じなので、冗長かもしれない。