{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "43a58377",
   "metadata": {},
   "source": [
    "---\n",
    "title: \"Day 1:\"\n",
    "author: The MidWit\n",
    "date: 2026-05-29\n",
    "description: \"Getting Santa's steps in\"\n",
    "categories: [student-log, rust, advent-of-code, learning]\n",
    "---\n",
    "\n",
    "\n",
    "::: {.callout-note}\n",
    "You can find the text of the puzzle at [here](puzzle.qmd). I've put some fake input that should give me a result of -1 so when you see output ending in -1, that means my implementation is working. \n",
    ":::\n",
    "\n",
    "# Overview\n",
    "\n",
    "The aim of this puzzle is to take in a long string of text, somewhat awkwardly, composed of \"(\" and \")\", and to iterate a counter up or down respectively until we come to a final floor (where Santa ends up after following the instructions).\n",
    "\n",
    "## Concepts\n",
    "\n",
    " - File IO\n",
    " - Iteration\n",
    " - control flow\n",
    " - mutability\n",
    " - wrapped value (`Result`)\n",
    "\n",
    "## Initial thoughts\n",
    "\n",
    "So in python-land I would read in the input string and iterate over the characters with a for loop, checking each char and incrementing/decrementing a counter to get the final number... so that's where I started. \n",
    "\n",
    "# Part 1\n",
    "\n",
    "## Reading in a text file. \n",
    "\n",
    "So rather than using [context manager](https://book.pythontips.com/en/latest/context_managers.html) to read the text and bind it to a variable, Rust has a function in the standard library: `use std::fs::read_to_string;`. \n",
    "\n",
    "```{rust}\n",
    "#| label: file-io-1\n",
    "\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    println!(\"{}\", input)//\n",
    "}\n",
    "```\n",
    "\n",
    "This was my first hurdle\n",
    "\n",
    "```{ansi}\n",
    "$ cargo rust\n",
    "  Compiling day_1 v0.1.0 (/path/to/day_1/main)\n",
    "error[E0277]: `Result<String, std::io::Error>` doesn't implement `std::fmt::Display`\n",
    " --> src/main.rs:5:20\n",
    "  |\n",
    "5 |     println!(\"{}\", input)//\n",
    "  |               --   ^^^^^ `Result<String, std::io::Error>` cannot be formatted with the default formatter\n",
    "  |               |\n",
    "  |               required by this formatting parameter\n",
    "  |\n",
    "  = help: the trait `std::fmt::Display` is not implemented for `Result<String, std::io::Error>`\n",
    "  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead\n",
    "\n",
    "For more information about this error, try `rustc --explain E0277`.\n",
    "error: could not compile `day_1` (bin \"day_1\") due to 1 previous error\n",
    "```\n",
    "\n",
    "`read_to_string` doesn't just return a `String` that I can manipulate directly (of course!) it returns a [Result\\<String\\>](https://doc.rust-lang.org/std/io/type.Result.html), and that creates all sorts of... opportunities for learning. \n",
    "\n",
    " - The value I want is *inside* a `Result` rather than directly available, so I gotta deal with that\n",
    " - The `Result` doesn't have the `Display Trait` so I need to put one of the formatting bugs inside the \"`{}`\"\n",
    "\n",
    "1 of those is easy to deal with: \n",
    "\n",
    "\n",
    "```{rust}\n",
    "#| label: file-io-2\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    println!(\"{:?}\", input)// put the debug syntax into the println! macro\n",
    "}\n",
    "```\n",
    "\n",
    "which gives me\n",
    "\n",
    "```{ansi}\n",
    "$cargo run\n",
    "   Compiling day_1 v0.1.0 (path/to/day_1)\n",
    "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s\n",
    "     Running `target/debug/day_1`\n",
    "Ok(\"()(((()()))()((()))())()())\\n\")\n",
    "```\n",
    "\n",
    "So we can see that the output shows us that my input is wrapped in `Ok()`, which is one of the variants of the `Result` enum.\n",
    "Which in some ways is fine, but I want the actual feed of characters, so I have a few options. \n",
    "\n",
    " - `.unwrap()` which will either give me the string directly or `Panic`\n",
    " - `.expect()` which is basically the same, but I can put an error message in to help me. \n",
    " - Properly `match` on the `Result` and either get the content or handle the error. \n",
    "    \n",
    "\n",
    "```{rust}\n",
    "#| label: file-io-expect\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    println!(\"{}\", input.expect(\"no text here my dude\"))// trying expect\n",
    "}\n",
    "```\n",
    "\n",
    "```{ansi}\n",
    "$cargo run\n",
    "   Compiling day_1 v0.1.0 (path/to/day_1)\n",
    "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s\n",
    "     Running `target/debug/day_1`\n",
    "()(((()()))()((()))())()())\n",
    "```\n",
    "So that did work, but everything I've read says that both `unwrap` and `expect` are great tools for rapid iteration without getting bogged down, but that they shouldn't be used in production code... and *yes* I'm not writing production code, but if I'm trying to learn more than just the basics, I should probably aim in that direction. \n",
    "\n",
    "## match\n",
    "\n",
    "A `match` expression is a way to check the state of an object and control what happens based on what's there. It's very similar to the `if/else if/else` concept, but it can be a lot more ergonomic depending on what you're checking, and `enum`s are a great usecase for it. Python actually has a similar concept also called a `match` expression but I hadn't come across that in my own work until recently so I would have relied on `if/elif/else` in previous work. I'm trying to practice \"idiomatic\" rust patterns here so lets `match`:\n",
    "\n",
    "\n",
    "```{rust}\n",
    "#| label: file-io-match\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input {\n",
    "        Ok(s) => println!(\"{}\", s),// match unpacks the value for us\n",
    "        Err(e) => println!(\"We got an error {}\", e),// Printing a custom message and the Error\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "OK so that gives us the actual input string as something I can use, so let me move on to actually tracking floors. \n",
    "\n",
    "# One step up N steps down\n",
    "\n",
    "So what were trying to do is, starting at 0 (the ground floor) find the floor number that Santa ends up on after taking all the steps indicated in the input: \"(\" = up 1, \")\" = down 1. Rust will let us iterate over the characters in a `String` by calling `.chars()`. This gives us back a collection we can iterate over. \n",
    "\n",
    "Coming from python, my instinct is to reach for a `loop` and `if/else`\n",
    "\n",
    "```{rust}\n",
    "#| label: immutable-loop\n",
    "// assume the main function and prelude\n",
    "\n",
    "let floor = 0;\n",
    "for c in input.chars() {\n",
    "    if c == \"(\" {\n",
    "        floor += 1 \n",
    "    } else if c == \")\" {\n",
    "        floor -= 1 \n",
    "    } else {\n",
    "        floor\n",
    "    }\n",
    "};\n",
    "println!(\"{}\", floor);\n",
    "```\n",
    "\n",
    "Which brings me to a (drum roll please) *RUST ROOKIE MISTAKE* : `mutability`. \n",
    "\n",
    "```{ansi}\n",
    "  --> src/main.rs:10:21\n",
    "   |\n",
    " 7 |             let floor = 0;\n",
    "   |                 ----- first assignment to `floor`\n",
    "...\n",
    "10 |                     floor += 1\n",
    "   |                     ^^^^^^^^^^ cannot assign twice to immutable variable\n",
    "   |\n",
    "help: consider making this binding mutable\n",
    "   |\n",
    " 7 |             let mut floor = 0;\n",
    "   |                 +++\n",
    "\n",
    "error[E0384]: cannot assign twice to immutable variable `floor`\n",
    "  --> src/main.rs:12:21\n",
    "   |\n",
    " 7 |             let floor = 0;\n",
    "   |                 ----- first assignment to `floor`\n",
    "...\n",
    "12 |                     floor -= 1\n",
    "   |                     ^^^^^^^^^^ cannot assign twice to immutable variable\n",
    "   |\n",
    "help: consider making this binding mutable\n",
    "   |\n",
    " 7 |             let mut floor = 0;\n",
    "   |                 +++\n",
    "\n",
    "For more information about this error, try `rustc --explain E0384`.\n",
    "```\n",
    "\n",
    "Rust, cause it knows I'm a midwit, makes things immutable by default, meaning that once I bind a value to a variable I can't change it... *unless* (\"unless\") I specifically say that that value is `mutable`. There's lots of really good reasons for this, but if you're reading this post and you haven't already seen those... then... I mean... welcome, I guess. \n",
    "\n",
    "Anyway, fortunately this one is easy to fix: \n",
    "\n",
    "\n",
    "```{rust}\n",
    "#| label: mutable-loop\n",
    "// assume the main function and prelude\n",
    "\n",
    "let mut floor = 0;\n",
    "for c in input.chars() {\n",
    "    if c == \"(\" {\n",
    "        floor += 1 \n",
    "    } else if c == \")\" {\n",
    "        floor -= 1 \n",
    "    } else {\n",
    "        floor\n",
    "    }\n",
    "};\n",
    "println!(\"{}\", floor);\n",
    "```\n",
    "\n",
    "And... that gave me back the correct answer (for part 1 at least). Boom. I've written more than hello world. And yet...\n",
    "\n",
    "# Closures {#closures}\n",
    "\n",
    "While the `for` loop is legitimate rust, an this solution works, it's not really, mutability and wrapping aside, that different from how I would solve a short problem like this in python, which ain't really my goal here. So I guess I better try tackling this with a [`closure`](https://doc.rust-lang.org/book/ch13-01-closures.html). \n",
    "\n",
    "My main problem with `closure`s isn't the concept so much as the number of possible options, and there's no way to learn these except to use them enough times. I really need to write a cheat sheet for them that I can look up later but for now, I'm going to ask my buddy `Claude` to recommend one[^1], or more accurately to recommend an [`iterator adapter`](https://doc.rust-lang.org/std/iter/#adapters) which will accept a closure and let me do the thing. \n",
    "\n",
    "## Fold {#fold}\n",
    "\n",
    "So again, let's think about what the puzzle wants: \n",
    "\n",
    "Starting at 0, iterate over a collection of `char`s incrementing or decrementing a number (*accumulating*), producing a count of the number of up or down steps we've taken. This looks like a job for `.fold()`. \n",
    "\n",
    "[^1]: I really don't like using LLMs for learning, for too many reasons to go into here, but honestly, as a docs reader I do think they are great, and I'm not above saving myself days of reading through docs or reddit to get an answer. If you think I got Claude to give me the whole solution, then you probably think I got Claude to write this whole post, so there's not really a lot I can do about that. We're all just tryin' to figure this out I suppose. \n",
    "\n",
    "```{rust}\n",
    "#| label: closure-fold\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input { // match on input\n",
    "        Ok(s) => { // when input is Ok()\n",
    "        let result = s.chars().fold( // bind the product of the closure to result\n",
    "                // 0, is the starting number\n",
    "                // |acc, is the variable name for 0 \n",
    "                // c| is the variable name for each char in input for each loop\n",
    "                0, |acc, c| match c { // matching on c\n",
    "                '(' => acc + 1, // incrementing acc\n",
    "                ')' => acc -1, // decrementing acc\n",
    "                _ => acc // using the wildcard so that the match is exhaustive\n",
    "            });\n",
    "        println!(\"{}\",result); //printing the result\n",
    "        },\n",
    "        Err(e) => println!(\"We got an error {}\", e),// Printing a custom message and the Error\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "```{ansi}\n",
    "#| label: closure-fold-output\n",
    "$cargo run\n",
    "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s\n",
    "     Running `target/debug/day_1`\n",
    "-1\n",
    "```\n",
    "\n",
    "So `.fold()` lets me set a starting value (in the above case it's 0), then bind that value to `acc` (standing for *accumulator*) and then bind the current `char` to `c` while looping over `input`, accumulating a count of steps for each `c`. \n",
    "\n",
    "As someone who's not a programmer, and who writes pretty quick and dirty python, I have to say I really like the closure approach. I can't really say why but it *feels* like it reduced some typing for me (for c in chars{ if/else}), but some of that is also just the `match` implementation as well. \n",
    "\n",
    "# Refactoring\n",
    "\n",
    "One of the things that I find challenging is reading deeply nested code, or it's probably more accurate to say that I find it really hard to debug deeply nested code. My imposter-syndrome self likes to tell me that real coders don't have a problem with this, but my better angels remind me that:\n",
    " - I don't want to be a real coder so I should just be happy for those that don't have this problem, and \n",
    " - There's probably loads of really talented engineers who also struggle with this. \n",
    "\n",
    "All this to say that I prefer when the code is split up into smaller blocks [^2] that I can reason about individually. While this isn't exactly deeply nested, it is a few layers deep between the 2 `match` blocks, and so now might be a good time to think about pulling some of this apart so I can put it back together. Especially given that there is a part two to this [puzzle](./puzzle.qmd), so re-usability might be nice to have...\n",
    "\n",
    "\n",
    "[^2]: I'm not qualified to say that this is 'right' or 'wrong' I'm saying that my brain and eyes prefer it. Maybe it is better to wire everything together in longer chunks, but I'm > 40 years old and I'm trying to learn what I'm trying to learn, so... get off my back! \n",
    "\n",
    "\n",
    "## Taking steps. \n",
    "\n",
    "The first clear thing I can do is pull the 'char' matching out into it's own function:\n",
    "\n",
    "**Take a `char` and an `i32` and then give back an updated `i32`**\n",
    "\n",
    "```{rust}\n",
    "#| label: take-step-definition\n",
    "\n",
    "//take step function\n",
    "//this just does what I was doing in the fold but in a function that I can\n",
    "//use in the .fold() closure\n",
    "fn take_step(c: char, value: i32) -> i32 {\n",
    "    match c {\n",
    "        '(' => value + 1,\n",
    "        ')' => value -1, \n",
    "        _ => value\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "Ok, that might not be the most perfect rust function but it does what I want it to do. I should probably make it return a `Result` and write some proper `Error` handling, but baby steps here (this is already much too long). \n",
    "\n",
    "So now my solution is \n",
    "\n",
    "```{rust}\n",
    "#| label: function-fold-1\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input {\n",
    "        Ok(s) => {\n",
    "        let result = s.chars().fold(\n",
    "                0, |acc, c| take_step(c, acc)\n",
    "            );\n",
    "        println!(\"{}\",result);\n",
    "        },\n",
    "        Err(e) => println!(\"We got an error {}\", e),// Printing a custom message and the Error\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "This compiles so the refactor works (boom) but also I find it easier to see what's going on inside the `.fold()` (second boom). \n",
    "\n",
    "This also prompted me to think about handling errors and other ways I could refactor to get rid of other nesting in my `main` function. Specifically I could re-work the file I/O to handle errors and let me drop that outer `match` expression but I'm going to call that my [first sidequest](day_1_sidequest.qmd) in which our hero write a module to handle reading challenge input that I can use in all the other day's of AOC. But for now let's move onto part 2. \n",
    "\n",
    "\n",
    "# Part 2: Don't go down there! It's dark..\n",
    "\n",
    "So for the second part, I have to find the first `char` that causes Santa to enter the basement (brings the counter below 0). \n",
    "\n",
    "In python land I would use some kind of `while` loop here and `enumerate` over the input string; but I'd like to see if there is a way to do this with a closure? \n",
    "\n",
    "I know that the `.enumerate()` method will give me back both the `index` and the `values` in a collection so adding that into my `adapter` chain is a good start, but `.fold()` isn't really the move here because we want to stop at a particular point, not take the whole collection. \n",
    "\n",
    "A little searching tells me that `.find()` might do what I want, and Claude suggested `.scan()`. I'm going to try [`.find()`](http://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find) first and see what happens. \n",
    "\n",
    "```{rust}\n",
    "#| label: find-1\n",
    "\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn take_step(c: char, value: i32) -> i32 {\n",
    "// -- snip --\n",
    "}\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input {\n",
    "        Ok(s) => {\n",
    "// -- snip --\n",
    "        let floor = 0;\n",
    "        let basement = s.chars()\n",
    "            .enumerate()\n",
    "            .find(|(i,c)|\n",
    "                take_step(c, floor) == -1\n",
    "                );\n",
    "\n",
    "        },\n",
    "// -- snip --\n",
    "    }\n",
    "}\n",
    "```\n",
    "This was my first attempt and it was really just an attempt to see what I get back from `.find()`. Here's what happened. \n",
    "\n",
    "```{ansi}\n",
    "#| label: find-1-output\n",
    "  --> src/main.rs:22:27\n",
    "   |\n",
    "22 |                 take_step(c, floor) == -1\n",
    "   |                 --------- ^ expected `char`, found `&char`\n",
    "   |                 |\n",
    "   |                 arguments to this function are incorrect\n",
    "   |\n",
    "note: function defined here\n",
    "  --> src/main.rs:3:4\n",
    "   |\n",
    " 3 | fn take_step(c: char, value: i32) -> i32 {\n",
    "   |    ^^^^^^^^^ -------\n",
    "help: consider dereferencing the borrow\n",
    "   |\n",
    "22 |                 take_step(*c, floor) == -1\n",
    "   |                           +\n",
    "```\n",
    "\n",
    "Ok, so what this is telling me is that `c` is getting passed into the function as a `borrow` rather than the actual `char` and so I need to `deref`. I'm not going to pretend I fully understand why right now, but I do know that I just need to do what the compiler tells me to fix it. And having done so we can see some output. \n",
    "\n",
    "```{ansi}\n",
    "#| label: find-1-output-2\n",
    "warning: unused variable: `i`\n",
    "  --> src/main.rs:21:21\n",
    "   |\n",
    "21 |             .find(|(i,c)|\n",
    "   |                     ^ help: if this is intentional, prefix it with an underscore: `_i`\n",
    "   |\n",
    "   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default\n",
    "\n",
    "warning: `day_1` (bin \"day_1\") generated 1 warning (run `cargo fix --bin \"day_1\" -p day_1` to apply 1 suggestion)\n",
    "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s\n",
    "     Running `target/debug/day_1`\n",
    "-1\n",
    "Some((1, ')'))\n",
    "```\n",
    "\n",
    "For now I'm going to ignore the `unused_variables` warning and focus on the fact that `.find()` is returning an `Option<(i,c)>` which is good news, if a little confusing to read. I'm not sure that this value is right though, so I'm going to do a little `println!` debugging to see what's happening.\n",
    "\n",
    "```{rust}\n",
    "#| label: find-1-println\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn take_step(c: char, value: i32) -> i32 {\n",
    "// -- snip --\n",
    "}\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input {\n",
    "        Ok(s) => {\n",
    "// -- snip --\n",
    "        let floor = 0;\n",
    "        let basement = s.chars()\n",
    "            .enumerate()\n",
    "            .find(|(i,c)| {\n",
    "                println!(\"floor = {}\", floor);\n",
    "                println!(\"index = {}\", i);\n",
    "                println!(\"char = {}\", c);\n",
    "                take_step(*c, floor) == -1\n",
    "            });\n",
    "// -- snip --\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "Which gives me \n",
    "\n",
    "```{ansi}\n",
    "#| label: find-1-println-output\n",
    "// --snip --\n",
    "floor = 0\n",
    "index = 0\n",
    "char = (\n",
    "floor = 0\n",
    "index = 1\n",
    "char = )\n",
    "Some((1, ')'))\n",
    "```\n",
    "\n",
    "I know, you saw the problem already and have been shouting at me for the last few paragraphs, but... \"MidWit\" remember?\n",
    "\n",
    "So `floor` isn't getting updated at any point which means while I'm actually getting a technically correct answer (which is the best kind of correct) it's not in the spirit of the puzzle. Really I'm just finding the first character that subtracts 1 from 0... let's see if I can fix it. \n",
    "\n",
    "```{rust}\n",
    "#| label: find-1-update\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn take_step(c: char, value: i32) -> i32 {\n",
    "// -- snip --\n",
    "}\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input {\n",
    "        Ok(s) => {\n",
    "// -- snip --\n",
    "        let floor = 0;\n",
    "        let basement = s.chars()\n",
    "            .enumerate()\n",
    "            .find(|(i,c)| {\n",
    "                println!(\"floor = {}\", floor);\n",
    "                println!(\"index = {}\", i);\n",
    "                println!(\"char = {}\", c);\n",
    "                floor += take_step(*c, floor); // Updating floor here\n",
    "                floor == -1\n",
    "            });\n",
    "// -- snip --\n",
    "    }\n",
    "}\n",
    "```\n",
    "```{ansi}\n",
    "#| label: find-1-update-output\n",
    "// -- snip --\n",
    "\n",
    "floor = 2001801\n",
    "index = 22\n",
    "char = (\n",
    "floor = 4003603\n",
    "index = 23\n",
    "char = )\n",
    "floor = 8007205\n",
    "index = 24\n",
    "char = (\n",
    "floor = 16014411\n",
    "index = 25\n",
    "char = )\n",
    "floor = 32028821\n",
    "index = 26\n",
    "char = )\n",
    "floor = 64057641\n",
    "index = 27\n",
    "char =\n",
    "\n",
    "None\n",
    "```\n",
    "*Sad Trombone* \n",
    "\n",
    "Ok, so, again you probably saw what I was doing wrong here: I'm not just taking a step each round. I'm adding `floor` to itself and then the `take_step` value. So `find()` doesn't easily keep track of the value we're trying to update well. While I could spend ages thinking about how to manage this, it might be time to see if `.scan()`, which is more similar to `.fold()`, can do for us. \n",
    "\n",
    "## Scan {#scan}\n",
    "\n",
    "Based on the docs, `.scan()` gives back another iterator and so that will need processing as well to get the actual point at which Santa enters the basement for the first time. I'm going to try to build this chain piece by piece starting with the scan. \n",
    "\n",
    "```{rust}\n",
    "#| label: scan-1-start\n",
    "// -- snip --\n",
    "\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input {\n",
    "        Ok(s) => {\n",
    "// -- snip --\n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                take_step(c, *acc);\n",
    "                Some(*acc)\n",
    "            }\n",
    "            \n",
    "            );\n",
    "        println!(\"{:?}\", basement);\n",
    "```\n",
    "\n",
    "```{ansi}\n",
    "#| label: scan-1-start-output\n",
    "// -- snip --\n",
    "Scan { iter: Chars(['(', ')', '(', '(', '(', '(', ')', '(', ')', ')', ')', '(', ')', '(', '(', '(', ')', ')', ')', '(', ')', ')',\n",
    " '(', ')', '(', ')', ')', '\\n']), state: 0 }\n",
    "```\n",
    "\n",
    "Great, we have a `Scan` object which is a collection of `char`s and a `state`... great... I * definitely know what to do with that... def'nitly. \n",
    "\n",
    "What do I know that can help me figure this out?\n",
    "\n",
    " - A lot of closures are 'lazy' meaning that I would need to `.collect()` or otherwise process it. \n",
    " - I still need to get a particular index, so `.enumerate()` is still going to be needed. \n",
    " - Speaking of which, `.find()` is probably going to come into it's own here. \n",
    " - Claude recommended `.scan()` so I might not be on the right track with `.scan()` either, but that's probably not as helpful to think about right now. \n",
    "\n",
    "Let me start by seeing what happens when I `.collect()` the `.scan()`. \n",
    "\n",
    "```{ansi}\n",
    "#| label: scan-1-collect-output\n",
    "error[E0283]: type annotations needed\n",
    "  --> src/main.rs:25:35\n",
    "   |\n",
    "25 |         println!(\"{:?}\", basement.collect());\n",
    "   |                                   ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect`\n",
    "   |\n",
    "   = note: cannot satisfy `_: FromIterator<i32>`\n",
    "note: required by a bound in `collect`\n",
    "  --> /rustc/59807616e1fa2540724bfbac14d7976d7e4a3860/library/core/src/iter/traits/iterator.rs:2051:4\n",
    "help: consider specifying the generic argument\n",
    "   |\n",
    "25 |         println!(\"{:?}\", basement.collect::<Vec<_>>());\n",
    "   |                                          ++++++++++\n",
    "\n",
    "For more information about this error, try `rustc --explain E0283`.\n",
    "\n",
    "```\n",
    "\n",
    "*Say it with me folks!! Rust. Rookie. Mistake!* The compiler needs to know what I'm trying to make so the code needs a *turbofish* [^3] where the type is specified. \n",
    "\n",
    "[^3]: If you think for one minute that the fact that it's called a *turbofish* isn't a big reason why I'm trying to learn rust, you're out of your mind. \n",
    "\n",
    "```{rust}\n",
    "#| label: scan-1-turbofish\n",
    "// -- snip --\n",
    "    \n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                take_step(c, *acc);\n",
    "                Some(*acc)\n",
    "            }\n",
    "            \n",
    "            );\n",
    "        println!(\"{:?}\", basement.collect::<Vec<_>>());\n",
    "// -- snip --\n",
    "```\n",
    "That gives me back a vector of 0s... because of course it does. I'm not sure what that means yet either, but I'm gonna keep going. We know that we're looking for an index as I said, so my next thought is to add `.enumerate()` to the chain, as this will give me a `Vec<(index, state)>` (I think). \n",
    "\n",
    "```{rust}\n",
    "#| label: scan-1-enumerate\n",
    "// -- snip --\n",
    "    \n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                take_step(c, *acc);\n",
    "                Some(*acc)\n",
    "            }\n",
    "            \n",
    "            )\n",
    "            .enumerate();\n",
    "        println!(\"{:?}\", basement.collect::<Vec<_>>());\n",
    "// -- snip --\n",
    "```\n",
    "```{ansi}\n",
    "#| label: scan-1-enumerate-output\n",
    "// -- snip --\n",
    "[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0), (10, 0), (11, 0), (12, 0), (13, 0), (14, 0), (15\n",
    ", 0), (16, 0), (17, 0), (18, 0), (19, 0), (20, 0), (21, 0), (22, 0), (23, 0), (24, 0), (25, 0), (26, 0), (27, 0)]\n",
    "// -- snip --\n",
    "```\n",
    "\n",
    "Yes! Well... half yes. I'm getting the tuple I expect (I think), but the fact that the second item is always 0 leads me to believe that something is going wrong in the way `.scan()` is interacting with my `take_step` function. Rather than move onto adding the `.find()` part of the chain I'm going to unpack the `take_step` functionality and do it explicitly inside the `closure`\n",
    "\n",
    "```{rust}\n",
    "#| label: scan-1-explicit\n",
    "// -- snip --\n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                acc += match c {\n",
    "                    '(' => acc + 1,\n",
    "                    ')' => acc -1, \n",
    "                    _ => acc\n",
    "                };\n",
    "                Some(*acc)\n",
    "            })\n",
    "            .enumerate();\n",
    "        println!(\"{:?}\", basement.collect::<Vec<_>>());\n",
    "// -- snip --\n",
    "```\n",
    "Oh boy, this next one is a doozy\n",
    "\n",
    "```{ansi}\n",
    "#| label: scan-1-explicit-output\n",
    "// -- snip --\n",
    "  --> src/main.rs:21:32\n",
    "   |\n",
    "21 |                     '(' => acc + 1,\n",
    "   |                            --- ^ - {integer}\n",
    "   |                            |\n",
    "   |                            &mut {integer}\n",
    "   |\n",
    "   = note: an implementation for `&{integer} + {integer}` exists\n",
    "help: consider reborrowing this side\n",
    "   |\n",
    "21 |                     '(' => &*acc + 1,\n",
    "   |                            ++\n",
    "\n",
    "error[E0369]: cannot subtract `{integer}` from `&mut {integer}`\n",
    "  --> src/main.rs:22:32\n",
    "   |\n",
    "22 |                     ')' => acc -1,\n",
    "   |                            --- ^- {integer}\n",
    "   |                            |\n",
    "   |                            &mut {integer}\n",
    "   |\n",
    "   = note: an implementation for `&{integer} - {integer}` exists\n",
    "help: consider reborrowing this side\n",
    "   |\n",
    "22 |                     ')' => &*acc -1,\n",
    "   |                            ++\n",
    "// -- snip --\n",
    "```\n",
    "OK, so, again, I'm not sure if this is accurately diagnosing what the issue was earlier, but it is showing me that `acc` is mutably borrowed inside the `closure`, so if I'm understanding correctly then it means I need to `deref` `acc` before the `match`, also if I leave `acc` in the match arms I'll end up with the same problem I had with the earlier find: doubling. \n",
    "\n",
    "```{rust}\n",
    "#| label: scan-1-deref\n",
    "// -- snip --\n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                *acc += match c {\n",
    "                    '(' => 1,\n",
    "                    ')' => -1, \n",
    "                    _ => 0\n",
    "                };\n",
    "                Some(*acc)\n",
    "            })\n",
    "            .enumerate();\n",
    "        println!(\"{:?}\", basement.collect::<Vec<_>>());\n",
    "// -- snip --\n",
    "```\n",
    "We have a third boom. \n",
    "\n",
    "```{ansi}\n",
    "#| label: scan-1-deref-output\n",
    "// -- snip --\n",
    "[(0, 1), (1, 0), (2, 1), (3, 2), (4, 3), (5, 4), (6, 3), (7, 4), (8, 3), (9, 2), (10, 1), (11, 2), (12, 1), (13, 2), (14, 3), (15, 4), (16, 3), (17, 2), (18, 1), (19, 2), (20, 1), (21, 0), (22, 1), (23, 0), (24, 1), (25, 0), (26, -1), (27, -1)]\n",
    "// -- snip --\n",
    "```\n",
    "\n",
    "So the state is now updating as we run through it, meaning that now I just need to `.find()` the first time we get a -1 in the state, which we can see is at index 26 in this output. \n",
    "\n",
    "What we have now is the vec of `(i, state)` that we need to pass into `.find()`, and because `.find()` takes only one parameter I need to pass them in in that format rather than as separate arguments.\n",
    "\n",
    "```{rust}\n",
    "#| label: scan-1-find\n",
    "// -- snip --\n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                *acc += match c {\n",
    "                    '(' => 1,\n",
    "                    ')' => -1, \n",
    "                    _ => 0\n",
    "                };\n",
    "                Some(*acc)\n",
    "            })\n",
    "            .enumerate()\n",
    "            .find(|(i, state)| *state == -1);\n",
    "        println!(\"{:?}\", basement.collect::<Vec<_>>());\n",
    "// -- snip --\n",
    "```\n",
    "```{ansi}\n",
    "#| label: scan-1-find-output\n",
    "// -- snip --\n",
    "  --> src/main.rs:29:35\n",
    "   |\n",
    "29 |         println!(\"{:?}\", basement.collect::<Vec<_>>());\n",
    "   |                                   ^^^^^^^ method cannot be called on `Option<(usize, {integer})>` due to unsatisfied trait b\n",
    "ounds\n",
    "   |\n",
    "   = note: the following trait bounds were not satisfied:\n",
    "           `Option<(usize, {integer})>: Iterator`\n",
    "           which is required by `&mut Option<(usize, {integer})>: Iterator`\n",
    "\n",
    "For more information about this error, try `rustc --explain E0599`.\n",
    "// -- snip --\n",
    "```\n",
    "\n",
    "Ok, so `.find()` returns an `Option` rather than a collection that needs to be `.collect()`ed so I need to drop that bit, so long turbofish!\n",
    "\n",
    "```{rust}\n",
    "#| label: scan-find-println\n",
    "// -- snip --\n",
    "    println!(\"{}\", basement);\n",
    "// -- snip --\n",
    "```\n",
    "Ladies and Jellyspoons, we have reached the 4th boom. \n",
    "\n",
    "```{ansi}\n",
    "#| label: scan-find-println-output\n",
    "// -- snip --\n",
    "warning: unused variable: `i`\n",
    "  --> src/main.rs:28:21\n",
    "   |\n",
    "28 |             .find(|(i, state)| *state == -1);\n",
    "   |                     ^ help: if this is intentional, prefix it with an underscore: `_i`\n",
    "   |\n",
    "   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default\n",
    "\n",
    "warning: `day_1` (bin \"day_1\") generated 1 warning (run `cargo fix --bin \"day_1\" -p day_1` to apply 1 suggestion)\n",
    "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s\n",
    "     Running `target/debug/day_1`\n",
    "-1\n",
    "Some((26, -1))\n",
    "// -- snip --\n",
    "```\n",
    "\n",
    "OK, so we have the `Some(tuple)` that shows us the index and the state we want. So functionally we have the output we want. The eagle eyed amongst you will have spotted that the last `char` in `input` is `'\\n'` and so the wildcard in the `match` is doing what we want as well and leaving `acc` as it is. \n",
    "\n",
    "Thus we have out answer to both parts!... except...\n",
    "\n",
    "As I said up above I'm trying to write towards production code, and while I have my answer, the output is ugly as fu... it doesn't look great. So, it might be worth it to try to make the output prettier. \n",
    "\n",
    "## Prettifying\n",
    "\n",
    "This is one of the places `.unwrap()` may work well because there is a `Some` that we just want to get the value out of. \n",
    "\n",
    "```{rust}\n",
    "#| label: scan-unwrap\n",
    "// -- snip --\n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                *acc += match c {\n",
    "                    '(' => 1,\n",
    "                    ')' => -1, \n",
    "                    _ => 0\n",
    "                };\n",
    "                Some(*acc)\n",
    "            })\n",
    "            .enumerate()\n",
    "            .find(|(i, state)| *state == -1)\n",
    "            .unwrap();\n",
    "// -- snip --\n",
    "```\n",
    "Which gives us back the tuple `(26,-1)`. Since we just want the zeroth item in the tuple we could just destructure it with `.` syntax as well to just get the `26` back in out output. However, I want to deal with that `unused_variables` warning now and I think that [`.map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) might let me do that. `.map()` will let me create a new iterator and apply a new closure to it *in line*, letting me destructure the tuple I get back from `.find()`.\n",
    "\n",
    "```{rust}\n",
    "#| label: pretty-map\n",
    "// -- snip --\n",
    "            .enumerate()\n",
    "            .find(|(i, state)| *state == -1)\n",
    "            .map(|(i, state)| i as i32)\n",
    "            .unwrap();\n",
    "// -- snip --\n",
    "```\n",
    "\n",
    "\n",
    "````{ansi}\n",
    "#| label: pretty-map-output\n",
    "// -- snip --\n",
    "warning: unused variable: `state`\n",
    "  --> src/main.rs:29:23\n",
    "   |\n",
    "29 |             .map(|(i, state)| i as i32)\n",
    "   |                       ^^^^^ help: if this is intentional, prefix it with an underscore: `_state`\n",
    "   |\n",
    "   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default\n",
    "\n",
    "warning: unused variable: `i`\n",
    "  --> src/main.rs:28:21\n",
    "   |\n",
    "28 |             .find(|(i, state)| *state == -1)\n",
    "   |                     ^ help: if this is intentional, prefix it with an underscore: `_i`\n",
    "\n",
    "warning: `day_1` (bin \"day_1\") generated 2 warnings (run `cargo fix --bin \"day_1\" -p day_1` to apply 2 suggestions)\n",
    "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s\n",
    "     Running \\`target/debug/day_1\\`\n",
    "-1\n",
    "26\n",
    "// -- snip --\n",
    "````\n",
    "\n",
    "OK, so the compiler is telling me that if I want to get rid of the `unused_variables` warning I just need to prefix the variable names with \"\\_\" and so let me do that one last time and check the output. \n",
    "\n",
    "# Final implementation {#final-implementation}\n",
    "\n",
    "```{rust}\n",
    "#| label: final-implementation\n",
    "use std::fs::read_to_string;// bring the function into scope\n",
    "\n",
    "fn take_step(c: char, value: i32) -> i32 {\n",
    "    match c {\n",
    "        '(' => value + 1,\n",
    "        ')' => value -1, \n",
    "        _ => value\n",
    "    }\n",
    "}\n",
    "fn main () {\n",
    "    let input = read_to_string(\"./input.txt\");// read the input\n",
    "    match input {\n",
    "        Ok(s) => {\n",
    "        let result = s.chars().fold(\n",
    "                0, |acc, c| take_step(c, acc)\n",
    "            );\n",
    "        println!(\"We're on floot {}\",result);\n",
    "        let basement = s.chars()\n",
    "            .scan(0, |acc, c| {\n",
    "                *acc += match c {\n",
    "                    '(' => 1,\n",
    "                    ')' => -1, \n",
    "                    _ => 0\n",
    "                };\n",
    "                Some(*acc)\n",
    "            })\n",
    "            .enumerate()\n",
    "            .find(|(_i, state)| *state == -1)\n",
    "            .map(|(i, _state)| i as i32)\n",
    "            .unwrap();\n",
    "        println!(\"The first time we hit the basement is {}\", basement);\n",
    "\n",
    "        },\n",
    "        Err(e) => println!(\"We got an error {}\", e),// Printing a custom message and the Error\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "```{ansi}\n",
    "#| label: final-output\n",
    "$cargo run\n",
    "   Compiling day_1 v0.1.0 (path/to/day_1)\n",
    "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s\n",
    "     Running `target/debug/day_1`\n",
    "We're on floor -1\n",
    "The first time we hit the basement is 26\n",
    "```\n",
    "\n",
    "**Ultimate BOOM!**. \n",
    "\n",
    "We have a solution.\n",
    "\n",
    "It's definitely not perfect and it spawned at least one [sidequest](day_1_sidequest.qmd) but as a fledgling rust writer I think I can be pretty happy with it. \n",
    "\n",
    "# What do I need to take from this? \n",
    "\n",
    " - Closures are great, but there's a lot of adaptors and, frankly the documentation isn't that easy to parse. \n",
    "   - `.find()` lets us look for a condition\n",
    "   - `.fold()` lets us accumulate a value over a collection (at least as far as I understand it)\n",
    "   - `.scan()` is like `.fold()`, except it gives back a collection and a state item that we can track\n",
    " - I need to learn more about referencing and dereferencing, there is a principle there around how something gets passed into a closure, but it hasn't clicked for me yet. \n",
    " - The compiler is a good ally, especially if the issue is rudimentary.\n",
    " - Walking through the problem is a good idea, even if it's after the fact. \n",
    "   - I wrote this up after I had a solved, but I was taking checkpoints as I went so that I could try to consolidate things. \n",
    "   - I definitely used Claude to help me parse the errors, and as I said above to suggest adaptors that might be useful to me. It would often tell me to just reach for a `for` loop though and I'd have to do a lot to get it to stick with my learning goals. Working with an LLM definitely saved time, but when my aim is to learn, not to meet KPIs as a developer this isn't ideal. I have a 'Rust-coach' skill which often works well, but I've found that it's tough to keep it from being too helpful and it's better for me to just not use one when I'm tired: too tempting to just get an answer, which isn't the same as learning a thing. \n",
    " - This write up took way too long. In future it would be better to hit highlights better, but then I don't really know what qualifies as a highlight this early in the show. \n",
    " - Refactoring is good *even if* it doesn't actually get reused. \n",
    "   - I certainly could have updated `take_step()` to accomodated Part 2, but as a learning excercise it was worth doing even though it just contributed to Part 1. \n",
    "\n",
    "Anyway, that's too much for a single post, espeshally a first'un.\n",
    "\n",
    "God's speed. \n",
    "\n",
    "The MidWit"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3",
   "path": "/home/runner/.local/share/jupyter/kernels/python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
