Trebuchet?!
Tags: adventofcode, javascript, programming, computerscience
Published: 2023-12-01 20:08:23

## [Advent of Code 2023 Day 1](https://adventofcode.com/2023/day/1)

### Part 1

#### Three steps - at least as I see it
1. A regular expression to find the digits
2. Extracting the matches at the book ends
3. Coercing, summing and reducing

Let's get to it!

##### A regular expression to find the digits
```
a1b2c3d4e5f
```

I need a regular expression that matches only the five digits `1-5` in the string above.

Thankfully, that's as simple as:

```
/\d/g
```

##### Extracting the matches at the book ends
Once I have the list of matches, I want the first and last ones only, event if they are the same from having only one digit in the string:

```js
  matches[0] , matches[matches.length - 1]
```

##### Coercing, summing and reducing
Then I need to coerce each match to numbers and fuse them together into a two-digit number:

```js
+(matches[0] + matches[matches.length - 1])
```

Lastly, this can all fit nicely in a larger `reduce`r function that iterates through the full input:
```
For each input string, accumulate a number starting at 0
  Find all digits in the string
  Extract the first and last matches
  Fuse them together into a two-digit number
  Return the sum of the accumulated number and this two-digit number

Return the accumulated sums
```

#### Altogether, in JavaScript
```js
input.split('\n').reduce(
  (sums, text) => {
    const matches = [...text.matchAll(/\d/g)].map(el => el[0])
    return sums + +(matches[0] + matches[matches.length - 1])
  }, 0
)
```

It generates the correct answer for the example input!

#### Confirming it works before submitting
This is what I see when running the algorithm on a few lines of my input:
```
[ '4' ] 44
[ '2' ] 22
[ '6' ] 66
[ '4' ] 44
[ '5' ] 55
[ '5', '2' ] 52
[ '1', '3', '7', '8', '1' ] 11
[ '8' ] 88
[ '4', '3', '1' ] 41
[ '6', '2', '2', '3' ] 63
```

It successfully doubles the single digits, and fuses together the first and last digits!

#### Getting excited for Part 2
A quick glance at my input revealed some numbers spelled out:
```
gtjtwonefourone6fouronefccmnpbpeightnine
     one    one     one             nine
        four    four           eight
```

I wonder if part two will pose the same challenge, but using the spelled out words instead of the digits?!

#### Submitting my answer to Part 1
It was correct!

### Part 2

#### I was right!...and then some!
Part 2 *does* require using the spelled out numbers.

But in addition to - not instead of - the digits!

Hmmm, this...just...got...trickier.

#### Matching the spelled out numbers
Seems like there's no way to avoid a legend:
```
['one','two','three','four',...,'nine']
```

Or is there...?

Could I do this with a regular expression, still?

```
/one|two|three|four|five|six|seven|eight|nine|\d/g
```

It works!

But how will I convert words to numbers before fusing or doubling?

#### Turning words into numbers when necessary

How about a dictionary a.k.a. object?
```
one: 1,
two: 2,
three: 3,
...
nine: 9
```

I'll need to check the matched string for whether it is a number:

```js
if (isNaN(match))
  look-up in dictionary
else
  already a number
```

#### All of that, in pseudocode
```
Set dictionary mapping words to digits
For each input string, accumulate a number starting at 0
  Find all numbers - word or digit - in the string
  Extract the first and last matches
  If either match is a word
    Convert word to digit
  Fuse them together into a two-digit number
  Return the sum of the accumulated number and this two-digit number

Return the accumulated sums
```

#### Now, in JavaScript
```js
const dict = { 'one': '1', 'two': '2', ... }
input.split('\n').reduce((sums, text) => {
  const regex = /one|two|three|four|five|six|seven|eight|nine|\d/g
  const matches = [...text.matchAll(regex)].map(el => el[0])
  let [first, last] = [matches[0], matches[matches.length - 1]]
  if (isNaN(first)) first = dict[first]
  if (isNaN(last)) last = dict[last]
  return sums + +(first + last)
}, 0)
```

#### Checking and submitting
It works on the example input!

The console shows the expected extractions for each line.

It generated the correct answer for my input, too!

### Lovin' me some `regex`
I'm so glad I took the time to learn and practice `regex` in earlier AoC challenges.

[Regexr](https://regexr.com) has been an invaluable tool as a beginner.

I'd hate to imagine being a beginner and trying today's challenge!

If that's you, I hope you find this series helpful and validation that you too can go from CS newbie to near-expert solver (except for shortest-path and performance-based algorithms) with enough practice, persistence and patience.

And now we wait for Day 2 to unlock...