Not Quite Lisp
AoC 2015 with Rust - Day 1
Jul 15 23 • 6 min read
Link to problem
Source of the final solution
Other posts in the series
This is the first post of the Aoc 2015 with Rust series, which will be a documented journey of me learning Rust language. I am a professional software developer so I already know a number of programming languages. For that I reason, I intend to skip parts that are common in other languages and, instead, focus on parts that are new or cryptic to me.
I will primarily use official docs and StackOverflow for more specific situations.
Toolchain is ready and installed thanks to rustup
. I will initialize projects with cargo init
, which should give us the base setup to work on. Aand let’s go!
Part 1
Santa wants to deliver presents in an apartment building but for floor directions, all he got is a set of parentheses. (
means one floor up, )
means one floor down. )())())
results in -3
, and ))((((()
results in 2
.
Piece of cake. I can increment or decrement a counter as I iterate through the set of these characters accordingly.
I remember some basic stuff from my 15 minutes of Rust experience like how to declare variables, variables being immutable by default, the mut
keyword, type inference etc. So I try some hello wordish things:
fn main() {
let text = "oi";
println!(text);
}
To my surprise, this did not work.
Compiling aoc-2015-01 v0.1.0 (/home/oz/dev/aoc/aoc-2015-01)
error: format argument must be a string literal
--> src/main.rs:3:14
|
3 | println!(text);
| ^^^^
|
help: you might be missing a string literal to format with
|
3 | println!("{}", text);
| +++++
error: could not compile `aoc-2015-01` (bin "aoc-2015-01") due to previous error
Yeh, string literals…
fn main() {
let text = "oi";
println!("{}", text);
}
//oi
The method that I will use is string.chars()
, which apparently returns an iterator (something that can be looped through), and with a for
loop, I can check each character in the string and act upon it. The question also includes some warnings about Unicode characters, which can resolve to multiple characters (ex: a̐
becomes ['a', '\u{310}']
), but since our input will only consist of parantheses, I don’t have to take any measures against this issue.
fn main() {
let instructions = "))((((()";
let mut currentFloor = 0;
for char in instructions.chars() {
if char == '(' {
currentFloor = currentFloor + 1;
} else {
currentFloor = currentFloor - 1;
}
}
println!("{}", currentFloor);
}
I found that strings has a method called chars()
which returns an iterator and, surely, running the code prints out 2
as expected. One minor hiccup
and surely, it prints out 2
.
One minor issue I faced when comparing the character to an opening paranthesis was, characters are expected to be surrounded by single quotes, not double quotes but I tried the latter first and the compiler kindly warned me and steered me into the right direction:
error[E0308]: mismatched types
--> src/main.rs:6:20
|
6 | if char == "(" {
| ---- ^^^ expected `char`, found `&str`
| |
| expected because this is `char`
|
help: if you meant to write a `char` literal, use single quotes
|
6 | if char == '(' {
| ~~~
For more information about this error, try `rustc --explain E0308`.
Now is the time for taking an input from AoC and pasting it into the instructions
variable, and run the code, hoping that it works as expected.
AoC gave me a very long string that resolved to 280
, and pasting this number into the solution box and sending it gave me this message:
Your puzzle answer was 280.
The first half of this puzzle is complete! It provides one gold star: *
Nice. On to part two!
P.S: At this point, I also realized that the compiler warned me about using camel case when naming the currentFloor
variable, so I will keep that in mind for later changes.
Part 2
The second part of the puzzle wants me to find the position of the first character that causes Santa to enter the basement (floor -1).
I want to simply add an index to the iteration, so I can pinpoint the exact location when Santa reaches the basement for the first time.
fn main() {
let instructions = "))((((()";
let mut currentFloor = 0;
let mut hasReachedBasement = false;
for (idx, char) in instructions.chars().enumerate() {
if char == '(' {
currentFloor = currentFloor + 1;
} else {
currentFloor = currentFloor - 1;
}
if !hasReachedBasement && currentFloor < 0 {
println!("{}", idx + 1);
hasReachedBasement = true;
}
}
println!("{}", currentFloor);
}
And it works! Part 2 of our puzzle is now complete.
Retrospective
The first blog post in the series turned out to be a lot longer than I wanted, and I found myself to be explaining basic programming concepts unintentionally, mostly because I am new to writing blog posts. I initially planned this series to be a “log”, rather than long explanations, but here we are… I decided to post this blog as is, but going forward, I will try to keep it as concise as possible. Let’s see how it goes.
Update: chopped most parts according to the retro