If you have a lisp installation, emacs, org-mode, and org-babel support for lisp installed you can run this by:
- Starting slime (
M-x slime
) - Typing
C-c C-c
in the block initialize. - In the repl type
(in-package :aoc-2021-02)
- Typing
C-c C-c
in the block answers
(unless (find-package :cl-ppcre)
(ql:quickload "cl-ppcre"))
(unless (find-package :iterate)
(ql:quickload "iterate"))
(unless (find-package :parseq)
(ql:quickload "parseq"))
(unless (find-package :lparallel)
(ql:quickload "lparallel"))
(unless (find-package :fiveam)
(ql:quickload "fiveam"))
(unless (find-package :series)
(ql:quickload "series"))
(unless (find-package :cl-permutation)
(ql:quickload "cl-permutation"))
(unless (find-package :bordeaux-threads)
(ql:quickload "bordeaux-threads"))
<<packages>>
(defpackage :aoc-2021-02
(:use :common-lisp
:parseq
:fiveam)
(:export :problem-a
:problem-b))
(in-package :aoc-2021-02)
(defun read-input (file)
(with-open-file (in file)
(loop
for direction = (read in nil)
for distance = (read in nil)
while (and direction distance)
collect (list direction distance))))
(defparameter *input* (read-input "input/02.txt"))
(defun follow-directions (directions)
(loop
with position = #C(0 0)
for (dir dist) in directions
finally (return (* (realpart position) (imagpart position)))
do (case dir
(up (decf position dist))
(down (incf position dist))
(forward (incf position (complex 0 dist))))))
(defun problem-a () (format t "Problem 02 A: ~a~%" (follow-directions *input*)))
(defun follow-directions-aim (directions)
(loop
with position = #C(0 0)
with aim = 0
for (dir dist) in directions
finally (return (* (realpart position) (imagpart position)))
do (case dir
(up (decf aim dist))
(down (incf aim dist))
(forward (incf position (complex (* aim dist) dist))))))
(defun problem-b () (format t "Problem 02 B: ~a~%" (follow-directions-aim *input*)))
<<read-input>>
<<input>>
<<follow-directions>>
<<follow-directions-aim>>
<<initialize>>
<<structs>>
<<functions>>
<<input>>
<<problem-a>>
<<problem-b>>
(problem-a)
(problem-b)
Problem 02 A: 2091984 Problem 02 B: 2086261056
(def-suite aoc.2021.02)
(in-suite aoc.2021.02)
(run! 'aoc.2021.02)
Simple runner.
with AOC2021.Day02;
procedure Day02 is
begin
AOC2021.Day02.Run;
end Day02;
Specification for solution.
package AOC2021.Day02 is
procedure Run;
end AOC2021.Day02;
with Text_IO; use Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
type Direction is (Up, Down, Forward);
package Direction_IO is new Enumeration_IO(Direction);
use Direction_IO;
function Follow_Directions return Integer is
Input_File : File_Type;
To : Direction;
By : Integer;
Depth : Integer := 0;
Horizontal : Integer := 0;
begin
Open (Input_File, In_File, "../input/02.txt");
loop
exit when end_of_file (Input_File);
Get (Input_File, To);
Get (Input_File, By);
case To is
when Up => Depth := Depth - By;
when Down => Depth := Depth + By;
when Forward => Horizontal := Horizontal + By;
end case;
end loop;
Close (Input_File);
return Depth * Horizontal;
end Follow_Directions;
function Follow_Directions_Aim return Integer is
Input_File : File_Type;
To : Direction;
By : Integer;
Depth : Integer := 0;
Horizontal : Integer := 0;
Aim : Integer := 0;
begin
Open (Input_File, In_File, "../input/02.txt");
loop
exit when end_of_file (Input_File);
Get (Input_File, To);
Get (Input_File, By);
case To is
when Up => Aim := Aim - By;
when Down => Aim := Aim + By;
when Forward =>
Horizontal := Horizontal + By;
Depth := Depth + Aim * By;
end case;
end loop;
Close (Input_File);
return Depth * Horizontal;
end Follow_Directions_Aim;
Actual implementation body.
<<ada-packages>>
package body AOC2021.Day02 is
<<types-and-generics>>
<<ada-part-1>>
<<ada-part-2>>
procedure Run is
begin
Put_Line("Advent of Code 2021 - Day 02");
Put_Line("The result for Part 1 is " & Integer'Image(Follow_Directions));
Put_Line("The result for Part 2 is " & Integer'Image(Follow_Directions_Aim));
end Run;
end AOC2021.Day02;
In order to run this you have to “tangle” the code first using C-c
C-v C-t
.
cd ada
gnatmake day02
./day02
Advent of Code 2021 - Day 02 The result for Part 1 is 2091984 The result for Part 2 is 2086261056
I’m not splitting it up this time, placing here for completeness. This is also located in Day 2 Rust Source.
Some thoughts:
- Type inference is great. I need to remember to specify types more
often, but Rust does a good job of propagating type
information.
d
,h
, andaim
didn’t have to be specified asi64
since this could be determined by the function return type. - str/string is confusing.
- The borrow checker is both friend and foe. I had a version that used an iterator (like day 1) but ran into a problem after splitting the input. Now I think I know the solution, but this version is probably clearer anyways.
use std::fs::File;
use std::io::{BufRead, BufReader};
pub fn day02_01() -> i64 {
let filename = "../input/02.txt";
let file = File::open(filename).unwrap();
let reader = BufReader::new(file);
let (mut h, mut d) = (0, 0);
for line in reader.lines() {
let line = line.unwrap();
let parts: Vec<_> = line.split_whitespace().collect();
let distance = parts[1].parse::<i64>().unwrap();
match parts[0] {
"forward" => h = h + distance,
"up" => d = d - distance,
"down" => d = d + distance,
_ => (),
}
}
return h * d;
}
pub fn day02_02() -> i64 {
let filename = "../input/02.txt";
let file = File::open(filename).unwrap();
let reader = BufReader::new(file);
let (mut h, mut d, mut aim) = (0, 0, 0);
for line in reader.lines() {
let line = line.unwrap();
let parts: Vec<_> = line.split_whitespace().collect();
let distance = parts[1].parse::<i64>().unwrap();
match parts[0] {
"forward" => {
h = h + distance;
d = d + distance * aim;
}
"up" => aim = aim - distance,
"down" => aim = aim + distance,
_ => (),
}
}
return h * d;
}