def factorial(n)
  (1..n).reduce(1,:*)
end



def catalan_direct(n)
  factorial(2*n) / (factorial(n+1) * factorial(n))
end



def catalan_rec1(n)
  return 1 if n == 0
  (0...n).inject(0) {|sum, i| sum + catalan_rec1(i) * catalan_rec1(n-1-i)}
end

def catalan_rec2(n)
  return 1 if n == 0
  2*(2*n - 1) * catalan_rec2(n-1) / (n+1)
end



require 'benchmark'
require 'memoize'
include Memoize

Benchmark.bm(17) do |b|
  b.report('catalan_direct')    {16.times {|n| catalan_direct(n)} }
  b.report('catalan_rec1')      {16.times {|n| catalan_rec1(n)} }
  b.report('catalan_rec2')      {16.times {|n| catalan_rec2(n)} }

  memoize :catalan_rec1
  b.report('catalan_rec1(memo)'){16.times {|n| catalan_rec1(n)} }
end

puts 
16.times {|n| puts  % [n, catalan_direct(n), catalan_rec1(n), catalan_rec2(n)]}