Module: POECSS::Simplifier

Defined in:
lib/poe-css/simplifier.rb

Constant Summary collapse

RARITY_TO_NUMBER =
{ 'Normal' => 0, 'Magic' => 1, 'Rare' => 2, 'Unique' => 3 }
NUMBER_TO_RARITY =
RARITY_TO_NUMBER.invert

Class Method Summary collapse

Class Method Details

.simplify_clause(clause) ⇒ Object

Removes impossible matches, duplicate matches, and duplicate commands.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/poe-css/simplifier.rb', line 10

def simplify_clause(clause)
  simplified_matches = clause.match_clauses.group_by(&:match_key).flat_map { |match_key, matches|
    case match_key
    when 'itemlevel', 'droplevel', 'quality', 'height', 'width', 'sockets', 'linkedsockets'
      simplify_numeric_matches(match_key, matches)
    when 'rarity'
      simple_bounds = simplify_bounds(
        matches.map { |m| [ m.match_arguments[:operator] || '=', RARITY_TO_NUMBER[m.match_arguments[:rarity]] ] }
      )

      simple_bounds&.map { |op, limit| MatchClause.new(match_key, { operator: op, rarity: NUMBER_TO_RARITY[limit] }) }
    when 'basetype', 'class', 'socketgroup'
      key =
        case match_key
        when 'basetype', 'class'
          :substrings
        when 'socketgroup'
          :sub_socket_groups
        else
          raise ArgumentError, key
        end

      # Matches a QUERY if for all match in matches, match.substrings.any? { |substring| QUERY[substring] }.
      matches_with_simplified_substrings = matches.uniq.map { |match|
        # We're in an OR-ing context now, so get rid of any substring
        # which is already subsumed by a different substring. If A is a
        # substring of B, then if QUERY[B] is true, then QUERY[A] must
        # also be true, so B can be eliminated from QUERY[A] || QUERY[B].
        queries = []
        match.match_arguments[key].sort_by(&:length).each do |s|
          if queries.none? { |q| s[q] }
            queries << s
          end
        end

        MatchClause.new(match_key, { key => queries })
      }

      # Now look for cases where a match can be subsumed by another
      # match. If match A's queries are a subset of match B's, then
      # match B is more restrictive than match A and match A can be
      # removed.

      matches = []
      matches_with_simplified_substrings.sort_by { |m| m.match_arguments[key].length }.each do |s|
        if matches.none? { |q| stricter_query?(q.match_arguments[key], s.match_arguments[key]) }
          matches << s
        end
      end

      matches
    when 'corrupted', 'elderitem', 'identified', 'shapedmap', 'shaperitem'
      key =
        case match_key
        when 'corrupted'
          :corrupted
        when 'elderitem'
          :elder_item
        when 'identified'
          :identified
        when 'shapedmap'
          :shaped_map
        when 'shaperitem'
          :shaper_item
        else
          raise ArgumentError, key
        end

      values = matches.map { |m| m.match_arguments[key] }.uniq

      if values.length == 1
        MatchClause.new(match_key, { key => values.first })
      end
    else
      raise ArgumentError, match_key
    end
  }

  # Some match reported that the match was impossible.
  return nil if simplified_matches.any?(&:nil?)

  # Only the last command of a particular key is used.
  simplified_commands = clause.command_clauses
    .group_by { |c|
      case c.command_key
      when 'show', 'hide' # Show and Hide need to be grouped together.
        'showhide'
      else
        c.command_key
      end
    }
    .map { |_, cs| cs.last }

  SimpleClause.new(simplified_matches, simplified_commands)
end