From 8b21ab556a944d39b8b8b8abbdc0f7473c64ca54 Mon Sep 17 00:00:00 2001 From: crc Date: Fri, 18 Dec 2020 20:44:56 +0000 Subject: [PATCH] add advent of code examples (2020, days 1-5) (re #27) FossilOrigin-Name: 54a80479319c1ce4c27fdae1169b09159fb624f6d10c5224a338273ec1ea160a --- example/advent-of-code-2020-day-1.retro | 106 +++++++++++ example/advent-of-code-2020-day-2.retro | 143 ++++++++++++++ example/advent-of-code-2020-day-3.retro | 178 ++++++++++++++++++ example/advent-of-code-2020-day-4.retro | 239 ++++++++++++++++++++++++ example/advent-of-code-2020-day-5.retro | 145 ++++++++++++++ 5 files changed, 811 insertions(+) create mode 100644 example/advent-of-code-2020-day-1.retro create mode 100644 example/advent-of-code-2020-day-2.retro create mode 100644 example/advent-of-code-2020-day-3.retro create mode 100644 example/advent-of-code-2020-day-4.retro create mode 100644 example/advent-of-code-2020-day-5.retro diff --git a/example/advent-of-code-2020-day-1.retro b/example/advent-of-code-2020-day-1.retro new file mode 100644 index 0000000..483f680 --- /dev/null +++ b/example/advent-of-code-2020-day-1.retro @@ -0,0 +1,106 @@ +# Day 1: Report Repair + +After saving Christmas five years in a row, you've decided +to take a vacation at a nice resort on a tropical island. +Surely, Christmas will go on without you. + +The tropical island has its own currency and is entirely +cash-only. The gold coins used there have a little picture +of a starfish; the locals just call them stars. None of the +currency exchanges seem to have heard of them, but somehow, +you'll need to find fifty of these coins by the time you +arrive so you can pay the deposit on your room. + +To save your vacation, you need to get all fifty stars by +December 25th. + +Collect stars by solving puzzles. Two puzzles will be made +available on each day in the Advent calendar; the second +puzzle is unlocked when you complete the first. Each puzzle +grants one star. Good luck! + +Before you leave, the Elves in accounting just need you to +fix your expense report (your puzzle input); apparently, +something isn't quite adding up. + +Specifically, they need you to find the two entries that +sum to 2020 and then multiply those two numbers together. + +For example, suppose your expense report contained the +following: + + 1721 + 979 + 366 + 299 + 675 + 1456 + +In this list, the two entries that sum to 2020 are 1721 +and 299. Multiplying them together produces +1721 \* 299 = 514579, so the correct answer is 514579. + +Of course, your expense report is much larger. Find the +two entries that sum to 2020; what do you get if you +multiply them together? + +---- + +The first step is to get the input into something I +can work with. My sample input has 200 entries, so I +can fit them all on the stack, which means it's easy +to create an array with them. + +Put your input into a file named `input-day-1`. + +~~~ +{ 'input-day-1 [ s:to-number ] file:for-each-line } +'INPUT const +~~~ + +And then a simple approach is to just loop through the +input twice, looking for any two values that add up to +2020. + +---- + +~~~ +:2020? dup-pair + #2020 eq? ; +:display dup-pair * n:put nl ; + +INPUT [ INPUT [ 2020? [ display ] if drop ] a:for-each drop ] a:for-each +~~~ + +The second part is just slightly different: + +---- + +The Elves in accounting are thankful for your help; one +of them even offers you a starfish coin they had left +over from a past vacation. They offer you a second one +if you can find three numbers in your expense report that +meet the same criteria. + +Using the above example again, the three entries that +sum to 2020 are 979, 366, and 675. Multiplying them +together produces the answer, 241861950. + +In your expense report, what is the product of the +three entries that sum to 2020? + +---- + +For this, I just add an additional iteration through the +input. This can be *slow*, but does work. To save time, +I `abort` after a match is found, so processing stops at +the first match. + +~~~ +:dup-three 'abc 'abcabc reorder ; +:2020? dup-three + + #2020 eq? ; +:display dup-three * * n:put nl abort ; + +:inner INPUT [ 2020? [ display ] if drop ] a:for-each drop ; + +INPUT [ INPUT [ inner ] a:for-each drop ] a:for-each +~~~ diff --git a/example/advent-of-code-2020-day-2.retro b/example/advent-of-code-2020-day-2.retro new file mode 100644 index 0000000..3fce23a --- /dev/null +++ b/example/advent-of-code-2020-day-2.retro @@ -0,0 +1,143 @@ +# Day 2: Password Philosophy + +Your flight departs in a few days from the coastal +airport; the easiest way down to the coast from +here is via toboggan. + +The shopkeeper at the North Pole Toboggan Rental +Shop is having a bad day. "Something's wrong with +our computers; we can't log in!" You ask if you can +take a look. + +Their password database seems to be a little +corrupted: some of the passwords wouldn't have been +allowed by the Official Toboggan Corporate Policy +that was in effect when they were chosen. + +To try to debug the problem, they have created a +list (your puzzle input) of passwords (according +to the corrupted database) and the corporate +policy when that password was set. + +For example, suppose you have the following list: + + 1-3 a: abcde + 1-3 b: cdefg + 2-9 c: ccccccccc + +Each line gives the password policy and then the +password. The password policy indicates the lowest +and highest number of times a given letter must +appear for the password to be valid. For example, +`1-3 a` means that the password must contain `a` at +least 1 time and at most 3 times. + +In the above example, 2 passwords are valid. The +middle password, cdefg, is not; it contains no +instances of b, but needs at least 1. The first and +third passwords are valid: they contain one a or +nine c, both within the limits of their respective +policies. + +How many passwords are valid according to their +policies? + +---- + +This is an easy problem. Just a little parsing and reduction. + +`range` is defined to parse the limits of the character. This +just means splitting the string and converting the pieces to +a number. + +The `reduce` word is slighly more complex. It takes the +password and the character and constructs a combinator for +use in filtering out other characters. + +The remaining characters will be counted and compared to +the range. + +Basically, an input line like: + + 1-3 a: abcde + +Becomes: + + 'abcde [ $a eq? ] s:filter s:length #1 #3 n:between? + +At this point, I just add up the flags (-1 for TRUE), and +use `n:abs` to get the final count. + +~~~ +:range + #0 a:fetch $- s:tokenize [ s:to-number ] a:for-each ; + +:reduce + [ #2 a:fetch ] [ #1 a:fetch fetch &eq? curry ] bi s:filter ; + +:process (na-n) + [ reduce s:length ] [ range ] bi n:between? + ; + +#0 'input-day-2 [ ASCII:SPACE s:tokenize process ] file:for-each-line +n:abs +~~~ + +---- + +# Part 2 + +While it appears you validated the passwords +correctly, they don't seem to be what the Official +Toboggan Corporate Authentication System is expecting. + +The shopkeeper suddenly realizes that he just +accidentally explained the password policy rules from +his old job at the sled rental place down the street! +The Official Toboggan Corporate Policy actually works +a little differently. + +Each policy actually describes two positions in the +password, where 1 means the first character, 2 means +the second character, and so on. (Be careful; Toboggan +Corporate Policies have no concept of "index zero"!) +Exactly one of these positions must contain the given +letter. Other occurrences of the letter are irrelevant +for the purposes of policy enforcement. + +Given the same example list from above: + + 1-3 a: abcde is valid: position 1 contains a and position 3 does not. + 1-3 b: cdefg is invalid: neither position 1 nor position 3 contains b. + 2-9 c: ccccccccc is invalid: both position 2 and position 9 contain c. + +How many passwords are valid according to the new +interpretation of the policies? + +---- + +So in this variation, I need to check two positions per +password. + +Being lazy here, I'm using `reorder` a couple of times +to restructure the stack. The only thing to remember is +that indexing is one based, so the word that extracts +the positions needs to decrement to adjust for Retro's +zero based indexing. + +~~~ +:grab-characters + 'abc 'abac reorder + fetch [ + fetch ] dip ; + +:check + 'abc 'abac reorder eq? [ eq? ] dip xor + ; + +:positions + #0 a:fetch $- s:tokenize [ s:to-number n:dec ] a:for-each ; + +:process (na-n) + [ #1 a:fetch fetch ] [ #2 a:fetch ] [ positions ] tri + grab-characters check ; + +#0 'input-day-2 [ ASCII:SPACE s:tokenize process ] file:for-each-line +n:abs +~~~ diff --git a/example/advent-of-code-2020-day-3.retro b/example/advent-of-code-2020-day-3.retro new file mode 100644 index 0000000..b3cfff0 --- /dev/null +++ b/example/advent-of-code-2020-day-3.retro @@ -0,0 +1,178 @@ +# Day 3: Toboggan Trajectory + +With the toboggan login problems resolved, you set off +toward the airport. While travel by toboggan might be +easy, it's certainly not safe: there's very minimal +steering and the area is covered in trees. You'll need +to see which angles will take you near the fewest trees. + +Due to the local geology, trees in this area only grow on +exact integer coordinates in a grid. You make a map (your +puzzle input) of the open squares (.) and trees (#) you can +see. For example: + + ..##....... + #...#...#.. + .#....#..#. + ..#.#...#.# + .#...##..#. + ..#.##..... + .#.#.#....# + .#........# + #.##...#... + #...##....# + .#..#...#.# + +These aren't the only trees, though; due to something you +read about once involving arboreal genetics and biome +stability, the same pattern repeats to the right many times: + + ..##.........##.........##.........##.........##....... + #...#...#..#...#...#..#...#...#..#...#...#..#...#...#.. + .#....#..#..#....#..#..#....#..#..#....#..#..#....#..#. + +You start on the open square (.) in the top-left corner and +need to reach the bottom (below the bottom-most row on your +map). + +The toboggan can only follow a few specific slopes (you opted +for a cheaper model that prefers rational numbers); start by +counting all the trees you would encounter for the slope right +3, down 1: + +From your starting position at the top-left, check the +position that is right 3 and down 1. Then, check the position +that is right 3 and down 1 from there, and so on until you go +past the bottom of the map. + +The locations you'd check in the above example are marked here +with O where there was an open square and X where there was a +tree: + + ..##.........##.........##.........##.........##....... + #..O#...#..#...#...#..#...#...#..#...#...#..#...#...#.. + .#....X..#..#....#..#..#....#..#..#....#..#..#....#..#. + +In this example, traversing the map using this slope would +cause you to encounter 7 trees. + +Starting at the top-left corner of your map and following a +slope of right 3 and down 1, how many trees would you +encounter? + +---- + +This will need more memory than a default Retro build has, +so start by building a version with a much larger memory +footprint and support for 64-bit cells: + + make CFLAGS="-DIMAGE_SIZE=8000000 -O2 -DBIT64" + +I am doing this in a simple way, constructing a large enough +map that I can just iterate through. + +Some math. + +My input file has 323 lines with 31 characters per line. With +a horizontal distance of 3 per row, the last position will be +at 969 characters out. So the lines need to be a little over +31 times longer than they are by default. + +The easy way to do this is to duplicate the pointer and use +`s:append` to concat them until I get it long enough. Five +iterations is plenty, but I'll do a bit more since I suspect +that I'll need a larger map for the second half. + +~~~ +:extend (s-s) + #7 [ dup s:append ] times s:keep ; +~~~ + +We also need to raise the limit on temporary string size. + +~~~ +#4096 !TempStringMax +~~~ + +With this, I can create an array for the inputs: + +~~~ +'input-day-3 'INPUT s:const + +(Count_the_number_of_lines) +#0 INPUT [ drop n:inc ] file:for-each-line + +(Create_the_array,_and_reserve_space) +'MAP d:create dup , allot + +(Fill_in_the_array) +MAP n:inc INPUT [ extend over store n:inc ] file:for-each-line drop +~~~ + +Now all that's left is to quickly iterate through it, increasing a +counter for the horizontal distance. + +~~~ +#0 #0 MAP [ over + fetch $# eq? [ &n:inc dip ] if #3 + ] a:for-each +drop n:put nl +~~~ + +---- + +# Part 2 + +Time to check the rest of the slopes - you need to minimize the +probability of a sudden arboreal stop, after all. + +Determine the number of trees you would encounter if, for each +of the following slopes, you start at the top-left corner and +traverse the map all the way to the bottom: + + Right 1, down 1. + Right 3, down 1. (This is the slope you already checked.) + Right 5, down 1. + Right 7, down 1. + Right 1, down 2. + +In the above example, these slopes would find 2, 7, 3, 4, and +2 tree(s) respectively; multiplied together, these produce the +answer 336. + +What do you get if you multiply together the number of trees +encountered on each of the listed slopes? + +---- + +This is pretty much the same, except for the last one, which +needs to ignore every other line. + +I start by just running through each of the trivial slopes, +reducing down the products. + +~~~ +'Right var + +:calculate + !Right + #0 #0 MAP [ over + fetch $# eq? [ &n:inc dip ] if @Right + ] a:for-each + drop ; + +{ #1 #3 #5 #7 } #1 [ calculate * ] a:reduce +~~~ + +Then create a new MAP, discarding the odd lines. + +~~~ +{ #0 MAP [ swap dup n:odd? [ nip ] if n:inc ] a:for-each } 'MAP const +~~~ + +And finally run through the final slope, multiplying by the +other products to get the final answer. + +~~~ +#0 #0 MAP [ over + fetch $# eq? [ &n:inc dip ] if #1 + ] a:for-each +drop * + +n:put nl +~~~ + diff --git a/example/advent-of-code-2020-day-4.retro b/example/advent-of-code-2020-day-4.retro new file mode 100644 index 0000000..739f50f --- /dev/null +++ b/example/advent-of-code-2020-day-4.retro @@ -0,0 +1,239 @@ +# Day 4: Passport Processing + +You arrive at the airport only to realize that you grabbed your +North Pole Credentials instead of your passport. While these +documents are extremely similar, North Pole Credentials aren't +issued by a country and therefore aren't actually valid +documentation for travel in most of the world. + +It seems like you're not the only one having problems, though; +a very long line has formed for the automatic passport scanners, +and the delay could upset your travel itinerary. + +Due to some questionable network security, you realize you might +be able to solve both of these problems at the same time. + +The automatic passport scanners are slow because they're having +trouble detecting which passports have all required fields. The +expected fields are as follows: + + byr (Birth Year) + iyr (Issue Year) + eyr (Expiration Year) + hgt (Height) + hcl (Hair Color) + ecl (Eye Color) + pid (Passport ID) + cid (Country ID) + +Passport data is validated in batch files (your puzzle input). +Each passport is represented as a sequence of key:value pairs +separated by spaces or newlines. Passports are separated by +blank lines. + +Here is an example batch file containing four passports: + + ecl:gry pid:860033327 eyr:2020 hcl:#fffffd + byr:1937 iyr:2017 cid:147 hgt:183cm + + iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884 + hcl:#cfa07d byr:1929 + + hcl:#ae17e1 iyr:2013 + eyr:2024 + ecl:brn pid:760753108 byr:1931 + hgt:179cm + + hcl:#cfa07d eyr:2025 pid:166559648 + iyr:2011 ecl:brn hgt:59in + +The first passport is valid - all eight fields are present. The +second passport is invalid - it is missing hgt (the Height field). + +The third passport is interesting; the only missing field is cid, +so it looks like data from North Pole Credentials, not a passport +at all! Surely, nobody would mind if you made the system +temporarily ignore missing cid fields. Treat this "passport" as +valid. + +The fourth passport is missing two fields, cid and byr. Missing +cid is fine, but missing any other field is not, so this passport +is invalid. + +According to the above rules, your improved system would report +2 valid passports. + +Count the number of valid passports - those that have all +required fields. Treat cid as optional. In your batch file, how +many passports are valid? + +---- + +I first create two data structures: an array of passport +strings, and a buffer to hold the current passport being +read in. + +The `Passports` array is constructed using the `buffer:` +words. + +~~~ +'Passports d:create #1024 allot +'Passport d:create #1024 allot + +&Passports n:inc buffer:set +~~~ + +Importing the passports is pretty easy. There's a blank line after +each entry is complete, so just gather the text until then, then +save the string and record a pointer into the `Passports` listing. + +~~~ +:add-data '_ s:append &Passport s:append &Passport s:copy ; +:record drop &Passport s:keep buffer:add #0 !Passport ; +:completed? dup s:length n:zero? ; +:finish &Passports n:inc s:length !Passports ; + +:passports:load + [ completed? [ record ] + [ add-data ] choose ] file:for-each-line finish ; + +'input-day-4 passports:load +~~~ + +Now that the passport database is loaded, we can simply check +each entry for the required fields, increasing a counter for +each one that proves valid. + +~~~ +:valid? + [ [ 'byr: s:contains-string? ] + [ 'iyr: s:contains-string? ] + [ 'eyr: s:contains-string? ] tri and and ] + + [ [ 'hgt: s:contains-string? ] + [ 'hcl: s:contains-string? ] + [ 'ecl: s:contains-string? ] tri and and ] + + [ 'pid: s:contains-string? ] tri and and ; + +#0 &Passports [ valid? [ n:inc ] if ] a:for-each +~~~ + +---- + +# Part Two + +The line is moving more quickly now, but you overhear airport +security talking about how passports with invalid data are +getting through. Better add some data validation, quick! + +You can continue to ignore the cid field, but each other +field has strict rules about what values are valid for +automatic validation: + + byr (Birth Year) - four digits; at least 1920 and at most 2002. + iyr (Issue Year) - four digits; at least 2010 and at most 2020. + eyr (Expiration Year) - four digits; at least 2020 and at most 2030. + hgt (Height) - a number followed by either cm or in: + If cm, the number must be at least 150 and at most 193. + If in, the number must be at least 59 and at most 76. + hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f. + ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth. + pid (Passport ID) - a nine-digit number, including leading zeroes. + cid (Country ID) - ignored, missing or not. + +Your job is to count the passports where all required fields +are both present and valid according to the above rules. Here +are some example values: + + byr valid: 2002 + byr invalid: 2003 + + hgt valid: 60in + hgt valid: 190cm + hgt invalid: 190in + hgt invalid: 190 + + hcl valid: #123abc + hcl invalid: #123abz + hcl invalid: 123abc + + ecl valid: brn + ecl invalid: wat + + pid valid: 000000001 + pid invalid: 0123456789 + +Here are some invalid passports: + + ... snipped ... + +Count the number of valid passports - those that have all +required fields and valid values. Continue to treat cid as +optional. In your batch file, how many passports are valid? + +---- + +I'll start this by defining some things. An array of valid eye +colors, and some words for validating ranges for particular +fields. + +~~~ +{ 'amb 'blu 'brn 'gry 'hzl 'oth 'grn } 'EYE-COLORS const + +:birth-year? s:to-number #1920 #2002 n:between? ; +:issue-year? s:to-number #2010 #2020 n:between? ; +:expire-year? s:to-number #2020 #2030 n:between? ; +:height-imperial? #59 #76 n:between? ; +:height-metric? #150 #193 n:between? ; +~~~ + +I'll store a count of the number of valid fields in a variable. + +~~~ +'Valid var +:record-result [ &Valid v:inc ] if ; +~~~ + +Then I implement the checks for each field. + +~~~ +:process-byr [ s:length #4 eq? ] + [ birth-year? ] bi and record-result ; +:process-iyr [ s:length #4 eq? ] + [ issue-year? ] bi and record-result ; +:process-eyr [ s:length #4 eq? ] + [ expire-year? ] bi and record-result ; +:process-hgt [ [ c:digit? ] s:filter s:to-number ] + [ #2 s:right 'cm s:eq? ] bi + [ height-metric? ] [ height-imperial? ] choose record-result ; +:process-hcl [ fetch $# eq? ] + [ s:length #7 eq? ] + [ [ 'abcdef0123456789 swap s:contains-char? ] s:filter s:length #6 eq? ] tri + and and record-result ; +:process-ecl EYE-COLORS a:contains-string? record-result ; +:process-pid [ s:length #9 eq? ] + [ [ c:digit? ] s:filter s:length #9 eq? ] bi and record-result ; +~~~ + +Processing each passport is just a matter of splitting it up +into fields and checking each. The final number of valid +passports will be left on the stack. + +~~~ +:split s:trim ASCII:SPACE s:tokenize ; +:get-field $: s:tokenize [ ] a:for-each swap ; + +:validate-field 'byr [ process-byr ] s:case + 'iyr [ process-iyr ] s:case + 'eyr [ process-eyr ] s:case + 'hgt [ process-hgt ] s:case + 'hcl [ process-hcl ] s:case + 'ecl [ process-ecl ] s:case + 'pid [ process-pid ] s:case + drop-pair ; + +:validate #0 !Valid split [ get-field validate-field ] a:for-each ; +#0 &Passports [ dup valid? [ validate @Valid #7 eq? [ n:inc ] if ] [ drop ] choose ] a:for-each +~~~ + diff --git a/example/advent-of-code-2020-day-5.retro b/example/advent-of-code-2020-day-5.retro new file mode 100644 index 0000000..68827d3 --- /dev/null +++ b/example/advent-of-code-2020-day-5.retro @@ -0,0 +1,145 @@ +# Day 5: Binary Boarding + +You board your plane only to discover a new problem: you dropped +your boarding pass! You aren't sure which seat is yours, and all +of the flight attendants are busy with the flood of people that +suddenly made it through passport control. + +You write a quick program to use your phone's camera to scan all +of the nearby boarding passes (your puzzle input); perhaps you +can find your seat through process of elimination. + +Instead of zones or groups, this airline uses binary space +partitioning to seat people. A seat might be specified like +FBFBBFFRLR, where F means "front", B means "back", L means +"left", and R means "right". + +The first 7 characters will either be F or B; these specify +exactly one of the 128 rows on the plane (numbered 0 through +127). Each letter tells you which half of a region the given +seat is in. Start with the whole list of rows; the first +letter indicates whether the seat is in the front (0 through +63) or the back (64 through 127). The next letter indicates +which half of that region the seat is in, and so on until +you're left with exactly one row. + +For example, consider just the first seven characters of +FBFBBFFRLR: + + Start by considering the whole range, rows 0 through 127. + F means to take the lower half, keeping rows 0 through 63. + B means to take the upper half, keeping rows 32 through 63. + F means to take the lower half, keeping rows 32 through 47. + B means to take the upper half, keeping rows 40 through 47. + B keeps rows 44 through 47. + F keeps rows 44 through 45. + The final F keeps the lower of the two, row 44. + + The last three characters will be either L or R; these + specify exactly one of the 8 columns of seats on the + plane (numbered 0 through 7). The same process as above + proceeds again, this time with only three steps. L means + to keep the lower half, while R means to keep the upper + half. + +For example, consider just the last 3 characters of FBFBBFFRLR: + + Start by considering the whole range, columns 0 through 7. + R means to take the upper half, keeping columns 4 through 7. + L means to take the lower half, keeping columns 4 through 5. + The final R keeps the upper of the two, column 5. + + So, decoding FBFBBFFRLR reveals that it is the seat at row + 44, column 5. + +Every seat also has a unique seat ID: multiply the row by 8, +then add the column. In this example, the seat has ID +44 \* 8 + 5 = 357. + +Here are some other boarding passes: + + BFFFBBFRRR: row 70, column 7, seat ID 567. + FFFBBBFRRR: row 14, column 7, seat ID 119. + BBFFBBFRLL: row 102, column 4, seat ID 820. + +As a sanity check, look through your list of boarding passes. +What is the highest seat ID on a boarding pass? + +---- + +This is actually *really* easy. In this case, the boarding passes +ultimately correspond directly to a binary value for the seat id. +So, all that's needed is to convert the boarding pass to a string +representation of the binary value, then convert that to an actual +number. + +Since Retro is decmal only, I started by bringing in some code to +work with other bases. + +~~~ +'Base var + +:binary #2 !Base ; +:decimal #10 !Base ; + +{{ + '0123456789ABCDEF 'DIGITS s:const + 'Number var + 'Mod var + :convert (c-) &DIGITS swap s:index-of + @Number @Base * + !Number ; + :check-sign (s-s) dup fetch $- eq? + [ #-1 !Mod n:inc ] [ #1 !Mod ] choose ; +---reveal--- + :s:to-number (s-n) + #0 !Number check-sign [ convert ] s:for-each @Number @Mod * ; +}} +~~~ + +Then the rest was trivial. + +~~~ +:c:to-binary + $F [ $0 ] case + $B [ $1 ] case + $L [ $0 ] case + $R [ $1 ] case ; +:s:to-binary-rep [ c:to-binary ] s:map ; +:convert s:to-binary-rep binary s:to-number ; + +#0 'input-day-5 [ convert n:max ] file:for-each-line +n:put nl +~~~ + +---- + +# Part Two --- + +Ding! The "fasten seat belt" signs have turned on. Time to find +your seat. + +It's a completely full flight, so your seat should be the only +missing boarding pass in your list. However, there's a catch: +some of the seats at the very front and back of the plane don't +exist on this aircraft, so they'll be missing from your list as +well. + +Your seat wasn't at the very front or back, though; the seats +with IDs +1 and -1 from yours will be in your list. + +What is the ID of your seat? + +---- + +This is also really easy. I just fill in a list of seats to see +which are used, then ignore the empty ones at the start before +returning the first empty one in the middle. + +~~~ +'Seats d:create #1024 allot +'input-day-5 [ convert &Seats + v:on ] file:for-each-line +&Seats n:inc [ fetch-next n:zero? ] while + [ fetch-next n:zero? ] until &Seats - n:put nl +~~~ + +