[2021][ruby][16.x] refactor

pull/2/head
Alpha Chen 3 years ago
parent f274c589c0
commit 28d2d2ca0c

@ -1,24 +1,23 @@
require "strscan" require "strscan"
def parse(ss) Packet = Struct.new(:version, :type_id, :content) do
include Enumerable
def self.parse(ss)
version = ss.scan(/.{3}/).to_i(2) version = ss.scan(/.{3}/).to_i(2)
type_id = ss.scan(/.{3}/).to_i(2) type_id = ss.scan(/.{3}/).to_i(2)
content = case type_id case type_id
when 4 # literal value when 4 # literal value
value = "" value = ss.scan(/(1.{4})*(0.{4})/).chars
while group = ss.scan(/1/) .each_slice(5).flat_map { _1[1..4] }.join
value << ss.scan(/.{4}/) .to_i(2)
end Literal.new(version, type_id, value)
ss.scan(/0/)
value << ss.scan(/.{4}/)
value.to_i(2)
else # operator else # operator
length_type_id = ss.scan(/./) sub_packets = case
case length_type_id when ss.scan(/0(.{15})/)
when ?0 length = ss.captures[0].to_i(2)
sub_packet_length = ss.scan(/.{15}/).to_i(2) sub_packet = ss.scan(/.{#{length}}/)
sub_packet = ss.scan(/.{#{sub_packet_length}}/)
sss = StringScanner.new(sub_packet) sss = StringScanner.new(sub_packet)
sub_packets = [] sub_packets = []
@ -26,43 +25,55 @@ def parse(ss)
sub_packets << parse(sss) sub_packets << parse(sss)
end end
sub_packets sub_packets
when ?1 when ss.scan(/1(.{11})/)
sub_packet_num = ss.scan(/.{11}/).to_i(2) n = ss.captures[0].to_i(2)
sub_packet_num.times.map { parse(ss) } n.times.map { parse(ss) }
else else
fail fail
end end
Operator.new(version, type_id, sub_packets)
end end
end
def each
return enum_for(__method__) unless block_given?
{ version: version, type_id: type_id, content: content } yield self
end
end end
message = ARGF.read.chomp.chars.map { _1.to_i(16).to_s(2).rjust(4, ?0) }.join class Literal < Packet
ss = StringScanner.new(message) def value = content
packet = parse(ss) end
def each(packet, &block) class Operator < Packet
return enum_for(__method__, packet) unless block_given? def each(&block)
super
block.(packet)
if (content = packet.fetch(:content)).is_a?(Array)
content.each do |sub_packet| content.each do |sub_packet|
each(sub_packet, &block) sub_packet.each(&block)
end end
end end
end
# p each(packet).sum { _1.fetch(:version) } def value
values = content.map(&:value)
case type_id
when 0 then values.sum
when 1 then values.inject(:*)
when 2 then values.min
when 3 then values.max
when 4 then fail
when 5 then values.inject(:>) ? 1 : 0
when 6 then values.inject(:<) ? 1 : 0
when 7 then values.inject(:==) ? 1 : 0
else fail
end
end
end
value = { message = ARGF.read.chomp.chars.map { _1.to_i(16).to_s(2).rjust(4, ?0) }.join
0 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.sum }, ss = StringScanner.new(message)
1 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.inject(:*) }, packet = Packet.parse(ss)
2 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.min },
3 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.max },
4 => ->(c) { c },
5 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.inject(:>) ? 1 : 0 },
6 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.inject(:<) ? 1 : 0 },
7 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.inject(:==) ? 1 : 0 },
}
p value.fetch(packet.fetch(:type_id)).(packet.fetch(:content)) p packet.sum(&:version)
p packet.value

Loading…
Cancel
Save