My attempts to work through the 2021 Advent of Code problems.

```commit 8d22868e18fc047526d469f40ac82afa11ed24e7
parent e7ed6b6452079a11a247c10b0b337d42f1208ce9
Date:   Sat,  4 Dec 2021 21:28:33 -0500

Solution to day 4, part 2

Diffstat:
```
```1 file changed, 40 insertions(+), 0 deletions(-)
diff --git a/day04_part2.py b/day04_part2.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+"""Very similar to part 1, except we run through all the numbers and find the
+last to win"""
+
+from utils import get_puzzle_input
+from day04_part1 import (parse_input,
+                         mark_boards,
+                         check_for_winner,
+                         score_winning_board)
+
+def find_winning_board(board_df, number_draws):
+    """Given the df of board data and the list of numbers drawn, go through the
+    numbers and find the _last_ winning board. Returns a tuple containing the
+    sum of the unmarked elements on the final winning board and last drawn
+    number"""
+    # In this approach, we'll still work through the numbers sequentially.
+    # Every time we find a winner, we note its score and remove it from the
+    # list of boards, until we've run through all of the numbers.
+    last_winning_score = None
+    winning_number = None
+
+    for number_draw in number_draws:
+        board_df = mark_boards(board_df, number_draw)
+        while (winning_board := check_for_winner(board_df)) is not None:
+            last_winning_score = score_winning_board(board_df, winning_board)
+            winning_number = number_draw
+
+            # Remove this board so we stop looking at it
+            board_df = board_df.loc[board_df['board'] != winning_board]
+
+    return last_winning_score * winning_number
+
+def solve_puzzle(input_string):
+    """Return the numeric solution to the puzzle"""
+    # 684 ms ± 7.04 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
+    return find_winning_board(*parse_input(input_string))
+
+if __name__ == "__main__":
+    print("Last winning puzzle score:",
+          solve_puzzle(get_puzzle_input(4)))
```