diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a3a745 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.txt +.DS_Store diff --git a/day1/main.pl b/day1/main.pl new file mode 100644 index 0000000..e6aff72 --- /dev/null +++ b/day1/main.pl @@ -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 +*/ diff --git a/day2/main.pl b/day2/main.pl new file mode 100644 index 0000000..3091537 --- /dev/null +++ b/day2/main.pl @@ -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 + ). diff --git a/day3/main.pl b/day3/main.pl new file mode 100644 index 0000000..9dd0ad0 --- /dev/null +++ b/day3/main.pl @@ -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).