@@ -16,6 +16,7 @@ Table of Contents
16
16
- [ Day 10 - Syntax Scoring] [ d10 ]
17
17
- [ Day 11 - Dumbo Octopus] [ d11 ]
18
18
- [ Day 12 - Passage Pathing] [ d12 ]
19
+ - [ Day 13 - Transparent Origami] [ d13 ]
19
20
20
21
21
22
Day 1 - Sonar Sweep
@@ -2390,6 +2391,176 @@ print('Part 2:', n)
2390
2391
2391
2392
As "easy" as that!
2392
2393
2394
+
2395
+ Day 13 - Transparent Origami
2396
+ ----------------------------
2397
+
2398
+ [ Problem statement] [ d13-problem ] — [ Complete solution] [ d13-solution ] — [ Back to top] [ top ]
2399
+
2400
+ ### Part 1
2401
+
2402
+ Today we need to fold a sheet of paper a bunch of times. Interesting. We are
2403
+ given a list of points in space (i.e. dots of ink on our paper sheet) in the
2404
+ form ` x,y ` . Our coordinate system starts from the top-left corner of our paper
2405
+ sheet, with X coordinates growing right, and Y coordinates growing * down* . After
2406
+ this, we are given a list of directions of two possible forms:
2407
+
2408
+ - ` fold along x=XXX ` we need to "fold" our paper sheet along the axis ` x=XXX ` ,
2409
+ which means folding * up* the bottom half of the sheet.
2410
+ - ` fold along y=YYY ` we need to "fold" our paper sheet along the axis ` y=YYY ` ,
2411
+ which means folding * left* the right half of the sheet.
2412
+
2413
+ Our sheet is transparent, so when folding, if two points end up being on top of
2414
+ each other we will only see one. For the first part, we only need to perform the
2415
+ first fold instruction, and then count the number of visible points.
2416
+
2417
+ Let's start by building our transparent paper sheet. Since it is transparent
2418
+ and, as the problem statement says, we need to count any overlapping points as a
2419
+ single point after folding, we can use a ` set ` of tuples ` (x, y) ` to represent
2420
+ the sheet. This will make it easy to ignore overlaps.
2421
+
2422
+ For each line of input, [ ` .split() ` ] [ py-str-split ] it in half and turn the two
2423
+ numbers into a ` tuple ` of ` int ` with the help of [ ` map() ` ] [ py-builtin-map ] .
2424
+ Then, add the tuple to the set. Since folding instructions are separated from
2425
+ the list of coordinates by an empty line, when we found one we'll ` break ` and
2426
+ stop processing coordinates.
2427
+
2428
+ ``` python
2429
+ sheet = set ()
2430
+
2431
+ for line in fin:
2432
+ if line == ' \n ' :
2433
+ break
2434
+
2435
+ coords = tuple (map (int , line.split(' ,' )))
2436
+ sheet.add(coords)
2437
+ ```
2438
+
2439
+ Folding our paper sheet is nothing more than a [ reflection] [ wiki-reflection ]
2440
+ along an axis that is only applied to the points past the axis. Since our
2441
+ reflection axes can only be horizontal or vertical, and since we only need to
2442
+ reflect points * past* the axis, the operation is quite simple. Reflecting a
2443
+ point is nothing more than "moving it" as far on the opposite side of the axis
2444
+ as its original distance from the axis.
2445
+
2446
+ - For a vertical reflection with axis ` x=A ` , the ` x ` coordinate of a point
2447
+ becomes ` A - (x - A) ` or ` 2*A - x ` .
2448
+ - For an horizontal reflection with axis ` y=A ` , the ` y ` coordinate of a point
2449
+ becomes ` A - (y - A) ` or ` 2*A - y ` .
2450
+
2451
+ Let's write a ` fold() ` function to do this. For simplicity, this function will
2452
+ take 3 arguments: the sheet, the distance of the reflection axis from the X or Y
2453
+ axis, and a boolean value to indicate whether we are folding vertically or
2454
+ horizontally. For each point of the sheet, depending on the folding direction,
2455
+ we'll move the X or Y coordinate as defined above, add the "moved" point to a
2456
+ new sheet.
2457
+
2458
+ ``` python
2459
+ def fold (sheet , axis , vertical = False ):
2460
+ folded = set ()
2461
+
2462
+ for x, y in sheet:
2463
+ if vertical:
2464
+ if x > axis:
2465
+ x = axis - (x - axis)
2466
+ elif y > axis:
2467
+ y = axis - (y - axis)
2468
+
2469
+ folded.add((x, y))
2470
+
2471
+ return folded
2472
+ ```
2473
+
2474
+ Now we can parse the first folding instruction and perform the fold. To only get
2475
+ one line of input we can either call [ ` next() ` ] [ py-builtin-next ] on the input
2476
+ file or use [ ` .readline() ` ] [ py-io-readline ] . The axis coordinate can be
2477
+ extracted by locating the ` = ` with [ ` .index() ` ] [ py-str-index ] , and the folding
2478
+ direction can be determined by checking whether the instruction contains ` 'x' `
2479
+ or not.
2480
+
2481
+ ``` python
2482
+ line = next (fin)
2483
+ axis = int (line[line.index(' =' ) + 1 :])
2484
+ vertical = ' x' in line
2485
+ sheet = fold(sheet, axis, vertical)
2486
+ n_points = len (sheet)
2487
+
2488
+ print (' Part 1:' , n_points)
2489
+ ```
2490
+
2491
+ ### Part 2
2492
+
2493
+ Predictably enough, now we need to apply * all* folding instructions. The point
2494
+ visible on the final folded paper sheet will line up to form a sequence of
2495
+ letters, which is our answer.
2496
+
2497
+ We already have all we need for folding... it's only a matter of wrapping it
2498
+ inside a loop:
2499
+
2500
+ ``` python
2501
+ for line in fin:
2502
+ axis = int (line[line.index(' =' ) + 1 :])
2503
+ sheet = fold(sheet, axis, ' x' in line)
2504
+ ```
2505
+
2506
+ After applying all folds, we can print out the resulting sheet and read the
2507
+ letters by hand. After determining the maximum X and Y coordinates for the
2508
+ points in the sheet, we can use a trivial double ` for ` loop to iterate over all
2509
+ the coordinates from ` (0, 0) ` to the maximum X and Y, printing one ` # `
2510
+ symbol for every point that is present in the sheet, and one space for every
2511
+ point that is not.
2512
+
2513
+ We can use [ ` max() ` ] [ py-builtin-max ] along with a generator expression to get
2514
+ the maximum values for the X and Y coordinates in our ` sheet ` . Note that we need
2515
+ to first iterate over Y and then over X to get the sheet printed in the proper
2516
+ direction!
2517
+
2518
+ ``` python
2519
+ def print_sheet (sheet ):
2520
+ maxx = max (p[0 ] for p in sheet)
2521
+ maxy = max (p[1 ] for p in sheet)
2522
+
2523
+ out = ' '
2524
+ for y in range (maxy + 1 ):
2525
+ for x in range (maxx + 1 ):
2526
+ out += ' #' if (x, y) in sheet else ' '
2527
+ out += ' \n '
2528
+
2529
+ print (out, end = ' ' )
2530
+ ```
2531
+
2532
+ We can also use [ ` itemgetter() ` ] [ py-operator-itemgetter ] to extract the
2533
+ coordinates from our points when calculating the minimum and maximum:
2534
+
2535
+ ``` diff
2536
+ def print_sheet(sheet):
2537
+ - maxx = max(p[0] for p in sheet)
2538
+ - maxy = max(p[1] for p in sheet)
2539
+ + maxx = max(map(itemgetter(0), sheet))
2540
+ + maxy = max(map(itemgetter(1), sheet))
2541
+ ...
2542
+ ```
2543
+
2544
+ Okay, let's print it!
2545
+
2546
+ ``` python
2547
+ print (' Part 2:' )
2548
+ print_sheet(sheet)
2549
+ ```
2550
+
2551
+ ```
2552
+ Part 2:
2553
+ ### ## # # ### # # # # # #
2554
+ # # # # # # # # # # # # # #
2555
+ # # # #### # # ## # ## #
2556
+ ### # ## # # ### # # # # # #
2557
+ # # # # # # # # # # # # #
2558
+ # ### # # # # # # #### # # ####
2559
+ ```
2560
+
2561
+ Cool puzzle! Today was also my first day of the year on the leaderboard (rank 37
2562
+ for P1). Phew, that took some time :')
2563
+
2393
2564
---
2394
2565
2395
2566
* Copyright © ; 2021 Marco Bonelli. This document is licensed under the [ Creative Commons BY-NC-SA 4.0] ( https://creativecommons.org/licenses/by-nc-sa/4.0/ ) license.*
@@ -2409,6 +2580,7 @@ As "easy" as that!
2409
2580
[ d10 ] : #day-10---syntax-scoring
2410
2581
[ d11 ] : #day-11---dumbo-octopus
2411
2582
[ d12 ] : #day-12---passage-pathing
2583
+ [ d13 ] : #day-13---transparent-origami
2412
2584
2413
2585
[ d01-problem ] : https://adventofcode.com/2021/day/1
2414
2586
[ d02-problem ] : https://adventofcode.com/2021/day/2
@@ -2422,6 +2594,7 @@ As "easy" as that!
2422
2594
[ d10-problem ] : https://adventofcode.com/2021/day/10
2423
2595
[ d11-problem ] : https://adventofcode.com/2021/day/11
2424
2596
[ d12-problem ] : https://adventofcode.com/2021/day/12
2597
+ [ d13-problem ] : https://adventofcode.com/2021/day/13
2425
2598
2426
2599
[ d01-solution ] : solutions/day01.py
2427
2600
[ d02-solution ] : solutions/day02.py
@@ -2435,6 +2608,7 @@ As "easy" as that!
2435
2608
[ d10-solution ] : solutions/day10.py
2436
2609
[ d11-solution ] : solutions/day11.py
2437
2610
[ d12-solution ] : solutions/day12.py
2611
+ [ d13-solution ] : solutions/day13.py
2438
2612
2439
2613
[ d03-orginal ] : original_solutions/day03.py
2440
2614
[ d07-orginal ] : original_solutions/day07.py
@@ -2458,6 +2632,7 @@ As "easy" as that!
2458
2632
[ py-builtin-map ] : https://docs.python.org/3/library/functions.html#map
2459
2633
[ py-builtin-max ] : https://docs.python.org/3/library/functions.html#max
2460
2634
[ py-builtin-min ] : https://docs.python.org/3/library/functions.html#min
2635
+ [ py-builtin-next ] : https://docs.python.org/3/library/functions.html#next
2461
2636
[ py-builtin-sorted ] : https://docs.python.org/3/library/functions.html#sorted
2462
2637
[ py-builtin-sum ] : https://docs.python.org/3/library/functions.html#sum
2463
2638
[ py-builtin-zip ] : https://docs.python.org/3/library/functions.html#zip
@@ -2468,20 +2643,22 @@ As "easy" as that!
2468
2643
[ py-frozenset ] : https://docs.python.org/3/library/stdtypes.html#frozenset
2469
2644
[ py-functools ] : https://docs.python.org/3/library/functools.html
2470
2645
[ py-functools-partial ] : https://docs.python.org/3/library/functools.html#functools.partial
2646
+ [ py-io-readline ] : https://docs.python.org/3/library/io.html#io.IOBase.readline
2471
2647
[ py-itertools-count ] : https://docs.python.org/3/library/itertools.html#itertools.count
2472
2648
[ py-itertools-product ] : https://docs.python.org/3/library/itertools.html#itertools.product
2473
2649
[ py-itertools-repeat ] : https://docs.python.org/3/library/itertools.html#itertools.repeat
2474
2650
[ py-itertools-starmap ] : https://docs.python.org/3/library/itertools.html#itertools.starmap
2475
2651
[ py-itertools-chain ] : https://docs.python.org/3/library/itertools.html#itertools.chain
2476
2652
[ py-list-sort ] : https://docs.python.org/3/library/stdtypes.html#list.sort
2653
+ [ py-operator-itemgetter ] : https://docs.python.org/3/library/operator.html#operator.itemgetter
2477
2654
[ py-set-intersection ] : https://docs.python.org/3/library/stdtypes.html#frozenset.intersection
2478
2655
[ py-statistics-median-low ] : https://docs.python.org/3/library/statistics.html#statistics.median_low
2656
+ [ py-str-index ] : https://docs.python.org/3/library/stdtypes.html#str.index
2479
2657
[ py-str-maketrans ] : https://docs.python.org/3/library/stdtypes.html#str.maketrans
2480
2658
[ py-str-rstrip ] : https://docs.python.org/3/library/stdtypes.html#str.rstrip
2481
2659
[ py-str-split ] : https://docs.python.org/3/library/stdtypes.html#str.split
2482
2660
[ py-str-splitlines ] : https://docs.python.org/3/library/stdtypes.html#str.splitlines
2483
2661
[ py-str-translate ] : https://docs.python.org/3/library/stdtypes.html#str.translate
2484
-
2485
2662
[ algo-bfs ] : https://en.wikipedia.org/wiki/Breadth-first_search
2486
2663
[ algo-dfs ] : https://en.wikipedia.org/wiki/Depth-first_search
2487
2664
[ algo-quicksort ] : https://en.wikipedia.org/wiki/Quicksort
@@ -2497,6 +2674,7 @@ As "easy" as that!
2497
2674
[ wiki-median ] : https://en.wikipedia.org/wiki/Median
2498
2675
[ wiki-pushdown-automata ] : https://en.wikipedia.org/wiki/Pushdown_automaton
2499
2676
[ wiki-queue ] : https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
2677
+ [ wiki-reflection ] : https://en.wikipedia.org/wiki/Reflection_(mathematics)
2500
2678
[ wiki-seven-segment-display ] : https://en.wikipedia.org/wiki/Seven-segment_display
2501
2679
[ wiki-stack ] : https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
2502
2680
[ wiki-triangular-number ] : https://en.wikipedia.org/wiki/Triangular_number
0 commit comments