What I've learned about Python from Advent of Code day 13
Tags: python, adventofcode
Published: 2021-12-18 19:59:27

Advent of Code puzzles are fun. I use them for learning new  python features that I rarely or never use at work. Day 13 was particularly interesting.

**WARNING!** This article contains spoilers! If you want to solve this puzzle, stop reading, go to the [advent of code page](https://adventofcode.com/2021/day/13) and have fun. You can back later :)

## The puzzle

You can read the details on the above link, but here is a short summary:
* We have a list of dots on a transparent paper (a foil).
* There is a list of folding instructions: fold the paper in half along the given row or column. One half will cover the other one, and as the paper is transparent, this is some kind of a union of the two halves.

The task is to apply these folding instructions (or just one in the first part).

## The learnings

### Split string into variables

I learned it long ago and I use it from time to time, but it was a big wow-moment for me coming with a java background, so I think it's worth mentioning here.

You can split a string into a list with the `str.split` method:

```python
coordinates = line.split(',')
```

It returns a list, but you can unpack it directly into variables:
```python
x, y = line.split(',')
```

I used it a lot when parsing puzzle input. Of course you have to be sure about how many parts the original string has, or you risk a `ValueError` at runtime. The split method also has a `maxsplit` argument that can prevent such an error, but in my opinion input validation is a better idea in a real world scenario.

### Partially applied functions

I wanted to try this for so long, I even changed my solution a bit to be able to use it.

I created two functions for the folding operations.
```python
def fold_horizontally(fold_row: int, dots: set[tuple[int, int]]) -> set[tuple[int, int]]:
  ...

def fold_vertically(fold_col: int, dots: set[tuple[int, int]]) -> set[tuple[int, int]]:
  ...
```

And I parsed the fold instruction strings to a list of [partially applied functions](https://docs.python.org/3/library/functools.html#functools.partial).
```python
from functools import partial

instructions = []
while line := f.readline():
  instruction, coord = line.split('=')
  fold_func = fold_horizontally if instruction.endswith('y') else fold_vertically
  instructions.append(partial(fold_func, int(coord)))
```

What does it do? The `partial` function returns a callable object for a function and a list of arguments. The remaining arguments will be the arguments of this callable object. In my case the base function is either `fold_horizontally` or `fold_vertically`. Those functions have 2 arguments: the row or column to fold along and the list of dots. I fixed the first argument, the fold coordinate to create a partially applied function, and I put it to the `instructions` list. These functions have one argument (the set of dots) and they can be called like this:
```python
  dots = instructions[i](dots)
```
I think this can be a quite powerful tool, I should use it more frequently.

## Unicode character name

The puzzle description uses `#` characters for the dots which is a good ASCII character for this purpose, but unicode has better options. What about a [full block](https://www.unicodepedia.com/unicode/block-elements/2588/full-block/) █ character? Or a [black large circle](https://www.unicodepedia.com/unicode/miscellaneous-symbols-and-arrows/2b24/black-large-circle/) ⬤ ? Or a [hexagon](https://www.unicodepedia.com/unicode/miscellaneous-symbols-and-arrows/2b22/black-hexagon/) ⬢ ?

You can copy-paste it into your python code, but there is an [escape sequence](https://docs.python.org/3/howto/unicode.html#python-s-unicode-support) that I like much better. This is how I used it to print a dot in the grid:
```python
  print('\N{FULL BLOCK}' if (col, row) in dots else ' ', end='')
```
The result looks like this:
```
 ██       █     ██  █ █   ██    ██  █  
             █         █         █     
   █       ███      ██   ███     █ █   
 ██     █ █     █   █  █ █       █     
█         █  █ █       █ █    █  █ █   
█       █      ████ █ █         █    █ 
                                       
█     ███ █  █   █   █   █     ██   █  
█    █  █ █         █            █    █
█    █ ██    █      █  █         █ █   
█    █    █  █   █    █                
█  █ █  █ █       █ █  █ █       █ █  █
██    ██  █  █ ████  █   ██ █       ██ 
```
It's cool, isn't it? :)

I really enjoyed this puzzle, I'm looking forward to my next python discoveries with Advent of Code.