海野秀之(うんのひでゆき)の外部記憶
Twitter (twilog) / RSS / アンテナ / ぶくま
◆ 当初答えを Web 公開するつもりなかったので、すっかり出遅れました。 Webに公開されたみなさんのを見ていると、 なんかみんなと答えが違うみたいなんですが。まちがったかな。
投稿には間に合わなかった Haskell 版:
sample_gems = [('a', 3), ('b', 1), ('c', 2)]
gems = zip "abcdefg" [1, 4, 1, 4, 2, 1, 3]
generate prefix gems len =
let
letters = gems >>= \(c, n) -> if n > 0 then [c] else []
gems' c gs =
gs >>= \(c', n) -> if c == c' then [(c', n - 1)] else [(c', n)]
in
if len > 0
then
prefix : (letters >>= \c ->
generate (prefix ++ [c]) (gems' c gems) (len-1))
else
[prefix]
sample_xs = zip [0..] (generate "" sample_gems 6)
xs = zip [0..] (generate "" gems 8)
lookup_string goal ((i,s):xs) = do
putStrLn $ (show i) ++ ":" ++ s
if s /= goal then lookup_string goal xs else putStr ""
main = lookup_string "eagcdfbe" xs
2回目に投稿した Ruby 版:
#!/usr/bin/env ruby
class GemGen
def initialize(len, prefix, gems)
@len = len
@prefix = prefix
@gems = gems
end
def i2c(i)
"abcdefg"[i]
end
def each &b
b.call(@prefix)
if @len > 0
@gems.each_with_index do |n, i|
if n > 0
subgems = @gems.dup
subgems[i] -= 1
c = i2c(i)
newprefix = "#{@prefix}#{c}"
g = GemGen.new(@len - 1, newprefix, subgems)
g.each {|str| b.call(str)}
end
end
end
end
end
Enumerator.new(GemGen.new(8, "", [1, 4, 1, 4, 2, 1, 3])).each_with_index do |s, i|
puts "#{i}:#{s}"
break if s == "eagcdfbe"
end
1回目の投稿は、長いし汚いので、気が向いたらどこかに貼ります。 いずれも、 850131 って出ました。
長さ 16 までなんですね。なぜか、16 個の宝石で、長さ 8 以下の列をつくると勘違いしてしまってました。
Haskell 版は、 xs = zip [0..] (generate "" gems 16)
Ruby 版は、 GemGen.new(16, "", [1, 4, 1, 4, 2, 1, 3])
に直せばいいだけのはずですが…やってみよう。
→でた:
$ ghc gemgen.hs [1 of 1] Compiling Main ( gemgen.hs, gemgen.o ) Linking gemgen.exe ... $ ./gemgen.exe 5578864439:eagcdfbe
Ruby 版の方はまだ実行結果でてませんが、直したものを GitHub においておきました: https://github.com/unnohideyuki/gemstring/tree/master
Generator っぽく書いたのは割と気に入っていたので、ミスってたのは残念。
あと、警告気になる。Enumerator 見よう見まねで使ってみたのに、deprecated って。
追記: 翌日になってみてみたけど、Ruby 版はまだ間違ってる。
>ruby gemgen.rb gemgen.rb:32: warning: Enumerator.new without a block is deprecated; use Object#to_enum 1283894713:eagcdfbe
なんでだろ。
5578864439 になるはずの結果が 1283894713 になってしまったのは、Fixnum の桁を超えてしまったせいなのかも。
irb(main):007:0> a = 5578864439 - 1283897143 => 4294967296 irb(main):008:0> printf "%x\n", a 100000000 => nil
今回使った Ruby は ruby 2.0.0p353 (2013-11-22) [x64-mingw32] だったのですが。
ちょっと試してみる:
enum = Enumerator.new {|x|
i = 0
loop {
x << i
i += 1
}
}
zero_occurence = 0
enum.each_with_index {|x, i|
if x != i
puts "abort: #{x} != #{i}"
exit 1
end
zero_occurence += 1 if i == 0
if zero_occurence == 2
puts "i == 0 twice"
exit 1
end
}
puts "normal end"
実行結果:
>ruby enum.rb abort: 2147483648 != -
なんか表示が変ですが。31-bit あふれたら wrap around するんかな。 意外。
→既知のバグ (#8010) で、Ruby 2.1.0 ではすでに直っていた。Ruby 2.0, Ruby 1.9 にもバックポートされるみたい。
# うんの [実行中…だけど、3時間くらいかかるのかな。 あと、Ruby の方は Ruby 2.0.0 でやったら警告でた: g..]
# うんの [GitHub にあげようと思ったら、Windows 版 git 1.8.5 のバグではまる。]
# うんの [GitHub アプリをインストールして push しました。]