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.