Madogiwa Blog

主に技術系の学習メモに使っていきます。

RubyKaigi 2019 Cookpad Daily Ruby Puzzlesを解いてみたので自分の解答をメモ

みなさん、こんにちは。まどぎわです(・∀・)
RubyKaigiでCookpadさんのブースで出題されていたRuby Puzzleを、Ruby Kaigi中に楽しくやっていたので、 解答も下記で公開されたので、自分の解答をメモしておきます。

techlife.cookpad.com

Day 1

Problem 1-1

# Hint: Use Ruby 2.6.
puts "#{"Goodbye" .. "Hello"} world"

My Answer(2文字)

puts "#{"Goodbye" .. && "Hello"} world"

HintにあるようにRuby2.6から追加された終端なしRangeを使って、 "Hello"だけを返せればいいのかなと思ったので&&を使ってみました。

www.ruby-lang.org

Problem 1-2

puts&.then {
  # Hint: &. is a safe
  # navigation operator.
  "Hello world"
}

My Answer(2文字)

puts 1&.then {
  # Hint: &. is a safe
  # navigation operator.
  "Hello world"
}

これはputsの返り値が、nilになってしまってthen以降が実行されなくなっていたので、 puts 1&.thenとして、putsの返り値を使用しないようにしてました。

Problem 1-3

include Math
# Hint: the most beautiful equation
Out, *,
     Count = $>,
             $<, E ** (2 * PI)
Out.puts("Hello world" *
         Count.abs.round)

My Answer (2文字)

include Math
# Hint: the most beautiful equation
Out, *,
     Count = $>,
             $<, E ** (2 * PI*0)
Out.puts("Hello world" *
         Count.abs.round)

Countが1に近い値になれば、"Hello world"が1回実行されるので、 E ** (2 * PI*0)として、1に近い値を作りました。

Day 2

Problem 2-1

def say
  -> {
    "Hello world"
  }
  # Hint: You should call the Proc.
  yield
end

puts say { "Goodbye world" }

My Answer(1文字)

def say
  -> {
    "Hello world"
  }.
  # Hint: You should call the Proc.
  yield
end

puts say { "Goodbye world" }

これは.yield.callと同じなので、それを使うようにしました。

docs.ruby-lang.org

Problem 2-2

e = Enumerator.new do |g|
  # Hint: Enumerator is
  # essentially Fiber.
  yield "Hello world"
end

puts e.next

My Answer(2文字)

e = Enumerator.new do |g|
  # Hint: Enumerator is
  # essentially Fiber.
  g.yield "Hello world"
end

puts e.next

gEnumerator::Yielderが返却される。

docs.ruby-lang.org

そして検索してたら下記のようなページを発見し、g.yieldと書けそうなことがわかったのでそれを使いました。

qiita.com

Problem 2-3

$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")

My Answer(2文字)

$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+8 != 35 or puts("Hello world")

$sが27を返すので、35となるように+8しました。

Day 3

Problem 3-1

def say s="Hello", t:'world'
  "#{ s }#{ t } world"
end
# Hint: Arguments in Ruby are
# difficult.

puts say :p

My Answer(1文字)

def say s="Hello", t:'world'
  "#{ s }#{ t } world"
end
# Hint: Arguments in Ruby are
# difficult.

puts say t:p

pの返り値はnilなので、s="Hello", t:nilとなり、"Hello world"が出力されます。

Problem 3-2

def say s, t="Goodbye "
  # Hint: You can ignore a warning.
  s = "#{ s } #{ t }"
  t + "world"
end

puts say :Hello

My Answer(3文字)

def say s, t="Goodbye "
  # Hint: You can ignore a warning.
  st = "#{ s } "#{ t }"
  st + "world"
end

puts say :Hello

ここは最初say :Hello,pのような形でいけるかと思ったのですが、 :Helloはsymbolのため+メソッドが使えないのです。。。

なので、st = "#{ s } "とすることで、stに"Hello"だけが入るようにして、 st + "world"として"Hello world"となるようにしました。

Problem 3-3

def say
  "Hello world" if
    false && false
  # Hint: No hint!
end

puts say

My Answer(2文字)

def say
  "Hello world" if
    :false && :false
  # Hint: No hint!
end

puts say

これは単純で、falsetrueになるようにすればいいので、 !falseと思ったのですが、それだとあまりにもと思ったので:falseにしました。

Extra Stage

Ruby Kaigi後に出題されたExtra Stageについてもやってみたので、解答をメモしておきます✍

"Cookpad Daily Ruby Puzzles" in RubyKaigi 2019 - Extra Stage · GitHub

⚠️⚠️⚠️ここからは解答がまだ発表されていないので、ネタバレ注意です⚠️⚠️⚠️























Problem Extra-1

Hello = "Hello"

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

puts Hello()

My Answer(2文字)

Hello = "Hello"

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

puts Hello()

これはHintの通り、メソッド呼び出しを止めればいいので、Hello+#() +として、変数側のHelloを参照するようにしました。

Problem Extra-2

s = ""
# Hint: https://techlife.cookpad.com/entry/2018/12/25/110240
s == s.upcase or
  s == s.downcase or puts "Hello world"

My Answer(1文字)

s = "Dz"
# Hint: https://techlife.cookpad.com/entry/2018/12/25/110240
s == s.upcase or
  s == s.downcase or puts "Hello world"

これはHintのURLを参考したら該当文字Dzが載っていたので、それを使うようにしました。

Problem Extra-3

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

My Answer(2文字)

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

tp.disableコメントアウトしたところ"Hello Ruby"が返されるようになったので、 tp.binding.local_variable_set(:s, 'Hello')だけが実行されるようにしました。

おわりに

Cookpadさんの問題が、面白すぎてセッションに集中出来なかった部分もありますが・・・笑
問題に取り組むなかで、マニュアルを読んだり、いろいろ調べたりするなかで、 rubyのイディオムやリテラル周りの知識が見について非常に勉強になりました🙌

来年のRuby Kaigiでは、もっといい感じの答えが出せるように頑張ろう💪