Skip to content

Instantly share code, notes, and snippets.

@alvises
Last active December 7, 2022 21:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alvises/c5e8fb5767dfe5568ea3a4073e9370b4 to your computer and use it in GitHub Desktop.
Save alvises/c5e8fb5767dfe5568ea3a4073e9370b4 to your computer and use it in GitHub Desktop.
AoC 2022 in Elixir
# AoC 2022 in Elixir
defmodule Game do
defstruct [:tot_score, :rounds]
# {me, opponent}
@winning [
{:rock, :scissors},
{:scissors, :paper},
{:paper, :rock}
]
def play(%{rounds: []}=game), do: game
def play(%{rounds: [round | remaining_rounds]=_rounds}=game) do
play(%{game | tot_score: game.tot_score + score(round), rounds: remaining_rounds})
end
# WIN
def score({me, opponent}) when {me, opponent} in @winning do
hand_score(me) + 6
end
# DRAW
def score({me, opponent}) when me == opponent do
hand_score(me) + 3
end
# LOSE
def score({me, _opponent}), do: hand_score(me)
def hand_score(:rock), do: 1
def hand_score(:paper), do: 2
def hand_score(:scissors), do: 3
defp map_symbol(s) when s in ["A", "X"], do: :rock
defp map_symbol(s) when s in ["B", "Y"], do: :paper
defp map_symbol(s) when s in ["C", "Z"], do: :scissors
def new(input) do
%__MODULE__{tot_score: 0, rounds: rounds_from_input(input)}
end
defp rounds_from_input(input) do
input
|> String.split("\n")
|> Enum.map(&String.trim/1)
|> Enum.map(&String.split/1)
|> Enum.filter(&not match?([], &1))
|> Enum.map(fn [opponent, me] -> {map_symbol(me), map_symbol(opponent)} end)
end
end
"/Users/alvise/code/aoc2022/input2.txt"
|> File.read!()
|> Game.new()
|> Game.play()
defmodule Item do
defstruct [:letter, :priority]
@type t :: %__MODULE__{
letter: String.t,
priority: integer
}
def new(letter) do
%__MODULE__{letter: letter, priority: priority_from_letter(letter)}
end
defp priority_from_letter(letter) do
letter
|> String.to_charlist()
|> List.first()
|> priority_from_ascii()
end
defp priority_from_ascii(ascii_code) when ascii_code in ?a..?z,
do: ascii_code - ?a + 1
defp priority_from_ascii(ascii_code) when ascii_code in ?A..?Z,
do: ascii_code - ?A + 27
end
defmodule Rucksack do
defstruct [:count, :comp1, :comp2]
@type t :: %__MODULE__{
count: integer,
comp1: [Item.t],
comp2: [Item.t]
}
@spec parse(String.t ) :: Rucksack.t
def parse(line) when is_binary(line) do
items =
line
|> String.trim()
|> String.graphemes()
count = Enum.count(items)
[first_compartment, second_compartment] = Enum.chunk_every(items,trunc(count/2))
%__MODULE__{
count: count,
comp1: Enum.map(first_compartment, &Item.new/1),
comp2: Enum.map(second_compartment, &Item.new/1)
}
end
def items_in_both_compartments(rucksack) do
MapSet.intersection(
MapSet.new(rucksack.comp1),
MapSet.new(rucksack.comp2)
)
|> MapSet.to_list()
end
end
defmodule Day3 do
def part1(input) do
input
|> String.split("\n")
|> Enum.map(&String.trim/1)
|> Enum.filter(& String.length(&1) > 0)
|> Stream.map(&Rucksack.parse/1)
|> Stream.flat_map(&Rucksack.items_in_both_compartments/1)
|> Stream.map(& &1.priority)
|> Enum.sum()
end
end
"input3.txt"
|> File.read!()
|> Day3.part1()
# PART 1
defmodule Cargo do
def parse(input) do
[stacks_input, moves_input] = String.split(input, "\n\n", trim: true)
%{
stacks: parse_stacks(stacks_input),
moves: parse_moves(moves_input)
}
end
defp parse_stacks(stacks_input) do
stacks_input
|> String.split("\n", trim: true)
|> Enum.map(&String.graphemes/1)
|> Enum.zip_with(& &1)
|> Enum.map(&Enum.reverse/1)
|> Enum.filter(&(not match?([" " | _rest], &1)))
|> Enum.map(fn [n | stack] ->
stack =
stack
|> Enum.filter(&(&1 != " "))
|> Enum.reverse()
{n, stack}
end)
|> Enum.into(%{})
end
defp parse_moves(moves_input) do
moves_input
|> String.split("\n", trim: true)
|> Enum.map(&scan_move/1)
end
@action_regex ~r/\w+\s+(\d+)\s+\w+\s+(\d+)\s+\w+\s+(\d+)/
@spec scan_move(String.t()) :: map
defp scan_move(line) do
[[_, count, from, to]] = Regex.scan(@action_regex, line)
%{count: String.to_integer(count), from: from, to: to}
end
def part1(cargo) do
cargo
|> move_crates()
|> top_crates()
|> Enum.join()
end
def top_crates(stacks) do
stacks
|> Enum.sort_by(&elem(&1, 0), :asc)
|> Enum.map(&(elem(&1, 1) |> hd()))
end
def move_crates(%{stacks: stacks, moves: moves} = _cargo, move_func) do
for move <- moves, _n <- 1..move.count, reduce: stacks do
acc -> move_func.(acc, move)
end
end
def move_crate_part1(stacks, move) do
{crate, updated_stacks} = Map.get_and_update!(stacks, move.from, &List.pop_at(&1, 0))
Map.update!(updated_stacks, move.to, &[crate | &1])
end
def move_crate_part2(stacks, move) do
{crates, updated_stacks} = Map.get_and_update!(stacks, move.from, &pop_by(&1, move.count))
Map.update!(updated_stacks, to, &[crate | &1])
end
defp pop_by(stack, amount) do
Enum.reduce(1..amount, {[], stack}, fn
_n, {acc, [crate | rest_of_stack]} ->
{acc ++ [crate],rest_of_stack}
end)
end
end
"""
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2
"""
|> Cargo.parse()
|> Cargo.part1()
defmodule Cargo do
def parse(input) do
[stacks_input, moves_input] = String.split(input, "\n\n", trim: true)
%{
stacks: parse_stacks(stacks_input),
moves: parse_moves(moves_input)
}
end
defp parse_stacks(stacks_input) do
stacks_input
|> String.split("\n", trim: true)
|> Enum.map(&String.graphemes/1)
|> Enum.zip_with(& &1)
|> Enum.map(&Enum.reverse/1)
|> Enum.filter(&(not match?([" " | _rest], &1)))
|> Enum.map(fn [n | stack] ->
stack =
stack
|> Enum.filter(&(&1 != " "))
|> Enum.reverse()
{n, stack}
end)
|> Enum.into(%{})
end
defp parse_moves(moves_input) do
moves_input
|> String.split("\n", trim: true)
|> Enum.map(&scan_move/1)
end
@action_regex ~r/\w+\s+(\d+)\s+\w+\s+(\d+)\s+\w+\s+(\d+)/
@spec scan_move(String.t()) :: map
defp scan_move(line) do
[[_, count, from, to]] = Regex.scan(@action_regex, line)
%{count: String.to_integer(count), from: from, to: to}
end
def part2(cargo) do
cargo
|> move_crates()
|> top_crates()
|> Enum.join()
end
def top_crates(stacks) do
stacks
|> Enum.sort_by(&elem(&1, 0), :asc)
|> Enum.map(&(elem(&1, 1) |> hd()))
end
def move_crates(%{stacks: stacks, moves: moves} = _cargo) do
for move <- moves, reduce: stacks do
acc ->
{crates, updated_stacks} = Map.get_and_update!(acc, move.from, &pop_by(&1, move.count))
Map.update!(updated_stacks, move.to, & crates ++ &1)
end
end
defp pop_by(stack, amount) do
Enum.reduce(1..amount, {[], stack}, fn
_n, {acc, [crate | rest_of_stack]} ->
{acc ++ [crate],rest_of_stack}
end)
end
end
"""
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2
"""
|> Cargo.parse()
|> Cargo.part2()
input = "tnmmpfmfzmmnsmsjmjjbvvhnhzzfmmgpmgpgbgnnwffjhffzqqmzzbnbssrqqrnnhsnngsszsqzszhzfhzfzwzfzrrmhmghgwhhjjqwqttwhttjllrtrtzzcfzfgzznfznfzfnnbddvmvzmmfsmfsmfffhlfldlqqrnrznnhmmgqqzhhmjhmhppqbpbbngnlldvvdqvvrtrdrtrnttnppfllrbbrprpnpdplpmllhwwddqpdprddzzfccqpcqpcpcbbdhdjdjwjcwcctdcttzgzmmscmsmdmttwhwzhhnjhnhlhvhlvlglpgpmmjmgmrgrddmwddjfftfwflfslffqtfqttpftppflfmmhvhvcvbvhbhggpbgbppvdpvpvfppbwwsnnhphllbdbnbvbmvvzffvsffdldmlmtmccnlnbnjbnjnhhbfhhgzzlwlfflzffdccggdcgcjjhffjfgfgcczjccvwcvvqgvvqvllqzqmqllhjjqnqggttsdddjgdjgjzzrgrfrbrssrgrgdgrgbbssmdsdfddsndnsdnsdnnmqqsspqqmrqqpmmsjmmszzqvqrvrzznnjdndtntfnttgtctqtwwnwswrrthrttsdttlhlvvdzzgqgttnppjpljplpgpvgvqqvppzmmqggtjgtgstslltjltjjgcjcmjmsshvvtppgmmlslqqshqshsllbggfpgffdsdgssncchctcwwtllgqlqblqlqvvmsvmmwnnzppqllsttgmttftvfvjjrzzswzzjvzjzljjchcshcscbbrdbrbcrrnvvtctntvtvbvjvqjqggsrspsprrbgghdghhmwwldldzdttrvrnrfftqtftrrdsszlzvvbtbffftzzrzqrrhjhghhwbhhsjsfsttdjdjnjhjmjpmplplrrdjdcdjdbjblllbqlqdlqlpqptppdhhqmqfqhqhchwwqjqfjqfqhqshsmswsbbvssdspdpsdssstntltrrgnnmttgmmsjjrlrnlrnrnwrwfwlfltlzllcjcmjcjpjhphcpcwppmvmjjzbzvbbfnfcflfddntddbmmmhnnsrnrrvdvnvcvwvcwvwrrqwqccqmmswmmjrjmmwjmjfjhwrtbjzdvlgrjmvzfmhcqsncvlhzzncjlbvcwrdwjmqjcnptqslvfzpsvltgzsvjdsjrppdrmqrbqwhddfhnftfblspsrhtdtjwdnhbcbtlwlvccsfscvczzrrqmwbwbdmwgzqntvflppqvppwrhnvtlsbzqglhsfdgssqzdtjdpwrrhbnbtwhhnmnlwfwlqffjjrndbpwwsvdrhddbjnnqzmtpvvtwbcpndjzlhcfrrdvmljswjzvmfqcdsgqwclqshwrmblszdvsnrpdgnllmlchzdjlrrpndmmgddjqgjqrhwfbwddqdfbvptrmzhtsqfsfswpnvmtswqprjhbzvntgrlzthhnqbtpplqpvcfnpgdtbhqbhflltbbtmmhcwztslmpznttmssclhmnbsbrwlblrbsdfmnpqbwwmsncvzmpqwhzjgcgdrzvglgdtswmstdhrprdjfmqtjlmplbjtzcgnrwpdvpfjjfwjfnnpmdtwtqsgfndngsbmcwjtglqwtfrclbczfcmjtgcwszhzrbcphrhwmhcwghjznzthnwpljjltdlvqtffsrbmwcsvrdmqqggbznnlzbbqtgspqvnjpbdhtzmgttrcwwszwpgdrcnfqtgrgqdrctlzwtdwqppbhnwgldnqltznnfpbfqtgmmwpcqnndbgmrrtgtvnmlfcwsldchjnnqfrhpzwtclrzftsqllgvpqbgmfjdhqjttwcvbpvfqsvhbhhtwnqnbgndbtzhcvgglbhghbzrbrmdllmgfgttqmhtdnwrpwllhnghrjctrbzrcpnjnctvmrlpjhftnfbczrjrnnbqplplcrbngbhvmmvcffmgvbhjzbhcmtwmwgmjmwjvvlqfldswpntjnsjvmdlbzqqlgbwspwvmnwtwjbczmwplrhmjgsppnmtwmvsfwnsgddgwqcvpftcpzrhpldnwmcjgtjmljjbcmjcqdbwczndnjnjgrmtjrqnnjndzqdqpcgdqptdbrqftnwrgqmrzrvsfmmmbpltlncvtgrjfjmvtgwqphczwjhdrdwtfvgztbhrndvpcbgfjfvmrrljwrvcrtdmtjndfnwgcnfrzgsnjpztbwwsbvqfnpjctgrhsflhnzbbsfqbnmtnvrmjzsbjfndvttpvpfjhqntflgbfnzcclcwmhbsgqfjdcgsvrhtstspfzgvgglgddqmclsmzgzgtncdsfmwdvtcsgwvbzjvclwppqdjgfcrcbzcwbdhrnssjbmnmfmwthdrnmlfhqlddwqrdhsdvdcsmcgjsgcmpnhlbnqftpdjswtmpbznlcrhtswgnmwjcdfmljdngzfsmlzjjnzmfzshmztdbdmcqwmlvcrzgpmbjqcghclwvdbrhgvwqchnndftnrtptmctdlhmfjvpzrpccddfpcdwmzqfhnsqzrvwblzfhcjdcjfctczwqrcbjnrpdcbbnsgnlvqqmnsfgsqschjlbzhhsrbvdbfrhvsgrlzwncgwpdbvmblgzbwbcbgqfwmdmgcrbbjfcvmqgztqpptdhwmvmsdqwplpgcjzgqzdrftzhqbltvhrmlrfffcgfpqzwrrbbtlsjgmtbjvtnmhwdpjptjwfwgjgvbfqwmflrrqzlzdcmtlnptdrpcpdnswcfscnndnrfbgwvvncdjgsdpbwptdtvrqlmrhmvvcwblhhzbjdpsbszhrftfbcgwhwrgglnjzqdhcqnvlhgqjhnddvrslhntssptsbhmqwwqqnbvfmcbgpvgjbrttnvlljdbtfplgmbwtcbcdtqdpqqdvhbmpmtszwpzblcfrtznhhtcljtdlhjdbnlhvwgjsmgvrslrfwnmzwlstpgltvrgnpdqztvfnvdhdtwwqdfsmtpbpdclsbnwcgjzchjcsjmvhbjshmjjlpgdzcgbmmchwmcsddsvhsnpqtcpnhqnbvwgwqhtjbqncgwwftnrzsbsjtvqmjzqvvncmncwflcfpcjqgdtbsmjzzsdjfvhnqbgjhmfgjghwscthbfmbndltbqzwpqtmrswvprpmgwqnqpfnmffrpdlpfqmhrthppzvzwbrtjvwvjndsqdlqtbpqwfcttggnjmcqqnmjwfhfjgcvlnmtlgbdvmctzlwbfgnflwtsflgnfbnfbhhdgjctzvvmrhdsmvmmtnqwtszmqcpsbrqrgjfrzctcbzmtdlhwjtfdqbtthdnqcrpwrhcrvjstbhpltvgmvpmvfjstgzjsgzprzcqzqztvvdcnrrqwrhddcrhhncdrlwzwqlnbbzcfmqtnwgfdscmrbwnbldlfrqchzdnlnmwncgrzdclnvcvplgwjsbzmbnnsdrsfhrlssvncnwmcrjdjbjpdtrrvlnbjvspfqbwdpcnnpjzfnmbhcdhlmdgbpvbzmfltzstnznfctcdzhbfsvnfbsjqzmwfllhtrsfghlrpjgrgzgchlwrdmqzbrncsvnwhfqmwjbnvjctzphcsftqsbmwntgvjqhhvwndvmfmjhhhmfdvrlhpvzmmhrbhbddqbdmgqqsvddsswmzqcjmvhztfqpchzpwhdshzjlmbmnsgzqhbnmrshwvtmgmgndtddpfwsjrrjdhncdhtlczdvlbvqplttnzrblthlcffdtfsdtpwzdgbldvnsttvpzmbgnqddrszftcpwrgmfzhjjvghpntmzcttcsnrjnfpqzqqqljhzlrpgwngllqjwnwfcsphqplgbzmfqfgbfsqpsrntszqbcqnhctsnbfshmlbwfflrwwsjwqwfqlgnftdwmctmclwjhjhbsspqldlshbmpbgrftpnbpsqldhrrbdqwfwvfhclrlfdjfmzgmptdjdcsplcspznfjrfhtsjndwpslrdgnllllwqjgznrhswfssdlvdpmwwgmstqbhfmdhtzvzzvhwzbrrvvsl"
## PART1
input
|> String.graphemes()
|> Stream.chunk_every(4, 1)
|> Stream.map(&Enum.uniq/1)
|> Stream.with_index(1)
|> Stream.filter(&Enum.count(elem(&1, 0)) == 4)
|> Enum.take(1)
|> List.first()
|> elem(1)
|> Kernel.+(3)
|> IO.inspect(label: "part1")
## PART2
# start of message marker
length = 14
input
|> String.graphemes()
|> Stream.chunk_every(length, 1)
|> Stream.map(&Enum.uniq/1)
|> Stream.with_index(1)
|> Stream.filter(&Enum.count(elem(&1, 0)) == length)
|> Enum.take(1)
|> List.first()
|> elem(1)
|> Kernel.+(length - 1)
|> IO.inspect(label: "part2")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment