The Exercism exercises Pangram and Sets helped me here
Python Solution
INPUT_TYPES = str
def part1(self, parsed_input: InputType) -> int:
"""Find the common element across the first and second half of each line."""
score = 0
for line in parsed_input:
middle = len(line) // 2
a, b = line[:middle], line[middle:]
common = set(a) & set(b)
assert len(common) == 1
score += SCORING.index(common.pop())
return score
def part2(self, parsed_input: InputType) -> int:
"""Find the common element across groups of three lines."""
score = 0
for lines in more_itertools.chunked(parsed_input, 3):
common = set(lines[0]) & set(lines[1]) & set(lines[2])
assert len(common) == 1
score += SCORING.index(common.pop())
return score
I was also wondering if sets were the best approach. It is my longest-running problem so far. You think it would be better to get it done with some string magic?
Solution in Elixir
defmodule AdventOfCode.Day03 do
def part1(args) do
args
|> String.split()
|> Enum.map(&splitInHalf/1)
|> Enum.map(&findDuplicate/1)
|> Enum.map(&convertToPriority/1)
|> Enum.sum()
end
def splitInHalf(str), do: String.split_at(str, div(String.length(str), 2))
def findDuplicate({str1, str2}),
do:
MapSet.intersection(
MapSet.new(String.codepoints(str1)),
MapSet.new(String.codepoints(str2))
)
|> MapSet.to_list()
|> hd()
def findCommon([str1, str2, str3]),
do:
MapSet.intersection(
MapSet.new(String.codepoints(str1)),
MapSet.intersection(
MapSet.new(String.codepoints(str2)),
MapSet.new(String.codepoints(str3))
)
)
|> MapSet.to_list()
|> hd()
def convertToPriority(<<c::utf8, _::binary>>) when c <= ?z and c >= ?a, do: c - ?a + 1
def convertToPriority(<<c::utf8, _::binary>>) when c <= ?Z and c >= ?A, do: c - ?A + 27
def convertToPriority(_), do: :error
def part2(args) do
args
|> String.split()
|> Stream.chunk_every(3)
|> Enum.map(&findCommon/1)
|> Enum.map(&convertToPriority/1)
|> Enum.sum()
end
end
@iHiD Can we have some nice syntax highlighting in Elixir code snippets?
I need to learn to read directions more carefully. I thought part 2 required you to find the sets of 3 instead of just evaluating progressive groups of three.
I am still a relatively newbie, and feedback is welcome.
go Solution
func part1(lines []string) (res int) {
for _, line := range lines {
split := len(line) / 2
res += decodeBinary(encodeBinary(line[:split]) & encodeBinary(line[split:]))
}
return res
}
func part2(lines []string) (res int) {
for i := 0; i < len(lines); i += 3 {
set := ^uint64(0)
for _, line := range lines[i : i+3] {
set &= encodeBinary(line)
}
res += decodeBinary(set)
}
return res
}
func decodeBinary(b uint64) (res int) {
for b >>= 1; b > 0; res++ {
b >>= 1
}
return res
}
func encodeBinary(line string) (res uint64) {
for _, char := range line {
res |= (1 << priority(char))
}
return res
}
func priority(char rune) int {
switch {
case unicode.IsLower(char):
return int(char-'a') + 1
default:
return int(char-'A') + 27
}
}
This went a lot easier than Day 2, and Iโll have some fun cleaning this one up later I think.
Julia Solution
module day03
priorities = Dict(char => v for (char , v) in zip([โaโ:โzโ; โAโ:โZโ], 1:52))
compartments(rucksack) = [rucksack[1:div(end,2)], rucksack[div(end,2)+1:end]]
function part01()
score = 0
for l in eachline("/Users/anagy/Documents/AdventOfCode2022/AdventOfCode2022-Julia/input/03/input.in")
if length(l) != 0
left, right = compartments(l)
uniq = intersect(left, right)[1]
score += priorities[uniq]
end
end
score
end
function part02()
score = 0
groups = eachline("/Users/anagy/Documents/AdventOfCode2022/AdventOfCode2022-Julia/input/03/input.in")
for group in Iterators.partition(groups, 3)
uniq = intersect(group...)[1]
score += priorities[uniq]
end
score
end
end
println(โP01: (day03.part01())")
println("P02: (day03.part02())โ)