master
  1def assert_equal(x, y)
  2  raise [x, y].inspect unless x == y
  3end
  4
  5class Card
  6  attr_reader :raw, :prefix, :letter, :number
  7  BITS = {
  8    "+" => 256,
  9    "-" => 128,
 10    "=" => 64,
 11    "A" => 32,
 12    "B" => 16,
 13    "C" => 8,
 14    "1" => 4,
 15    "2" => 2,
 16    "3" => 1,
 17  }
 18
 19  def initialize(raw)
 20    @raw = raw
 21    @prefix = raw[0]
 22    @letter = raw[1]
 23    @number = raw[1..-1].size
 24  end
 25
 26  def <=>(other)
 27    self.score <=> other.score
 28  end
 29
 30  def score
 31    @score ||= begin
 32      score = 0
 33      score += BITS[prefix]
 34      score += BITS[letter]
 35      score += BITS[number.to_s]
 36      score
 37    end
 38  end
 39
 40  def match?(*others)
 41    others << self
 42    [:prefix, :letter, :number].each do |property|
 43      x = others.map(&property).uniq.count
 44      return false if x != 1 && x != others.size
 45    end
 46
 47    true
 48  end
 49
 50  def to_s
 51    raw
 52  end
 53end
 54
 55class Solution
 56  # time: O(n^3)
 57  # space: O(n) ?
 58  def run(row)
 59    cards = row.split
 60    cache = Hash.new do |hash, key|
 61      hash[key] = Card.new(key)
 62    end
 63
 64    for i in (0...cards.size)
 65      x = cache[cards[i]]
 66      for p in (i+1...cards.size)
 67        y = cache[cards[p]]
 68        for q in (p+1...cards.size)
 69          z = cache[cards[q]]
 70
 71          if x.match?(y, z)
 72            return [x, y, z].join(' ')
 73          end
 74        end
 75      end
 76    end
 77
 78    ""
 79  end
 80
 81=begin
 82|4|2|1|
 83|+|-|=|
 84
 85|4|2|1|
 86|A|B|C|
 87
 88123
 89
 90|256|128| 64| 32| 16|  8|  4|  2|  1|
 91|  +|  -|  =|  A|  B|  C|  1|  2|  3|
 92
 93-A: 128 + 32 + 3
 94-B: 128 + 16 + 3
 95
 96=end
 97  def run(row)
 98    cards = row.split.map { |x| Card.new(x) }
 99    for i in (0...cards.size)
100      x = cards[i]
101      for p in (i+1...cards.size)
102        y = cards[p]
103        for q in (p+1...cards.size)
104          z = cards[q]
105          return [x, y, z].join(' ') if x.match?(y, z)
106        end
107      end
108    end
109
110    ""
111  end
112end
113
114assert_equal(true, Card.new("+C").match?(Card.new("-CC"), Card.new("=CCC")))
115assert_equal(true, Card.new("-A").match?(Card.new("-B"), Card.new("-C")))
116assert_equal(false, Card.new("-A").match?(Card.new("-B"), Card.new("-BB")))
117assert_equal(false, Card.new("-A").match?(Card.new("-BBB"), Card.new("-CCC")))
118
119solution = Solution.new
120result = solution.run("-A -B -BB +C -C -CC =CCC")
121assert_equal(true, result == "+C -CC =CCC" || result == '-A -B -C')
122assert_equal("", solution.run("-A +B -BB +C -C -CC +CCC"))
123assert_equal("", solution.run("-A"))
124assert_equal("", solution.run("-A +B"))
125assert_equal("", solution.run("-A +B +C"))
126assert_equal("-A +B =C", solution.run("-A +B =C"))
127assert_equal("-A +BB =CCC", solution.run("-A +BB =CCC"))
128assert_equal("", solution.run("-A -BB =CCC"))
129assert_equal("+A +A +A", solution.run("+A +A +A"))
130assert_equal("", solution.run("+A +A +B"))
131puts "Yay!"