Aoc23 Day1

This year I wanted to try to solve some Advent of code problems, and what better way to do it than using a new language, in my case that language is Scheme.

I’m using Windows and scoop to install software so I found this nice scheme implementation called Gauche. So I’ve started with:

>scoop install gauche
>gosh 

and now I’m in a nice scheme REPL.

Let’s see how you read a file in Scheme.

(define input-file (open-input-file "input-file.txt" :if-does-not-exist :error))

Using open-input-file I get back a port if input-file.txt exists or an error if it doesn’t. Now with this port, I have to read the data and here I found this nice method that reads everything and returns a list of strings for each row.

(define input-data (port->string-list input-file))

Now that I have the puzzle input in input-data I can start solving the problem, for reference, the problem text can be found here, basically find the first and last digit in each row, form a number using those digits, and return the sum of all the numbers.

Let’s start by writing a function that gets the number from the string:

(define (get-number input-string)
    (let ((char-list (filter char-numeric? (string->list input-string))))
    (string->number (string (car char-list) (last char-list)))))

What this does is split the string into a list of chars then we filter that list for numeric chars and then take the first and last element from the list combine them and return a number.

The final piece of the puzzle is to fold over the input-data

input-data
("1abc2" "pqr3stu8vwx" "a1b2c3d4e5f" "treb7uchet")

(fold + 0 (map get-number input-data))

result 142

This seems to solve part 1 of the puzzle but surprise surprise there’s a second part where we have to take into account digits written as strings for example “one2ast4nine” should be 19 instead of 24. Splitting the string in a list of chars doesn’t work for this so let’s try finding all the digit positions.

First I defined all the string digits:

(define string-digits '("one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
(define digit-list '(1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9))

now we need to get positions for all of these in a string

(define (get-positions f input-string)
 (map (lambda (digit) (f input-string digit)) string-digits))

using f here because I’ll pass string-scan and string-scan-right to scan from the left when getting the first digit and from the right for the second digit. Here’s a helpful zip function and the get-number2 function

(define (zip . x) (apply map list x))

(define
 (get-number2 input-string)
 (let
  ((left-number  
     (cadar
      (sort
      (filter (lambda (x) (number? (car x)))
        (zip (get-positions string-scan input-string) digit-list)))))
   (right-number
    (last
    (last
     (sort
       (filter (lambda (x) (number? (car x)))
        (zip (get-positions string-scan-right input-string) digit-list)))))))
  (+ (* 10 left-number) right-number)))

(fold + 0 (map get-number2 input-data))

That’s about it, not the best solution but good enough for my first try.