Hi, I have a tendency to over-engineer things, so I intentionally tried to keep this simple. Given the quiz requirements, it seemed simplest to represent the match-tree as a collection of nested arrays. The presentation code is slightly clever in that it dynamically mixes a particular renderer module into the tournament to be rendered. * Sample run $ ruby tournament.rb 1 2 3 4 5 R1 R2 R3 ============ 1 --- |--- --- | bye | |--- 4 | | --- | | |--- | --- | 5 | |--- 2 | --- | |--- | --- | | bye | | |--- 3 | --- | |--- --- bye * Code #! /usr/bin/env ruby require 'facet/symbol/to_proc' class << Math def log2(n); log(n) / log(2); end end class Array def half_size; size >> 1; end def top_half; self[0, half_size]; end def bottom_half; self[half_size, half_size]; end end class Tournament def initialize(players) raise "Tournament requires 2 or more players" if players.size < 2 @players = players @matches = (0...nrounds).inject(seed) do |(memo,)| memo.top_half.zip(memo.bottom_half.reverse) end end attr_reader :players attr_reader :matches def render(renderer = AsciiRenderer) extend renderer render_tournament end protected def seed; @seed ||= players + Array.new(nbyes, :bye); end def nplayers; players.size; end def nrounds; Math.log2(nplayers).ceil; end def nbyes; (1 << nrounds) - nplayers; end end module Tournament::AsciiRenderer protected def render_tournament render_header.concat(render_rounds).join("\n") end private def render_header [ (1..nrounds).collect { |r| "R#{r}".ljust(width + 1) }.join, ('=' * (nrounds * (width + 1))) ] end def render_rounds render_match(matches.first) end def render_match(match) unless match.kind_of? Array draw = [ render_player(match), slot1 ] (@flip = !@flip) ? draw : draw.reverse else draw = match.collect do |match_| render_match(match_) end.inject do |memo, draw_| (memo << (' ' * memo.first.size)).concat(draw_) end fh = (draw.size - 3) / 4 sh = [ (draw.size + 1) / 4, 2 ].max draw_ = [ [space]*sh, [flow]*fh, slot, [flow]*fh, [space]*sh ] draw.zip(draw_.flatten).collect(&:join) end end def render_player(player) player.to_s.ljust(width) end def slot; '|' << ('-' * width); end def slot1; ('-' * width); end def flow; '|' << (' ' * width); end def space; ' ' << (' ' * width); end def width @width ||= seed.collect { |x| x.to_s.size }.max; end end if __FILE__ == $0 puts Tournament.new(ARGV).render end -Marshall