CONTENT = { House:       '',
            Nationality: %i[English Swedish Danish Norwegian German],
            Colour:      %i[Red Green White Blue Yellow],
            Pet:         %i[Dog Birds Cats Horse Zebra],
            Drink:       %i[Tea Coffee Milk Beer Water],
            Smoke:       %i[PallMall Dunhill BlueMaster Prince Blend] }

def adjacent? (n,i,g,e)
  (0..3).any?{|x| (n[x]==i and g[x+1]==e) or (n[x+1]==i and g[x]==e)}
end

def leftof? (n,i,g,e)
  (0..3).any?{|x| n[x]==i and g[x+1]==e}
end

def coincident? (n,i,g,e)
  n.each_index.any?{|x| n[x]==i and g[x]==e}
end

def solve_zebra_puzzle
  CONTENT[:Nationality].permutation{|nation|
    next unless nation.first == :Norwegian                              
    CONTENT[:Colour].permutation{|colour|
      next unless leftof?(colour, :Green, colour, :White)               
      next unless coincident?(nation, :English, colour, :Red)           
      next unless adjacent?(nation, :Norwegian, colour, :Blue)          
      CONTENT[:Pet].permutation{|pet|
        next unless coincident?(nation, :Swedish, pet, :Dog)            
        CONTENT[:Drink].permutation{|drink|
          next unless drink[2] == :Milk                                 
          next unless coincident?(nation, :Danish, drink, :Tea)         
          next unless coincident?(colour, :Green, drink, :Coffee)       
          CONTENT[:Smoke].permutation{|smoke|
            next unless coincident?(smoke, :PallMall, pet, :Birds)      
            next unless coincident?(smoke, :Dunhill, colour, :Yellow)   
            next unless coincident?(smoke, :BlueMaster, drink, :Beer)   
            next unless coincident?(smoke, :Prince, nation, :German)    
            next unless adjacent?(smoke, :Blend, pet, :Cats)            
            next unless adjacent?(smoke, :Blend, drink, :Water)         
            next unless adjacent?(smoke, :Dunhill,pet, :Horse)          
            print_out(nation, colour, pet, drink, smoke)
  } } } } }
end

def print_out (nation, colour, pet, drink, smoke)
  width = CONTENT.map{|x| x.flatten.map{|y|y.size}.max}
  fmt = width.map{|w| }.join()
  national = nation[ pet.find_index(:Zebra) ]
  puts ,
  puts fmt % CONTENT.keys, fmt % width.map{|w| *w}
  [nation,colour,pet,drink,smoke].transpose.each.with_index(1){|x,n| puts fmt % [n,*x]}
end

solve_zebra_puzzle