Gah. Prolog is hard. I'm not able to find logic programming solutions to these, so I'm just doing it like I would in any other language, which is sort of defeating the point. I may go back and redo days 1 and 2, now that I understand Prolog a bit more, I'm sure I can do those better.

master
Dustin Swan 1 month ago
parent 4c52e88b12
commit 01c9db8b9a
Signed by: dustinswan
GPG Key ID: AB49BD6B2B3A6377

2
.gitignore vendored

@ -0,0 +1,2 @@
*.txt
.DS_Store

@ -0,0 +1,66 @@
file_to_lines(Path, Lines) :-
read_file_to_string(Path, S, []),
split_string(S, "\n", "\n", Lines).
% Convert "L68" into the tuple l-68
line_to_turn(Turn, Dir-Dist) :-
sub_atom(Turn, 0, 1, Len, Dir0),
sub_string(Turn, 1, Len, _, Dist0),
number_string(Dist, Dist0),
downcase_atom(Dir0, Dir).
main :-
file_to_lines("data.txt", Lines),
maplist(line_to_turn, Lines, Turns),
part1(50, 0, Turns, Res),
writeln(Res),
part2(50, 0, Turns, Res2),
writeln(Res2).
% PART 1
turn_knob(Start, Dir-Dist, Result) :-
Dir = l
-> Result is (Start - Dist) mod 100
; Result is (Start + Dist) mod 100.
% recursion base case, if list is empty, unify the NumZeros with the Result
part1(_, Res, [], Res).
% recurse through the list, turning the knob, counting zeros
part1(Start, NumZeros, [Turn|Rest], Res) :-
turn_knob(Start, Turn, NewStart),
(NewStart = 0
-> NewNumZeros is NumZeros + 1,
part1(NewStart, NewNumZeros, Rest, Res)
; part1(NewStart, NumZeros, Rest, Res)).
% PART 2
% 6225 too low
% 6323 too high
% 6238 wrong
turn_knob_count_zeros(Start, Dir-Dist, Result, Zeros) :-
( Dir = l -> Diff is -Dist ; Diff is Dist ),
Next is Start + Diff,
divmod(Next, 100, Zeros0, Result0),
Result is ((Result0 mod 100) + 100) mod 100, % normalize result
Zeros1 is abs(Zeros0),
(Start = 0, Dir = l, Dist < 100 -> Zeros2 is Zeros1 - 1 ; Zeros2 is Zeros1),
(Next = 0 -> Zeros is Zeros2 + 1 ; Zeros = Zeros2),
format('Start: ~w Dir: ~w Dist: ~w Next: ~w Result: ~w Zeros: ~w~n',
[Start, Dir, Dist, Next, Result, Zeros]).
part2(_, Res, [], Res).
part2(Start, NumZeros, [Turn|Rest], Res) :-
turn_knob_count_zeros(Start, Turn, NewStart, Zeros),
NewNumZeros is Zeros + NumZeros,
format('New Zeros ~w~n', NewNumZeros),
part2(NewStart, NewNumZeros, Rest, Res).
/*
Start: 0 Dir: l Dist: 223 Next: -223 Result: 77 Zeros: 3
Start: 52 Dir: r Dist: 192 Next: 244 Result: 44 Zeros: 2
*/

@ -0,0 +1,79 @@
file_to_ranges(Path, Ranges) :-
read_file_to_string(Path, S, []),
split_string(S, ",", ",", Ranges).
range_to_tuple(Range, Start-End) :-
split_string(Range, "-", "\n", [Start0|[End0]]),
number_string(Start, Start0),
number_string(End, End0).
is_even(N) :- integer(N), mod(N, 2) =:= 0.
main :-
file_to_ranges("data.txt", Ranges),
maplist(range_to_tuple, Ranges, Tuples),
% Part 1
maplist(find_invalids_part1, Tuples, InvalidsPart1Unflattened),
flatten(InvalidsPart1Unflattened, InvalidsPart1),
sumlist(InvalidsPart1, Part1Sum),
write("Part 1: "),
writeln(Part1Sum),
% Part 2
maplist(find_invalids_part2, Tuples, InvalidsPart2Unflattened),
flatten(InvalidsPart2Unflattened, InvalidsPart2),
sumlist(InvalidsPart2, Part2Sum),
write("Part 2: "),
writeln(Part2Sum).
% Part 1
find_invalids_part1(Start-End, Invalids) :-
numlist(Start, End, Numbers),
include(is_invalid_part1, Numbers, Invalids).
is_invalid_part1(Number) :-
number_string(Number, String),
string_length(String, Len),
(is_even(Len) ->
Len2 is Len / 2,
sub_string(String, 0, Len2, _, Start),
sub_string(String, Len2, Len2, _, End),
Start = End
; false).
% Part 2
find_invalids_part2(Start-End, Invalids) :-
numlist(Start, End, Numbers),
include(is_invalid_part2, Numbers, Invalids).
is_invalid_part2(Number) :-
number_string(Number, String),
string_length(String, FullLength),
SubLenMax is floor(FullLength / 2),
numlist(1, SubLenMax, Lengths),
maplist(generate_substrings(String), Lengths, Subs),
include(is_made_of_subs(String), Subs, Results),
length(Results, L),
L > 0.
generate_substrings(S, Len, Sub) :- sub_string(S, 0, Len, _, Sub).
% don't want to try to do this smartly, let's just check a bunch
is_made_of_subs(String, Sub) :-
string_concat(Sub, Sub, Twice),
string_concat(Twice, Sub, Thrice),
string_concat(Thrice, Sub, FourTimes),
string_concat(FourTimes, Sub, FiveTimes),
string_concat(FiveTimes, Sub, SixTimes),
string_concat(SixTimes, Sub, SevenTimes),
(
String = Twice;
String = Thrice;
String = FourTimes;
String = FiveTimes;
String = SixTimes;
String = SevenTimes
).

@ -0,0 +1,52 @@
:- use_module(library(lists)).
main :-
File = "data.txt",
run(File, 2, Part1),
writeln(Part1),
run(File, 12, Part2),
writeln(Part2).
file_bank(Path, Bank) :-
read_file_to_string(Path, S, []),
split_string(S, "\n", "\n", Lines),
member(Line, Lines),
number_string(Number, Line),
number_chars(Number, Chars),
maplist(atom_number, Chars, Bank).
run(Path, DigitSize, Sum) :-
findall(N,
(file_bank(Path, Bank), bank_max(Bank, DigitSize, N)),
Ns),
sumlist(Ns, Sum).
bank_max(Bank, DigitSize, Max) :-
bank_max_acc(Bank, DigitSize, [], Answer),
list_to_number(Answer, Max).
bank_max_acc(_, 0, NumList, NumList).
bank_max_acc(Bank, DigitsLeft, NumList, Answer) :-
length(Bank, Len),
SplitIndex is Len - DigitsLeft + 1,
split_list_at_index(Bank, SplitIndex, Left, _),
max_list(Left, Digit),
nth0(FoundIndex, Left, Digit),
DigitsLeft2 is DigitsLeft - 1,
append(NumList, [Digit], NumList2),
NewSplitIndex is FoundIndex + 1,
split_list_at_index(Bank, NewSplitIndex, _, Rest),
bank_max_acc(Rest, DigitsLeft2, NumList2, Answer),
!.
% Helpers
split_list_at_index(List, Index, Left, Right) :-
length(Left, Index),
append(Left, Right, List).
list_to_number(Digits, Number) :- list_to_number_acc(Digits, 0, Number).
list_to_number_acc([], Acc, Acc).
list_to_number_acc([Digit|Rest], AccIn, Number) :-
AccNext is AccIn * 10 + Digit,
list_to_number_acc(Rest, AccNext, Number).
Loading…
Cancel
Save