かけっこのパズル(Ruby)

qiita.com
 

問題

一郎、二郎、三郎の三人で駆けっこをして、その結果を次のように言っています。
 
一郎:「僕は一番じゃない」
二郎:「僕は一番だ」
三郎:「僕は二番だ」

三人のなかで一人だけウソをついています。それは誰でしょう?
 

Ruby で解いてみた

総当りで解いています。
0, 1, 2 でそれぞれ一郎、二郎、三郎を表しています。

names = %W(一郎 二郎 三郎)
(0..2).each do |usotsuki|    #嘘つきを選びます
  table = [-1, 1, 2]    #与えられた条件(否定は負にします)
  #嘘をつかせます
  table[usotsuki] = -table[usotsuki]
  #可能性のある順位を配列にします
  tmp = table.map { _1 < 0 ? [1, 2, 3] - [-_1] : [_1] }
  #順位を総当りでまわして判定します
  [1, 2, 3].permutation do |candidate|
    if candidate.zip(tmp).all? { |c, ary| ary.include?(c) }
      puts "嘘つきは#{names[usotsuki]}です。"
      str = names.zip(candidate).map { |n, c| "#{n}#{c}" }.join("")
      puts "ちなみに順位は#{str}です。"
    end
  end
end

 

結果

嘘つきは三郎です。
ちなみに順位は一郎が2位、二郎が1位、三郎が3位です。