From f274c589c02021c33809e8c2a728fff075195f03 Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Wed, 15 Dec 2021 22:13:58 -0800 Subject: [PATCH] [2021][ruby][16.x] --- 2021/ruby/day_16.rb | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 2021/ruby/day_16.rb diff --git a/2021/ruby/day_16.rb b/2021/ruby/day_16.rb new file mode 100644 index 0000000..b15b10e --- /dev/null +++ b/2021/ruby/day_16.rb @@ -0,0 +1,68 @@ +require "strscan" + +def parse(ss) + version = ss.scan(/.{3}/).to_i(2) + type_id = ss.scan(/.{3}/).to_i(2) + + content = case type_id + when 4 # literal value + value = "" + while group = ss.scan(/1/) + value << ss.scan(/.{4}/) + end + ss.scan(/0/) + value << ss.scan(/.{4}/) + value.to_i(2) + else # operator + length_type_id = ss.scan(/./) + case length_type_id + when ?0 + sub_packet_length = ss.scan(/.{15}/).to_i(2) + sub_packet = ss.scan(/.{#{sub_packet_length}}/) + + sss = StringScanner.new(sub_packet) + sub_packets = [] + until sss.eos? + sub_packets << parse(sss) + end + sub_packets + when ?1 + sub_packet_num = ss.scan(/.{11}/).to_i(2) + sub_packet_num.times.map { parse(ss) } + else + fail + end + end + + { version: version, type_id: type_id, content: content } +end + +message = ARGF.read.chomp.chars.map { _1.to_i(16).to_s(2).rjust(4, ?0) }.join +ss = StringScanner.new(message) +packet = parse(ss) + +def each(packet, &block) + return enum_for(__method__, packet) unless block_given? + + block.(packet) + if (content = packet.fetch(:content)).is_a?(Array) + content.each do |sub_packet| + each(sub_packet, &block) + end + end +end + +# p each(packet).sum { _1.fetch(:version) } + +value = { + 0 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.sum }, + 1 => ->(c) { c.map { value.fetch(_1.fetch(:type_id)).(_1.fetch(:content)) }.inject(:*) }, + 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))