If you have a lisp installation, emacs, org-mode, and org-babel support for lisp installed you can run this by:
- Starting slime (
M-x slime
) - Typing
C-c C-c
in the block initialize. - In the repl type
(in-package :aoc-2020-06)
- Typing
C-c C-c
in the block answers
(unless (find-package :cl-ppcre)
(ql:quickload "cl-ppcre"))
(unless (find-package :iterate)
(ql:quickload "iterate"))
(unless (find-package :parseq)
(ql:quickload "parseq"))
(unless (find-package :fiveam)
(ql:quickload "fiveam"))
(unless (find-package :series)
(ql:quickload "series"))
(unless (find-package :cl-permutation)
(ql:quickload "cl-permutation"))
(unless (find-package :bordeaux-threads)
(ql:quickload "bordeaux-threads"))
<<packages>>
(defpackage :aoc-2020-06
(:use :common-lisp
:iterate
:parseq
:fiveam)
(:export :problem-a
:problem-b))
(in-package :aoc-2020-06)
(defun read-input (file)
(iter (for line in-file file using #'read-line)
(collect line)))
(defparameter *input*
(read-input "input/06.txt"))
The input consists of series of question answers from multiple people. I will take their answers, put them into a hash table (so duplicates aren’t double counted) and then total answers given over all groups.
(defun split-groups (raw)
(loop for s in raw
with total = nil
with current = ""
do (cond ((string= "" s)
(push current total)
(setf current ""))
(t (setf current (concatenate 'string current s))))
finally (return (push current total))))
(defun count-anyone-answers (s)
(loop for c across s
with h = (make-hash-table)
do (setf (gethash c h) t)
finally (return (hash-table-count h))))
(defun tally-anyone-answers (groups)
(reduce #'+ (mapcar #'count-anyone-answers groups)))
<<split-groups>>
<<count-anyone-answers>>
<<tally-anyone-answers>>
(defun problem-a () (format t "Problem 06 A: ~a~%" (tally-anyone-answers (split-groups *input*))))
Instead of questions anyone answers yes to, we need the count of ones they all answered yes to. Same tally across all groups, but now the way we tally changes.
(defun gather-groups (raw)
(loop for s in raw
with total = nil
with current = nil
do (cond ((string= "" s)
(push current total)
(setf current nil))
(t (push s current)))
finally (return (push current total))))
(defun count-everyone-answers (group)
(let ((letters "abcdefghijklmnopqrstuvwxyz"))
(loop for s in group
with l = letters
do (loop for c across letters
do (unless (position c s)
(setf l (remove c l))))
finally (return (length l)))))
(defun tally-everyone-answers (groups)
(reduce #'+ (mapcar #'count-everyone-answers groups)))
<<gather-groups>>
<<count-everyone-answers>>
<<tally-everyone-answers>>
(defun problem-b ()
(format t "Problem 06 B: ~a~%"
(tally-everyone-answers (gather-groups *input*))))
<<read-input>>
<<input>>
<<initialize>>
<<structs>>
<<functions>>
<<input>>
<<problem-a>>
<<problem-b>>
(problem-a)
(problem-b)
Problem 06 A: 6249 Problem 06 B: 3103
(def-suite aoc.2020.06)
(in-suite aoc.2020.06)
(run! 'aoc.2020.06)
Simple runner.
with AOC2020.Day06;
procedure Day06 is
begin
AOC2020.Day06.Run;
end Day06;
Specification for solution.
package AOC2020.Day06 is
procedure Run;
end AOC2020.Day06;
Actual implementation body.
with Text_IO; use Text_IO;
package body AOC2020.Day06 is
procedure Sum_Of_Anyones_Answers is
F : File_Type;
Count, T : Natural := 0;
Answers : array (Character range 'a' .. 'z') of Boolean
:= (others => False);
C : Character;
begin
Open (F, In_File, "../input/06.txt");
loop
if End_Of_Line (F) or End_Of_File (F)
then
if End_Of_Line (F) then Skip_Line(F); end if;
if End_Of_Line (F) or End_Of_File(F)
then
T := 0;
for B of Answers loop
if B
then T := T + 1;
end if;
end loop;
Count := Count + T;
Answers := (others => False);
exit when End_Of_File(F);
end if;
end if;
Get (F, C);
Answers (C) := True;
end loop;
Close (F);
Put_Line ("The result for Part 1 is: " & Count'Image);
end Sum_Of_Anyones_Answers;
procedure Sum_Of_Everyones_Answers is
F : File_Type;
Count, T : Natural := 0;
Answers : array (Character range 'a' .. 'z') of Integer
:= (others => 0);
Group_Count : Natural := 0;
C : Character;
begin
Open (F, In_File, "../input/06.txt");
loop
if End_Of_Line (F) or End_Of_File (F)
then
if End_Of_Line (F) then Skip_Line (F); end if;
Group_Count := Group_Count + 1;
if End_Of_Line (F) or End_Of_File (F)
then
T := 0;
for I of Answers loop
if I = Group_Count
then T := T + 1;
end if;
end loop;
Count := Count + T;
Group_Count := 0;
Answers := (others => 0);
exit when End_Of_File(F);
end if;
end if;
Get (F, C);
Answers (C) := Answers (C) + 1;
end loop;
Close (F);
Put_Line("The result for Part 2 is: " & Count'Image);
end Sum_Of_Everyones_Answers;
procedure Run is
begin
Put_Line("Advent of Code 2020 - Day 06:"); New_Line;
Sum_Of_Anyones_Answers;
Sum_Of_Everyones_Answers;
end Run;
end AOC2020.Day06;
In order to run this you have to “tangle” the code first using C-c
C-v C-t
.
cd ada
gnatmake day06
./day06
Advent of Code 2020 - Day 06: The result for Part 1 is: 6249 The result for Part 2 is: 3103