Advent of Code 2023
Siarhei Siamashka
siarhei.siamashka at gmail.com
Sun Dec 3 14:51:37 UTC 2023
On Saturday, 2 December 2023 at 13:33:33 UTC, Johannes
Miesenhardt wrote:
> I am a bloody beginner so if there are any things that are very
> wrong with this please point them out.
Everything is fine as long as it works and does the job.
> The fact that I need a template for accepting both a string and
> a char[] is very weird but I went with it.
The `string` type is not the same as `char[]`. It's actually
`immutable(char)[]`. The differences are explained in the D
language spec:
https://dlang.org/spec/const3.html#const_and_immutable
Strings can be safely passed around between functions and
multiple instances of the same string can share the same memory
location, the characters inside of a string are read-only.
Whereas character arrays allow read/write access.
Casting between character arrays and strings is a bad idea by
design. Converting between strings and character arrays involves
allocating memory for a new copy and this happens under the hood
when calling `.dup`, `.idup`, `.to!string` or `.byLineCopy`.
> I am also curious if there is a better way for the reversible
> for-loop to happen. I saw foreach and foreach_reverse but I
> don't think that helps me here, since I swap them out based on
> a runtime argument.
Below is my solution for the day 1 puzzle, which used
https://dlang.org/library/std/range/retro.html to search
characters starting from the end:
```D
import std;
void main() {
auto input = stdin.byLineCopy.array;
try {
input.map!(s => (s.find!"a >= '0' && a <= '9'".front - '0') *
10 +
s.retro.find!"a >= '0' && a <= '9'".front -
'0')
.sum.writefln!"Part1: %d";
} catch (Error e) {
writefln!"Part1: malformed input";
}
auto words = "one, two, three, four, five, six, seven, eight,
nine"
.split(", ").zip(iota(1, 10))
.map!(x => tuple(x[0], x[0] ~ x[1].to!string ~
x[0])).array;
input.map!(s => words.fold!((a, subst) =>
a.replace(subst[]))(s))
.map!(s => (s.find!"a >= '0' && a <= '9'".front - '0') *
10 +
s.retro.find!"a >= '0' && a <= '9'".front -
'0')
.sum.writefln!"Part2: %d";
}
```
The key features are:
* I'm using `import std;` and this makes the source code smaller
(at the expense of a bit longer compile time). This is a bad
style in real applications, but suitable here.
* I'm reading the input data from `stdin`, because it's a common
convention for solving algorithmic puzzles on various websites
(such as codeforces or atcoder).
* The string "one, two, three, four, five, six, seven, eight,
nine" was copy-pasted from the puzzle text and then parsed by the
code. This was it's a bit faster to implement and less prone to
typos.
* For part2 the input text was preprocessed ("one" is replaced by
"one1one", "two" is replaced by "two2two" and so on). And after
such search & replace is complete, the whole task becomes the
same as the already solved part1. Such approach makes the code
slower, but the code is simpler and faster to implement. A useful
tradeoff for the Advent of Code puzzles.
More information about the Digitalmars-d-learn
mailing list