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.
parent
4c52e88b12
commit
01c9db8b9a
@ -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…
Reference in New Issue