1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RubyKaigi 2019 Cookpad Daily Ruby Puzzles を全パターン試して解く

Last updated at Posted at 2019-05-02

RubyKaigi 2019のクックパッドブースで"Cookpad Daily Ruby Puzzles"というのをやっていたらしくて、イベント終了後に正解と解説というエントリーも出ていました。

RubyKaigi 2019 Cookpad Daily Ruby Puzzles の正解と解説

この問題、結果的には全て問題のコードに1文字を追加するだけで解けるらしいので、全パターン試して解くという方法を試してみました。こんなコードです。

solv.rb
CODES = {}

CODES["Example"] = <<'EOS'
def foo
  "Hello world" if
       false
end
puts foo
EOS

CODES["Problem 1-1"] = <<'EOS'
# Hint: Use Ruby 2.6
puts "#{"Goodbye" .. "Hello"} world"
EOS

CODES["Problem 1-2"] = <<'EOS'
puts&.then {
  # Hint: &. is a safe
  # navigation operator
  "Hello world"
}
EOS

CODES["Problem 1-3"] = <<'EOS'
include Math
# Hint: the most beautiful equation
Out, *,
     Count = $>,
             $<, E ** (2 * PI)
Out.puts("Hello world" *
         Count.abs.round)
EOS

CODES["Problem 2-1"] = <<'EOS'
def say
  -> {
    "Hello world"
  }
  # Hint: you should call the Proc.
  yield
end

puts say { "Goodbye world" }
EOS

CODES["Problem 2-2"] = <<'EOS'
e = Enumerator.new do |g|
  # Hint: Enumerator is
  # essentially Fiber.
  yield "Hello world"
end

puts e.next
EOS

CODES["Problem 2-3"] = <<'EOS'
$s = 0
def say(n = 0)
  $s = $s * 4 + n
end

i, j, k = 1, 2, 3

say i
say j
say k

# Hint: Binary representation.
$s != 35 or puts("Hello world")
EOS

CODES["Problem 3-1"] = <<'EOS'
def say s="Hello", t:'world'
  "#{ s }#{ t } world"
end
# Hint: Arguments in Ruby are
# difficult.

puts say :p
EOS

CODES["Problem 3-2"] = <<'EOS'
def say s, t="Goodbye "
  # Hint: You can ignore a warning.
  s = "#{ s } #{ t }"
  t + "world"
end

puts say :Hello
EOS

CODES["Problem 3-3"] = <<'EOS'
def say
  "Hello world" if
    false && false
  # Hint: No hint!
end

puts say
EOS

CODES["Extra 1"] = <<'EOS'
Hello = "Hello"

# Hint: Stop the recursion.
def Hello
  Hello() +
    " world"
end

puts Hello()
EOS

CODES["Extra 2"] = <<'EOS'
s = ""
# Hint: https://techlife.cookpad.com/entry/2018/12/25/110240
s == s.upcase or
  s == s.downcase or puts "Hello world"
EOS

CODES["Extra 3"] = <<'EOS'
def say
  s = 'Small'
  t = 'world'
  puts "#{s} #{t}"
end

TracePoint.new(:line){|tp|
  tp.binding.local_variable_set(:s, 'Hello')
  tp.binding.local_variable_set(:t, 'Ruby')
  tp.disable
}.enable(target: method(:say))

say
EOS


require 'timeout'

CHARS =
  ('0'..'9').to_a +
  ('a'..'z').to_a +
  ('A'..'Z').to_a +
  %w( ! ? # % & | + - * / ^ ' . , < > = ~ $ @ _ " : ` \\ ; ) +
  [' ', "\n", "Dz"]

CODES.each do |name, code|
  puts
  puts "#{name}"
  puts Time.now
  (0...code.length).each do |i|
    putc '.'
    CHARS.each do |char|
      code_inserted = code.clone.insert(i, char)
      File.open("code.rb", "w") { |f| f.puts(code_inserted) }
      begin
        Timeout.timeout(1) do
          result = `ruby code.rb 2>/dev/null`
          if result == "Hello world\n"
            puts
            puts '-----'
            puts code_inserted
            puts '-----'
          end
        end
      rescue Timeout::Error
      end
    end
  end
  puts
  puts Time.now
end

このコードと、実行結果はgistに置いておきました。

最初はevalでコードを実行して試していたのですが、evalで実行した結果、たとえば!を再定義してしまって、次のループでの実行結果に影響を及ぼすことがあったりして、別ファイルにしてバッククオートでrubyコマンドで実行することにしました。

正解と解説に書いてありますが、"Problem 1-3"には「ブルートフォースよけ」が仕込まれています。まんまとはまってしまいました。Timeout.timeout(1) do ... endで囲って、一秒以上かかる場合は諦めるようにしました。

CHARSには数字、アルファベット、記号、空白文字、改行文字、そして"Dz"を入れています。"Dz"は"Extra 2"のためだけに入れました。。。("Extra 2"はヒントがなければ全パターン試したつもりでも解けませんね。。。)

全パターン試して解こうと思ったモチベーションの1つは、別解を見つけることだったのですが、"Example"以外は別解が見つかりませんでした。"Example"の別解は、if !falseの代わりにif :falseを使うというものです。ただ、"Example"は解答が発表されているわけではないので、厳密には別解というわけではないですね。別解が見つからないということは、問題作成者の方も私がやったような全パターンを試すスクリプトを書いて事前に確認しているのだと思います。

"Extra 3"は1文字解答が2つあるらしいのですが、まだ解答が1つしか見つかっていません。全パターン試しているはずなのに、なんででしょうかね。。。

(追記:2019/05/03 08:07)
コードにミスがありました。バックスラッシュ(\)とセミコロン(;)を別々の文字列にしたかったのに、\ ;と書いていて、空白とセミコロンの2文字の文字列ということになっていました。\\ ;に書き換えました。それにより、"Extra 3"の2つ目の1文字解答も見つけることができました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?