# Ruby 295

<!-- language-all: lang-rb -->

    F=->i{l=i.lines
    g={}
    l.size.times{|y|i.size.times{|x|l[y][x]==?+&&g[[y,x]]=[[y,x]]}}
    c=->a,b{w=g[b]+g[a];w.map{|x|g[x]=w}}
    k=g.keys
    k.product(k).map{|n,o|
    r,p=n
    s,q=o
    ((r==s&&p<q&&l[r][p...q]=~/^\+-[|-]*$/)||(p==q&&r<s&&l[r...s].map{|l|l[p]||c}.join=~/^\+\|[|-]*$/))&&c[n,o]}
    g.values.uniq.size}

Try it online: http://ideone.com/kIKELi (_I added a `#to_a` call on the first line, because ideone.com uses Ruby 1.9.3, which does not support `#size` for `Enumerable`s. In Ruby 2.1.5+ the code runs OK._)



The approach is the following:

* make a list of all the `+` signs in the input and consider each of them a distinct shape
* find horizontal and vertical lines that link two `+` signs and combine their shapes into one
* in the end, the number of distinct shapes matches the result

Here's a more readable version:

    def ascii_topology_count(input)
      lines = input.lines
      max_length = lines.map(&:size).max
    
      # hash in which the keys are corners ("+"s), represented by their [y, x] coords
      # and the values are arrays of corners, representing all corners in that group
      corner_groups = {}
    
      lines.size.times { |y|
        max_length.times { |x|
          if lines[y][x] == ?+
            corner_groups[[y, x]] = [[y, x]]
          end
        }
      }
    
      # function that combines the groups of two different corners
      # into only one group
      combine_groups =-> c1, c2 {
        g1 = corner_groups[c1]
        g2 = corner_groups[c2]
    
        g2 += g1
        corner_groups[c1] = g2
        g2.map{|x| corner_groups[x] = g2}
      }
    
      corner_groups.keys.product(corner_groups.keys).map{|c1, c2|
        y1,x1=c1
        y2,x2=c2
        if y1 == y2 && x1 < x2
          # test horizontal edge
          t = lines[y1][x1...x2]
          if t =~ /^\+-[|-]*$/
            # p "#{c1}, #{c2}, [H] #{t}"
            combine_groups[c1, c2]
    
          end
        end
    
        if x1 == x2 && y1 < y2
          # test vertical edge
          t=lines[y1...y2].map{|l|l[x1]||' '}.join
    
          if t =~ /^\+\|[|-]*$/
            # p "#{c1}, #{c2}, [V] #{t}"
            combine_groups[c1, c2]
          end
        end
      }
    
      corner_groups.values.uniq.count
    end