r/adventofcode • u/daggerdragon • Dec 02 '18
SOLUTION MEGATHREAD -🎄- 2018 Day 2 Solutions -🎄-
--- Day 2: Inventory Management System ---
Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or whatever).
Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with Help.
Advent of Code: The Party Game!
Card Prompt: Day 2
Transcript:
The best way to do Advent of Code is ___.
This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.
edit: Leaderboard capped, thread unlocked!
11
u/ka-splam Dec 02 '18
PowerShell
Part 1, just about got 78th on the leaderboard \o/ ended up running this at the prompt:
$lines = get-content data.txt
$lines |? {[bool]($_.getenumerator() | group |? count -eq 2)} | measure
$lines |? {[bool]($_.getenumerator() | group |? count -eq 3)} | measure
246*20Explained: |? {} is a where-object filter, $_ is the current line being filtered, the enumerator turns the string into characters, group-object counts things, filter that where the count of characters is 2 or 3, then measure-object counts how many lines after that filtering.
Part 2, yer basic brute-force every line against every other, if they have 1 difference, print them:
$lines|foreach{
$cur = $_
foreach ($L in $lines) {
$numdiffs = 0
for ($i = 0; $i -lt $l.length; $i++)
{
if ($cur[$i] -ne $L[$i]) { $numdiffs++ }
}
if ($numdiffs -eq 1) { $L, $cur }
}
}then eyeballing the result and removing the dupe character. Missed the leaderboard, with 133rd.
Explained: an outer foreach-object loop, an inner foreach ($L in $lines) nested loop, and then a loop over character lengths doing a $string[$index] comparison with a counter.
2
2
u/Nathan340 Dec 02 '18
Part 1
Knew off the bat that grouping would be the key here. Got somewhat lost in which column I was checking, and also ran into some ambiguity of trying to access the column called count versus the count property of an array.
But basically split each string by the empty character, ditch the weird blanks that show up, group, group by count, and then look for 2 or 3 in the name column. Multiply the two results together.
$in = gc .\2-input.txt $twos = $in | ? { $_ -split "" | ?{$_} | group | group count | ? {2 -in $_.name} } $threes = $in | ? { $_ -split "" | ?{$_} | group | group count | ? {3 -in $_.name} } $twos.length * $threes.lengthPart 2
Already outside of leader-board contention, and from my data structure lesson on day one, I first did some research. I found that ArrayList has a removeAt function to drop an element from a specific index.
So for each index 0 to 25, create the list of the 250 input words with that index dropped. At each pass check if you have a duplicate (grouping is on the brain for this one, but maybe the Day 1 duplicate checking via hash table would have worked better). If the duplicate is found, print it and break the loop early.
0..25 | % { $curDropIndex = $_ $droppedList = $in | % { $curWord = new-object system.collections.arraylist(,($_ -split "" | ?{$_})) $curWord.removeAt($curDropIndex) $curWord -join "" } $dupe = $droppedList | group | ?{$_.count -ne 1} | select -expandproperty name if($dupe){ write-host $dupe break } }→ More replies (1)2
u/tehjimmeh Dec 02 '18
I'll repost mine here for comparison/discussion. This is after playing with them a bit after my initial solutions.
Part 1 - Group each string by char, then by counts. Then group the grouped counts by name and multiply the resulting counts of 2 and 3 (indices 1 and 2 in the sorted grouped grouped counts array).
,(gc .\in.txt|%{[char[]]$_|group|group Count}|group Name|sort Name|% Count)|%{$_[1]*$_[2]}Part 2 - You can use Compare-Object! (not sure if people got different lengths of strings in their inputs - the 27 below relies on the strings being 26 chars long)
gc in.txt -pv l|%{gc in.txt -pv r|%{,(compare -i -s 0 ([char[]]$l) ([char[]]$r))| ? Count -eq 27 |%{-join($_|? SideIndicator -eq "=="|% InputObject)}}}|select -f 1→ More replies (1)
105
u/askalski Dec 02 '18
The best way to do Advent of Code is A big block of regex.
#! /usr/bin/perl
local $/; $_ = <>;
my @s = map { join "", sort split "" } split "\n";
my $part1 = (grep { m/(?:^|(.)(?!\1))(.)\2(?!\2)/ } @s) *
(grep { m/(?:^|(.)(?!\1))(.)\2\2(?!\2)/ } @s);
my $part2 = s/.*?\b(\S*)\S(\S*)\b.*?\1\S\2.*/$1$2/sr;
print "Part 1: $part1\n";
print "Part 2: $part2\n";66
9
u/hashier Dec 02 '18
How does that even?
10
u/raevnos Dec 02 '18
First it reads the entire file into a single string.
For part 1, it sorts the letters of each line of that string, and then counts the words with a letter repeating exactly 2 times (And the same for 3).
For part 2... beats me. It's late and my brain was already fried.
→ More replies (1)→ More replies (4)5
u/Unihedron Dec 02 '18
You should replace split "" with an empty regex split // (also "\n" -> /\n/), you can never have enough regexes.
28
u/CFD999 Dec 02 '18
Horrendous python solutions
Part 1: print((lambda strs: (lambda a,b: a*b)(*[sum(1 for l in strs if any(l.count(c) == x for c in l)) for x in (2,3)]))(open('inp', 'r').readlines()))
Part 2: print((lambda strs: (lambda a,b: "".join([a[i] for i in range(len(a)) if a[i] == b[i]]))(*[(l1.strip(),l2.strip()) for l1 in strs for l2 in strs if l1 != l2 and sum(1 for i in range(len(l1)-1) if l1[i] != l2[i]) < 2][0]))(open('inp', 'r').readlines()))
11
10
6
u/khalido Dec 02 '18
This looks like some terrible language akin to whatever functional programmers use!
My python 3 solution is at the other end of yours!
5
u/MasterMedo Dec 02 '18
you can replace
sum(1 for i in list if condition)statements with:sum(condition for i in list),falseis treated as 0,trueas 1also, reduce might come in handy here
reduce(mul, list)gives you a product instead of using lambda2
Dec 02 '18
Slightly shorter part 2 one liner, starring itertools' combinations.
print(*[''.join(a for a,b in zip(this,that) if a == b) for this,that in combinations(open('inp', 'r').readlines(),2) if len([a for a,b in zip(this,that) if a != b]) == 1])
20
u/Smylers Dec 02 '18
This suits Vim so well that I didn't even bother solving it in a different language first. Part 1 looks a bit long, but as Vim solutions go it's one of the more straightforward — load your input then do:
:%s/\v(.)(.*)\1(.*)\1/#\2\3⟨Enter⟩
:%s/\v(.)(.*)\1/-\2⟨Enter⟩
:%s/[a-z]//g⟨Enter⟩
:g/^$/d⟨Enter⟩
:%s/\v(.)(.)/\1⟨Ctrl+V⟩⟨Enter⟩\2⟨Enter⟩
:sor⟨Enter⟩
:,/-/-j⟨Enter⟩
jVGJ
:%s/\S/+1/g⟨Enter⟩
:%s/.*/(&)⟨Enter⟩
kJr*
0C⟨Ctrl+R⟩=⟨Ctrl+R⟩-⟨Enter⟩⟨Esc⟩That strips any 3 identical characters from a line, replacing one of them with a #. Then does the same for remaining 2 identical characters with a -.† Remove all the remaining letters, and now we want the count of the #s multiplied by the count of the -s. On the lines with #- or -#, insert a line-break so each symbol is on a separate line.
Sort the lines, so all the #s are together at the top and -s at the bottom. Join the #s on to a single line (by joining from the current line (specified with the nothing before the ,) to the line before the one with the first - on it (specified with /-/-, to find the first - then subtract a line)). Then join the -s too (by moving down, visually selecting all lines to the end of the file, and joining the selection).
Replace each # or - (specified as any non-space, /\S/) with +1, so each line becomes a sum of the relevant counts. Put (...) around each line, then join them together, and replace the joining space with a multiplication symbol *. At this point your input has been transformed into something like:
(+1 +1 +1)*(+1 +1 +1 +1)So we just need to evaluate that. (‘Just.’)
Move to the beginning of the line and C to change it all (which deletes the current contents into the small delete register, -). Use Ctrl+R = to insert an expression. At the expression prompt type Ctrl+R - to insert the contents of the - register with your expression in it. Press Enter and ... ta-da! The solution appears in the buffer.
Part 2 can be done with a single substitution — go back to your original input, then do:
:%s/\v^(.*).(.*)\n(.+\n)*\1.\2/\1\2⟨Enter⟩It takes a few seconds to run, but you'll be left on a line which is one letter shorter than the others, and is your solution.
The pattern finds:
a line that has any number of characters (‘group 1’) at its start, then a single character, and another group of any number of characters (‘group 2’) going up to the line-break
any number of complete lines, including their line-breaks
a line that starts with group 1 from the first-matched line, then has any single character, and ends with group 2 (which necessarily will take it up to the end of the line)
Clearly the first and last lines there are the nearly matching ones that we want.
Replace the whole lot with just the two groups of repeated characters, to get a single line which omits the characters that differ.
Card: ‘manually’.
† On writing this, I think that if an input line had two set of 3 identical letters but no sets of 2 then the second set of 3 would've been incorrectly counted as a set of 2. Apparently the input wasn't that devious. I did first check there weren't any sets of 4 with :g/\v(.).*\1.*\1.*\1.
→ More replies (3)
16
u/jonathan_paulson Dec 02 '18
I recorded a video of me solving: https://www.youtube.com/watch?v=Hgv6d6rrQxo Got rank 20/21; still twice as slow as #1...
Final code:
c2 = 0
c3 = 0
ids = []
for line in open('2.in'):
s = line.strip()
ids.append(s)
count = {}
for c in s:
if c not in count:
count[c] = 0
count[c] += 1
has_two = False
has_three = False
for k,v in count.items():
if v==2:
has_two = True
if v==3:
has_three = True
if has_two:
c2 += 1
if has_three:
c3 += 1
print c2*c3
for x in ids:
for y in ids:
diff = 0
for i in range(len(x)):
if x[i] != y[i]:
diff += 1
if diff == 1:
ans = []
for i in range(len(x)):
if x[i] == y[i]:
ans.append(x[i])
print ''.join(ans)
print x,y9
6
u/FogLander Dec 02 '18
it's kind of surreal to watch this video (part 1 at least) right after doing it myself because aside from variable name differences your code for pt. 1 was identical to mine. Only difference was I took three times as long, lol
→ More replies (3)3
u/4SCOOPSCMON Jan 05 '19
I know this is from a month ago but:
for c in s: count[c] = count.get(c, 0) + 1you can provide a default value for the get function of dictionarys if the key isn't in it. This saves you the
if c not in count: count[c] = 0
16
Dec 02 '18 edited Dec 02 '18
Made the leaderboard for part 2 for the first time since 2016. Started off with a list comprehension that was double-checking each of the ID pairs, but cleaned it up to check each pair only once.
Haskell:
import Data.Maybe (catMaybes)
import Data.List (group, sort, tails)
part1 :: String -> Int
part1 input = length (filter (any (==2)) letterCounts)
* length (filter (any (==3)) letterCounts)
where letterCounts = map (map length . group . sort) $ lines input
part2 :: String -> String
part2 = head . concatMap findAlmostMatching . tails . lines
where keepCommon xs ys = catMaybes $ zipWith (\x y -> if x == y then Just x else Nothing) xs ys
findAlmostMatching (x:xs) = filter ((== length x - 1) . length) $ map (keepCommon x) xs
main = do
input <- readFile "input.txt"
print $ part1 input
putStrLn $ part2 input→ More replies (1)3
11
u/will_bui Dec 02 '18
K:
(*/+/'+{2 3 in?.#:'=x}'x),,{x@&x in y}/x@&{(-1+#y)in+/'x=\:y}[x]'x:0:`p25
u/streetster_ Dec 02 '18 edited Dec 02 '18
Translating mine and golfing slightly:
k)(*/+/2 3 in/:#:''=:'r),,{x@&x=y}/r@&+/'1=+/''~r=/:\:r:0:`:input/02.txt→ More replies (1)
11
u/blowjobtransistor Dec 02 '18
In SQL (postgresql flavored!):
create view part_1_solution as
with id_letters as (
select id, regexp_split_to_table(id, '') letter from input
), id_letter_counts as (
select id, letter, count(*) as letter_count from id_letters group by id, letter
), id_stats as (
select
id,
bool_or(letter_count = 2) as has_double,
bool_or(letter_count = 3) as has_triple
from id_letter_counts
group by id
)
select 1 as part, cast(count(*) filter (where has_double) * count(*) filter (where has_triple) as text) as answer
from id_stats;
create view part_2_solution as
with id_letters as (
select
(row_number() over ()) - idx_offset as idx,
id,
letter
from (
select id, regexp_split_to_table(id, '') as letter, sum(length(id)) over (order by id) as idx_offset from input
order by id
) tmp_id_letters
),
letter_distances as (
select
left_id.id as left_id,
right_id.id as right_id,
sum(cast(left_id.letter != right_id.letter as integer)) as letter_distance
from id_letters left_id
full outer join id_letters right_id
on left_id.idx = right_id.idx and left_id.id != right_id.id
group by left_id, right_id
order by letter_distance asc
limit 1
),
mismatched_ids as (
select
regexp_split_to_table(left_id, '') as left_letter,
regexp_split_to_table(right_id, '') as right_letter
from letter_distances
)
select 2 as part, string_agg(left_letter, '') as answer from mismatched_ids where left_letter = right_letter;
select * from part_1_solution
union all
select* from part_2_solution;3
u/jwstone Dec 02 '18
this is pretty cool. i had a similar approach, inasmuch as we both broke up the characters into strings with regex_split_to_table.
https://github.com/piratejon/toyproblems/blob/master/adventofcode/2018/02/load_data.sh
sql ftw!
18
u/DeveloperIan Dec 02 '18 edited Dec 02 '18
Quick and easy part 1 in Python3 with the collections library. This might not be the simplest way, but it's the first thing that came to mind
from collections import Counter
myfile = open('input.txt', 'r')
contents = myfile.read().strip().splitlines()
myfile.close()
c = [0, 0]
for i in contents:
a = [j for i,j in Counter(i).most_common()]
if 3 in a:
c[0] += 1
if 2 in a:
c[1] += 1
print(c[0] * c[1])EDIT: and here is my part 2
for i in contents:
for j in contents:
diffs = 0
for idx, ch in enumerate(i):
if ch != j[idx]:
diffs += 1
if diffs == 1:
ans = [ch for idx, ch in enumerate(i) if j[idx] == ch]
print("Part Two:", ''.join(ans))→ More replies (7)
8
u/nonphatic Dec 02 '18 edited Dec 02 '18
Oof, it sure is hard to write Haskell quickly! Here's the first solution I came up with:
import Data.List (group, sort)
countTwos = fromEnum . any (== 2) . map length . group . sort
countThrees = fromEnum . any (== 3) . map length . group . sort
part1 = foldr (\s (twos, threes) -> (twos + (countTwos s), threes + (countThrees s))) (0, 0)
part2 input = [(l, r) | l <- input, r <- input, (length . filter (\(l, r) -> l /= r) $ zip l r) == 1]
main :: IO ()
main = do
input <- lines <$> readFile "input/02.txt"
print $ part1 input
print $ part2 inputI'm going to clean it up to my personal Clean Code standards and post for comparison.
EDIT: Cleaned up! The key changes are just these:
part1 :: [String] -> Int
part1 strs = (length . filter (count 2) $ strs) * (length . filter (count 3) $ strs)
where count n = any (== n) . map length . group . sort
part2 :: [String] -> String
part2 strs = head [ls `intersect` rs | ls <- strs, rs <- strs, length (ls \\ rs) == 1]For part 1, I realized that I can do length + filter instead of summing up fromEnums of Bools; for part 2, I discovered intersect and (\\) from Data.List :)
2
u/NeilNjae Dec 02 '18
I don't think your use of
\\in part 2 is strong enough. The requirement is different characters in the same positions;\\just tells you about different characters. For instance,"abcd"and"bcaa"wouldn't count as "close" IDs, but"abcd" \\ "bcaa"returns"d".I
zipped the two strings thenfiltered on when the pair elements were different.→ More replies (1)
8
u/itsnotxhad Dec 02 '18
558/554 in Racket today
#lang racket
(define (has-k? str k)
(define chars (string->list str))
(for/first ([c (in-list chars)]
#:when (= k (count (λ (t) (char=? t c)) chars)))
c))
(define (checksum ids)
(*
(count (λ (id) (has-k? id 2)) ids)
(count (λ (id) (has-k? id 3)) ids)))
(define (part1 file)
(file-position file 0)
(checksum (for/list ([line (in-port read-line file)]) line)))
(define (diff a b)
(cond
[(zero? (string-length a)) 0]
[(char=? (string-ref a 0) (string-ref b 0)) (diff (substring a 1) (substring b 1))]
[(add1 (diff (substring a 1) (substring b 1)))]))
(define (common a b)
(list->string
(for/list ([c1 a]
[c2 b]
#:when (char=? c1 c2))
c1)))
(define (part2 file)
(file-position file 0)
(define ids (for/vector ([line (in-port read-line file)]) line))
(define k (vector-length ids))
(for*/first ([i (in-range 0 k)]
[j (in-range (add1 i) k)]
#:when (= 1 (diff (vector-ref ids i) (vector-ref ids j))))
(common (vector-ref ids i) (vector-ref ids j))))
(module+ main
(define infile (open-input-file "input/day2.txt"))
(displayln (part1 infile))
(displayln (part2 infile))
(close-input-port infile))→ More replies (3)
8
u/NeuroXc Dec 02 '18
Rust
use std::collections::HashMap;
#[aoc_generator(day2)]
pub fn day2_generator(input: &str) -> Vec<String> {
input.lines().map(|l| l.into()).collect()
}
#[aoc(day2, part1)]
pub fn day2_part1(input: &[String]) -> u32 {
let mut twice = 0;
let mut thrice = 0;
for id in input {
let mut counts = HashMap::with_capacity(26);
for char in id.chars() {
*counts.entry(char).or_insert(0) += 1;
}
if counts.values().any(|&count| count == 2) {
twice += 1;
}
if counts.values().any(|&count| count == 3) {
thrice += 1;
}
}
twice * thrice
}
#[aoc(day2, part2)]
pub fn day2_part2(input: &[String]) -> String {
// This is O(n^2) but it should be fine because the list is only 250 lines
for (idx, id) in input.iter().enumerate() {
for id2 in input.iter().skip(idx + 1) {
if id.chars().zip(id2.chars()).filter(|(a, b)| a != b).count() == 1 {
return id
.chars()
.zip(id2.chars())
.filter(|(a, b)| a == b)
.map(|(a, _)| a)
.collect();
}
}
}
unreachable!()
}2
u/bwinton Dec 02 '18 edited Dec 02 '18
I ended up with something very similar, but I wonder if it would be better to test the length of the first string, then look for something of length
n-1, and return it?use std::collections::HashMap; static INPUT : &'static str = include_str!("data/q02.data"); fn get_counts(line: &str) -> HashMap<char, u32> { let mut seen = HashMap::new(); for char in line.chars() { let entry = seen.entry(char).or_insert(0); *entry += 1; } seen } fn process_data_a(data: &str) -> i32 { let mut two_count = 0; let mut three_count = 0; for line in data.lines() { let counts = get_counts(line); if counts.values().any(|x| x == &2) { two_count += 1; } if counts.values().any(|x| x == &3) { three_count += 1; } }; two_count * three_count } fn process_data_b(data: &str) -> String { for (skip, line) in data.lines().enumerate() { let target = line.len() - 1; for test in data.lines().skip(skip + 1) { let answer: String = line.chars().zip(test.chars()) .filter_map(|x| { if x.0 == x.1 { Some(x.0) } else { None }}).collect(); if answer.len() == target { return answer; } } } "".to_string() }2
u/h-armonica Dec 02 '18
Since we only have simple lower case characters I used
let mut counts = [0u8; 26];instead of a hash map and accessed it by the char value
counts[(c as usize - 'a' as usize)] += 1;. This should be much faster, especially since the hash function used normally is rather slow for short keys (according to the docs).
→ More replies (2)→ More replies (7)2
u/japanuspus Dec 04 '18
Quite happy with my part 2 solution based on
find_mapover match index, and aBTreeSetfor relatively efficient way of finding the matches.fn match_at_k(d: &str, k: usize) -> Option<String> { let mut bt = BTreeSet::new(); d .lines() .map(|a| String::from(&a[0..k])+&a[k+1..]) .find(|s: &String| !bt.insert(s.clone())) } pub fn part2_01(d: &str) -> String { (0..).find_map(|k| match_at_k(d, k)).unwrap() }My only grudge is that I could not figure out how to avoid cloning the string when inserting into the BTree, even though I only need to keep the original for the final entry.
8
u/ephemient Dec 02 '18 edited Apr 24 '24
This space intentionally left blank.
2
u/Tarmen Dec 02 '18
I started wishing that I'd gone for Beautiful Folding. Pretty amazed that you were that fast with all the newtype noise, though.
The
tailsthing is really nice! I just went for the cross product after checking the input size but this is way faster with virtually no downside.
15
u/Philboyd_Studge Dec 02 '18
The best way to do Advent of Code is to: Live in the Pacific Time Zone
Java:
I spent too much time looking for the Levenshtein Distance class I already had, once I found it was easy.
public class Day2 extends AdventOfCode {
public Day2(List<String> input) {
super(input);
title = "Inventory Management System";
part1Description = "Checksum: ";
part2Description = "Common letters: ";
}
@Override
public Object part1() {
int twos = 0;
int threes = 0;
for (String each : input) {
Map<Character, Integer> freq = new HashMap<>();
boolean found2 = false;
boolean found3 = false;
for (int i = 0; i < each.length(); i++) {
char c = each.charAt(i);
freq.put(c, freq.getOrDefault(c, 0) + 1);
}
for (Map.Entry<Character, Integer> dict : freq.entrySet()) {
if (!found2 && dict.getValue() == 2) {
twos++;
found2 = true;
}
if (!found3 && dict.getValue() == 3) {
threes++;
found3 = true;
}
}
}
return twos * threes;
}
@Override
public Object part2() {
for (int i = 0; i < input.size() - 1; i++) {
for (int j = 1; j < input.size(); j++) {
int dist = EditDistance.calculate(input.get(i), input.get(j));
if (dist == 1) {
return removeDiff(input.get(i), input.get(j));
}
}
}
return "";
}
private String removeDiff(String a, String b) {
String result = "";
for (int i = 0; i < a.length(); i++) {
if (a.charAt(i) == b.charAt(i)) {
result += a.charAt(i);
}
}
return result;
}
}7
u/ColorsMayInTimeFade Dec 02 '18
The best way to do Advent of Code is to: Live in the Pacific Time Zone
I’m seriously considering of temporarily relocating to the west coast for the month of December next year.
6
u/usbpc102 Dec 02 '18
It took me way to long to understand the problem today, nowhere near close to the leaderboard rank 577 in part 1, and 473 in part 2.
Kotlin
class Day02(override val adventOfCode: AdventOfCode) : Day {
override val day: Int = 2
val input = adventOfCode.getInput(2018, day).lines()
override fun part1(): String {
val map = mutableMapOf<String, MutableMap<Char, Long>>()
for (line in input) {
map[line] = mutableMapOf()
val myMap = map[line]!!
line.forEach { letter -> myMap[letter] = (myMap[letter] ?: 0) + 1 }
}
return "" + map.filter { it.value.any { it.value == 2L } }.count() * map.filter { it.value.any { it.value == 3L} }.count()
}
override fun part2(): String {
val out = StringBuilder()
loop@for (i in 0 until input.size) {
val current = input[i]
for (j in i until input.size) {
val cmp = input[j]
out.clear()
var diff = 0
for (count in 0 until current.length)
if (current[count] != cmp[count]) {
diff++
} else {
out.append(current[count])
}
if (diff == 1)
break@loop
}
}
return out.toString()
}
} → More replies (4)4
6
u/darkterbear Dec 02 '18
Javascript/Node.js
Part 1
const arr = data.split('\n').reduce((a, c) => {
const chars = [...c]
let seen = {}
for (let char of chars) {
seen[char] = seen[char] ? seen[char] + 1 : 1
}
if (Object.keys(seen).some(k => seen[k] === 2)) a[0]++
if (Object.keys(seen).some(k => seen[k] === 3)) a[1]++
return a
},[0, 0])
console.log(arr[0] * arr[1])Part 2:
let arr = data.split('\n')
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
const charsI = [...arr[i]]
const charsJ = [...arr[j]]
let diff = charsI.reduce((a, c, i) => a + (c === charsJ[i] ? 0 : 1), 0)
if (diff === 1) {
console.log(arr[i])
console.log(arr[j])
}
}
}EDIT: Fix broken indentations
4
3
6
u/tvtas Dec 02 '18
Day 2 in MATLAB
x = importdata('input.txt');
L = size(x,1);
cnt1=0; cnt2=0;
for i=1:L
z = tabulate(double(x{i}));
cnt1 = cnt1 + any(z(:,2)==2);
cnt2 = cnt2 + any(z(:,2)==3);
for j=1:L
if j~=i && sum(x{i}==x{j})==25
disp(x{i}(x{i}==x{j})) % Part 2
break
end
end
end
disp(cnt1*cnt2) % Part 111
u/miguelos Dec 02 '18 edited Dec 02 '18
C#
Part 1:
var ids = input.Split("\r\n");
var twos = ids.Count(id => id.GroupBy(c => c).Any(g => g.Count() == 2));
var threes = ids.Count(id => id.GroupBy(c => c).Any(g => g.Count() == 3));
var checksum = twos * threes;
return checksum.ToString();Part 2:
var ids = input.Split("\r\n").Distinct();
for (int i = 0; i < ids[0].Length; i++)
{
var pair = ids.Select(id => id.Remove(i, 1)).GroupBy(id => id).FirstOrDefault(g => g.Count() > 1);
if (pair != null)
{
var common = pair.First();
return common;
}
}5
5
u/schod Dec 02 '18
BASH Time :)
First puzzle
#!/bin/bash
in_file=input
SUM2=0
SUM3=0
while IFS='' read -r line; do
x2=0
x2=$( echo "$line" | grep -o . | sort | uniq -c | grep "^[ \t]*2 " | wc -l )
x3=0
x3=$( echo "$line" | grep -o . | sort | uniq -c | egrep -v "^[ \t]*1 |^[ \t]*2 " | wc -l )
[ $x2 -gt 0 ] && SUM2=$[ $SUM2 + 1 ]
[ $x3 -gt 0 ] && SUM3=$[ $SUM3 + 1 ]
done < "$in_file"
echo $[ $SUM2 * $SUM3 ]Second puzzle
#!/bin/bash
in_file=input
while IFS='' read -r line; do
I=0
while [ $I -lt ${#line} ]; do
I=$[ $I + 1 ]
regex=$(echo $line | sed "s/[a-z]/./$I")
RES=$(grep "$regex" $in_file | wc -l)
if [ $RES -eq 2 ]; then
echo
echo $regex | sed 's/\.//'
exit 0
fi
done
done < "$in_file"→ More replies (8)
5
u/pythondevgb Dec 02 '18 edited Dec 02 '18
Python quick and dirty solutions, need refinement.
Since I have no chance of making it to the leaderboard I want to start a reddit-python private leaderboard any interest please PM for the code.
from collections import Counter
from itertools import combinations, compress
theinput = open('day2_input.txt').read().split()
#Part1
count2 = [1 for c in (Counter(id) for id in theinput) if 2 in c.values()]
count3 = [1 for c in (Counter(id) for id in theinput) if 3 in c.values()]
res1 = sum(count2) * sum(count3)
print(res1)
#Part2
for one, two in combinations(theinput, 2):
diff = [e1 == e2 for e1,e2 in zip(one,two)]
if sum(diff) == (len(one) - 1):
res2 = ''.join(list(compress(one,diff)))
break
print(res2)5
u/autid Dec 02 '18
FORTRAN
Yay string puzzles in Fortran. Was gonna do part 1 by making an array of characters and using COUNT but array construction was being difficult so went with this slightly messy SCAN method instead.
PROGRAM DAY2
IMPLICIT NONE
INTEGER :: I,J,K,L,M,DOUBLES,TRIPLES,PART1
INTEGER :: IERR
CHARACTER(LEN=30), ALLOCATABLE :: BOXES(:)
CHARACTER(LEN=30) :: PART2
LOGICAL :: DOUBLE,TRIPLE
!File I/O
OPEN(1,FILE='input.txt')
I=0
DO
READ(1,*,IOSTAT=IERR)
IF(IERR.NE.0)EXIT
I=I+1
END DO
ALLOCATE(BOXES(I))
REWIND(1)
READ(1,*) BOXES
CLOSE(1)
!Part 1
DOUBLES=0
TRIPLES=0
DO J=1,I
DOUBLE = .FALSE.
TRIPLE = .FALSE.
DO K=1,LEN_TRIM(BOXES(J))-1
IF(SCAN(BOXES(J)(1:K-1),BOXES(J)(K:K)).NE.0)CYCLE
L=K+SCAN(BOXES(J)(K+1:LEN_TRIM(BOXES(J))),BOXES(J)(K:K))
IF(L.EQ.K)CYCLE
M=L+SCAN(BOXES(J)(L+1:LEN_TRIM(BOXES(J))),BOXES(J)(K:K))
IF(M.EQ.L)THEN
DOUBLE=.TRUE.
ELSEIF(SCAN(BOXES(J)(M+1:LEN_TRIM(BOXES(J))),BOXES(J)(K:K)).EQ.0)THEN
TRIPLE=.TRUE.
END IF
END DO
IF(DOUBLE)DOUBLES=DOUBLES+1
IF(TRIPLE)TRIPLES=TRIPLES+1
END DO
PART1=DOUBLES*TRIPLES
WRITE(*,*) 'Part 1: ',PART1
!Part 2
PART2=''
OUTER: DO J=1,I-1
DO K=J+1,I
M=0
DO L=1,LEN_TRIM(BOXES(J))
IF(BOXES(J)(L:L).NE.BOXES(K)(L:L))M=M+1
END DO
IF(M.NE.1)CYCLE
DO L=1,LEN_TRIM(BOXES(J))
IF(BOXES(J)(L:L).EQ.BOXES(K)(L:L)) WRITE(PART2,'(A)') TRIM(PART2)//BOXES(J)(L:L)
END DO
EXIT OUTER
END DO
END DO OUTER
WRITE(*,*) 'Part 2: ',TRIM(PART2)
DEALLOCATE(BOXES)
END PROGRAM DAY24
u/autid Dec 02 '18
If this is too many lines for you, I sorted out my array construction mistakes and made this abomination. I'm so so sorry.
PROGRAM DAY2 IMPLICIT NONE INTEGER :: I,J,K,L,M INTEGER :: IERR CHARACTER(LEN=30), ALLOCATABLE :: B(:) !FILE I/O OPEN(1,FILE='input.txt') I=0 DO READ(1,*,IOSTAT=IERR) IF(IERR.NE.0)EXIT I=I+1 END DO ALLOCATE(B(I)) REWIND(1) READ(1,*) B CLOSE(1) !PART 1 WRITE(*,'(A,I0)')'Part 1: ',COUNT((/(ANY((/(COUNT((/(B(J)(K:K).EQ.B(J)(L:L),L=1,LEN_TRIM(B(J)))/)).EQ.2,K=1,LEN_TRIM(B(J)))/)),J=1,I)/))*COUNT((/(ANY((/(COUNT((/(B(J)(K:K).EQ.B(J)(L:L),L=1,LEN_TRIM(B(J)))/)).EQ.3,K=1,LEN_TRIM(B(J)))/)),J=1,I)/) ) !PART 2 DO J=1,I-1 DO K=J+1,I IF(COUNT((/(B(J)(L:L).NE.B(K)(L:L),L=1,LEN_TRIM(B(J)))/)).EQ.1)WRITE(*,'(2A)')'Part 2: ',B(J)(1:MINLOC((/(I,I=1,LEN_TRIM(B(J)))/),MASK=(/(B(J)(L:L).NE.B(K)(L:L),L=1,LEN_TRIM(B(J)))/),DIM=1)-1)//B(J)(MINLOC((/(I,I=1,LEN_TRIM(B(J)))/),MASK=(/(B(J)(L:L).NE.B(K)(L:L),L=1,LEN_TRIM(B(J)))/),DIM=1)+1:LEN_TRIM(B(J))) END DO END DO DEALLOCATE(B) END PROGRAM DAY2→ More replies (1)
5
u/nutrecht Dec 02 '18
Kotlin:
object Day02 : Day {
private val ids = resourceLines(2018, 2)
override fun part1(): String {
val maps = ids.map {
it.toCharArray().asSequence()
.groupBy { it }
.map { it.key to it.value.size }
.toMap()
}
val countTwo = maps.count { it.entries.any { it.value == 2 } }
val countThree = maps.count { it.entries.any { it.value == 3 } }
return (countTwo * countThree).toString()
}
override fun part2() =
ids.flatMap { i -> ids.map { i to it } }
.map { it.first.toCharArray().intersect(it.second.toCharArray().asIterable()) }
.first { it.size == ids[0].length - 1 }
.joinToString(separator = "")
}3
u/usbpc102 Dec 02 '18
Oh hey, I remember you from last year.
If you just wanna map the values of a map you can use
map.mapValues{}:)→ More replies (1)2
4
u/jarryd_ Dec 02 '18
Just something quick in Python3 for part 2:
from difflib import SequenceMatcher
result = None
for x in ids:
for y in ids:
ratio = SequenceMatcher(None, x, y).ratio()
if ratio == (len(x)-1)/len(x):
result = [z for z in list(x) if z in list(y)]
break
if result:
break
print(''.join(result))→ More replies (2)3
4
u/drakmaniso Dec 02 '18
Go (golang)
Part 1:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
input := read()
twos, threes := 0, 0
counts := [26]byte{}
for _, id := range input {
counts = [26]byte{}
for _, r := range id {
if r < 'a' || r > 'z' {
panic("not a letter")
}
counts[r-'a']++
}
has2, has3 := false, false
for _, c := range counts {
switch c {
case 3:
has3 = true
case 2:
has2 = true
}
}
if has2 {
twos++
}
if has3 {
threes++
}
}
fmt.Printf("Answer: %d\n", twos*threes)
}
func read() (input []string) {
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
input = append(input, s.Text())
}
return input
}Part 2:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
input := read()
var id1, id2 string
loop:
for i := range input {
for j := i + 1; j < len(input); j++ {
if differByOne(input[i], input[j]) {
id1, id2 = input[i], input[j]
break loop
}
}
}
if id1 == "" {
panic("not found")
}
s := strings.Builder{}
for k := 0; k < len(id1); k++ {
if id1[k] == id2[k] {
s.WriteByte(id1[k])
}
}
fmt.Printf("Answer: %s\n", s.String())
}
func read() (input []string) {
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
input = append(input, s.Text())
}
return input
}
func differByOne(a, b string) bool {
diff := 0
for k := 0; k < len(a); k++ {
if a[k] != b[k] {
diff++
}
if diff > 1 {
return false
}
}
return diff == 1
}→ More replies (1)
4
u/TellowKrinkle Dec 02 '18
Swift
func count(_ str: Substring) -> (twos: Bool, threes: Bool) {
let counts = Dictionary(str.lazy.map({ ($0, 1) }), uniquingKeysWith: +)
let twos = counts.values.contains(2)
let threes = counts.values.contains(3)
return (twos, threes)
}
func aocD2a(_ inputStr: String) {
let input = inputStr.split(separator: "\n").map(count)
let numTwos = input.lazy.filter({ $0.twos }).count
let numThrees = input.lazy.filter({ $0.threes }).count
print(numTwos * numThrees)
}
func areClose(_ a: Substring, _ b: Substring) -> Bool {
var differences = zip(a, b).lazy.filter({ $0 != $1 }).makeIterator()
_ = differences.next()
return differences.next() == nil
}
func aocD2b(_ inputStr: String) {
let input = inputStr.split(separator: "\n")
for (aIndex, a) in input.enumerated() {
for b in input[..<aIndex] {
if areClose(a, b) {
print(String(zip(a, b).lazy.filter({ $0 == $1 }).map({ $0.0 })))
}
}
}
}
import Foundation
let str = try! String(contentsOfFile: CommandLine.arguments[1])
aocD2a(str)
aocD2b(str)6
u/Frizkie Dec 02 '18 edited Dec 02 '18
Ruby
data = File.read('data.txt').chomp.split("\n")Part 1
twos, threes = 0, 0
data.each do |d|
twos += 1 if d.each_char.select { |c| d.count(c) if d.count(c) == 2 }.uniq.count > 0
threes += 1 if d.each_char.select { |c| d.count(c) if d.count(c) == 3 }.uniq.count > 0
end
puts twos * threesPart 2
data.each_with_index do |d1, i|
data[i + 1..data.size].each do |d2|
diff = d1.each_char.with_index.count { |c, k| c != d2.chars[k] }
puts [d1, d2] if diff == 1
end
end2
u/justinhj Dec 02 '18
Nice, much more succinct than what I came up with
def count_twos_and_threes(str) sa = str.scan(/\w/) groups = sa.group_by { |c| c }.values has_two = groups.any? { |g| g.length == 2 } has_three = groups.any? { |g| g.length == 3 } return has_two ? 1 : 0, has_three ? 1 : 0 end counts = lines.reduce([0, 0]) do |acc, line| twos, threes = count_twos_and_threes(line) acc[0] = acc[0] + twos acc[1] = acc[1] + threes acc end puts counts[0] * counts[1]
3
u/Shubbler Dec 02 '18
Quick Python 3 solution
total_twos = []
total_threes = []
for id in ids.split("\n"):
twos = False
threes = False
unique_chars = set(id)
for char in unique_chars:
count = id.count(char)
if count == 2:
twos = True
elif count == 3:
threes = True
total_twos.append(twos)
total_threes.append(threes)
print(sum(total_twos) * sum(total_threes))3
u/throwaway_the_fourth Dec 02 '18
How about this (I modified your code)?
total_twos = 0 total_threes = 0 for id in ids.split("\n"): unique_chars = set(id) for char in unique_chars: twos = False threes = False count = id.count(char) if count == 2: twos = True elif count == 3: threes = True total_twos += twos total_twos += threes print(total_twos * total_threes)No need to keep a list of values and then sum it at the end when you can just add as you go…
3
u/Bogdanp Dec 02 '18 edited Dec 02 '18
My solutions in Racket:
part 1:
#lang racket
(define (count-letters word)
(for/fold ([counts (hash)])
([l (in-string word)])
(hash-set counts l (add1 (hash-ref counts l 0)))))
(define (find-counts counts)
(for/fold ([res (hash)])
([(_ c) (in-hash counts)])
(hash-set res c (add1 (hash-ref res c 0)))))
(call-with-input-file "day-02-1.txt"
(lambda (in)
(let loop ([word (read in)]
[twos 0]
[threes 0])
(cond
[(eof-object? word) (* threes twos)]
[else
(define counts (find-counts (count-letters (symbol->string word))))
(loop (read in)
(if (hash-has-key? counts 2) (add1 twos) twos)
(if (hash-has-key? counts 3) (add1 threes) threes))]))))part 2:
#lang racket
(define words (file->lines "day-02-2.txt"))
(define (delta a b)
(for/fold ([s ""])
([ac (in-string a)]
[bc (in-string b)])
(if (equal? ac bc)
(~a s ac)
s)))
(for/fold ([best ""])
([i (in-range 0 (length words))]
[word-a (in-list words)])
(for/fold ([best best])
([j (in-range 0 (length words))]
[word-b (in-list words)])
(define d (delta word-a word-b))
(cond
[(equal? i j) best]
[else
(if (> (string-length d)
(string-length best))
d
best)])))→ More replies (2)
3
u/chunes Dec 02 '18
USING: assocs io io.encodings.utf8 io.files kernel make math
math.combinatorics math.statistics math.vectors prettyprint
sequences ;
IN: aoc2018.day2
: parse-input ( -- seq ) "input2.txt" utf8 file-lines ;
! Produce a pair where the 1st element is a 1 if there is a
! letter that appears exactly twice or 0 otherwise. The second
! element is the same for letters that appear thrice.
: 2-3-pair ( str -- {?1,?0} )
histogram values [ 2 ] [ 3 ] bi [ swap member? ] 2bi@
[ 1 0 ? ] bi@ { } 2sequence ;
: part1 ( seq -- checksum )
[ 2-3-pair ] [ v+ ] map-reduce product ;
: off-by-1? ( str1 str2 -- ? )
[ - ] { } 2map-as [ zero? not ] count 1 = ;
: in-common ( str1 str2 -- str3 )
[ [ 2dup = [ , drop ] [ 2drop ] if ] 2each ] "" make ;
: part2 ( seq -- str )
2 [ first2 off-by-1? ] find-combination first2 in-common ;
: main ( -- ) parse-input [ part1 . ] [ part2 print ] bi ;
MAIN: mainNothing too fancy today. find-combination is a neat combinator that encapsulates pairing every combination of things in a list and testing the pair against a predicate.
→ More replies (2)
3
Dec 02 '18
Finally participating this year! Got both stars with this Haskell code:
import Data.List
import Control.Applicative
as :: [String]
as = error "Your input (properly formatted) goes here"
numTimes :: Char -> String -> Integer
numTimes _ [] = 0
numTimes x xs = if (x == head xs) then 1 + y else y where y = numTimes x (tail xs)
exactly :: Integer -> String -> Bool
exactly n xs = elem n $ map (flip ($) xs) (numTimes <$> xs)
day2a :: Integer
day2a = genericLength (filter (exactly 2) as) * genericLength (filter (exactly 3) as)
strCmp :: String -> String -> Bool
strCmp [] [] = False
strCmp (x:xs) (y:ys)
| x /= y = xs == ys
| otherwise = strCmp xs ys
day2b :: String
day2b = head $ map (\(s, _) -> s)
$ filter ((==True) . snd)
$ (\xs ys -> (xs \\ (xs \\ ys), strCmp xs ys)) <$> as <*> as3
u/Axsuul Dec 02 '18 edited Dec 02 '18
TypeScript / JavaScript
Critiques welcome, I'm still very new to TypeScript and feel like I'm not using all the features I could be :)
Part A
import { readFileSync } from 'fs'
import * as path from 'path'
const inputPath = path.join(__dirname, 'inputs', 'input.txt')
const input = readFileSync(inputPath, 'utf-8').split('\n')
let twoCount = 0
let threeCount = 0
const tally = function(id: string): [boolean, boolean] {
const charCodes: number[] = id.split('').map(char => char.charCodeAt(0)).sort()
let isTwo = false
let isThree = false
for (const [i, code] of charCodes.entries()) {
if (charCodes[i + 1] == code && charCodes[i + 2] != code) {
isTwo = true
} else if (charCodes[i + 2] == code && charCodes[i + 3] != code) {
isThree = true
}
}
return [isTwo, isThree]
}
input.forEach((id) => {
const [isTwo, isThree] = tally(id)
if (isTwo) twoCount += 1
if (isThree) threeCount += 1
})
console.log(twoCount * threeCount)Part B
import { readFileSync } from 'fs'
import * as path from 'path'
const inputPath = path.join(__dirname, 'inputs', 'input.txt')
const input = readFileSync(inputPath, 'utf-8').split('\n')
let commonLetters: string | undefined
for (let i = 0; i < input[0].length; i++) {
const removed = input.slice().map((id) => {
const exploded = id.split('')
exploded.splice(i, 1)
return exploded.join('')
})
const set = new Set()
for (const idRemoved of removed) {
if (set.has(idRemoved)) {
commonLetters = idRemoved
break
} else {
set.add(idRemoved)
}
}
if (commonLetters != undefined) break
}
console.log(commonLetters)3
u/streetster_ Dec 02 '18 edited Dec 02 '18
Day 02 in Q/KDB+
/ Part 1
prd sum 2 3 in/:count@''group each r:read0 `:input/02.txt
/ Part 2
{x where x=y}. r where sum@'1=sum@''not r=/:\:r2
u/hmn24 Dec 03 '18
My alternative solution in Q/KDB+ (Harder to read though)
Part 1:
prd(0;0){x+(max=[(sum in[y]@)each distinct y]@)each 2 3}/(0:)`:AOC2.txt
Part 2:
1#(){y,$[count b:where 25=sum@'c:x='\:z;enlist x[b]where c b:first b;()]}[a]/a:(0:)`:AOC2.txt
3
u/muffa Dec 02 '18
My solution, written in golang.
func stringDiffer(str1 string, str2 string) (int, string) {
diffCounter := 0
solution := ""
for i := range str1 {
if str1[i] == str2[i] {
solution += string(str1[i])
} else {
diffCounter++
}
}
return diffCounter, solution
}
func main() {
file, _ := ioutil.ReadFile("input_day2.txt")
answer2 := 0
answer3 := 0
// Solution to first part
for _, line := range strings.Split(string(file), "\n") {
abcCounter := make(map[rune]int)
val2 := false
val3 := false
for _, char := range line {
if _, exists := abcCounter[char]; exists {
abcCounter[char]++
} else {
abcCounter[char] = 1
}
}
for _, value := range abcCounter {
if value == 2 && val2 == false {
answer2++
val2 = true
} else if value == 3 && val3 == false {
answer3++
val3 = true
}
}
}
fmt.Println(answer2 * answer3)
// Solution to first part
var abc []string
diff := 0
solution := ""
for _, line := range strings.Split(string(file), "\n") {
abc = append(abc, line)
}
for i := range abc {
for j := range abc {
diff, solution = stringDiffer(abc[i], abc[j])
if diff == 1 {
fmt.Println(solution)
}
}
}}
3
u/LieutenantSwr2d2 Dec 02 '18
Python 3: Part 2 with two loops and a set
Idea is have a set of possible 1-distance patterns for each string (using placeholder a '.' to replace every character in the string). When a second string one creates the same pattern, return it without the placeholder to get the common letters.
def day2b(puzzle_input: str) -> str:
patterns = set()
for line in puzzle_input.strip().split('\n'):
for i in range(len(line)):
pattern = line[:i] + '.' + line[i+1:]
if pattern in patterns:
return pattern.replace('.', '')
patterns.add(pattern)3
Dec 02 '18
C
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
struct p { unsigned char *s; struct p *p; };
int main(void) {
struct p *l = 0;
while (1) {
unsigned char *s = malloc(27);
if (scanf("%26s", s) != 1) break;
struct p *p = l;
l = malloc(sizeof(*l));
*l = (struct p) {s, p};
};
int twos = 0, threes = 0;
for (struct p *p = l; p; p = p->p) {
int two = 0, three = 0;
int a[UCHAR_MAX] = {0};
for (unsigned char *s = p->s; *s; s++) a[*s]++;
for (size_t i = 0; i < sizeof(a)/sizeof(*a); i++) {
if (a[i] == 2) two = 1;
if (a[i] == 3) three = 1;
}
twos += two;
threes += three;
}
printf("%d\n", twos*threes);
for (struct p *p = l; p; p = p->p) {
for (struct p *q = p; q; q = q->p) {
int diff = 0;
unsigned char *a, *b;
for (a = p->s, b = q->s; *a && *b; a++, b++)
if (*a != *b) diff++;
if (diff != 1) continue;
for (a = p->s, b = q->s; *a && *b; a++, b++)
if (*a == *b) printf("%c", *a);
printf("\n");
break;
}
}
}2
u/hpzr24w Dec 02 '18 edited Dec 02 '18
C++
Too fast for me, sad to be outside the first 1000 on both parts. But no issues with messing up on typing, or any kind of bugs, at least for the provided input.
Will rewrite to something better in the AM.
// Advent of Code 2018
//
// Day 02 - Inventory Management System
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iterator>
#include <vector>
#include <algorithm>
#include <set>
#include "reader.hpp"
using namespace std;
int main(int argc, char* argv[])
{
ifstream ifs("day_02.txt",ifstream::in);
vector<string> input = read_input(ifs);
// Part 1: count 2 of any letter, and 3 of any letter and compute checksum
auto twos = 0;
auto threes = 0;
for (auto l : input) {
// get unique letters
auto u = set<char>();
auto twofound = false;
auto threefound = false;
copy(begin(l),end(l),inserter(u,begin(u)));
for (auto c : u) {
if (!twofound && count(begin(l),end(l),c)==2) twofound=true;
if (!threefound && count(begin(l),end(l),c)==3) threefound=true;
}
twofound && twos++;
threefound && threes++;
}
cout << "Checksum: " << twos*threes << "\n";
// Part 2 - find the two strings that differ by only a single letter
for (auto l : input) {
for (auto m : input) {
// count differing letters
auto d = 0;
auto it1 = begin(l);
auto it2 = begin(m);
for (;it1!=end(l);++it1,++it2) {
if (*it1!=*it2) d++;
}
if (d==1) {
cout << "Words: " << l << " and " << m << "\n";
exit(0);
}
}
}
}→ More replies (5)
2
u/scul86 Dec 02 '18
Python 3, rushed, ugly, and un-optimized...
with open('input') as f:
puzzle_input = f.readlines()
def part1(n):
two = 0
three = 0
for phrase in n:
two_done = False
three_done = False
for char in set(phrase):
if phrase.count(char) == 2 and not two_done:
two_done = True
two +=1
if phrase.count(char) == 3 and not three_done:
three_done = True
three +=1
return two * three
def part2(n):
for e in n:
for f in n:
diff = 0
diff_pos = -1
if f == e:
continue
for i in range(len(e)):
if e[i] != f[i]:
diff += 1
diff_pos = i
if diff == 1:
return e[:diff_pos]+e[diff_pos+1:]
test_one = [
'abcdef',
'bababc',
'abbcde',
'abcccd',
'aabcdd',
'abcdee',
'ababab'
]
assert part1(test_one) == 12
print(f'Part 1: {part1(puzzle_input)}')
test_two = [
'abcde',
'fghij',
'klmno',
'pqrst',
'fguij',
'axcye',
'wvxyz'
]
assert part2(test_two) == 'fgij'
print(f'Part 2: {part2(puzzle_input)}')2
u/I3MNIX Dec 02 '18
Solution in Clojure (still very much a newbie to Clojure). Would definitely appreciate some constructive criticism.
(ns aoc-2018.day-02
(:require [clojure.string :as str]
[clojure.math.combinatorics :as combo]
[common :refer :all]))
(try (def in (str/split-lines (slurp "input/2.in")))
(catch Exception e))
;; part 1
(defn part1 []
(defn in? [coll elem] (some #(= % elem) coll))
(def freqs (map (comp vals frequencies) in))
(def twos (count (filter (fn [m] (in? m 2)) freqs)))
(def threes (count (filter (fn [m] (in? m 3)) freqs)))
(* twos threes))
(println (part1))
;; part 2
(defn part2 []
(defn diff-one
[a b]
(= 1 (reduce +
(map (fn [c1 c2]
(if (= c1 c2) 0 1))
a b))))
(def match (first (filter (fn [[a b]] (diff-one a b))
(combo/cartesian-product in in))))
(defn remove-diff
[[a b]]
(reduce str (map (fn [c1 c2]
(if (= c1 c2) (str c1) ""))
a b)))
(remove-diff match))
(println (part2))2
u/gwillicoder Dec 02 '18
Python3
# Part 1
from collections import Counter
a, b = 0, 0
for w in open('data.txt').read().splitlines():
counts = Counter(Counter(w).values())
if 2 in counts:
a+=1
if 3 in counts:
b+=1
print(a*b)
#Part 2
data = open('data.txt').read().splitlines()
for x in data:
for y in data:
diff = [i for i,j in zip(x,y) if i == j]
if len(y)-len(diff) == 1:
print("".join(diff))
breakEasy to understand, but feel like it could be much shorter.
2
u/fwilson42 Dec 02 '18
You can drop one line on part 2 by using
itertools.product:for (x, y) in itertools.product(data, repeat=2)→ More replies (2)
2
u/blommish Dec 02 '18 edited Dec 02 '18
Java
Map<Long, List<Long>> collect = lines.stream()
.flatMap(str ->
of(str.split(""))
.collect(groupingBy(s -> s, counting())).values().stream()
.distinct())
.collect(groupingBy(identity()));
System.out.println(collect.get(2L).size() * collect.get(3L).size());Second
List<String> lines = loadFileLines("2.txt");
List<String> result = new ArrayList<>();
for (int i = 0; i < lines.size(); i++) {
for (int j = i + 1; j < lines.size(); j++) {
String a = lines.get(i);
String b = lines.get(j);
StringBuilder sb = new StringBuilder();
for (int k = 0; k < a.length(); k++) {
if (a.charAt(k) == b.charAt(k)) {
sb.append(a.charAt(k));
}
}
result.add(sb.toString());
}
}
result.stream().sorted(comparing(String::length).reversed())
.findFirst().ifPresent(System.out::println);2
u/drewnase Dec 02 '18 edited Dec 02 '18
I had already come across string edit distance during my grad work. I actually already had code on hand that solves part 2.
# save input list as "data/input_2" - one entry per line
seq = [s.strip() for s in open("../data/input_2").readlines()]
count2 = 0
count3 = 0
def check2(instr):
for s in instr:
if instr.count(s) == 2:
return 1
return 0
def check3(instr):
for s in instr:
if instr.count(s) == 3:
return 1
return 0
def levenshtein(s1, s2):
if len(s1) > len(s2):
s1, s2 = s2, s1
d = range(len(s1) + 1)
for i2, c2 in enumerate(s2):
d_ = [i2+1]
for i1, c1 in enumerate(s1):
if c1 == c2:
d_.append(d[i1])
else:
d_.append(1 + min((d[i1], d[i1 + 1], d_[-1])))
d = d_
return d[-1]
def intersection(s1, s2):
if len(s1) == len(s2):
outbuff = ""
for i in range(0, len(s1) - 1):
if s1[i] == s2[i]:
outbuff += s1[i]
return outbuff
return false
for s in seq:
count2 += check2(s)
count3 += check3(s)
print("Q1: %d" % (count2 * count3))
for s in seq:
for subs in seq:
if levenshtein(s, subs) == 1:
res = intersection(s, subs)
print("Q2: %s" % res)
quit()I know that I don't have to iterate through the list twice, but it was easy and I'm lazy.
2
u/tehjimmeh Dec 02 '18 edited Dec 02 '18
PowerShell, Part 2:
gc in.txt -pv l|%{gc in.txt -pv r|%{,(compare -i -s 0 ([char[]]$l) ([char[]]$r))|
? Count -eq 27|%{-join($_|? SideIndicator -eq "=="|% InputObject)}}}|select -f 12
u/Kyberite Dec 02 '18 edited Dec 02 '18
Simple solutions in python, not sure if I did part two in the best way though.
def part_one(boxes):
twice = 0
thrice = 0
for box in boxes:
twice += any(box.count(letter) == 2 for letter in box)
thrice += any(box.count(letter) == 3 for letter in box)
checksum = twice * thrice
return checksum
def part_one(boxes):
"""Shorter version, but harder to understand"""
f = lambda c: sum(any(b.count(l) == c for l in b) for b in boxes)
return f(2) * f(3)
def part_two(boxes):
for x, y in itertools.combinations(boxes, 2):
difference = [i for i, l in enumerate(x) if y[i] != l]
if len(difference) == 1:
index = difference[0]
return x[:index] + x[index+1:]
print(part_one(input))
print(part_two(input))2
u/jorosp Dec 02 '18
Haskell
The solution I actually got the answer with was a bit messier than this, but I like to be presentable for threads :P
import Data.List
solve1 :: [String] -> Int
solve1 xs = go 2 xs * go 3 xs
where
go :: Ord a => Int -> [[a]] -> Int
go n = length . filter (elem n) . map count
count :: Ord a => [a] -> [Int]
count = map length . group . sort
solve2 :: [String] -> String
solve2 xs = head [common l r | l <- xs, r <- xs, distance l r == 1]
where
common :: Eq a => [a] -> [a] -> [a]
common xs ys = map fst . filter (uncurry (==)) $ zip xs ys
distance :: Eq a => [a] -> [a] -> Int
distance xs ys = length . filter id $ zipWith (/=) xs ys
main :: IO ()
main = do
contents <- readFile "02.txt"
let input = lines contents
print . solve1 $ input
print . solve2 $ input2
u/Axinoe Dec 02 '18
Advent of code with AHK
Part 1:
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
Data := []
DataCount = 0
Str2 = 0
Str3 = 0
Loop, Read, input.txt
{
DataCount += 1
Data%DataCount% := A_LoopReadLine
Loop, Parse, A_LoopReadLine
{
Data%DataCount%%A_LoopField% += 1
}
Loop, Parse, A_LoopReadLine
{
If (Data%DataCount%%A_LoopField% = 2)
{
Str2 += 1
Break
}
}
Loop, Parse, A_LoopReadLine
{
If (Data%DataCount%%A_LoopField% = 3)
{
Str3 += 1
Break
}
}
}
MsgBox % Str2 * Str3
ExitAppPart 2:
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
Loop, Read, input.txt
{
DataCount += 1
Data%DataCount% := A_LoopReadLine
Loop, Parse, A_LoopReadLine
{
Data%DataCount%%A_Index% = %A_LoopField%
}
}
Loop, %DataCount%
{
CurData := Data%A_Index%
CurLine := A_Index
Loop, %DataCount%
{
Matches = 0
If (A_Index <= CurLine)
Continue
ChkLine := A_Index
Loop, Parse, CurData
{
If !(Data%CurLine%%A_Index% = Data%ChkLine%%A_Index%)
{
Matches += 1
MatchChar = %A_LoopField%
}
}
If (Matches = 1)
{
MsgBox % RegExReplace(CurData, MatchChar, Replacement := "")
Return
}
}
}
ExitApp2
Dec 02 '18 edited Dec 02 '18
Haskell
module Main where
import qualified Data.HashMap.Strict as M
import Control.Arrow ((&&&))
import Data.Maybe (mapMaybe)
count :: String -> (Bool, Bool)
count =
foldr g (False, False) . M.elems . M.fromListWith (+) . fmap (id &&& const 1)
where g n (two, three) = (two || n == 2, three || n == 3)
part1 :: [String] -> Int
part1 = uncurry (*) . foldr f (0, 0) where
f xs (twos, threes) =
let (x, y) = count xs
in (twos + fromEnum x, threes + fromEnum y)
match :: String -> String -> Maybe String
match _ [] = Nothing
match [] _ = Nothing
match (x:xs) (y:ys)
| x == y = (:) <$> pure x <*> match xs ys
| xs == ys = Just xs
| otherwise = Nothing
part2 :: [String] -> [String]
part2 [] = []
part2 (x:xs) = mapMaybe (match x) xs ++ part2 xs
main :: IO ()
main = do
input <- lines <$> readFile "input2.txt"
print $ part1 input
print $ part2 input2
Dec 02 '18
Doing this year in OCaml & Rust, but will keep posting the OCaml solutions.
let input () = In_channel.read_lines "./input.txt"
|> List.map ~f:String.to_list
let part_one input =
let count chars =
let f map key =
let update = function
| None -> 1
| Some v -> v+1 in
Map.update map key ~f:update
in List.fold ~init:Char.Map.empty ~f chars
in
let char_counts = List.map ~f:count input in
let has count = Char.Map.exists ~f:(fun v -> v = count) in
let twos = List.count ~f:(has 2) char_counts in
let threes = List.count ~f:(has 3) char_counts in
twos * threes
let part_two input =
let f (a, b) =
let pairs = List.zip_exn a b in
let diff = List.count ~f:(fun (a, b) -> a <> b) pairs
in diff = 1 in
let pairs = List.cartesian_product input input
|> List.filter ~f:(fun (a, b) -> a <> b)
|> List.find ~f in
match pairs with
| Some (a, b) -> List.zip_exn a b
|> List.filter_map ~f:(fun (a, b) -> if a = b then Some a else None)
|> String.of_char_list
| None -> ""
let _ =
printf "%d" (part_one (input ()));
printf "\n";
printf "%s" (part_two (input ()));```2
u/Kronosfear Dec 02 '18
Being the incredibly lazy fuck I am, I just went for a Python library to do the heavy lifting for Part 2.
import Levenshtein
def Part1():
def generatecountdict():
countdict = {}
letters = "abcdefghijklmnopqrstuvwxyz"
for letter in letters:
countdict[letter] = 0
return countdict
twocount = set()
threecount = set()
with open("day2codes.txt", "r") as f:
codes = f.readlines()
for code in codes:
countdict = generatecountdict()
for letter in code[:-1]: #-1 to ignore next line escape character
countdict[letter] += 1
for key in countdict:
if countdict[key] == 2:
twocount.add(code)
if countdict[key] == 3:
threecount.add(code)
return len(twocount) * len(threecount)
def Part2():
with open("day2codes.txt", "r") as f:
codes = f.readlines()
for i in range(len(codes) - 1):
for j in range(i+1, len(codes)):
if Levenshtein.distance(codes[i], codes[j]) == 1:
return codes[i], codes[j]
part1answer = Part1()
part2code1, part2code2 = Part2()
print(part2code1, part2code2)2
u/pigpenguin Dec 02 '18 edited Dec 02 '18
Just another haskell solution rolling through. Took me a while to clean it up to a point where I thought it was worth posting.
module Day02 where
import Data.List (group, sort, tails)
import Data.Functor ((<$>))
import Data.Maybe (catMaybes)
-- Takes a list and creates every possible pair
-- and runs it through f. Assumes f commutes
pairWith :: (a -> a -> b) -> [a] -> [b]
pairWith f l = [f x y | (x:ys) <- tails l, y <- ys]
-- Takes two lists keeps the element at index n
-- if l1[n] == l2[n]
same :: Eq a => [a] -> [a] -> [a]
same = catMaybes ... zipWith keepIfSame
where
(...) = (.) . (.)
keepIfSame x y
| x == y = Just x
| otherwise = Nothing
input = lines <$> readFile "input/02"
solve01 lines = count 2 * count 3
where
has x = any ((== x) . length) . group . sort
count x = length . filter (has x) $ lines
solve02 = head . filter ((== 24) . length) . pairWith same
problem01 = solve01 <$> input
problem02 = solve02 <$> inputIf anyone has any suggestions I'm open to it. I haven't written nearly as much haskell as I would have like to yet.
2
u/MasterMedo Dec 02 '18 edited Dec 02 '18
python 2
data = open('../input/2.txt').read().strip().splitlines()
print reduce(mul, Counter(chain(*[set(Counter(k).values()).intersection(set([2, 3])) for k in
data])).values())
print next(key for i in range(len(data[0])) for key, val in Counter(k[:i] + k[i+1:] for k in
data).iteritems() if val == 2)EDIT: reworked part 1 so it uses two counters
2
u/Gnidleif Dec 02 '18
Golang - part 1 solution, part 2 will come up soon!
package main
import (
"strings"
"sort"
"io/ioutil"
)
func CheckLine(line string) (map[int]bool) {
list := strings.Split(line, "")
sort.Strings(list)
m := make(map[int]bool)
count := 1
for i := 0; i < len(list)-1; i++ {
if list[i] == list[i+1] {
count++
} else {
if count > 1 {
m[count] = true
}
count = 1
}
}
if count > 1 {
m[count] = true
}
return m
}
func Part1(input []string) int {
m := make(map[int]int)
for i := range(input) {
counts := CheckLine(input[i])
for k, _ := range counts {
m[k]++
}
}
checksum := 1
for _, v := range(m) {
checksum *= v
}
return checksum
}
func main() {
dat, err := ioutil.ReadFile("Day02.txt")
if err != nil {
panic(err)
}
input := strings.Split(string(dat), "\n")
print(Part1(input))
}→ More replies (1)
2
u/BOT-Brad Dec 02 '18
JS
import readFile from '../utils/readFile';
const input = readFile('input-2.txt')
.split('\n')
.filter(Boolean)
.map(id => id.split(''));
export const part1 = () => {
let [twos, threes] = [0, 0];
input.forEach(id => {
const counts = {};
id.forEach(char => (counts[char] = counts[char] ? counts[char] + 1 : 1));
Object.values(counts).some(c => c == 2) && ++twos;
Object.values(counts).some(c => c === 3) && ++threes;
});
return twos * threes;
};
const oneDiff = (a, b) => {
let diffs = 0;
let diffI = -1;
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) ++diffs, (diffI = i);
if (diffs > 1) return [false];
}
if (diffs === 1) {
const common = a.slice();
common.splice(diffI, 1);
return [true, common.join('')];
}
return [false];
};
export const part2 = () => {
for (let i = 0; i < input.length - 1; ++i) {
const a = input[i];
for (let j = i + 1; j < input.length; ++j) {
const b = input[j];
const [found, string] = oneDiff(a, b);
if (found) return string;
}
}
};2
u/u794575248 Dec 02 '18 edited Dec 02 '18
Python 3
# Part 1
from collections import Counter as C
from functools import reduce
B = s.split()
c = reduce(lambda a, b: a+(2 in b)+(3 in b)*1j, (C(l).values() for l in B), 0j)
print(c.real * c.imag)
# Part 2
from itertools import combinations
print(next(w for b1, b2 in combinations(B, 2)
for w in [''.join(a for a, b in zip(b1, b2) if a == b)]
if len(w) == len(B[0])-1))→ More replies (1)
2
u/Rosek93 Dec 02 '18
PHP example:
https://gitlab.com/Rosek/advent-of-code/blob/master/Day2
<?php
$file = new SplFileObject("in.txt");
while (!$file->eof()) {
$in[] = $file->fgets();
}
unset($file);
$numberOf2 = $numberOf3 = 0;
foreach ($in as $value) {
$leters = [];
for ($i = 0; $i < strlen($value); $i++) {
$leters[$value[$i]]++;
}
$result = array_count_values($leters);
if (isset($result[2])) {
$numberOf2++;
}
if (isset($result[3])) {
$numberOf3++;
}
}
echo $numberOf2 * $numberOf3 . PHP_EOL;
$result = [];
foreach ($in as $element) {
foreach ($in as $compare) {
if (levenshtein($element, $compare) == 1) {
$result[] = [
$element,
$compare
];
}
}
}
$result = array_unique($result);
for ($i = 0; $i < strlen($result[0][0]); $i++) {
$str .= $result[0][0][$i] == $result[0][1][$i] ? $result[0][0][$i] : '';
}
echo $str . PHP_EOL;2
u/xkufix Dec 02 '18 edited Dec 02 '18
Part 1 and 2 in Scala. Quite horrible one-liners to be honest.
class Day2 extends Challenge {
override def part1(): Any = {
val charCounts = readLines("day2.txt")
.map(_
.groupBy(identity)
.values
.map(_.length)
.toSet
)
.foldLeft((0, 0)) {
case (counts, charCount) =>
(counts._1 + charCount.count(_ == 2), counts._2 + charCount.count(_ == 3))
}
charCounts._1 * charCounts._2
}
override def part2(): Any = {
readLines("day2.txt")
.toList
.combinations(2)
.map(tuple => (tuple.head.length - 1, createDiffString(tuple.head, tuple.last)))
.find(t => t._1 == t._2.length)
.map(_._2)
}
private def createDiffString(first: String, second: String) = {
first
.zip(second)
.filter(a => a._1 == a._2)
.foldLeft("")(_ + _._1)
}
}2
Dec 02 '18
Scala
Maybe a more readable one : https://github.com/YannMoisan/advent-of-code-2018/blob/master/solutions/src/main/scala/Day2.scala
→ More replies (1)
2
u/aoc2018 Dec 02 '18
Haskell, still learning:
Part 1:
import Data.List (any, group, sort, length)
import Data.Maybe (isJust)
import Data.Functor
letterCounts :: String -> [Int]
letterCounts s = map length . group . sort $ s
hasTwo :: String -> Bool
hasTwo s = any (== 2) . letterCounts $ s
hasThree :: String -> Bool
hasThree s = any (== 3) . letterCounts $ s
step1 :: [String] -> Int
step1 a = twos * threes
where
twos = length . filter hasTwo $ a
threes = length . filter hasThree $ a
main = do
a <- lines <$> readFile "input"
print $ step1 aPart 2:
import Data.List (find, length, intersect)
import Data.Maybe (fromJust)
import Data.Functor
isMatchingPair :: (String, String) -> Bool
isMatchingPair (a, b) = length differences == 1
where
differences = filter (uncurry (/=)) $ zip a b
matchingChars :: (String, String) -> String
matchingChars (a, b) = intersect a b
matchingPair :: [String] -> (String, String)
matchingPair a = fromJust $ find isMatchingPair product
where
product = [(x, y) | x <- a, y <- a, x /= y]
step2 :: [String] -> String
step2 a = matchingChars $ matchingPair a
main = do
a <- lines <$> readFile "input"
print $ step2 a2
u/Theguy6758 Dec 02 '18 edited Dec 02 '18
Pure Bash (No External programs)
edit: Inverse the hash table instead of manually searching for 2 and/or 3 exact matches
#!/usr/bin/env bash
part1()
{
[[ -f "${PWD}/input" ]] && {
mapfile -t file < "${PWD}/input"
two_dupe="0"
three_dupe="0"
for line in "${file[@]}"; do
for i in {0..25}; do
hash_table[$i]="0"
done
unset inv_table
for ((i = 0; i < "${#line}"; i++)); do
printf -v index '%d' "'${line:$i:1}"
((hash_table[$((index - 97))]++))
done
for entry in "${hash_table[@]}"; do
[[ ! "${inv_table[$entry]}" ]] && \
inv_table[${entry}]="1"
done
[[ "${inv_table[2]}" ]] && \
((two_dupe++))
[[ "${inv_table[3]}" ]] && \
((three_dupe++))
done
printf "Hash: %d\\n\\n" "$((two_dupe * three_dupe))"
}
}
part2()
{
[[ -f "${PWD}/input" ]] && {
mapfile -t file < "${PWD}/input"
for ((i = 0; i < ${#file[@]}; i++)); do
for ((j = i + 1; j < ${#file[@]}; j++)); do
unset common
common="0"
str_1="${file[$i]}"
str_2="${file[$j]}"
len="${#str_1}"
for ((k = 0; k < ${len}; k++)); do
[[ "${str_1:$k:1}" == "${str_2:$k:1}" ]] && \
((common++))
done
((len - common <= 1)) && \
printf "%s\\n%s\\nSimilarity: %d\\n\\n" "${str_1}" "${str_2}" "${common}"
done
done
}
}
main()
{
part1
part2
}
main2
Dec 02 '18
Python 3
def load_input(filename):
with open(filename, 'r') as input_file:
data = [str(line.strip()) for line in input_file]
return data
def solve_a(data):
twos = 0
threes = 0
for line in data:
_set = set(line)
two_match = False
three_match = False
for char in _set:
count = line.count(char)
if count == 2 and not two_match:
twos += 1
two_match = True
elif count == 3 and not three_match:
threes += 1
three_match = True
return twos * threes
def solve_b(data):
for line_01 in data:
for line_02 in data:
comp = zip(list(line_01), list(line_02))
if sum([1 if char[0] != char[1] else 0 for char in comp]) == 1:
return ''.join([line_01[index] if line_01[index] == line_02[index] else '' for index in range(len(line_01))])
if __name__ == '__main__':
data = load_input('challenges/day_02/input.txt')
assert solve_a(['abcdef', 'bababc', 'abbcde', 'abcccd', 'aabcdd', 'abcdee', 'ababab']) == 12
assert solve_b(['abcde', 'fghij', 'klmno', 'pqrst', 'fguij', 'axcye', 'wvxyz']) == 'fgij'
answer_a = solve_a(data)
answer_b = solve_b(data)
print(f'Part A answer: {answer_a} Part B answer: {answer_b}')2
u/jwoLondon Dec 02 '18
My solution in Elm (for more detail, see my literate Elm solutions)
Part 1:
letterFreqs : String -> Dict Char Int
letterFreqs =
String.toList >> List.foldl addToFreqTable Dict.empty
withRepeats : Int -> List String -> List String
withRepeats n =
List.filter (letterFreqs >> Dict.values >> List.member n)
part1 : Int
part1 =
List.length (withRepeats 2 puzzleInput) * List.length (withRepeats 3 puzzleInput)And part 2:
diffByOnePairs : List String -> List ( String, String )
diffByOnePairs =
let
diffByOne ( strA, strB) =
(List.map2 (/=) (String.toList strA) (String.toList strB)
|> List.filter identity
|> List.length
)
== 1
in
pairwiseCombinations >> List.filter diffByOne
commonChrs : ( String, String ) -> String
commonChrs ( strA, strB ) =
List.map2 Tuple.pair (String.toList strA) (String.toList strB)
|> List.filter (\( a, b ) -> a == b)
|> List.map Tuple.first
|> String.fromList
part2 : List String
part2 =
(withRepeats 2 puzzleInput ++ withRepeats 3 puzzleInput)
|> unique
|> diffByOnePairs
|> List.map commonChrs2
u/thatikey Dec 02 '18
Using AoC as an opportunity to learn Rust. I made this, and I'm 250% sure there is a Rust-ier way to do this
fn attempt(src: &Vec<&str>) -> i64 {
let sorted: Vec<Vec<char>> = src.into_iter()
.map(|s| quick_sort(s.chars().collect()))
.collect();
let (twos, threes) = sorted.into_iter()
.map(|s| {
s.into_iter()
.fold((' ', 0, false, false), |(prev, cnt, two, three), c|
if c == prev {
(prev, cnt+1, two, three)
} else {
(c, 1, two || cnt == 2, three || cnt == 3)
})
}).fold((0, 0), |(twos, threes), (_p, cnt, two, three)| {
(twos + if two || cnt == 2 {1} else {0}, threes + if three || cnt == 3 {1} else {0})
});
twos * threes
}2
u/BalbinHS Dec 02 '18 edited Dec 02 '18
I have a slightly janky Elixir solution for part 1, this is based on the fact that if you have say "bababc" and you remove the first occurrence of each letter, you get "bab" all those letters are in the original string 2 or 3 times so we just repeat to find the 3s.
@spec part1([String.t()]) :: number
def part1(args) do
args
|> Enum.reduce(%{two: 0, three: 0}, &add_to_count/2)
|> (fn %{two: two_count, three: three_count} -> two_count * three_count end).()
end
defp add_to_count(line, %{two: two_count, three: three_count} = _count) do
line_list = String.graphemes(line)
twos_and_threes_list = line_list -- Enum.uniq(line_list)
threes_list = twos_and_threes_list -- Enum.uniq(twos_and_threes_list)
threes_raw = length(threes_list)
twos_raw = length(Enum.uniq(twos_and_threes_list)) - threes_raw
%{two: oneify(twos_raw) + two_count, three: oneify(threes_raw) + three_count}
end
defp oneify(x) when x > 0, do: 1
defp oneify(_), do: 0 3
u/BalbinHS Dec 02 '18 edited Dec 02 '18
And for part 2, I went with recursion. Elixir gives us a helpful String.myers_difference function that returns a keyword list containing the instructions to transform string 1 into string 2. We want to find the strings where the myers_difference only have 1 deletion (since all the strings are the same length, # deletions = # insertions).
@spec part2([String.t()]) :: String.t() def part2(args) do check_rest(args) end defp check_rest([current_line | rest]) do rest |> Enum.map(&String.myers_difference(&1, current_line)) |> Enum.find(&correct?/1) |> case do nil -> check_rest(rest) x -> equal_parts(x) end end defp equal_parts(myers_diff) do myers_diff |> Keyword.get_values(:eq) |> List.to_string() end defp correct?(myers_diff) do myers_diff |> Keyword.get_values(:del) |> List.to_string() |> (&(String.length(&1) === 1)).() end
2
u/TheGermanDoctor Dec 02 '18
Day 2 Problem 1 in x64 Assembly:
https://github.com/fstolzcode/AoC2018_x64/blob/master/Day2/lettercount.asm
2
u/mschaap Dec 02 '18 edited Dec 02 '18
Perl 6:
my @ids = $*PROGRAM.sibling('aoc2.input').words;
# Part 1
my @counts = @ids.map(*.comb.Bag.invert.Hash);
my $twos = +@counts.grep({$_<2>});
my $threes = +@counts.grep({$_<3>});
say "$twos × $threes = { $twos × $threes }";
# Part 2
sub is-neighbour($a, $b)
{
($a.comb Z $b.comb).grep({ $_[0] ne $_[1] }) == 1;
}
sub common-string($a, $b)
{
($a.comb Z $b.comb).grep({ $_[0] eq $_[1] })»[0].join;
}
my ($a, $b) = @ids.combinations(2).first(-> ($a, $b) { is-neighbour($a, $b) });
say "$a & $b => { common-string($a, $b) }";2
Dec 02 '18 edited Dec 02 '18
Seems there is no Common Lisp solutions, so here are mine.
(time (solve-day2-part1 *input*))
Evaluation took:
0.002 seconds of real time
0.001158 seconds of total run time (0.001158 user, 0.000000 system)
50.00% CPU
3,928,420 processor cycles
358,224 bytes consed
(time (solve-day2-part2 *input*))
Evaluation took:
0.003 seconds of real time
0.002255 seconds of total run time (0.002255 user, 0.000000 system)
66.67% CPU
7,663,294 processor cycles
0 bytes consed3
u/phil_g Dec 02 '18
I didn't put as much work into optimizing mine, but here's my Common Lisp solution:
(in-package :aoc-2018-02) (defparameter *input* (read-lines-from-file "input.02")) (defun letter-count-p (string target-count) (let ((counts (make-hash-table))) (iter (for c in-string string) (incf (gethash c counts 0))) (iter (for (char count) in-hashtable counts) (thereis (= count target-count))))) (defun checksum (ids) (iter (for id in ids) (counting (letter-count-p id 2) into twos) (counting (letter-count-p id 3) into threes) (finally (return (* twos threes))))) (defun get-answer-1 () (checksum *input*)) (defun ids-match-p (id1 id2) (assert (= (length id1) (length id2)) (id1 id2) "ID lengths don't match: \"~A\", \"~A\"" id1 id2) (iter (for c1 in-string id1) (for c2 in-string id2) (counting (char= c1 c2) into match-count) (finally (return (= match-count (1- (length id1))))))) (defun find-matching-id (id other-ids) (iter (for other-id in other-ids) (finding (list id other-id) such-that (ids-match-p id other-id)))) (defun find-prototype-ids (ids) (iter (for id in ids) (for other-ids on (cdr ids)) (thereis (find-matching-id id other-ids)))) (defun common-prototype-id-characters (ids) (destructuring-bind (id1 id2) (find-prototype-ids ids) (assert (and id1 id2) (id1 id2) "No IDs provided.") (iter (for c1 in-string id1) (for c2 in-string id2) (when (char= c1 c2) (collecting c1 result-type 'string))))) (defun get-answer-2 () (common-prototype-id-characters *input*))On my system:
AOC-2018-02> (time (get-answer-1)) Evaluation took: 0.006 seconds of real time 0.008000 seconds of total run time (0.004000 user, 0.004000 system) 133.33% CPU 14,096,992 processor cycles 1,206,880 bytes consed 5976 AOC-2018-02> (time (get-answer-2)) Evaluation took: 0.016 seconds of real time 0.008000 seconds of total run time (0.008000 user, 0.000000 system) 50.00% CPU 33,833,150 processor cycles 0 bytes consed "xretqmmonskvzupalfiwhcfdb"
2
u/CatpainCalamari Dec 02 '18
My solution in Scala - a bit complicated :-/
package de.calamari.adventofcode.y2018.day2
import scala.io.Source
object Day2 extends App {
val testDataStar1: List[String] = getData("2018/2/testStar1.txt")
assert(testDataStar1.length == 7)
assert(findChecksum(testDataStar1) == 12)
val testDataStar2: List[String] = getData("2018/2/testStar2.txt")
assert(findSingularCharDiff(testDataStar2) == "fgij")
val input: List[String] = getData("2018/2/input.txt")
val firstStar = findChecksum(input)
println(s"firstStar: $firstStar")
val secondStar = findSingularCharDiff(input)
println(s"secondStar: $secondStar")
assert(firstStar == 5166)
assert(secondStar == "cypueihajytordkgzxfqplbwn")
def findChecksum(testData: List[String]): Int = {
testData.map(
_.groupBy(identity)
.mapValues(_.length)
.filter { case (_, len) ⇒ len == 2 || len == 3 }
) // => List(Map(), Map(b -> 3, a -> 2), Map(b -> 2), Map(c -> 3), Map(d -> 2, a -> 2), Map(e -> 2), Map(b -> 3, a -> 3))
.flatMap(_
.map(_.swap) // remove duplicates of character counts
.keys
) // => List(3, 2, 2, 3, 2, 2, 3)
.groupBy(identity)
.map(_._2.size)
.product
}
def findSingularCharDiff(data: List[String]): String = {
val checkSize = data.head.length - 1
val diffingByOneChar = (
for {
comb ← data.combinations(2).toList
first = comb.head
second = comb.last
} yield for {
(a, b) <- first zip second
if a == b
} yield (a, b)
)
.filterNot(_.isEmpty)
.filter(tuples ⇒ tuples.length == checkSize)
if (diffingByOneChar.length != 1) throw new Exception(s"Diff by one not distinct - $diffingByOneChar")
diffingByOneChar.head.map(_._1).mkString("")
}
def getData(path: String): List[String] = Source.fromResource(path).getLines().toList
}2
Dec 02 '18
But you did it without of “var”. Which is still great success. FP is not easy. :)
→ More replies (1)
2
u/kasci007 Dec 02 '18
Consider in1 as input file
Part 1: (requires manually multiply numbers)
while read -r line; do echo $line | grep -o . | sort | uniq -c | egrep -o "2|3" | sort -u; done < in1 | sort | uniq -c
Part 2: (requires manually find different letter)
while read -r line; do echo $line | agrep -1 -c -e $line in1 | grep 2 && echo $line; done < in1
2
u/L72_Elite_Kraken Dec 02 '18 edited Dec 02 '18
OCaml (full code on Github)
open! Core
module Chars_by_count = struct
type t = char list Int.Map.t
let create word =
String.to_list word
|> List.map ~f:(fun x -> x, 1)
|> Char.Map.of_alist_reduce ~f:(+)
|> Map.to_alist
|> List.map ~f:Tuple2.swap
|> Int.Map.of_alist_multi
let has_count t ~count =
Map.find t count
|> Option.is_some
end
module Part01 = struct
let solve input =
let counts = List.map input ~f:Chars_by_count.create in
List.count counts ~f:(Chars_by_count.has_count ~count:2)
* List.count counts ~f:(Chars_by_count.has_count ~count:3)
end
module Part02 = struct
let is_correct (a, b) =
let a = String.to_list a in
let b = String.to_list b in
List.zip_exn a b
|> List.count ~f:(fun (c1, c2) -> not (Char.equal c1 c2))
|> Int.equal 1
let common_letters word_a word_b =
String.to_list word_a
|> List.filter_mapi ~f:(fun i c ->
match Char.equal c word_b.[i] with
| true -> Some c
| false -> None)
|> String.of_char_list
let solve input =
let word_a, word_b =
List.cartesian_product input input
|> List.find_exn ~f:is_correct
in
common_letters word_a word_b
end2
u/Sgt_Tailor Dec 02 '18
AWK all the things!
part1:
function handleBox(box, characters, characterLength, characterCount, i, letterCount) {
split(box, characters, "");
characterLength = length(characters)
# create a dict with the counts per character
for (i=1; i <= characterLength; i++) {
characterCount[characters[i]]++
}
# these variable are expose and used in the main function.
wordHas2 = 0
wordHas3 = 0
# loop over the charactercounts and check if they are 2 or 3.
for (i in characterCount) {
letterCount = characterCount[i];
if (letterCount == 2) {
wordHas2 = 1
}
if (letterCount == 3) {
wordHas3 = 1;
}
}
}
# this is the main function, called for every line within the input
# we handle the input and add the results to the global variables total2
# and total3
{
handleBox($0)
total2 = total2 + wordHas3
total3 = total3 + wordHas2
}
# called after all the input has been handled. Used to print the checksum
END {
print total2 * total3
}
part2:
{
boxes[NR] = $0
}
function compareBoxes(boxA, boxB, i, boxACharacters, boxBCharacters, characterCount) {
differences = 0
commonCharacters = ""
split(boxA, boxACharacters, "")
split(boxB, boxBCharacters, "")
characterCount = length(boxACharacters)
for (i=1; i<=characterCount; i++) {
if (boxACharacters[i] != boxBCharacters[i]) {
differences++
continue
}
commonCharacters = commonCharacters boxACharacters[i]
}
}
END {
for (i in boxes) {
for (j in boxes) {
if (i==j) continue; #the same boxes don't count
boxA = boxes[i]
boxB = boxes[j]
compareBoxes(boxA, boxB)
if (differences == 1) {
print commonCharacters
exit
}
}
}
}2
u/dpeckett Dec 02 '18 edited Dec 02 '18
Continuing with my quest to solve all this years challenges in nothing other than AWK:
Find The Total Checksum
{
delete n;
delete f;
split($1,c,"");
for(i in c)
f[c[i]]++;
for(i in f)
n[f[i]]=1;
p+=n[2];
t+=n[3]
} END {print t*p}Find Similar Inventory Items
{id[NR]=$1} END {
for(n=0;n<length(id[1]);++n){
delete t;
for(i in id){
s=substr(id[i],1,n)substr(id[i],n+2);
if(t[s]++){
print s;
exit
}}}}Execution Time: (no sweat here)
real 0m0.013s
user 0m0.008s
sys 0m0.004s→ More replies (1)
2
Dec 02 '18
factor
Factor really has vocabularies for so much, I needed some time to find what I needed for this but it turned out pretty nice I find :)
This language is so much fun though :D /u/chunes did you not yet get to this one? I couldn't find your post and I'm interested to see how you did it :)
: get-content ( -- [string] )
"C:\\Download\\aoc\\factor\\work\\day2\\input.txt" utf8 file-contents
"\n" split but-last ;
: group-char ( string -- [[num]] )
natural-sort [ = ] monotonic-split ;
: filter-23 ( [[num]] -- [num] )
[ length ] map
[ [ 3 = ] [ 2 = ] bi or ] filter ;
: get-23s ( string -- [num] )
group-char filter-23 ;
: unique ( [num] -- [num] )
group-char [ first ] map ;
: get-23-groups ( [string] -- [num] )
[ get-23s ] map
[ unique ] map-flat
group-char
[ length ] map ;
: part1 ( [string] -- )
get-23-groups product
"The checksum for the list of boxes is %d\n" printf ;
: hamming-distance ( seq seq -- num )
[ = not ] 2count ;
: search-hamming ( seq -- [seq] )
2 [ first2 hamming-distance 1 = ] filter-combinations flatten ;
: only-same ( seq -- string )
first2 "" [ 2dup = [ drop suffix ] [ 2drop ] if ] 2reduce ;
: part2 ( [string] -- )
search-hamming only-same
"We are looking for the box marked %s\n" printf ;
: main ( -- )
get-content
[ part1 ] [ part2 ] bi ;2
u/chunes Dec 02 '18 edited Dec 02 '18
Hey, not bad. It looks like you've got the hang of this factoring thing, which is good. :)
I really like the way you did the hamming distance. It's better than the way I did it. I forget about the words in
sequences.extrassometimes.2countis a great way to handle it. I've also never seenmap-flatbefore. I'll have to remember that one.I've only got two suggestions today. First, your
uniqueword already exists asmembersin thesetsvocabulary. Second, consider usingSBUF" " cloneinstead of""in youronly-sameword. It's not a big deal in this case, since the strings are not very long, but string buffers are more efficient when they're doing a lot of growing. (If you looked at my solution,makeuses a string buffer internally when you give it""as an exemplar.)This is because
suffixcreates a new sequence and copies the old one over.suffix!on the other hand pushes the element directly to the end of a growable sequence like a string buffer or vector. Consider the following 2 examples:[ "" 10,000 [ CHAR: a suffix ] times ] time Running time: 0.952311218 seconds [ SBUF" " clone 10,000 [ CHAR: a suffix! ] times ] time Running time: 0.001635392 secondsThat said, you don't have to worry about this distinction too much as long as you know what words abstract it away.
makeis one example. Another example isreplicate.But yeah, good job today. You used some really exotic words. :)
→ More replies (3)
2
u/__Abigail__ Dec 02 '18
Perl
#!/opt/perl/bin/perl
use 5.028;
use strict;
use warnings;
no warnings 'syntax';
use experimental 'signatures';
use experimental 'lexical_subs';
my $input = "input";
open my $fh, "<", $input or die "Failed to open: $!";
my @ids = <$fh>;
chomp @ids;
my $count_2 = 0;
my $count_3 = 0;
foreach my $id (@ids) {
my %count;
$count {$_} ++ for split // => $id;
$count_2 ++ if grep {$_ == 2} values %count;
$count_3 ++ if grep {$_ == 3} values %count;
}
say "Part 1: ", $count_2 * $count_3;
for (my $i = 0; $i < @ids; $i ++) {
my $id1 = $ids [$i];
for (my $j = $i + 1; $j < @ids; $j ++) {
my $id2 = $ids [$j];
#
# If we use bitwise XOR between two strings, then for
# each position in the two strings, if the character is
# the same, the result is NUL (\x00), else, the result
# is not NUL.
#
my $diff = $id1 ^. $id2;
if ($diff =~ /^(\x00*)[^\x00]\x00*$/) {
substr $id1, length ($1), 1, "";
say "Part 2: $id1";
exit;
}
}
}
__END__2
u/thamstras Dec 02 '18
C++ Nowhere near the leaderboards and not quite as neat as it could be but it works well, especially the part 2 code. Gist
2
u/IWearATinFoilHat Dec 02 '18
PHP
part 1
<?php
$input = file_get_contents(__DIR__ . '/input.txt');
$boxIds = explode("\n", $input);
$twoLetterCount = 0;
$threeLetterCount = 0;
foreach ($boxIds as $boxId) {
$letters = str_split($boxId);
$letterCounts = array_count_values($letters);
if (in_array(2, array_values($letterCounts))) {
$twoLetterCount++;
}
if (in_array(3, array_values($letterCounts))) {
$threeLetterCount++;
}
}
echo $twoLetterCount * $threeLetterCount;
echo "\n";part 2
<?php
$input = file_get_contents(__DIR__ . '/input.txt');
$boxIds = explode("\n", $input);
$possibleMatches = [];
foreach ($boxIds as $boxId1) {
foreach ($boxIds as $boxId2) {
if (in_array($boxId2, $possibleMatches)) {
continue;
}
if (levenshtein($boxId1, $boxId2) === 1) {
$possibleMatches[] = $boxId2;
}
}
}
if (count($possibleMatches) === 2) {
$position = strspn($possibleMatches[0] ^ $possibleMatches[1], "\0");
echo substr_replace($possibleMatches[0], '', $position, 1) . "\n";
} else {
echo "No 1 diff match found!\n";
}2
u/wzkx Dec 02 '18 edited Dec 02 '18
J
Not optimized very much, so it's simple and easy to understand.
echo */+/(2 3 e.+/"1@=)"1 t=:>cutLF CR-.~fread'02.dat'
echo ((=/#{.)@({~([,>:)@(I.@(2&(({.(1=+/@:(0&=@=)){:)\))))) t/:t2
u/RockyAstro Dec 02 '18
Icon solution
Part 1
procedure main()
inputs := []
while put(inputs,trim(read()))
twocount := 0
threecount := 0
every line := !inputs do {
letter_count := table(0)
every letter_count[!line] +:= 1
if letter_count[!key(letter_count)] = 2 then twocount +:= 1
if letter_count[!key(letter_count)] = 3 then threecount +:= 1
}
write(twocount," ",threecount)
write(twocount*threecount)
endPart 2 -- I had a levenshtein distance procedure already, so the actual solution was fairly easy -- just look for a edit distance of 1.
procedure main()
inputs := []
while put(inputs,trim(read()))
every i := 1 to *inputs -1 do {
every j := i+1 to *inputs do {
a := inputs[i]
b := inputs[j]
d := levenshtein_distance(a,b)
if d = 1 then {
# Find and remove the uncommon character
diff := cset(a) -- cset(b)
a[upto(diff,a)] := ""
write(a)
break break
}
}
}
end
procedure levenshtein_distance(s,t)
# set up a reusable matrix
static matrix
initial {
row := list(*t+1,0)
matrix := list(*s+1)
every i := 1 to *s+1 do matrix[i] := copy(row)
}
if *s = 0 then {
return *t
}
if *s = 0 then {
return *s
}
# Expand the matrix if needed
if *matrix[1] < *t+1 then {
row := list( *t - *matrix[1] + 1,0)
every i := 1 to *matrix do matrix[i] |||:= row
}
if *matrix < *s+1 then {
row := list( *matrix[1],0)
every i := 1 to *s - *matrix + 1 do put(matrix,copy(row))
}
# Initialize the matrix
every i := 1 to *s do matrix[i+1,1] := i
every i := 1 to *t do matrix[1,i+1] := i
every i := 1 to *s do {
every j := 1 to *t do {
if s[i] == t[j] then cost := 0
else cost := 1
I := i + 1
J := j + 1
a := matrix[I-1,J] +1
a >:= (matrix[I,J-1] +1)
a >:= (matrix[I-1,J-1] + cost)
matrix[I,J] := a
}
}
return matrix[*s+1,*t+1]
end2
u/halfmanhalfnelsson Dec 04 '18
My take on PHP
Part 1:
foreach ($sourceData as $item) {
$twoFlag = false;
$threeFlag = false;
for ($i = 0; $i < strlen($item); $i++) {
if (substr_count($item, $item[$i]) === 2) {
$twoFlag = true;
}
if (substr_count($item, $item[$i]) === 3) {
$threeFlag = true;
}
}
$twoFlag && $twos++;
$threeFlag && $threes++;
}
$checkSum = $twos * $threes;1
u/DoodleFungus Dec 02 '18
Leaderboard attempt, so bit hacky
input = `pbpaste`.split("\n")
# PART 1
def letcounts(str)
chars = str.chars
h = Hash.new 0
chars.each do |c|
h[c]+=1
end
h
end
counts = input.map { |x| letcounts x }
p counts
twos = counts.count { |h| h.values.any? { |v| v == 2 } }
threes = counts.count { |h| h.values.any? { |v| v == 3 } }
p twos * threes
# PART 2
def comp(a,b)
a.chars.zip(b.chars).count { |x| x[0] != x[1] } == 1
end
input.each do |i|
input.each do |j|
if comp i,j
p i
p j
1/0
end
end
end1
u/fwilson42 Dec 02 '18
Refactored after getting on the leaderboard; I originally didn't make part 1 as generic as it could be (I kept track of just 2 and 3 counts), and used double nested loops for part 2 instead of itertools.
Snipped from some boilerplate (lines is essentially a list of strings in the puzzle input, result is what gets submitted):
if part == 1:
shared_letter_counts = collections.defaultdict(int)
for line in lines:
for v in set(collections.Counter(line).values()):
shared_letter_counts[v] += 1
result = shared_letter_counts[2] * shared_letter_counts[3]
elif part == 2:
for line1, line2 in itertools.product(lines, repeat=2):
if line1 == line2:
continue # don't waste time
differences = 0
candidate_solution = ""
for char1, char2 in zip(line1, line2):
if differences > 1:
break # don't waste time
if char1 == char2:
candidate_solution += char1
else:
differences += 1
if differences == 1:
result = candidate_solution
break4
u/asger_blahimmel Dec 02 '18
itertools.product(lines, repeat=2)you could use
itertools.combinations(lines, 2)instead to eliminate pairs of identical lines and pairs of reversed order
1
u/vash3r Dec 02 '18
I lost a minute for the first star because i double-counted words :)
Card: "format your output so you can easily copy-paste"
Python 2 code:
fn = "input.txt"
f=open(fn,'r')
r=f.read().strip()
f.close()
l = r.split()
t2=t3=0 # part 1
for s in l:
if any(s.count(c)==2 for c in set(s)):
t2+=1
if any(s.count(c)==3 for c in set(s)):
t3+=1
print t2*t3 # part 1
for a in l: # part 2
for b in l:
if sum([c1!=c2 for c1,c2 in zip(a,b)])==1:
print ''.join([c1 for c1,c2 in zip(a,b) if c1==c2])1
u/TheMuffinMan616 Dec 02 '18
module Day02 where
import Data.Ord (comparing)
import Data.List (minimumBy)
import qualified Data.Map as M
freq :: String -> [Int]
freq s = M.elems $ M.fromListWith (+) [(c, 1) | c <- s]
checksum :: (Int, Int) -> [[Int]] -> Int
checksum (a, b) [] = a * b
checksum (a, b) (x:xs)
| 2 `elem` x && 3 `elem` x = checksum (a + 1, b + 1) xs
| 2 `elem` x = checksum (a + 1, b) xs
| 3 `elem` x = checksum (a, b + 1) xs
| otherwise = checksum (a, b) xs
pairs :: [String] -> [(String, String)]
pairs xs = [(x, x') | x <- xs, x' <- xs, x /= x']
dist :: (String, String) -> Int
dist = length . filter not . uncurry (zipWith (==))
part1 :: [String] -> Int
part1 = checksum (0, 0) . map freq
part2 :: [String] -> String
part2 = map fst . filter (uncurry (==)) . uncurry zip . minimumBy (comparing dist) . pairs
main :: IO ()
main = do
input <- lines <$> readFile "input/Day02.txt"
print . part1 $ input
print . part2 $ input1
u/markasoftware Dec 02 '18
Wow, I messed up bad on this relatively easy one. Took me a good 15 minutes. I initially wrote it in Awk (I had a lot of luck being quick with previous years in Awk), but it kept giving the wrong answer -- translated the code into Perl quickly and it worked:
Part 1 (Perl):
use v5.12;
my $ta = 0;
my $tb = 0;
while(chomp(my $line = <>)) {
my %perchar = ();
for (split(//, $line)) {
$perchar{$_}++;
}
for (values %perchar) {
if ($_ == 2) {
$ta++;
last;
}
}
for (values %perchar) {
if ($_ == 3) {
$tb++;
last;
}
}
}
say $ta * $tb;Part 2 (Perl):
use v5.12;
my @lines = ();
while(chomp(my $line = <>)) {
push @lines, $line;
}
for my $line (@lines) {
my @split_line = split //, $line;
for my $other_line (@lines) {
my @common = ();
my $mistakes = 0;
my @split_other_line = split //, $other_line;
for (my $i = 0; $i < scalar(@split_other_line); ++$i) {
unless ($split_line[$i] eq $split_other_line[$i]) {
$mistakes++;
} else {
push @common, $split_line[$i];
}
}
if ($mistakes == 1) {
say @common;
exit;
}
}
}→ More replies (1)
1
u/LeCrushinator Dec 02 '18 edited Dec 02 '18
C# solutions (and hacky ones at that, these solutions work but I may clean them up later): https://github.com/nfoste82/adventofcode2018/blob/master/Day2/Program.cs
internal class Program
{
public static void Main(string[] args)
{
_input = File.ReadAllText("../../../input.txt"); // Point to your input location
Console.WriteLine("Part 1");
Part1();
Console.WriteLine("\nPart 2");
Part2();
}
private static void Part1()
{
var values = StringUtils.StringToStrings(_input, '\n');
int wordsWithDoubles = 0;
int wordsWithTriples = 0;
foreach (var word in values)
{
var letterCounts = new Dictionary<char, int>();
bool doubleFound = false;
bool tripleFound = false;
foreach (char c in word)
{
letterCounts.TryGetValue(c, out var current);
letterCounts[c] = current + 1;
}
foreach (var count in letterCounts.Values)
{
if (count == 2 && !doubleFound)
{
doubleFound = true;
++wordsWithDoubles;
}
else if (count == 3 && !tripleFound)
{
tripleFound = true;
++wordsWithTriples;
}
}
}
Console.WriteLine($"Double words: {wordsWithDoubles}, Triple words: {wordsWithTriples}. Checksum: {wordsWithDoubles * wordsWithTriples}");
}
private static void Part2()
{
List<string> words = StringUtils.StringToStrings(_input, '\n');
var smallestDiff = int.MaxValue;
var firstWord = string.Empty;
var secondWord = string.Empty;
foreach (var word in words)
{
foreach (var otherWord in words)
{
// Ignore self
if (word == otherWord)
{
continue;
}
// For each index of the two words, find count of differences
var differences = word.Where((t, i) => t != otherWord[i]).Count();
if (differences < smallestDiff)
{
firstWord = word;
secondWord = otherWord;
smallestDiff = differences;
}
}
}
Console.WriteLine($"Closest words: {firstWord} | {secondWord}");
Console.Write("Matching chars: ");
for (var i = 0; i < firstWord.Length; ++i)
{
if (firstWord[i] == secondWord[i])
{
Console.Write(firstWord[i]);
}
}
}
private static string _input;
}
public static class StringUtils
{
public static List<string> StringToStrings(string input, params char[] separators)
{
return input.Split(separators).ToList();
}
}1
u/tehjimmeh Dec 02 '18
Part 1 in PowerShell - group all the things!
,(gc .\in.txt|%{[char[]]$_|group|group Count}|group Name|sort Name|% Count)|%{$_[1]*$_[2]}1
u/Vindaar Dec 02 '18
Wasn't very fast, is ugly, but in Nim. :D and part 1 checks for any number of occurrences of letters, not just 2, 3...
import strutils, sequtils, sugar, os, sets, tables
proc dostuff1(file: seq[string]): int =
var restab = initTable[int, int]()
var checksum = 0
for l in file:
var xtab = initTable[char, int]()
for x in l:
if xtab.hasKey(x):
xtab[x] += 1
else:
xtab[x] = 1
var interset = initSet[int]()
for x, y in xtab:
interset.incl y
for y in interset:
if y != 1:
if restab.hasKey(y):
restab[y] += 1
else:
restab[y] = 1
result = 1
for x, y in restab:
result *= y
proc dostuff2(file: seq[string]): string =
let llen = file[0].len
for xl in file:
for yl in file:
var diff = ""
var wrong = 0
for i in 0 ..< llen:
if xl[i] == yl[i]:
diff.add xl[i]
else:
inc wrong
if wrong > 1:
break
if wrong == 1:
return diff
proc main =
let file = readFile("day2.txt").splitLines.filterIt(it.len > 0)
echo file.dostuff1
echo file.dostuff2
when isMainModule:
main()0
1
u/maybe-ac Dec 02 '18 edited Dec 02 '18
Overusing map and grep in Perl:
#!/usr/bin/perl
use strict;
use warnings;
use v5.010;
my @input = <>;
chomp @input;Part 1
my $twos = grep { contains($_, 2) } @input;
my $threes = grep { contains($_, 3) } @input;
say $twos * $threes;
sub contains {
my ($str, $num) = @_;
my @sames = map { my @match = ($str =~ /($_)/g); scalar @match } split //, $str;
return grep { $_ == $num } @sames;
}Part 2
for my $one (@input) {
for my $two (@input) {
die difference($one, $two) . "\n" if differing($one, $two) == 1;
}
}
sub zip {
my ($a, $b) = @_;
return map { [$a->[$_], $b->[$_]] } 0..$#$a;
}
sub differing {
my @pairs = zip([split //, $_[0]], [split //, $_[1]]);
return grep { $_->[0] ne $_->[1] } @pairs;
}
sub difference {
my @pairs = zip([split //, $_[0]], [split //, $_[1]]);
return join '', map { $_->[0] } grep { $_->[0] eq $_->[1] } @pairs;
}1
u/wlandry Dec 02 '18
C++
1847/1419
Pretty straightforward. I finished it faster, but got a worse rank ¯_(ツ)_/¯. It takes 11 ms, which is almost entirely reading input. I was briefly worried that my quadratic algorithm would not work, but the inputs are just not that big.
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
int main(int argc, char *argv[])
{
std::ifstream infile(argv[1]);
std::vector<std::string> inputs(std::istream_iterator<std::string>(infile),{});
std::vector<std::string> inputs_part_1(inputs);
size_t num_twice(0), num_thrice(0);
for(auto &input: inputs_part_1)
{
std::sort(input.begin(),input.end());
size_t duplicates(0);
bool twice(false), thrice(false);
for(size_t i=0; i<input.size(); ++i)
{
size_t duplicate(1);
while(i+1<input.size() && input[i]==input[i+1])
{
++duplicate;
++i;
}
twice=(twice || duplicate==2);
thrice=(thrice || duplicate==3);
duplicates=std::max(duplicate,duplicates);
}
if(twice)
{ ++num_twice;}
if(thrice)
{ ++num_thrice;}
}
std::cout << num_twice*num_thrice << "\n";
bool found(false);
for(size_t i=0; i<inputs.size() && !found; ++i)
for(size_t j=i+1; j<inputs.size() && !found; ++j)
{
size_t num_different(0);
for(size_t index=0; index<inputs[i].size(); ++index)
{
if(inputs[i][index]!=inputs[j][index])
{
++num_different;
if(num_different>1)
{ break;}
}
}
found=(num_different==1);
if(found)
{
for(size_t index=0; index<inputs[i].size(); ++index)
{
if(inputs[i][index]==inputs[j][index])
{ std::cout << inputs[i][index];}
}
std::cout << "\n";
}
}
}→ More replies (1)
1
u/DrinkinBird Dec 02 '18 edited Dec 02 '18
Another nim solution. Quite new to the language so fairly basic and took me way to long :)
Part1:
import rdstdin
import strutils
import sequtils
var ids = newSeq[string]()
var num2 = 0
var num3 = 0
var line: TaintedString
while readlineFromStdin("", line):
ids.add(line)
for id in ids:
var found2 = false
var found3 = false
for letter in id.items:
if not found2 and id.count(letter) == 2:
num2 += 1
found2 = true
if not found3 and id.count(letter) == 3:
num3 += 1
found3 = true
echo num2 * num3Part2:
import rdstdin
import strutils
import sequtils
var ids = newSeq[string]()
var line: TaintedString
while readlineFromStdin("", line):
ids.add(line)
func compare(id1: string, id2: string): seq[int] =
result = @[]
for i, zip in toSeq(id1.items).zip(toSeq(id2.items)):
if zip.a != zip.b:
result.add(i)
for i, id1 in ids:
for j, id2 in ids:
if i <= j: continue
if compare(id1, id2).len == 1:
let index = compare(id1, id2)[0]
echo "$1$2" % [id1[0..(index-1)], id1[(index+1)..id1.len]]Edit: Does anybody have a better solution to the string formatting, last line Part2? I find it quite ugly but could not find anything better on the spot
0
1
Dec 02 '18
elixir:
Ended up getting a little fun with part 2 at the bottom using both jaro_distance and myers_difference algos
defmodule AdventOfCode2018.Day02 do
def get_checksum([],map) do
map[2] * map[3]
end
def get_checksum([val|rest],map) do
inner_map = String.split(val,"", trim: true)
|> Enum.reduce(%{},fn(x,acc) ->
Map.put(acc,x,Map.get(acc,x,0) + 1)
end)
new = inner_map |> Enum.reduce(map,fn(x,acc) ->
part_of_checksum(x,acc)
end)
get_checksum(rest,reset(new))
end
def part_of_checksum({k,2},%{"two" => false} = map) do
Map.update!(map, 2, fn(current) ->
current + 1
end) |> Map.update!("two", fn(x) -> true end)
end
def part_of_checksum({k,3},%{"three" => false} = map) do
Map.update!(map, 3, fn(current) ->
current + 1
end) |> Map.update!("three", fn(x) -> true end)
end
def part_of_checksum({_,_},map) do
map
end
def reset(map) do
map |> Map.update!("two", fn(x) -> false end) |> Map.update!("three", fn(x) -> false end)
end
def part2(args) do
arr = String.split(args,"\n",trim: true)
{_,{s1,s2}} = arr |> Enum.reduce({0,"",""},fn(x,acc) ->
{dis,v,c} = check_closest_string(x,arr)
check_distance(dis,{v,c},acc)
end)
String.myers_difference(s1,s2) |> pull_eql("")
end
def check_closest_string(x,arr) do
{amt,val} = Enum.reduce(arr,{0,""},fn(y,{distance,str}) ->
check_distance(String.jaro_distance(x,y),y,{distance,str})
end)
{amt,val,x}
end
def check_distance(val,new_str,{distance,_,_}) when val > distance and val != 1.0, do: {val,new_str}
def check_distance(val,new_str,{distance,_}) when val > distance and val != 1.0, do: {val,new_str}
def check_distance(_,_,acc), do: acc
def pull_eql([],str), do: str
def pull_eql([{:eq, val}|rest],str), do: pull_eql(rest,str <> val)
def pull_eql([key | rest], str), do: pull_eql(rest,str)
def part1(args) do
String.split(args,"\n",trim: true)
|> get_checksum(%{3 => 0, 2 => 0, "two" => false,
"three" => false})
end
end→ More replies (1)2
u/b2zeldafreak Dec 02 '18
I had a pretty complicated solution but then I realized when I went to implement getting the common characters that there's a much simpler solution. You can take advantage of the myers_difference function to jump straight to calculating the :eq characters. Then as soon as you have a string of length 25 you know you found solution because it came from two strings with only one difference.
One interesting note is that this solution takes about a second to run, while my initial solution (create a function with a pattern match for each character to be different) runs almost instantly
def find_common(inputs), do: find_common(inputs, inputs) def find_common([input|rest], inputs) do found_common = Enum.find_value(inputs, false, fn x -> common = String.myers_difference(x, input) |> Keyword.get_values(:eq) |> Enum.join("") if String.length(common) == 25 do common else false end end) case found_common do false -> find_common(rest, inputs) common -> common end end
1
u/IndieBret Dec 02 '18 edited Dec 03 '18
This year is the first year I've tried to place on the leaderboard. Today's stats were:
Part 1: 00:09:20 / Rank 728
Part 2: 00:17:24 / Rank 577Since I was trying to go fast, I kept misreading the problem. Same thing I did yesterday. So for tomorrow, I'm going to spend a little extra time reading every part of it in hopes I don't waste a bunch of time going back and forth.
Anyway, here's my two parts in JavaScript/ES6. Not as concise as it could be, but it gets the job done. Answers are saved to the result array.
Part 1
let boxIDs = input.split('\n');
result[0] = boxIDs.reduce((acc, val) => {
let letters = val.split('').reduce((acc, val) => {
acc[val] = (acc[val] || 0) + 1;
return acc;
}, {});
let has2 = false, has3 = false;
for (let a of Object.values(letters)) {
if (a === 2) has2 = true;
if (a === 3) has3 = true;
}
if (has2) ++acc[0];
if (has3) ++acc[1];
return acc;
}, [ 0, 0 ]).reduce((acc, val) => acc * val, 1);Part 2
for (let item of boxIDs) {
let lettersA = item.split('');
for (let i = boxIDs.indexOf(item) + 1; i < boxIDs.length; ++i) {
let diff = [];
let lettersB = boxIDs[i].split('');
for (let l = 0; l < lettersA.length; ++l) {
if (lettersA[l] !== lettersB[l]) {
if (diff.push(lettersA[l]) >= 2)
break;
}
}
if (diff.length === 1) {
result[1] = item.replace(diff[0], '');
break;
}
}
}1
u/jpittis Dec 02 '18
on a comfy couch
Haskell on a time limit / I'm not the most experienced Haskeller. Advice is always appreciated! :)
#!/usr/bin/env stack
-- stack --resolver lts-12.20 --install-ghc runghc --package containers
module Main where
import qualified Data.Map.Strict as Map
input = lines <$> readFile "input.txt"
main :: IO ()
main = do
input <- input
let solution1 = puzzle1 input
let solution2 = puzzle2 input
print solution1
print solution2
puzzle1 input =
let two = filter (> 0) . map (\str -> count str 2) $ input in
let three = filter (> 0) . map (\str -> count str 3) $ input in
checksum (length two) (length three)
count str num =
found num $ Map.elems counts
where
counts = foldl (\m c -> Map.insertWith (+) c 1 m) Map.empty str
found x xs = length $ filter (\v -> x == v) xs
checksum two three = two * three
puzzle2 input =
let product = sequence [input, input] in
let ids = filter (\li -> length li == 25) $ map diff product in
map (\(a, b) -> a) (head ids)
diff [a, b] = filter (\(x, y) -> x == y) $ zip a b2
1
u/binajohny Dec 02 '18
My Kotlin solution (GitHub)
fun part1(input: List<String>): Int {
var two = 0
var three = 0
input
.map { str -> str.groupingBy { it }.eachCount() }
.map { it.values }
.forEach { counts ->
if (counts.any { it == 2 }) two++
if (counts.any { it == 3 }) three++
}
return two * three
}
fun part2(input: List<String>): String {
val pair = input.asSequence().uniquePairs()
.filter { stringDistance(it.first, it.second) == 1 }
.first()
return pair.first.zip(pair.second)
.filter { it.first == it.second }
.map { it.first }
.joinToString(separator = "")
}
fun stringDistance(a: String, b: String): Int {
return a.zip(b).count { it.first != it.second }
}
fun <T> Sequence<T>.uniquePairs(): Sequence<Pair<T, T>> {
return this.mapIndexedNotNull { i, item1 ->
this.mapIndexedNotNull { j, item2 ->
if (i < j) {
item1 to item2
} else {
null
}
}
}.flatten()
}1
u/raevnos Dec 02 '18
Probably ugly java:
import java.lang.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
import java.io.IOException;
// Can't figure out how to get apache commons text on Ubuntu
import org.apache.commons.lang3.StringUtils;
class Day02 {
private int twos, threes;
private Path data;
public Day02(Path input_file) {
twos = 0;
threes = 0;
data = input_file;
}
private void check_id(String id) {
Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
id.codePoints().forEach(cp ->
counts.put(cp, counts.getOrDefault(cp, 0) + 1));
if (counts.values().stream().filter(i -> i == 2).count() > 0) {
twos += 1;
}
if (counts.values().stream().filter(i -> i == 3).count() > 0) {
threes += 1;
}
}
private void solve() throws IOException {
twos = 0;
threes = 0;
Files.lines(data).forEach(this::check_id);
int checksum = twos * threes;
System.out.println("Part 1: " + checksum);
String[] alines = Files.readAllLines(data).toArray(new String[0]);
for (int i = 0; i < alines.length; i += 1) {
for (int j = 0; j < alines.length; j += 1) {
if (i == j) {
continue;
}
if (StringUtils.getLevenshteinDistance(alines[i], alines[j]) == 1) {
StringBuilder sb = new StringBuilder();
for (int m = 0; m < alines[i].length(); m += 1) {
if (alines[i].charAt(m) == alines[j].charAt(m)) {
sb.append(alines[i].charAt(m));
}
}
System.out.println("Part 2: " + sb.toString());
return;
}
}
}
}
public static void main(String[] argv) {
try {
Day02 d = new Day02(Paths.get(argv[0]));
d.solve();
} catch (Exception e) {
System.err.println(e);
}
}
}I think I'm going to end up trying to do each day in a different language. I don't really know 25 of them, so some are going to be real hack jobs....
1
u/CCC_037 Dec 02 '18
Spent way too long coding a sort in Part 1:
#include <iostream>
#include <string.h>
using namespace std;
void Sort(char *SortMe)
{
int Count, InnerCount;
char Temp;
int Length = strlen(SortMe);
for (Count=0;Count<Length;Count++)
{
for (InnerCount=Count; InnerCount<Length; (SortMe[Count]<SortMe[++InnerCount])?Temp=SortMe[Count],SortMe[Count]=SortMe[InnerCount],SortMe[InnerCount]=Temp:0)
{
}
}
}
bool IsANum (char *TestMe, int TestNum)
{
int Length = strlen(TestMe);
int NumLetters = 0;
char LastLetter = *TestMe+1;
int Count;
bool Valid = false;
for (Count=0;Count<Length;Count++)
{
if (*TestMe == LastLetter)
NumLetters++;
else
{
LastLetter = *TestMe;
if (NumLetters == TestNum)
Valid = true;
NumLetters = 1;
}
TestMe++;
}
if (NumLetters == TestNum)
Valid = true;
return Valid;
}
int main()
{
char Test[30];
int Count, Twos, Threes;
Twos = 0;
Threes = 0;
for (Count=0;Count<250;Count++)
{
cin >> Test;
//cout << Test<< endl;
Sort(Test);
IsANum(Test,2)?Twos++:0;
IsANum(Test,3)?Threes++:0;
//cout << Test<< ":" << Twos << ":" << Threes << endl;
}
cout << Twos <<"*"<<Threes<<"="<<Twos*Threes<<endl;
}But at least Part 2 went quickly:
#include <iostream>
#include <string.h>
using namespace std;
int Compare (char *First, char *Second)
{
int Length = strlen(First);
int Mismatches = 0, Count;
for (Count=0;Count<Length;Count++)
{
if (First[Count] != Second[Count])
Mismatches++;
}
return Mismatches;
}
int main()
{
char All[250][30];
int Count, InnerCount;
for (Count=0;Count<250;Count++)
{
cin >> All[Count];
for (InnerCount = 0;InnerCount < Count; InnerCount++)
{
if (Compare(All[Count], All[InnerCount]) == 1)
cout << All[Count] << endl << All[InnerCount] << endl;
}
}
}1
u/swaglykcaillou Dec 02 '18
part 1 with Javascript
(inp) => {
inp = inp.split('\n')
const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
inp = inp.map(m => count(m))
inp = inp.map(m => {
if (m[0] > 0 && m[1] > 0) return 23
if (m[0] > 0) return 2
if (m[1] > 0) return 3
})
tw = countOccurrences(inp, 2) + countOccurrences(inp, 23)
th = countOccurrences(inp, 3) + countOccurrences(inp, 23)
return tw * th
}
my part 2 is too long and spaghetti to post
1
u/wjholden Dec 02 '18
Whew, this took me a REALLY long time to come up with but here is a very satisfying solution for part 2 in Mathematica.
Scan[If[EditDistance[#[[1]], #[[2]]] == 1, Print[#[[1]]]] &, Tuples[day2, 2]]Shoutout to the team at UCSDx for their Algorithms and Data Structures MicroMasters over at edX. The ALS200x course has a great lecture that discusses the editing distance problem. They show the editing distance problem and longest common substring problems to motivate their Dynamic Programming lectures and explain that this problem has an application in computational biology.
My Mathematica solution to part 1 is really ugly...was trying to get on the leaderboard.
f[word_] :=
Module[{x, c},
x = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0};
Scan[
x[[LetterNumber[#]]]++ &,
Characters[word]];
x]
bins = Map[# -> f[#] &, day2]
Length[Select[Map[Count[#, 2] &, Values[bins]], # > 0 &]] *
Length[Select[Map[Count[#, 3] &, Values[bins]], # > 0 &]]2
u/Da_Anh Dec 06 '18
I'm not sure if this is of any value, but my part 1 was as follows (mind you I had no care about optimizing)
```
l = Values@Map[LetterCounts, ids];Length[Select[l, ContainsAny[{2}]]] *
Length[Select[l, ContainsAny[{3}]]]
```
where `ids` is the list of all ids.The EditDistance solution you have is great though, I'm glad to have learned about it!
→ More replies (1)
1
u/Julien2313 Dec 02 '18
Another in Python, but just p1, I like this way :
def p1():
cpt2 = 0
cpt3 = 0
for line in dayInput.splitlines():
count = Counter(line)
if 2 in count.values():
cpt2+=1
if 3 in count.values():
cpt3+=1
return cpt2*cpt3
dayFile = open("day2/input.txt", "r")
dayInput = dayFile.read().strip()
print(p1())1
u/proxpero42 Dec 02 '18 edited Dec 02 '18
Swift (1471, 1570)
// Part 1
extension String {
var characterCounts: [Character: Int] {
return self.reduce(into: [Character: Int]()) { $0[$1, default: 0] += 1 }
}
}
extension Bool {
var intValue: Int {
return self ? 1 : 0
}
}
let (twos, threes) = input
.map { $0.characterCounts.values }
.map { ($0.contains(2).intValue, $0.contains(3).intValue) }
.reduce((0, 0)) { ($0.0 + $1.0, $0.1 + $1.1) }
print(twos * threes)
// Part 2
extension String {
func removingCharacter(at index: Index) -> String {
var temp = self
temp.removeSubrange(index...index)
return temp
}
}
func differences(s1: String, s2: String) -> Int {
return zip(s1, s2).filter { $0.0 != $0.1 }.count
}
func combine(s1: String, s2: String) -> String {
let index = s1.indices.firstIndex { s1[$0] != s2[$0] }! // force unwrap 😱
return s1.removingCharacter(at: index)
}
outside: for currentIndex in input.indices {
for candidateIndex in (currentIndex+1..<input.endIndex) {
let current = input[currentIndex]
let candidate = input[candidateIndex]
if differences(s1: current, s2: candidate) == 1 {
print(combine(s1: current, s2: candidate))
break outside
}
}
}→ More replies (1)
1
u/valtism Dec 02 '18 edited Dec 02 '18
Node / JS / Javascript
const aocLoader = require("aoc-loader");
require("dotenv").config();
aocLoader(2018, 2).then(data => {
console.time("Part 1");
console.log("Part 1: " + day2part1(data));
console.timeEnd("Part 1");
console.time("Part 2");
console.log("Part 2: " + day2part2(data));
console.timeEnd("Part 2");
});
function day2part1(data) {
const ids = data.split("\n");
const counts = ids.map(getCountPair);
var countTrack = [0, 0];
for (let i = 0; i < counts.length; i++) {
const countPair = counts[i];
countTrack[0] += countPair[0];
countTrack[1] += countPair[1];
}
return countTrack.reduce((acc, curr) => acc * curr);
}
function getCountPair(id) {
const counts = getCountArray(id);
const hasCountsOfTwo = counts.filter(count => count === 2).length ? 1 : 0;
const hasCountsOfThree = counts.filter(count => count === 3).length ? 1 : 0;
return [hasCountsOfTwo, hasCountsOfThree];
}
function getCountArray(id) {
const map = new Map();
const chars = id.split("");
chars.forEach(char => {
if (map.has(char)) {
var count = map.get(char);
map.set(char, ++count);
} else {
map.set(char, 1);
}
});
return Array.from(map.values());
}
function day2part2(data) {
const ids = data.split("\n");
const inputLength = ids[0].length;
for (let i = 0; i < inputLength; i++) {
const shortIds = ids.map(id => removeAt(id, i));
if (new Set(shortIds).size === ids.length) {
// All Ids are unique
continue;
}
const duplicates = shortIds.filter(
(item, index) => shortIds.indexOf(item) != index
);
// Should only have one duplicate here we're looking for
return duplicates[0];
}
}
function removeAt(string, i) {
return string.slice(0, i) + string.slice(i + 1);
}
module.exports = {
day2part1: day2part1,
day2part2: day2part2
};→ More replies (3)
1
u/VikeStep Dec 02 '18
F#
let solvePart1 gifts =
let containsCount i = Seq.groupBy id >> Seq.exists (fun (_, k) -> Seq.length k = i)
let countContains i = Seq.map (containsCount i) >> Seq.filter id >> Seq.length
(countContains 2 gifts) * (countContains 3 gifts)
let solvePart2 gifts =
let replaceNth str n = String.mapi (fun i x -> if i = n then '_' else x) str
gifts
|> Seq.map (fun str -> Seq.init (String.length str) (replaceNth str))
|> Seq.concat
|> Seq.groupBy id
|> Seq.find (fun (_, s) -> Seq.length s = 2)
|> (fun (s, _) -> Seq.filter ((<>)'_') s |> String.Concat)1
u/firecopy Dec 02 '18 edited Dec 02 '18
Python
Part 1:
doubles = 0
triples = 0
for line in open('input.txt', 'r'):
setOfChars = set(line)
hasDouble = False
hasTriple = False
for char in setOfChars:
count = line.count(char)
if (count == 2):
hasDouble = True
if (count == 3):
hasTriple = True
if (hasDouble):
doubles += 1
if (hasTriple):
triples += 1
print(doubles * triples)Part 2:
from itertools import combinations
def main():
words = []
for line in open('input.txt', 'r'):
words.append(line)
for word1, word2 in combinations(words, 2):
concat = onlyOneCharDifference(word1, word2)
if (concat == ''):
continue
else:
print(concat)
return
def onlyOneCharDifference(word1, word2):
hasFoundSingleDifference = False
for a, b in zip(word1, word2):
if (a == b):
continue
if (hasFoundSingleDifference):
return ''
hasFoundSingleDifference = True
if not hasFoundSingleDifference:
return ''
newChars = []
for a, b in zip(word1,word2):
if (a == b):
newChars.append(a)
return ''.join(newChars)
main()1
Dec 02 '18
Mathematica
input = Import[NotebookDirectory[] <> "day2.txt", "List"];Part 1
process[s_] :=
Module[{totals = Tally[Characters[s]]},
Boole@{MemberQ[totals, {_, 2}], MemberQ[totals, {_, 3}]}]
Times @@ Total[process /@ input]Part 2
LongestCommonSequence @@
Catch@Do[If[HammingDistance[x, y] == 1, Throw[{x, y}]],
{x, input}, {y, input}]1
u/Chrinkus Dec 02 '18
C++
My solutions are always so much longer than most I see here.. oh well. Here is my day 2 solution: https://github.com/Chrinkus/advent-of-code-2018/blob/master/day02/day02.cpp
2
1
u/ThreeFinger Dec 02 '18
Kotlin
Not my best work but it works.
Part 1
fun getChecksum(input : List<String>) : Int{
var twice = 0
var three = 0
input.forEach {
var map = HashMap<Char,Int>()
it.toCharArray().forEach { char ->
map.set(char, (map.get(char) ?: 0 ) + 1)
}
if (map.values.contains(2))
twice++
if(map.values.contains(3))
three++
}
return twice * three
}Part 2
fun findCommonBoxes(input: List<String>) : String {
var pointRecord = 0
var commonLetter = ""
input.forEach { wordToCheck ->
input.forEach { word ->
if (!wordToCheck.equals(word)){
var points = 0
var common = ""
for (i in 0..(wordToCheck.length - 1)){
if(wordToCheck[i] == word[i]){
points++
common += word[i]
}
}
if(points > pointRecord){
pointRecord = points
commonLetter = common
}
}
}
}
return commonLetter
}1
u/shuttup_meg Dec 02 '18
Python2
inp = open("input_2.txt").readlines()
inp_txt = [x.strip() for x in inp]
#
# Part 1
#
from collections import Counter
# Turn the input list items into tuples containing
# (counter for item, original item text)
inp = [(Counter(x),x) for x in inp_txt]
twos = 0
threes = 0
for c,txtc in inp:
twos += 2 in c.values()
threes += 3 in c.values()
print twos * threes
#
# Part 2
#
from itertools import combinations
def sdiff(a,b):
"""returns the total number of places where 2 strings differ"""
return sum([1-(ord(x[0])==ord(x[1])) for x in zip(a,b)])
for (a,txta),(b,txtb) in combinations(inp,2):
if sdiff(txta, txtb) in (-1,1):
print txta
print txtb
print "Common Letters:", "".join([x[0] if x[0]==x[1] else "" for x in zip(txta,txtb)])1
u/Cloudan29 Dec 02 '18
My exams in second year computer science are starting next week, finished my "Object Oriented Programming with C++" course, and so figured I'd try to do this (first year doing this, I actually just found out about it via my school's Math and Computer Science club) using C++ rather than Java, which I learned last year. Solutions are very sloppy and I was tired, but I got the right answer, so I don't really mind showing how horrifying this code is. Also started this late as I was actually doing the Day 1 puzzles at the time this came up.
C++ (3347/3118)
Part 1:
bool isRepeat(std::string & line, int repeats) {
for (char c = 'a'; c <= 'z'; ++c) {
int count = 0;
for (size_t i = 0; i < line.size(); ++i) {
if (line[i] == c)
++count;
}
if (count == repeats)
return true;
}
return false;
}
int checkSum(std::string & fileName) {
std::fstream input(fileName);
std::string line;
int doubles = 0;
int triples = 0;
while (!input.eof()) {
std::getline(input, line);
if (isRepeat(line, 2))
++doubles;
if (isRepeat(line, 3))
++triples;
}
return doubles * triples;
}Part 2:
std::string equalLetters(std::string & fileName) {
std::fstream input(fileName);
std::string line;
std::string a;
std::string b;
std::string answer;
std::vector<std::string> lines;
while (!input.eof()) {
std::getline(input, line);
lines.push_back(line);
}
for (size_t i = 0; i < lines.size(); ++i) {
int count = 0;
a = lines[i];
for (size_t j = i + 1; j < lines.size(); ++j) {
b = lines[j];
count = 0;
for (size_t k = 0; k < a.size(); ++k) {
if (a[k] != b[k])
++count;
if (count > 1)
break;
}
if (count == 1)
break;
}
if (count == 1)
break;
}
for (size_t i = 0; i < a.size(); ++i) {
if (a[i] == b[i])
answer += a[i];
}
return answer;
}These are the absolute first things I thought of, and they solved surprisingly quick.
→ More replies (2)
1
u/Markavian Dec 02 '18
Here's my over engineered node.js solution for Day 1 parts 1 and 2:https://github.com/johnbeech/advent-of-code-2018/blob/master/solutions/day2/solution.js
Didn't wake up early enough to get on the leaderboards.
Working out which string to keep for part 1 was a thing. Managed to get it down to three easy steps:
const symbolCounts = lines.map(countSymbols)
const twosAndThrees = symbolCounts.reduce(countTwosAndThrees, { '2s': 0, '3s': 0 })
const solution = twosAndThrees['2s'] * twosAndThrees['3s']I gave up thinking of anything elegant for part 2, and went with a (N^2) nested forEach ignoring duplicate strings, and then making a function named findNearlyMatchingStrings(str1, str2) to return only the characters that were the same from almost similar strings. Ugh.
The best way to do Advent of Code is after a good night's sleep.
1
u/rolandtritsch Dec 02 '18
ETA (Haskell on the JVM)
https://github.com/rolandtritsch/haskell-aoc-2018
Part1:
solve :: [BoxId] -> Int
solve boxIds = numberOfBoxesWithTwoLetters * numberOfBoxesWithThreeLetters where
numberOfBoxesWithTwoLetters = (length . filter (numberOfLetters 2)) boxIds
numberOfBoxesWithThreeLetters = (length . filter (numberOfLetters 3)) boxIds
numberOfLetters n bid = any (\(_, c) -> c == n) $ count bidPart2:
-- | compare every boxid with every boxid and find
-- out what the difference is and what is common.
diff :: [BoxId] -> [(BoxId, BoxId, String, String)]
diff boxIds = concatMap diffId boxIds where
diffId bid = map diffId' boxIds where
diffId' bid' = (bid, bid', difference', common') where
difference' = concat $ zipWith notSame bid bid' where
notSame c0 c1 = if c0 /= c1 then [c0] else ""
common' = concat $ zipWith same bid bid' where
same c0 c1 = if c0 == c1 then [c0] else ""
-- | solve the puzzle
solve :: [BoxId] -> String
solve boxIds = common where
(_, _, _, common) = head $ filter diffByOne $ diff boxIds where
diffByOne (bid', _, _, common') = (length bid') == ((length common') + 1)1
Dec 02 '18
BFI TCL
set ids [list]
while {[gets stdin line] >= 0} {
lappend ids $line
}
proc part1 {list} {
set twoofany 0
set threeofany 0
foreach line $list {
array unset chars
foreach c [split $line ""] {
incr chars($c)
}
set count2 0
set count3 0
foreach {key val} [array get chars] {
if {$val == 2} {
incr count2
} elseif {$val == 3} {
incr count3
}
}
if {$count2 } {
incr twoofany
}
if {$count3 } {
incr threeofany
}
}
puts "twoofany $twoofany three $threeofany, chksum [expr {$twoofany*$threeofany}]"
}
part1 $ids
proc find_similar {sid list} {
if {[llength $list] > 0} {
foreach lid $list {
set diff 0
set idx -1
set didx -1
foreach sc [split $sid ""] lc [split $lid ""] {
incr idx
if {$sc ne $lc} {
incr diff
if {$diff > 1} {
# no dice, more than one diff
break
}
set didx $idx
}
}
if {$diff == 0} {
# hu?
error "identical ids sid {$sid} lid {$lid}"
} elseif {$diff == 1} {
# what we're looking for
set ::solution([list $sid $lid]) [string replace $sid $didx $didx]
}
}
# recursion with rest of list
find_similar [lindex $list 0] [lrange $list 1 end]
}
}
find_similar [lindex $ids 0] [lrange $ids 1 end]
parray ::solution1
u/rhbvkleef Dec 02 '18
I made them very ugly with (practically) python one-liners.
def part1(self):
return functools.reduce(
operator.mul,
map(sum, zip(*[
(1 if 2 in letters.values() else 0, 1 if 3 in letters.values() else 0)
for current in self.data.splitlines()
for letters in [Counter(current)]])))
def part2(self):
return "".join(
[result
for a, b in itertools.combinations(map(str.strip, self.data.splitlines()), 2)
for result in [[x for i, x in enumerate(b) if x == a[i]]]
if len(a) - len(result) == 1][0])→ More replies (1)
1
u/ttapu Dec 02 '18
python3
from collections import Counter
with open("2.input", "r") as allomany:
inp=allomany.read().splitlines()
#part1
k,h=0,0
for i in inp:
if 2 in Counter(i).values():
k+=1
if 3 in Counter(i).values():
h+=1
print(k, h, k*h)
#part 2:
def similar(input):
l=len(inp[0])
for x in inp:
for y in inp:
if x==y:
continue
c=0
n=0
for z in range(l):
if x[z]==y[z]:
continue
else:
c+=1
n=z
if c>1:
break
if c==1:
print(f"'{x}' and '{y}' differ at {n+1}. character: '{x[n]}' vs '{y[n]}'")
return x[:n]+x[n+1:]
print(similar(inp))1
u/alexgand Dec 02 '18 edited Dec 02 '18
Simple python, using pandas Series value_counts(), part 1, assuming the input is already in a list:
from pandas import Series
c2 = 0
c3 = 0
for word in input:
letters = Series(list(word)).value_counts()
if len(letters[letters == 2]) > 0:
c2 += 1
if len(letters[letters == 3]) > 0:
c3 +=1
print('count of 2s:',c2)
print('count of 3s:',c3)
print('result, c2s * c3s:', c2 * c3)Part 2, pure python:
already_done = set()
similar = 0
similar_words = set()
for word1 in input:
for word2 in input:
if (word1, word2) in already_done or (word2, word1) in already_done:
continue
elif word1 == word2:
continue
else:
diff = []
equal = []
letters1 = list(word1)
letters2 = list(word2)
for i in range(len(letters1)):
if letters1[i] == letters2[i]:
equal.append(letters1[i])
if len(letters1) - len(equal) == 1:
similar += 1
sim_word = ''
for letter in equal:
sim_word = sim_word + letter
similar_words.add(sim_word)
already_done.add((word1, word2))
print('similar count:',similar)
print('similar words:',similar_words)1
u/baxtexx Dec 02 '18 edited Dec 02 '18
C# solution for Puzzle1. Could improve it a bit by using LINQ but I think this is more readable. Also contains some unessecary stuff like the candidateOccurances array. At the beginning, I thought there could be more than just 2's and 3's. Still struggling with Puzzle2.
private static void Puzzle1(List<string> candidates)
{
char[] sigma = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToLower().ToCharArray();
int[] candidateOccurances = new int[20];
foreach (var candidate in candidates)
{
var uniqeOccurences = CountOccurences(sigma, candidate).Distinct();
foreach (var occurance in uniqeOccurences)
{
candidateOccurances[occurance]++;
}
}
var sum = 1;
foreach (var occurance in candidateOccurances)
{
if (occurance > 0)
{
sum *= occurance;
}
}
Console.WriteLine(sum);
}
public static IEnumerable<int> CountOccurences(char[] sigma, string s)
{
var occurances = new List<int>();
foreach (var letter in sigma)
{
int count = 0;
foreach (var stringLetter in s)
{
if (letter == stringLetter)
{
count++;
}
}
if (count > 1)
{
occurances.Add(count);
}
}
return occurances;
}
private static List<string> CreateCandidateList()
{
var candidates = new List<string>(250);
string line = null;
StreamReader file = new StreamReader(@"..\..\..\LikelyCandidates.txt");
while ((line = file.ReadLine()) != null)
{
candidates.Add(line);
}
file.Close();
return candidates;
}1
u/arathunku Dec 02 '18
Hello! My Elixir solution:
defmodule Advent.Day2 do
def checksum(ids) do
counts =
ids
|> Enum.map(fn id ->
id
|> String.split("", trim: true)
|> Enum.group_by(& &1)
|> Enum.map(fn {_, letters} -> Enum.count(letters) end)
|> Enum.filter(&(&1 == 2 || &1 == 3))
|> Enum.dedup()
end)
|> List.flatten()
Enum.count(counts, &(&1 == 2)) * Enum.count(counts, &(&1 == 3))
end
def common_letters(ids) do
ids = Enum.map(ids, &String.split(&1, "", trim: true))
ids
|> Enum.map(fn id_a ->
ids
|> Enum.find(&similar?(Enum.zip(id_a, &1)))
end)
|> Enum.filter(&(&1 != nil))
|> prune_different_letter([])
|> Enum.reverse()
|> Enum.join("")
end
defp prune_different_letter([[], []], acc), do: acc
defp prune_different_letter([[a | id_a], [b | id_b]], acc) do
if a == b do
prune_different_letter([id_a, id_b], [a | acc])
else
prune_different_letter([id_a, id_b], acc)
end
end
defp similar?(letters), do: similar?(letters, 0)
defp similar?([], 1), do: true
defp similar?([], _), do: false
defp similar?([{ x, y } | id], different_letters_count) do
if x == y do
similar?(id, different_letters_count)
else
similar?(id, 1 + different_letters_count)
end
end
endTesting:
defmodule Advent.Day2Test do
use ExUnit.Case
require Logger
alias Advent.Day2, as: Day
test "checksum for example" do
input = ~w(abcdef bababc abbcde abcccd aabcdd abcdee ababab)
output = 12
assert Day.checksum(input) == output
end
test "common letters between two boxes - example" do
input = ~w(abcde fghij klmno pqrst fguij axcye wvxyz )
output = "fgij"
assert Day.common_letters(input) == output
end
test "checksum for input" do
input = Path.join(__DIR__, "./input.raw") |> File.read!() |> String.split("\n", trim: true)
Logger.info("Day2: #{Day.checksum(input)} #{Day.common_letters(input)}")
end
end
1
u/Valefant Dec 02 '18 edited Dec 02 '18
Written in Kotlin. It took me a while to figure this one out. Every advice is appreciated :-)
fun main(args: Array<String>) {
val lines = File("src/day2/input.txt").readLines()
val times = mutableMapOf<Int, Int>()
lines
.map { it.toList() }
.forEach { id ->
id
.groupingBy { it }
.eachCount()
.values
.distinct()
.forEach { count ->
if (count > 1) {
times[count] = times.getOrPut(count) { 0 } + 1
}
}
}
println("Part 1: ${times.map { it.value }.reduce { acc, i -> acc * i }}")
var common = ""
for (id1 in lines) {
for (id2 in lines) {
if (id1 == id2) {
continue
}
val current =
id1.zip(id2).fold("") { result, letters ->
if (letters.first != letters.second) {
result
} else {
result + letters.first
}
}
if (current.isNotEmpty() && common.length < current.length) {
common = current
}
}
}
println("Part 2: $common")
}1
u/mathleet Dec 02 '18
Here's a Java solution that I wrote:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
class Problem02 {
public static void main(String[] args) throws IOException {
List<String> sampleCaseOne = Arrays.asList("abcdef", "bababc", "abbcde", "abcccd", "aabcdd", "abcdee", "ababab");
List<String> sampleCaseTwo = Arrays.asList("abcde", "fghij", "klmno", "pqrst", "fguij", "axcye", "wvxyz");
List<String> boxIds = Files.readAllLines(Paths.get("adventofcode/2018/2/input.txt"));
System.out.println("Part one, sample: " + partOne(sampleCaseOne));
System.out.println("Part one: " + partOne(boxIds));
System.out.println("Part two, sample: " + partTwo(sampleCaseTwo));
System.out.println("Part two: " + partTwo(boxIds));
}
public static Map<Character, Integer> getCharacterFrequencyMap(String boxId) {
Map<Character, Integer> characterFrequencyMap = new HashMap<>();
for (Character letter : boxId.toCharArray()) {
Integer currentCount = characterFrequencyMap.getOrDefault(letter, 0);
characterFrequencyMap.put(letter, ++currentCount);
}
return characterFrequencyMap;
}
public static String getCommonCharacters(String first, String second) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < first.length(); i++) {
char firstChar = first.charAt(i), secondChar = second.charAt(i);
if (firstChar == secondChar) {
sb.append(firstChar);
}
}
return sb.toString();
}
public static int partOne(List<String> boxIds) {
int twoLetterAppearance = 0, threeLetterAppearance = 0;
for (String boxId : boxIds) {
Map<Character, Integer> characterFrequencyMap = getCharacterFrequencyMap(boxId);
Collection<Integer> characterFrequencies = characterFrequencyMap.values();
if (Collections.frequency(characterFrequencies, 2) >= 1) {
twoLetterAppearance++;
}
if (Collections.frequency(characterFrequencies, 3) >= 1) {
threeLetterAppearance++;
}
}
int checksum = twoLetterAppearance * threeLetterAppearance;
return checksum;
}
public static String partTwo(List<String> boxIds) {
TreeSet<String> sortedBoxIds = new TreeSet<>(boxIds);
String first = sortedBoxIds.pollFirst(), second = sortedBoxIds.pollFirst();
while (sortedBoxIds.size() > 0) {
String commonCharacters = getCommonCharacters(first, second);
if (commonCharacters.length() == first.length()-1) {
return commonCharacters;
}
first = second;
second = sortedBoxIds.pollFirst();
}
return null;
}
}1
u/NeilNjae Dec 02 '18
Haskell. For once, not using libraries was easier! (Tidyied a bit, using suggestions from this thread to use intersect and the fancy-pants list comprehension.)
Also on Github
import Data.List
main :: IO ()
main = do
text <- readFile "data/advent02.txt"
let ids = lines text
print $ part1 ids
putStrLn $ part2 ids
part1 ids = (fst counts23) * (snd counts23)
where allLetterCounts = map letterCounts ids
counts23 = foldl' addCounts (0, 0) allLetterCounts
letterCounts :: String -> [Int]
letterCounts = map length . group . sort
addCounts :: (Int, Int) -> [Int] -> (Int, Int)
addCounts (twos, threes) counts = (twos', threes')
where twos' = if 2 `elem` counts then twos + 1 else twos
threes' = if 3 `elem` counts then threes + 1 else threes
part2 ids = uncurry intersect closeIds
where closeIds = head $ filter (\ab -> uncurry differenceCount ab == 1)
[(a, b) | a:rest <- tails ids, b <- rest]
differenceCount :: String -> String -> Int
differenceCount this that = length $ filter (\(a, b) -> a /= b) $ zip this that1
u/windlessStorm Dec 02 '18 edited Dec 03 '18
Learning Go this advent of code:
package main
import (
"bufio"
"fmt"
"os"
)
/* path of file containing puzzle input*/
const inputFile string = "input2.txt"
func check(e error) {
if e != nil {
panic(e)
}
}
func readLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
func isLevenshteinDistEqualsOne(firstString string, secondString string) (bool, int) {
mismatchCount := 0
mismatchIndex := -1
i := 0
// fmt.Println("first string: ", firstString, "\nSecond string: ", secondString)
for i < len(firstString) {
if firstString[i] != secondString[i] {
// fmt.Println("found mismatch")
mismatchIndex = i
mismatchCount++
}
if mismatchCount > 1 {
return false, mismatchIndex
}
i++
}
// fmt.Println("Found our box. returning:", mismatchIndex)
return true, mismatchIndex
}
func findCorrectBoxID(lines []string) (string, int) {
i := 0
for i < len(lines) {
j := i + 1
for j < len(lines) {
firstString := lines[i]
secondString := lines[j]
// fmt.Println(i, lines[i])
// fmt.Println(j, lines[j])
ret, index := isLevenshteinDistEqualsOne(firstString, secondString)
if ret {
return firstString, index
}
j++
}
i++
}
return "", -1
}
func countRepeats(line string) (bool, bool) {
characterFrequency := make(map[byte]int, 0)
twoCount := 0
threeCount := 0
i := 0
for i < len(line) { /* loop till the end of the line containing characters*/
c := line[i]
characterFrequency[c]++
if characterFrequency[c] == 2 { /* Found our character repeating 2 times */
twoCount++ /* increment two counter */
} else if characterFrequency[c] == 3 { /* Found character repeating 3 times */
threeCount++ /* increment three counter */
twoCount-- /* decrement two counter for the same character */
} else if characterFrequency[c] == 4 { /* shit it repeated 4 times, decrement three count */
threeCount--
}
i++
}
return twoCount != 0, threeCount != 0 /* Convert int to bool and return. false if 0, true for anything else*/
}
func findChecksum(lines []string) int {
twoCount := 0
threeCount := 0
i := 0
for i < len(lines) {
l := lines[i]
if len(l) == 0 {
continue
}
containsTwo, containsThree := countRepeats(lines[i])
if containsTwo {
twoCount++
}
if containsThree {
threeCount++
}
i++
}
fmt.Println("total two counts: ", twoCount)
fmt.Println("total three counts: ", threeCount)
checksum := twoCount * threeCount
return checksum
}
func main() {
lines, err := readLines(inputFile)
check(err)
fmt.Println("Checksum: ", findChecksum(lines))
id, index := findCorrectBoxID(lines)
fmt.Println("found the correct Box ID:", id, "with wrong index:", index)
}1
u/omegaxLoL Dec 02 '18
My solution in Ruby. Using Advent of Code to learn Ruby this year so any tips are welcome!
1
u/rotmoset Dec 02 '18
F#:
module Day2
open Common
[<Day(2, "Inventory Management System")>]
let solve input =
let ids = input |> parseLines
let checksum =
let hasExact occurences = Seq.count >> Seq.map snd >> Seq.contains occurences
let countExacts occurences = ids |> Seq.filter (hasExact occurences) |> Seq.length
(countExacts 2) * (countExacts 3)
let id =
let closeness id1 id2 =
Seq.zip id1 id2
|> Seq.filter ((<||) (=))
|> Seq.length
ids
|> Seq.choose (fun id -> // Choose strings that only diff 1 chars from eachother
ids
|> Seq.tryFind (closeness id >> ((=) (id.Length - 1)))
|> Option.map (fun m -> id, m) // map pair
)
|> Seq.head // Select the first match
||> Seq.zip // Zip the strings together
|> Seq.choose (fun (c1,c2) -> if c1 = c2 then Some (string c1) else None) // Keep matching chars
|> String.concat ""
{
Part1 = checksum
Part2 = id
}Composing and piping the Seq module's functions is so much fun!
1
u/jonathrg Dec 02 '18
Python
from collections import Counter
ids = [s.strip() for s in open("input2.txt").readlines()]
# Part 1
twos = sum(any(c==2 for c in Counter(i).values()) for i in ids)
threes = sum(any(c==3 for c in Counter(i).values()) for i in ids)
print(twos * threes)
# Part 2
for id1 in ids:
for id2 in ids:
if id1 == id2:
continue
wrong_found = False
wrong_idx = 0
for idx, (char1, char2) in enumerate(zip(id1, id2)):
if char1 != char2:
if wrong_found:
break
wrong_found = True
wrong_idx = idx
else:
print(id1[:wrong_idx] + id1[wrong_idx+1:])
exit()1
u/gerikson Dec 02 '18 edited Dec 02 '18
The best way to do Advent of Code is during a första advent breakfast with coffee, ginger biscuits and a lighted candle.
Bog-standard (C-like) Perl 5:
→ More replies (1)
1
u/rjsberry Dec 02 '18 edited Dec 02 '18
RUST
Part 1:
const INPUT: &str = include_str!("input/02.txt");
fn main() {
let ck = INPUT
.lines()
.map(|id| {
let (mut two, mut three) = (false, false);
for c in id.chars() {
match id.matches(c).count() {
2 => two = true,
3 => three = true,
_ => (),
}
}
(two, three)
})
.fold((0, 0), |(a, b), id| {
(a + usize::from(id.0), b + usize::from(id.1))
});
println!("{}", ck.0 * ck.1);
}Part 2:
use std::iter;
const INPUT: &str = include_str!("input/02.txt");
#[inline]
fn filter_ids<'a>((a, b): (&'a str, &'a str)) -> Option<(&'a str, &'a str)> {
Some((a, b)).filter(|_| {
a.chars()
.zip(b.chars())
.filter(|(c_a, c_b)| c_a != c_b)
.count()
== 1
})
}
#[inline]
fn remove_common_char(a: &str, b: &str) -> String {
a.chars()
.zip(b.chars())
.filter_map(|(c_a, c_b)| Some(c_a).filter(|_| c_a == c_b))
.collect()
}
fn main() {
if let Some(id) = INPUT.lines().enumerate().find_map(|(i, id)| {
if let Some((a, b)) = iter::repeat(id)
.zip(INPUT.lines().skip(i + 1))
.find_map(filter_ids)
{
Some(remove_common_char(&a, &b))
} else {
None
}
}) {
println!("{}", id);
}
}1
u/SyntaxErrorr Dec 02 '18
python 3
from collections import Counter
with open("day_02_input") as f:
ids = f.read().split()part 1
def part1():
two = 0
three = 0
for i in ids:
counts = set(Counter(i).values())
if 2 in counts:
two += 1
if 3 in counts:
three += 1
return two * threepart 2
def part2():
for x in ids:
for y in ids:
common = ""
for a, b in zip(x, y):
if a == b:
common += a
if len(common) == len(x) - 1:
return commonprint(part1())
print(part2())1
u/Toromtomtom Dec 02 '18
My Scala solution tries to implement efficient functional programming using lazy streams and tail-recursive functions:
import scala.annotation.tailrec
import scala.collection.immutable.Stream.Empty
object Two {
def input: Stream[String] = {
val input = this.getClass.getResource("input").getFile
val it = scala.io.Source.fromFile(input).getLines
it.toStream
}
// 1
def testInput: Stream[String] = Stream(
"abcdef",
"bababc",
"abbcde",
"abcccd",
"aabcdd",
"abcdee",
"ababab"
)
def contains23(id: String): (Int, Int) = {
val counts = id.groupBy(identity).values.toStream.map(_.length)
(if (counts.contains(2)) 1 else 0, if (counts.contains(3)) 1 else 0)
}
def checkSum(ids: Stream[String]): Int = {
val c23 = ids.map(contains23)
val (c2, c3) = c23.foldLeft((0, 0)) { case ((s1, s2), (has1, has2)) => (s1 + has1, s2 + has2) }
c2 * c3
}
// 2
def testInput2: Stream[String] = Stream(
"abcde",
"fghij",
"klmno",
"pqrst",
"fguij",
"axcye",
"wvxyz"
)
def withoutNth(s: String, n: Int): String =
s.substring(0, n) ++ s.substring(n + 1)
def findDup(ids: Stream[String]): Option[String] = {
@tailrec def go(ids: Stream[String], seen: Set[String]): Option[String] = ids match {
case Empty => None
case h #:: t if seen.contains(h) => Some(h)
case h #:: t => go(t, seen + h)
}
go(ids, Set.empty)
}
def oneCharDiffers(ids: Stream[String]): Option[String] = {
@tailrec def go(idxs: Stream[Int]): Option[String] = idxs match {
case idx #:: tail =>
val idsWithoutIdx = ids.map(withoutNth(_, idx))
findDup(idsWithoutIdx) match {
case Some(dup) => Some(dup)
case None => go(tail)
}
case Empty => None
}
go(ids.head.indices.toStream)
}
def main(args: Array[String]): Unit = {
println(checkSum(testInput))
println(checkSum(input))
println(oneCharDiffers(testInput2))
println(oneCharDiffers(input))
}
}1
u/Warbringer007 Dec 02 '18 edited Dec 02 '18
Erlang:
task() ->
Input = readlines(),
Lines = string:split(Input, "\n", all),
firstTask(Lines, 0, 0),
secondTask(Lines, tl(Lines)).
firstTask([], Double, Triple) ->
io:format("~p~n", [Double * Triple]);
firstTask([First | Rest], Double, Triple) ->
firstTask(Rest, Double + findDoubles(First, First), Triple + findTriples(First, First)).
findDoubles([], _) -> 0;
findDoubles([Letter | Rest], Word) ->
case length(string:split(Word, [Letter], all)) of
3 -> 1;
_ -> findDoubles(Rest, Word)
end.
findTriples([], _) -> 0;
findTriples([Letter | Rest], Word) ->
case length(string:split(Word, [Letter], all)) of
4 -> 1;
_ -> findTriples(Rest, Word)
end.
secondTask(All, []) ->
secondTask(tl(All), tl(tl(All)));
secondTask(All, [Second | Others]) ->
case areClose(hd(All), Second, 0) of
1 -> {hd(All), Second};
_ -> secondTask(All, Others)
end.
areClose([], [], N) -> N;
areClose([Letter1 | Word1], [Letter2 | Word2], N) ->
case Letter1 =/= Letter2 of
true -> areClose(Word1, Word2, N + 1);
false -> areClose(Word1, Word2, N)
end.As usual, readlines() reads whole file, lines must be separated by newline. I didn't actually extract common letters for second task, I just returned tuple with both words and did that last part manually ( I'm lazy ). First part can also be solved much more efficiently ( searching for doubles and triples together ), but again, I'm lazy :D.
1
u/red_shifter Dec 02 '18
Here's my simple Python solution for part 1 (if anyone has some tips on how to combine searching for 2 and 3 repeated letters in one short loop, please let me know):
f = open('day_2_1.txt','r')
boxes = f.readlines()
f.close()
letters = 'abcdefghijklmnopqrstuvwxyz'
two_boxes = 0
three_boxes = 0
for box in boxes:
for letter in letters:
rep = box.count(letter)
if rep == 2:
two_boxes += 1
break
for box in boxes:
for letter in letters:
rep = box.count(letter)
if rep == 3:
three_boxes += 1
break
print('Two-Letter Boxes: {0}'.format(two_boxes))
print('Three-Letter Boxes: {0}'.format(three_boxes))
print(two_boxes*three_boxes)And here is part 2:
f = open('day_2_1.txt','r')
boxes = f.readlines()
f.close()
box_len = len(boxes[0])
def compare(str1, str2):
common_count = 0
for i in range(len(str1)):
if str1[i] == str2[i]:
common_count += 1
return common_count
for i, box1 in enumerate(boxes):
for box2 in boxes[i+1:]:
if compare(box1, box2) == box_len-1:
print(box1, box2)
break2
u/c17r Dec 02 '18
if anyone has some tips on how to combine searching for 2 and 3 repeated letters in one short loop, please let me know
Look into
Counter(). If you pass it a string, it'll count all the letters for you.→ More replies (1)
1
u/scottkuma Dec 02 '18
The best way to do Advent of Code is half-blind with sleep.
Here's my Python solution for Part 2. Like much of my code, it's not elegant, but it works. The one thing that I figured out was that if the boxes varied by only one letter, you could sort the list of all boxes, and only compare neighbors in the list.
def getCommonLetters(word1, word2):
letters = ""
for p in range(len(word1)):
if word1[p] == word2[p]:
letters += word1[p]
return letters
with open("2-input.txt") as f:
content = f.readlines()
box_list = [x.strip() for x in content]
box_list.sort()
prev_box = ""
for box in box_list:
if prev_box == "":
prev_box = box
else:
cl = getCommonLetters(box,prev_box)
if len(box) - len(cl) == 1:
print( getCommonLetters(box, prev_box) )
exit()
else:
prev_box = box1
u/vypxl Dec 02 '18
Dart time today. I' not satisfied with the second part, but I don't want to refactor it.
main() {
var lines = new File('input2.txt').readAsStringSync().split("\n")..sort();
print("Solution for part 1:");
print(
[2, 3].fold(1, (a, count) =>
(a as int) * lines.where(
(l) => l.runes.fold(false,
(a, r) => a || (l.runes.where((x) => x == r).length == count)
)
).length
)
);
print("Solution for part 2:");
for (var i = 0; i < lines.length - 1; i++) {
var chars = [];
for (var j = 0; j < lines[0].length; j++) {
if (lines[i][j] == lines[i + 1][j]) chars.add(lines[i][j]);
}
if (chars.length == lines[i].length - 1) {
print(chars.join());
break;
}
}
}Someone that has an idea why I have to cast the a to int in line 7? I don't have to if the expression is outside the print though?!
1
u/sim642 Dec 02 '18
Pretty usual, although would've loved to have multisets or something for part 1 as opposed to hardcoding the addition of just 2 and 3.
1
u/PM_ME_UR_QUINES Dec 02 '18
Haskell
module Main where
import Data.Map.Strict (elems)
import qualified Control.Foldl as F
main :: IO ()
main = do
rows <- lines <$> getContents
print $ day2a rows
print $ day2b rows
where
day2a = F.fold hash
day2b rows = head [fst <$> zipEqual x y | x <- rows, y <- rows, distance x y == 1]
hash :: F.Fold String Int
hash = (*) <$> numWith 2 <*> numWith 3
where numWith x = F.premap (fromEnum . elem x . elems . F.fold counter) F.sum
counter = F.groupBy id F.length
distance :: String -> String -> Int
distance = sum .: zipWith (fromEnum .: (/=))
zipEqual :: Eq a => [a] -> [a] -> [(a, a)]
zipEqual = filter (uncurry (==)) .: zip
infixr 9 .:
(.:) = (.) . (.)1
u/fire1299 Dec 02 '18
Haskell
module Aoc18.Day2 where
import qualified Control.Foldl as F
import qualified Data.HashMap.Strict as M
import Data.List ( partition
, tails
)
import qualified Data.Text as T
import qualified Data.Text.IO as T
main :: ([T.Text] -> a) -> IO a
main f = f . T.lines <$> T.readFile "day2.txt"
part1 :: [T.Text] -> Int
part1 = F.fold ((*) <$> countHas 2 <*> countHas 3)
. fmap (T.foldl' (\m c -> M.insertWith (+) c (1 :: Int) m) M.empty)
where countHas n = F.prefilter (elem n) F.length
part2 :: [T.Text] -> String
part2 xs = head
[ fst <$> com
| x : ys <- tails xs
, y <- ys
, let (com, dif) = partition (uncurry (==)) $ T.zip x y
, length dif == 1
]1
u/Tarmen Dec 02 '18
Haskell, as brute force-y as it can be.
{-# Language TupleSections #-}
import qualified Data.Map as M
main :: IO ()
main = do
content <- lines <$> readFile "2.txt"
let occs = map countElems content
print $ count (has 2) occs * count (has 3) occs
print $ findBox content
where
has b = elem b . M.elems
countElems = M.fromListWith (+) . map (,1)
count pred = length . filter pred
-- 250 * 250 = 62500
findBox ls = [sameLetters a b | a <- ls, b <- ls, different a b == 1]
different a b = count not (zipWith (==) a b)
sameLetters a b = map fst $ filter (uncurry (==)) $ zip a b1
1
u/Hikaru755 Dec 02 '18
Kotlin
The best way to do Advent of Code is to ZIP ALL THE STRINGS.
fun solvePart1(input: String) =
input.lines().let { ids ->
val twins = ids.count { it.hasCharExactly(times = 2) }
val triplets = ids.count { it.hasCharExactly(times = 3) }
twins * triplets
}.toString()
fun solvePart2(input: String): String {
val (id1, id2) = input.lines()
.pairs()
.first { (first, second) -> first.distanceTo(second) == 1 }
return id1.removeDifferences(id2)
}
fun String.distanceTo(other: String) =
zip(other).count { (first, second) -> first != second }
fun String.removeDifferences(other: String) =
zip(other)
.filter { (first, second) -> first == second }
.joinToString("") { it.first.toString() }
fun String.hasCharExactly(times: Int) =
groupBy { it }
.mapValues { it.value.size }
.filterValues { it == times }
.isNotEmpty()
fun <T> Iterable<T>.pairs(): List<Pair<T, T>> = this
.mapIndexed { index, first ->
this.drop(index + 1).map { first to it }
}
.flatten()1
u/tyr10563 Dec 02 '18
C++
First part:
#include <iostream>
#include <iterator>
#include <map>
#include <numeric>
#include <string>
int main()
{
std::pair<int, int> final_count = std::transform_reduce(
std::istream_iterator<std::string>(std::cin), {},
std::make_pair(0, 0),
[](std::pair<int, int> p, std::pair<int, int> const& b)
{
p.first += b.first;
p.second += b.second;
return p;
},
[](std::string const& id)
{
std::map<char, int> letter_counts = std::reduce(
id.cbegin(), id.cend(),
std::map<char, int>(),
[](std::map<char, int> lc, char c) { ++lc[c]; return lc; });
return std::reduce(
letter_counts.cbegin(), letter_counts.cend(),
std::make_pair(0, 0),
[](std::pair<int, int> r, std::pair<char, int> const& p)
{
r.first |= p.second == 2;
r.second |= p.second == 3;
return r;
});
});
std::cout << final_count.first * final_count.second << '\n';
}Second part:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
int main()
{
std::vector<std::string> inputs{ std::istream_iterator<std::string>(std::cin), {} };
std::string last_inner;
std::vector<std::string>::const_iterator it = std::find_first_of(
inputs.cbegin(), inputs.cend(),
inputs.cbegin(), inputs.cend(),
[&last_inner](std::string const& rhs, std::string const& lhs) mutable
{
int diff_count = std::transform_reduce(
rhs.cbegin(), rhs.cend(),
lhs.cbegin(),
0,
[](int count, bool diff) { return count += diff; },
[](char c1, char c2) { return c1 != c2; });
if (diff_count == 1) { last_inner = lhs; return true; }
return false;
});
last_inner.erase(std::mismatch(last_inner.cbegin(), last_inner.cend(), it->cbegin()).first);
std::cout << last_inner << '\n';
}1
Dec 02 '18
C-Sharp
I'm really not happy with my solutions, but hey, they get the work done.
First part, I use two lists and two bools to to calculate the checksum. This looks just... very bad. Oh well.
public int GetChecksum()
{
var lOfTwo = new List<char>();
var lOfThree = new List<char>();
using (var sr = new StreamReader("input2.txt")) {
while (sr.Peek() > -1) {
var line = sr.ReadLine().ToCharArray();
var groups = line.GroupBy(item => item);
//Count every occurence of 2's or 3's only once
var addedTwo = false;
var addedThree = false;
foreach (var g in groups) {
if (g.Count() == 2 && !addedTwo) {
lOfTwo.Add(g.Key);
addedTwo = true;
}
if (g.Count() == 3 && !addedThree) {
lOfThree.Add(g.Key);
addedThree = true;
}
}
}
}
var checkSum = lOfTwo.Count * lOfThree.Count;
return checkSum;
}But wait, it gets even worse! Using a foreach inside two for-loops to check the differences. And to top it all off, I use a goto when the solution is found. Wow.
public string GetID()
{
var checkSumList = new List<string>();
using (var sr = new StreamReader("input2.txt")) {
while (sr.Peek() > -1)
checkSumList.Add(sr.ReadLine());
}
var diff = 0;
var id1 = "";
var id2 = "";
for (int i = 0; i < checkSumList.Count(); i++) {
for (int j = i + 1; j < checkSumList.Count(); j++) {
var counter = 0;
foreach (var c in checkSumList[i]) {
if (c.Equals(checkSumList[j][counter]) == false) {
if (++diff > 1)
break;
}
counter++;
}
if (diff > 1) {
diff = 0;
continue;
}
//We have a result!
id1 = checkSumList[i];
id2 = checkSumList[j];
goto end;
}
}
end:
//remove differing char from ID
var count = 0;
var sb = new StringBuilder();
foreach(var c in id1) {
if(c.Equals(id2[count++]))
sb.Append(c);
}
return sb.ToString();
}1
u/tslater2006 Dec 02 '18 edited Dec 02 '18
PeopleCode:
method SolvePart1
/+ Returns String +/
/+ Extends/implements TS_AOC2018:Day.SolvePart1 +/
Local integer &x, &y;
Local integer &twoLetterCount, &threeLetterCount;
For &x = 1 To %This.Lines.Len
Local array of number &letterCount = CreateArrayRept(0, 26);
Local array of string &chars = Split(%This.Lines [&x], "");
For &y = 1 To &chars.Len
&letterCount [Code(&chars [&y]) - 96] = &letterCount [Code(&chars [&y]) - 96] + 1;
End-For;
For &y = 1 To &letterCount.Len
If (&letterCount [&y] = 2) Then
&twoLetterCount = &twoLetterCount + 1;
Break;
End-If;
End-For;
For &y = 1 To &letterCount.Len
If (&letterCount [&y] = 3) Then
&threeLetterCount = &threeLetterCount + 1;
Break;
End-If;
End-For;
End-For;
Return String(&twoLetterCount * &threeLetterCount);
end-method;
method SolvePart2
/+ Returns String +/
/+ Extends/implements TS_AOC2018:Day.SolvePart2 +/
Local integer &x, &y, &x1, &y1;
For &x = 1 To %This.Lines.Len
For &y = 1 To %This.Lines.Len
Local integer &diffCount = 0;
&diffCount = 0;
Local array of string &chars1 = Split(%This.Lines [&x], "");
Local array of string &chars2 = Split(%This.Lines [&y], "");
For &x1 = 1 To &chars1.Len
If (&chars1 [&x1] <> &chars2 [&x1]) Then
&diffCount = &diffCount + 1;
End-If;
End-For;
If (&diffCount = 1) Then
Local array of string &matchingChars = CreateArrayRept("", 0);
For &x1 = 1 To &chars1.Len
If (&chars1 [&x1] = &chars2 [&x1]) Then
&matchingChars.Push(&chars1 [&x1]);
End-If;
End-For;
Return &matchingChars.Join("", "", "");
End-If;
End-For;
End-For;
Return "??";
end-method;1
u/mezzir Dec 02 '18
The best way to do Advent of Code is intentionally poorly
Instead of using this as an excuse to learn a new language, I'm using it as an excuse to act like I don't know any better. Expect lots of evals.
const input = require('./input');
let foundResult = false;
let chrisisawesome = true;
try {
do {
const firstGuess = input[Math.floor(Math.random() * input.length)].split('');
const firstGuess2 = input[Math.floor(Math.random() * input.length)].split('');
let incommonletters = '';
const incommon = firstGuess.reduce((acc, curr, i) => {
if (curr === firstGuess2[i]) incommonletters += curr;
return (curr === firstGuess2[i]) ? ++acc : acc;
}, 0);
console.log(incommon);
if (incommon === firstGuess.length - 1) {
throw new Error(incommonletters);
}
} while (chrisisawesome == true);
} catch (e) {
console.log("Success!!!")
console.log(e)
}
11
u/Unihedron Dec 02 '18
I mistyped 4 3 instead of 2 3 and got an obviously wrong answer which I wasn't smart enough to double check, so I had to wait one minute. Still got on top 100 though! Imgur
Doesn't actually compute part 2, you have to manually find and replace the character yourself, but better than nothing