DEV Community

Cover image for Advent of Code 2020 Solution Megathread - Day 6: Custom Customs
Ryan Palo
Ryan Palo

Posted on • Edited on

Advent of Code 2020 Solution Megathread - Day 6: Custom Customs

Yesterday, a lot of you finished quickly and were looking for more to keep you occupied on a Saturday. All of the golfed one-liners were really funny to read through.

The Puzzle

In today’s puzzle, we're helping our fellow passengers fill out customs forms. 26 questions represented by 'a'-'z', and the presence of a particular letter in our input means a "yes" for that question for that particular person. We're just helping tally up the results.

The Leaderboards

As always, this is the spot where I’ll plug any leaderboard codes shared from the community.

Ryan's Leaderboard: 224198-25048a19 
Enter fullscreen mode Exit fullscreen mode

If you want to generate your own leaderboard and signal boost it a little bit, send it to me either in a DEV message or in a comment on one of these posts and I'll add it to the list above.

Yesterday’s Languages

Updated 03:07PM 12/12/2020 PST.

Language Count
Ruby 3
Go 2
Python 2
Haskell 2
JavaScript 2
C 2
Rust 2
COBOL 1
Elixir 1
D 1
TypeScript 1

Merry Coding!

Top comments (28)

Collapse
 
bgaster profile image
Benedict Gaster

OK, today seemed pretty straightforward, although it took me to reach task 2 to have the insight that it was union and then intersect... oh well it is a Sunday :-)

Anyway Haskell was a nice fit and simply used set operations on lists to keep with my somewhat weak goal of using lists.

main = do xs <- IOT.readFile "day6_input" <&> fmap (map unpack . T.lines) . T.splitOn "\n\n" print (sum $ fmap (length . foldr1 union) xs) print (sum $ fmap (length . foldr1 intersect) xs) 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
kais_blog profile image
Kai • Edited

I've created a step-by-step tutorial (TypeScript) again:

and I did something with bits, just for fun:

Collapse
 
mgasparel profile image
Mike Gasparelli

Clever solution. I had an instinct that I could use binary to solve Day5, although couldn't quite flesh out a working solution (ended up solving it in a different way). It didn't even dawn on me that you could use binary for this challenge, although it seems obvious now. 👍

Collapse
 
meseta profile image
Yuan Gao • Edited

Python one-liners, thanks to set theory and list comprehension, and map
Part 1:

sum([len(set(entry.replace("\n",""))) for entry in open("input.txt").read().split("\n\n")]) 
Enter fullscreen mode Exit fullscreen mode

Part 2:

sum(len(set.intersection(*map(set, entry.split()))) for entry in open("input.txt").read().split("\n\n")) 
Enter fullscreen mode Exit fullscreen mode

I try to explain this more fully at dev.to/meseta/advent-of-code-2020-...

Collapse
 
mgasparel profile image
Mike Gasparelli

I thought the most obvious way to do this would be to intersect a bunch of HashSets, but seemed to be more short & sweet to just check that every character in the first line was contained in every other line 🤷

Part 1

 public class Part1 : Puzzle<IEnumerable<PlaneGroup>, int> { public override int SampleAnswer => 11; public override IEnumerable<PlaneGroup> ParseInput(string rawInput) => rawInput .Split(Environment.NewLine + Environment.NewLine) .Where(line => line.Length > 0) .Select(group => new PlaneGroup( group .Split(Environment.NewLine) .Where(x => x.Length > 0))); public override int Solve(IEnumerable<PlaneGroup> input) => input.Sum(x => x.CountDistinctAnswers()); } 
Enter fullscreen mode Exit fullscreen mode

Part 2

 public class Part2 : Part1 { public override int SampleAnswer => 6; public override int Solve(IEnumerable<PlaneGroup> input) => input.Sum(x => x.CountIntersectingAnswers()); } 
Enter fullscreen mode Exit fullscreen mode

PlaneGroup

 public class PlaneGroup { List<string> answers; public PlaneGroup(IEnumerable<string> answers) { this.answers = answers.ToList(); } public int CountDistinctAnswers() => new HashSet<char>(answers.SelectMany(a => a)) .Count(); public int CountIntersectingAnswers() => answers.First() .Count(c => answers.All(a => a.Contains(c))); } 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
galoisgirl profile image
Anna

COBOL

 IDENTIFICATION DIVISION. PROGRAM-ID. AOC-2020-06-2. AUTHOR. ANNA KOSIERADZKA. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT INPUTFILE ASSIGN TO "d6.input" ORGANIZATION IS LINE SEQUENTIAL. DATA DIVISION. FILE SECTION. FD INPUTFILE RECORD IS VARYING IN SIZE FROM 1 to 99 DEPENDING ON REC-LEN. 01 INPUTRECORD PIC X(99). WORKING-STORAGE SECTION. 01 FILE-STATUS PIC 9 VALUE 0. 01 REC-LEN PIC 9(2) COMP. 01 WS-GROUP-ANSWERS PIC 9 OCCURS 26 TIMES. 01 WS-CHAR PIC X. LOCAL-STORAGE SECTION. 01 I UNSIGNED-INT VALUE 1. 01 C UNSIGNED-INT VALUE 1. 01 X UNSIGNED-INT VALUE 1. 01 GROUP-SIZE UNSIGNED-INT VALUE 0. 01 GROUP-TOTAL UNSIGNED-INT VALUE 0. 01 TOTAL UNSIGNED-INT VALUE 0. PROCEDURE DIVISION. 001-MAIN. PERFORM 004-INIT-VARIABLES. OPEN INPUT INPUTFILE. PERFORM 002-READ UNTIL FILE-STATUS = 1. CLOSE INPUTFILE. PERFORM 004-NEXT-GROUP. DISPLAY TOTAL. STOP RUN. 002-READ. READ INPUTFILE AT END MOVE 1 TO FILE-STATUS NOT AT END PERFORM 003-PROCESS-RECORD END-READ. 003-PROCESS-RECORD. IF REC-LEN = 0 THEN PERFORM 004-NEXT-GROUP ELSE PERFORM 005-PROCESS-ROW END-IF. 004-INIT-VARIABLES. PERFORM VARYING I FROM 1 BY 1 UNTIL I > 26 MOVE 0 TO WS-GROUP-ANSWERS(I) END-PERFORM. MOVE 0 TO GROUP-SIZE. MOVE 0 TO GROUP-TOTAL. 004-NEXT-GROUP. IF GROUP-SIZE > 0 THEN PERFORM 006-TALLY-GROUP-TOTAL END-IF. ADD GROUP-TOTAL TO TOTAL. PERFORM 004-INIT-VARIABLES. 005-PROCESS-ROW. ADD 1 TO GROUP-SIZE. PERFORM VARYING I FROM 1 BY 1 UNTIL I > REC-LEN MOVE INPUTRECORD(I:1) TO WS-CHAR COMPUTE C = FUNCTION ORD(WS-CHAR) COMPUTE X = WS-GROUP-ANSWERS(C - 97) + 1 MOVE X TO WS-GROUP-ANSWERS(C - 97) END-PERFORM. 006-TALLY-GROUP-TOTAL. PERFORM VARYING I FROM 1 BY 1 UNTIL I > 26 IF WS-GROUP-ANSWERS(I) = GROUP-SIZE THEN ADD 1 TO GROUP-TOTAL END-IF END-PERFORM. 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
benwtrent profile image
Benjamin Trent

Rust!

use std::collections::HashSet; #[aoc_generator(day6)] fn to_vec(input: &str) -> Vec<Vec<Vec<char>>> { input .split("\n\n") .map(|i| { i.lines() .map(|s| s.chars().collect::<Vec<char>>()) .collect() }) .collect() } #[aoc(day6, part1)] fn answer_count(input: &Vec<Vec<Vec<char>>>) -> usize { input .iter() .map(|group| { group .iter() .flat_map(|v| v.iter().map(|c| *c).collect::<HashSet<char>>()) .collect::<HashSet<char>>() .len() }) .sum() } #[aoc(day6, part2)] fn abs_answer_count(input: &Vec<Vec<Vec<char>>>) -> usize { input .iter() .map(|group| { group .iter() .map(|v| v.iter().map(|c| *c).collect::<HashSet<char>>()) .fold(Option::None, |l, g| { if l.is_none() { Some(g.clone()) } else { Some( l.unwrap_or(HashSet::new()) .intersection(&g) .map(|c| *c) .collect(), ) } }) .unwrap_or(HashSet::new()) .len() }) .sum() } 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ballpointcarrot profile image
Christopher Kruse

Ugh, made it too late for this day (but I had it done in time for the problem, honest!).

Used HashSet to my benefit here, as I could apply set theory to the problem and get it done easily.

As always, in Github.

use aoc_runner_derive::{aoc, aoc_generator}; use std::collections::HashSet; #[aoc_generator(day6)] fn parse_input_day6(input: &str) -> Vec<String> { input .split("\n\n") .map(|group| String::from(group)) .collect() } #[aoc(day6, part1)] fn sum_group_questions(input: &Vec<String>) -> usize { let answers: Vec<HashSet<char>> = input .iter() .map(|group| group.chars().filter(|x| *x != '\n').collect()) .collect(); answers.iter().map(|group| group.len()).sum() } #[aoc(day6, part2)] fn sum_group_common_questions(input: &Vec<String>) -> usize { input .iter() .map(|group| { let mut first_run = true; group .lines() .map(|answers| answers.chars().collect::<HashSet<char>>()) .fold(HashSet::new(), |memo, ans| { if memo.is_empty() && first_run { first_run = false; ans.clone() } else { let intersect = memo.intersection(&ans).cloned().collect(); intersect } }) .len() }) .sum() } 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
readyready15728 profile image
readyready15728

Ruby, part 2:

require 'set' groups = File.read('06.txt').split /\n\n/ puts (groups.map do |group| responses = group.split(/\n/).map { |response| Set.new(response.each_char) } responses.inject { |product, current| product.intersection(current) }.length end).sum 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
willsmart profile image
willsmart

Python impl today. Prob not great python but works.

print(reduce( lambda acc, v: acc + len( set(v.replace('\n', '')) ), open("6.txt").read().split('\n\n'), 0 )) print(reduce( lambda acc, v: acc + len(reduce( lambda acc, v: acc & v, map( lambda v: set(v), v.split('\n') ) )), open("6.txt").read().split('\n\n'), 0 )) 
Enter fullscreen mode Exit fullscreen mode

Tomorrow will try something like prolog?!
Failing that, maybe Haskell.

Collapse
 
flwidmer profile image
flwidmer

I decided to do this year in Haskell. Perhaps if it gets too crazy, I'll revert to what I know better, but until now it's been fun.

I might start a library with the groups and addAll functions, seems I'm going to use them for every puzzle...

import Data.List.Split ( splitOn ) import Data.List ( intersect, nub ) main :: IO () main = do input <- readFile "input" putStrLn "day6" print $ solve1 input print $ solve2 input solve1 :: String -> Int solve1 a = let grouped = groups a answers = map (filter (\x -> x `elem` ['a'..'z']) . nub) grouped in addAll answers solve2 :: String -> Int solve2 a = let grouped = map lines $ groups a intersected = map (foldr1 intersect) grouped in addAll intersected addAll :: [[a]] -> Int addAll = sum . map length groups :: String -> [String] groups = splitOn "\n\n" 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
particleflux profile image
Stefan Linke

2 Solutions again.

Go:

package main import ( "bytes" "fmt" "io/ioutil" "os" ) func countQuestions(group []byte) (int, int) { counts := map[byte]int{} numPeople := 1 for _, question := range group { if question == '\n' { numPeople++ } else { counts[question]++ } } numAllYes := 0 for _, c := range counts { if c == numPeople { numAllYes++ } } return len(counts), numAllYes } func main() { input, _ := ioutil.ReadAll(os.Stdin) groups := bytes.Split(input, []byte("\n\n")) sum1, sum2 := 0, 0 for _, group := range groups { a, b := countQuestions(group) sum1 += a sum2 += b } fmt.Println(sum1, sum2) } 
Enter fullscreen mode Exit fullscreen mode

And tweet-sized PHP:

<?for($i=0,$z=explode(" ",file_get_contents('input'));$z[$i];){$a+=count($f=count_chars($z[$i++],1))-(($n=$f[10])>0);foreach($f as$k=>$v)$b+=$k!=10&$v==$n+1;}echo"$a $b"; 
Enter fullscreen mode Exit fullscreen mode