From f2288eb8f38d9fe9c052cd8c9f871f9cc930cedc Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Sat, 18 Dec 2021 16:59:26 +0000 Subject: [PATCH] Day 16 done --- advent-of-code21.cabal | 6 ++ advent16/Main.hs | 177 ++++++++++++++++++++++++++++++++ data/advent16.txt | 1 + problems/day16.html | 224 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 408 insertions(+) create mode 100644 advent16/Main.hs create mode 100644 data/advent16.txt create mode 100644 problems/day16.html diff --git a/advent-of-code21.cabal b/advent-of-code21.cabal index d200a4f..bb917ae 100644 --- a/advent-of-code21.cabal +++ b/advent-of-code21.cabal @@ -176,3 +176,9 @@ executable advent15prof -Wall -threaded -rtsopts "-with-rtsopts=-N -p -s -hT" + +executable advent16 + import: common-extensions, build-directives + main-is: advent16/Main.hs + build-depends: binary, bytestring, bitstring, mtl + diff --git a/advent16/Main.hs b/advent16/Main.hs new file mode 100644 index 0000000..1a6a78f --- /dev/null +++ b/advent16/Main.hs @@ -0,0 +1,177 @@ +-- Writeup at https://work.njae.me.uk/2021/12/16/advent-of-code-2021-day-14/ + +import Data.Word +import Data.Bits +import Data.Char +import Data.List +import Data.Int + +import Control.Monad.State.Lazy + +import qualified Data.ByteString as BYS +import qualified Data.BitString.BigEndian as BS +-- import Data.Binary.Strict.Get + +type ParseState = BS.BitString + +data Packet = Packet Integer PacketContents + deriving (Show, Eq) + +data PacketContents + = Literal Integer + -- | Operator [Packet] + | Sum [Packet] + | Product [Packet] + | Minimum [Packet] + | Maximum [Packet] + | GreaterThan Packet Packet + | LessThan Packet Packet + | EqualTo Packet Packet + deriving (Show, Eq) + +main :: IO () +main = + do text <- readFile "data/advent16.txt" + let packetStream = bitify text + let (packet, _remaining) = runState getPacket packetStream + print $ part1 packet + print $ part2 packet + +part1 :: Packet -> Integer +part1 = packetVersionSum + +part2 :: Packet -> Integer +part2 = evaluatePacket + +bitify :: String -> BS.BitString +bitify = BS.bitString . BYS.pack . hexPack . map (fromIntegral . digitToInt) +-- byteify = BYS.pack . hexPack . map (fromIntegral . digitToInt) + +hexPack :: [Word8] -> [Word8] +hexPack [] = [] +hexPack (x:[]) = hexPack [x, 0] +hexPack (x:y:xs) = ((x `shift` 4) .|. y) : hexPack xs + +wordify :: BS.BitString -> Integer +wordify bs = foldl' addBit 0 $ BS.to01List bs + where addBit w b = (w * 2) + (fromIntegral b) + + +getBool :: State ParseState Bool +getBool = + do bs <- get + let value = head $ BS.toList $ BS.take 1 bs + put (BS.drop 1 bs) + return value + +getInt :: Int64 -> State ParseState Integer +getInt n = + do bs <- get + let bits = BS.take n bs + put (BS.drop n bs) + return (wordify bits) + +getBits :: Int64 -> State ParseState BS.BitString +getBits n = + do bs <- get + let bits = BS.take n bs + put (BS.drop n bs) + return bits + +getLiteral :: State ParseState Integer +getLiteral = getLiteralAcc 0 + +getLiteralAcc :: Integer -> State ParseState Integer +getLiteralAcc acc = + do continues <- getBool + nybble <- getInt 4 + let acc' = acc * 16 + nybble + if continues + then (do getLiteralAcc acc') + else (return acc') + +-- getLiteralPacket :: State ParseState (Integer, Integer, Integer) +-- getLiteralPacket = +-- do version <- getInt 3 +-- pType <- getInt 3 +-- val <- getLiteral +-- return (version, pType, val) + + +getPacket :: State ParseState Packet +getPacket = + do version <- getInt 3 + pType <- getInt 3 + payload <- case pType of + 4 -> do val <- getLiteral + return $ Literal val + _ -> do contents <- getOperatorContents + return $ mkOperator pType contents + return $ Packet version payload + +mkOperator :: Integer -> [Packet] -> PacketContents +mkOperator pType contents = case pType of + 0 -> Sum contents + 1 -> Product contents + 2 -> Minimum contents + 3 -> Maximum contents + 5 -> GreaterThan (contents!!0) (contents!!1) + 6 -> LessThan (contents!!0) (contents!!1) + 7 -> EqualTo (contents!!0) (contents!!1) + + +getOperatorContents :: State ParseState [Packet] +getOperatorContents = + do isNumPackets <- getBool + if isNumPackets + then do numPackets <- getInt 11 + getPacketsByCount numPackets + else do numBits <- getInt 15 + subString <- getBits (fromIntegral numBits) + return $ getPacketsByLength subString + +getPacketsByLength :: BS.BitString -> [Packet] +getPacketsByLength bits + | BS.null bits = [] + | otherwise = p : (getPacketsByLength remaining) + where (p, remaining) = runState getPacket bits + +getPacketsByCount :: Integer -> State ParseState [Packet] +getPacketsByCount 0 = return [] +getPacketsByCount n = + do p <- getPacket + ps <- getPacketsByCount (n - 1) + return (p : ps) + +packetVersionSum :: Packet -> Integer +packetVersionSum (Packet version contents) = + version + (contentsVersionSum contents) + +contentsVersionSum :: PacketContents -> Integer +contentsVersionSum (Sum packets) = sum $ map packetVersionSum packets +contentsVersionSum (Product packets) = sum $ map packetVersionSum packets +contentsVersionSum (Minimum packets) = sum $ map packetVersionSum packets +contentsVersionSum (Maximum packets) = sum $ map packetVersionSum packets +contentsVersionSum (Literal _) = 0 +contentsVersionSum (GreaterThan packet1 packet2) = + (packetVersionSum packet1) + (packetVersionSum packet2) +contentsVersionSum (LessThan packet1 packet2) = + (packetVersionSum packet1) + (packetVersionSum packet2) +contentsVersionSum (EqualTo packet1 packet2) = + (packetVersionSum packet1) + (packetVersionSum packet2) + +evaluatePacket :: Packet -> Integer +evaluatePacket (Packet _version contents) = evaluateContents contents + +evaluateContents :: PacketContents -> Integer +evaluateContents (Sum packets) = sum $ map evaluatePacket packets +evaluateContents (Product packets) = product $ map evaluatePacket packets +evaluateContents (Minimum packets) = minimum $ map evaluatePacket packets +evaluateContents (Maximum packets) = maximum $ map evaluatePacket packets +evaluateContents (Literal n) = n +evaluateContents (GreaterThan packet1 packet2) = + if (evaluatePacket packet1) > (evaluatePacket packet2) then 1 else 0 +evaluateContents (LessThan packet1 packet2) = + if (evaluatePacket packet1) < (evaluatePacket packet2) then 1 else 0 +evaluateContents (EqualTo packet1 packet2) = + if (evaluatePacket packet1) == (evaluatePacket packet2) then 1 else 0 diff --git a/data/advent16.txt b/data/advent16.txt new file mode 100644 index 0000000..cf8974a --- /dev/null +++ b/data/advent16.txt @@ -0,0 +1 @@ +C20D718021600ACDC372CD8DE7A057252A49C940239D68978F7970194EA7CCB310088760088803304A0AC1B100721EC298D3307440041CD8B8005D12DFD27CBEEF27D94A4E9B033006A45FE71D665ACC0259C689B1F99679F717003225900465800804E39CE38CE161007E52F1AEF5EE6EC33600BCC29CFFA3D8291006A92CA7E00B4A8F497E16A675EFB6B0058F2D0BD7AE1371DA34E730F66009443C00A566BFDBE643135FEDF321D000C6269EA66545899739ADEAF0EB6C3A200B6F40179DE31CB7B277392FA1C0A95F6E3983A100993801B800021B0722243D00042E0DC7383D332443004E463295176801F29EDDAA853DBB5508802859F2E9D2A9308924F9F31700AA4F39F720C733A669EC7356AC7D8E85C95E123799D4C44C0109C0AF00427E3CC678873F1E633C4020085E60D340109E3196023006040188C910A3A80021B1763FC620004321B4138E52D75A20096E4718D3E50016B19E0BA802325E858762D1802B28AD401A9880310E61041400043E2AC7E8A4800434DB24A384A4019401C92C154B43595B830002BC497ED9CC27CE686A6A43925B8A9CFFE3A9616E5793447004A4BBB749841500B26C5E6E306899C5B4C70924B77EF254B48688041CD004A726ED3FAECBDB2295AEBD984E08E0065C101812E006380126005A80124048CB010D4C03DC900E16A007200B98E00580091EE004B006902004B00410000AF00015933223100688010985116A311803D05E3CC4B300660BC7283C00081CF26491049F3D690E9802739661E00D400010A8B91F2118803310A2F43396699D533005E37E8023311A4BB9961524A4E2C027EC8C6F5952C2528B333FA4AD386C0A56F39C7DB77200C92801019E799E7B96EC6F8B7558C014977BD00480010D89D106240803518E31C4230052C01786F272FF354C8D4D437DF52BC2C300567066550A2A900427E0084C254739FB8E080111E0 \ No newline at end of file diff --git a/problems/day16.html b/problems/day16.html new file mode 100644 index 0000000..6324cfa --- /dev/null +++ b/problems/day16.html @@ -0,0 +1,224 @@ + + + + +Day 16 - Advent of Code 2021 + + + + + + + +

Advent of Code

Neil Smith (AoC++) 32*

   sub y{2021}

+ + + +
+ +

--- Day 16: Packet Decoder ---

As you leave the cave and reach open waters, you receive a transmission from the Elves back on the ship.

+

The transmission was sent using the Buoyancy Interchange Transmission System (BITS), a method of packing numeric expressions into a binary sequence. Your submarine's computer has saved the transmission in hexadecimal (your puzzle input).

+

The first step of decoding the message is to convert the hexadecimal representation into binary. Each character of hexadecimal corresponds to four bits of binary data:

+
0 = 0000
+1 = 0001
+2 = 0010
+3 = 0011
+4 = 0100
+5 = 0101
+6 = 0110
+7 = 0111
+8 = 1000
+9 = 1001
+A = 1010
+B = 1011
+C = 1100
+D = 1101
+E = 1110
+F = 1111
+
+

The BITS transmission contains a single packet at its outermost layer which itself contains many other packets. The hexadecimal representation of this packet might encode a few extra 0 bits at the end; these are not part of the transmission and should be ignored.

+

Every packet begins with a standard header: the first three bits encode the packet version, and the next three bits encode the packet type ID. These two values are numbers; all numbers encoded in any packet are represented as binary with the most significant bit first. For example, a version encoded as the binary sequence 100 represents the number 4.

+

Packets with type ID 4 represent a literal value. Literal value packets encode a single binary number. To do this, the binary number is padded with leading zeroes until its length is a multiple of four bits, and then it is broken into groups of four bits. Each group is prefixed by a 1 bit except the last group, which is prefixed by a 0 bit. These groups of five bits immediately follow the packet header. For example, the hexadecimal string D2FE28 becomes:

+
110100101111111000101000
+VVVTTTAAAAABBBBBCCCCC
+
+

Below each bit is a label indicating its purpose:

+
    +
  • The three bits labeled V (110) are the packet version, 6.
  • +
  • The three bits labeled T (100) are the packet type ID, 4, which means the packet is a literal value.
  • +
  • The five bits labeled A (10111) start with a 1 (not the last group, keep reading) and contain the first four bits of the number, 0111.
  • +
  • The five bits labeled B (11110) start with a 1 (not the last group, keep reading) and contain four more bits of the number, 1110.
  • +
  • The five bits labeled C (00101) start with a 0 (last group, end of packet) and contain the last four bits of the number, 0101.
  • +
  • The three unlabeled 0 bits at the end are extra due to the hexadecimal representation and should be ignored.
  • +
+

So, this packet represents a literal value with binary representation 011111100101, which is 2021 in decimal.

+

Every other type of packet (any packet with a type ID other than 4) represent an operator that performs some calculation on one or more sub-packets contained within. Right now, the specific operations aren't important; focus on parsing the hierarchy of sub-packets.

+

An operator packet contains one or more packets. To indicate which subsequent binary data represents its sub-packets, an operator packet can use one of two modes indicated by the bit immediately after the packet header; this is called the length type ID:

+
    +
  • If the length type ID is 0, then the next 15 bits are a number that represents the total length in bits of the sub-packets contained by this packet.
  • +
  • If the length type ID is 1, then the next 11 bits are a number that represents the number of sub-packets immediately contained by this packet.
  • +
+

Finally, after the length type ID bit and the 15-bit or 11-bit field, the sub-packets appear.

+

For example, here is an operator packet (hexadecimal string 38006F45291200) with length type ID 0 that contains two sub-packets:

+
00111000000000000110111101000101001010010001001000000000
+VVVTTTILLLLLLLLLLLLLLLAAAAAAAAAAABBBBBBBBBBBBBBBB
+
+
    +
  • The three bits labeled V (001) are the packet version, 1.
  • +
  • The three bits labeled T (110) are the packet type ID, 6, which means the packet is an operator.
  • +
  • The bit labeled I (0) is the length type ID, which indicates that the length is a 15-bit number representing the number of bits in the sub-packets.
  • +
  • The 15 bits labeled L (000000000011011) contain the length of the sub-packets in bits, 27.
  • +
  • The 11 bits labeled A contain the first sub-packet, a literal value representing the number 10.
  • +
  • The 16 bits labeled B contain the second sub-packet, a literal value representing the number 20.
  • +
+

After reading 11 and 16 bits of sub-packet data, the total length indicated in L (27) is reached, and so parsing of this packet stops.

+

As another example, here is an operator packet (hexadecimal string EE00D40C823060) with length type ID 1 that contains three sub-packets:

+
11101110000000001101010000001100100000100011000001100000
+VVVTTTILLLLLLLLLLLAAAAAAAAAAABBBBBBBBBBBCCCCCCCCCCC
+
+
    +
  • The three bits labeled V (111) are the packet version, 7.
  • +
  • The three bits labeled T (011) are the packet type ID, 3, which means the packet is an operator.
  • +
  • The bit labeled I (1) is the length type ID, which indicates that the length is a 11-bit number representing the number of sub-packets.
  • +
  • The 11 bits labeled L (00000000011) contain the number of sub-packets, 3.
  • +
  • The 11 bits labeled A contain the first sub-packet, a literal value representing the number 1.
  • +
  • The 11 bits labeled B contain the second sub-packet, a literal value representing the number 2.
  • +
  • The 11 bits labeled C contain the third sub-packet, a literal value representing the number 3.
  • +
+

After reading 3 complete sub-packets, the number of sub-packets indicated in L (3) is reached, and so parsing of this packet stops.

+

For now, parse the hierarchy of the packets throughout the transmission and add up all of the version numbers.

+

Here are a few more examples of hexadecimal-encoded transmissions:

+
    +
  • 8A004A801A8002F478 represents an operator packet (version 4) which contains an operator packet (version 1) which contains an operator packet (version 5) which contains a literal value (version 6); this packet has a version sum of 16.
  • +
  • 620080001611562C8802118E34 represents an operator packet (version 3) which contains two sub-packets; each sub-packet is an operator packet that contains two literal values. This packet has a version sum of 12.
  • +
  • C0015000016115A2E0802F182340 has the same structure as the previous example, but the outermost packet uses a different length type ID. This packet has a version sum of 23.
  • +
  • A0016C880162017C3686B18A3D4780 is an operator packet that contains an operator packet that contains an operator packet that contains five literal values; it has a version sum of 31.
  • +
+

Decode the structure of your hexadecimal-encoded BITS transmission; what do you get if you add up the version numbers in all packets?

+
+

Your puzzle answer was 852.

--- Part Two ---

Now that you have the structure of your transmission decoded, you can calculate the value of the expression it represents.

+

Literal values (type ID 4) represent a single number as described above. The remaining type IDs are more interesting:

+
    +
  • Packets with type ID 0 are sum packets - their value is the sum of the values of their sub-packets. If they only have a single sub-packet, their value is the value of the sub-packet.
  • +
  • Packets with type ID 1 are product packets - their value is the result of multiplying together the values of their sub-packets. If they only have a single sub-packet, their value is the value of the sub-packet.
  • +
  • Packets with type ID 2 are minimum packets - their value is the minimum of the values of their sub-packets.
  • +
  • Packets with type ID 3 are maximum packets - their value is the maximum of the values of their sub-packets.
  • +
  • Packets with type ID 5 are greater than packets - their value is 1 if the value of the first sub-packet is greater than the value of the second sub-packet; otherwise, their value is 0. These packets always have exactly two sub-packets.
  • +
  • Packets with type ID 6 are less than packets - their value is 1 if the value of the first sub-packet is less than the value of the second sub-packet; otherwise, their value is 0. These packets always have exactly two sub-packets.
  • +
  • Packets with type ID 7 are equal to packets - their value is 1 if the value of the first sub-packet is equal to the value of the second sub-packet; otherwise, their value is 0. These packets always have exactly two sub-packets.
  • +
+

Using these rules, you can now work out the value of the outermost packet in your BITS transmission.

+

For example:

+
    +
  • C200B40A82 finds the sum of 1 and 2, resulting in the value 3.
  • +
  • 04005AC33890 finds the product of 6 and 9, resulting in the value 54.
  • +
  • 880086C3E88112 finds the minimum of 7, 8, and 9, resulting in the value 7.
  • +
  • CE00C43D881120 finds the maximum of 7, 8, and 9, resulting in the value 9.
  • +
  • D8005AC2A8F0 produces 1, because 5 is less than 15.
  • +
  • F600BC2D8F produces 0, because 5 is not greater than 15.
  • +
  • 9C005AC2F8F0 produces 0, because 5 is not equal to 15.
  • +
  • 9C0141080250320F1802104A08 produces 1, because 1 + 3 = 2 * 2.
  • +
+

What do you get if you evaluate the expression represented by your hexadecimal-encoded BITS transmission?

+
+

Your puzzle answer was 19348959966392.

Both parts of this puzzle are complete! They provide two gold stars: **

+

At this point, you should return to your Advent calendar and try another puzzle.

+

If you still want to see it, you can get your puzzle input.

+

You can also this puzzle.

+
+ + + + + + \ No newline at end of file -- 2.34.1