Module: AtCoderFriends::Parser::InputFormat

Includes:
InputFormatConstants
Defined in:
lib/at_coder_friends/parser/input_format.rb

Overview

parses input data format and generates input definitons

Defined Under Namespace

Classes: Iterator

Constant Summary

Constants included from InputFormatConstants

AtCoderFriends::Parser::InputFormatConstants::PARSERS, AtCoderFriends::Parser::InputFormatConstants::SECTIONS

Class Method Summary collapse

Class Method Details

.match_smp!(inpdefs, smp) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/at_coder_friends/parser/input_format.rb', line 153

def match_smp!(inpdefs, smp)
  lines = smp.split("\n")
  inpdefs.each_with_index do |inpdef, i|
    break if i >= lines.size
    next if inpdef.item != :number

    inpdef.item = :string if lines[i].split[0] =~ /[^\-0-9]/
    break if i[varray matrix].include?(inpdef.container)
  end
  inpdefs
end

.max_smp(smps) ⇒ Object

rubocop:enable Metrics/MethodLength, Metrics/AbcSize



146
147
148
149
150
151
# File 'lib/at_coder_friends/parser/input_format.rb', line 146

def max_smp(smps)
  smps
    .select { |smp| smp.ext == :in }
    .max_by { |smp| smp.txt.size }
    &.txt
end

.normalize(fmt) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/at_coder_friends/parser/input_format.rb', line 106

def normalize(fmt)
  fmt
    .gsub(/[+*-]\d+/, '') # N-1, N+1 -> N
    .gsub(%r{[-/ ]}, ' ') # a-b, a/b -> a b
    .gsub(/\{.*?\}/) { |w| w.delete(' ') } # {1, 1}->{1,1} shortest match
    .gsub(/[_,'\\(){}|$]/, '')
    .gsub(/[・::…‥]+/, '..')
    .gsub(/[clv]?dots/, '..')
    .gsub(/^\s*\.[.\s]*$/, '..')
    .split("\n")
    .map(&:strip)
end

.parse(str, smps) ⇒ Object



98
99
100
101
102
103
104
# File 'lib/at_coder_friends/parser/input_format.rb', line 98

def parse(str, smps)
  lines = normalize(str)
  inpdefs = parse_fmt(lines)
  smpx = max_smp(smps)
  smpx && match_smp!(inpdefs, smpx)
  inpdefs
end

.parse_fmt(lines) ⇒ Object

rubocop:disable Metrics/MethodLength, Metrics/AbcSize



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/at_coder_friends/parser/input_format.rb', line 120

def parse_fmt(lines)
  it = Iterator.new(lines + ['']) # sentinel
  prv = nil
  cur = it.next
  Enumerator.new do |y|
    loop do
      unless (parser = PARSERS.find { |ps| ps[:pat] =~ cur })
        puts "unknown format: #{cur}" unless cur.empty?
        (cur = it.next) ? next : break
      end
      container, item = parser.values_at(:container, :item)
      m = parser[:pat].match(cur)
      names = parser[:names].call(m)
      pat2 = parser[:pat2].call(names)
      loop do
        prv = cur
        cur = it.next
        break unless pat2 && pat2 =~ cur
      end
      size = parser[:size].call(prv)
      y << Problem::InputFormat.new(container, item, names, size)
    end
  end.to_a
end

.process(pbm) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/at_coder_friends/parser/input_format.rb', line 89

def process(pbm)
  str =
    SECTIONS
    .map { |key| pbm.sections[key]&.code_block }
    .find(&:itself) || ''
  inpdefs = parse(str, pbm.samples)
  pbm.formats = inpdefs
end