🦌 Advent Of Code 2020
The goals are:
Learn Julia
Write readable code (avoid golfing)
Write efficient code if possible
See Advent Of Code 2020 for more information.
Day 1
156
413
444
508
684
847
900
961
1068
1083
1094
1105
1123
1130
1137
1140
1146
1154
1157
1165
1986
1990
1991
1994
1995
1999
2000
2001
2005
2007
day1_part1 (generic function with 1 method)xxxxxxxxxxfunction day1_part1(input) for n ∈ input r = searchsorted(input_day1, 2020 - n) if r.start ≤ r.stop return n * input[r.start] end endendday1_part2 (generic function with 1 method)xxxxxxxxxxfunction day1_part2(input) l = length(input) for i ∈ 1:l for j ∈ i+1:l v = 2020 - input[i] - input[j] if v ≤ 0 break end r = searchsorted(input_day1, v) if r.start ≤ r.stop return input[i] * input[j] * input[r.start] end end endendResult for part 1: 913824
Result for part 2: 240889536
Day 2
xxxxxxxxxxstruct Password policy_range :: UnitRange policy_char :: Char p :: Stringend nb_of_valid_passwords_part2 (generic function with 1 method)xxxxxxxxxxnb_of_valid_passwords_part2(passwords) = count( password -> (password.p[password.policy_range.start] == password.policy_char) ⊻ (password.p[password.policy_range.stop] == password.policy_char), passwords )parse_day2 (generic function with 1 method)xxxxxxxxxxfunction parse_day2(lines) line_regexp = r"^(\d+)-(\d+) ([a-z]): ([a-z]+)$" function parse_line(line) m = match(line_regexp, line) Password( UnitRange(parse(Int, m.captures[1]), parse(Int, m.captures[2])), m.captures[3][1], m.captures[4] ) end parse_line.(lines)endnb_of_valid_passwords_part1 (generic function with 1 method)xxxxxxxxxxnb_of_valid_passwords_part1(passwords) = count( password -> count(==(password.policy_char), password.p) ∈ password.policy_range, passwords )Test 1, part 1: true
Test 1, part 2: true
1:13
'r'
"gqdrspndrpsrjfjx"
5:16
'j'
"jjjjkjjzjjjjjfjzjjj"
14:16
'r'
"rrrnrrrrrcnrgxrr"
1:3
'k'
"bkktwhgktv"
3:5
'q'
"dxqqqzmqvs"
11:14
's'
"sssssssssssssv"
1:3
'd'
"cdzdq"
13:16
'q'
"scdqpdgpkvbwwqbv"
9:10
'd'
"ddrdddlddd"
15:17
'v'
"jvvvvvvgcvvvvrcvnv"
2:3
's'
"xssx"
8:15
'j'
"jwjjjjkhjjjltjmjjjr"
7:15
'm'
"wqspfmtpjftmplwp"
1:11
's'
"swdgzhgsxtssndzfm"
3:4
'b'
"bgjrg"
1:12
'x'
"jxgxxxpjwpsht"
5:15
'x'
"xxjxwshpxjxxxxsnxvz"
4:11
'r'
"bjnrpswfprrng"
12:14
'j'
"wjjzmwnmmvzsjhnnkj"
3:4
'd'
"dddv"
14:15
'z'
"nlzzzzzzzzzdzzzzzz"
8:12
'r'
"zrrrrprrxrrrrkrhk"
1:2
'z'
"qlfzd"
1:6
'j'
"kqjpjzpsgjjqz"
1:5
's'
"qfssks"
2:5
'r'
"nrrzrr"
4:6
'g'
"kggggg"
6:7
'c'
"cccccdqcc"
2:6
'x'
"vjkxbrfwnj"
16:18
's'
"kssssssswssssssssssb"
Result for part 1: 600
Result for part 2: 245
Day 3
parse_day3 (generic function with 1 method)xxxxxxxxxxfunction parse_day3(lines) map(==("#"), hcat(split.(lines, "")...))'endnb_trees_encountered (generic function with 2 methods)xxxxxxxxxxfunction nb_trees_encountered(area :: AbstractArray{Bool, 2}, moves = [(1, 3)]) m, n = size(area) map(moves) do (di, dj) foldl(1:di:m, init = (1, 0)) do (j, sum), i mod1(j + dj, n), sum + area[i, j] end[2] endendnb_trees_encountered_part2 (generic function with 1 method)xxxxxxxxxxnb_trees_encountered_part2(area) = nb_trees_encountered(area, [(1, 1), (1, 3), (1, 5), (1, 7), (2, 1)])Test 1, part 1: true
Test 1, part 2: true
323×31 LinearAlgebra.Adjoint{Bool,Array{Bool,2}}:
0 0 1 0 0 0 0 0 0 1 1 1 0 0 … 0 0 1 1 0 0 1 0 1 0 0 0 0
0 1 0 1 0 0 0 0 0 1 0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 1 1
0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0
0 0 0 1 0 0 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 1 1
0 0 0 0 0 0 1 0 1 0 1 1 0 0 … 0 1 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 1 1 0 0 0 0 0 0 1 0
⋮ ⋮ ⋮ ⋱ ⋮ ⋮ ⋮
0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1
0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 1 0 1 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 1 1 … 0 0 0 0 0 0 0 0 0 1 0 0 1
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0
0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0Result for part 1: 262
Result for part 2: 2698900776
Day 4
parse_day4 (generic function with 1 method)xxxxxxxxxxfunction parse_day4(lines) passports = [Dict{String, String}()] for line ∈ lines if line == "" push!(passports, Dict()) else for value in split(line, ' ') key_value = split(value, ':') last(passports)[key_value[1]] = key_value[2] end end end passportsendcount_nb_valid_passport (generic function with 2 methods)xxxxxxxxxxfunction count_nb_valid_passport(passports :: AbstractArray{Dict{String,String}}, check_fields_integrity = false) required_fields = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"] function check_field(field, value) try field == "byr" && 1920 ≤ parse(Int, value) ≤ 2020 || field == "iyr" && 2010 ≤ parse(Int, value) ≤ 2020 || field == "eyr" && 2020 ≤ parse(Int, value) ≤ 2030 || field == "hgt" && ((inches = match(r"(\d+)in", value)) ≠ nothing && 59 ≤ parse(Int, inches.captures[1]) ≤ 76 || (cm = match(r"(\d+)cm", value)) ≠ nothing && 150 ≤ parse(Int, cm.captures[1]) ≤ 193) || field == "hcl" && occursin(r"^#[0-9a-f]{6}$", value) || field == "ecl" && value ∈ ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"] || field == "pid" && occursin(r"^[0-9]{9}$", value) catch false end end count(passports) do p all(required_fields) do f haskey(p, f) && (!check_fields_integrity || check_field(f, p[f])) end endendTest 1, part 1: true
Test 1, part 2: true
Test 2, part 2: true
"hcl"
"#6c4ab1"
"ecl"
"oth"
"cid"
"189"
"hgt"
"174cm"
"iyr"
"2015"
"eyr"
"2026"
"pid"
"526744288"
"byr"
"1947"
"hcl"
"#808e9e"
"ecl"
"grn"
"pid"
"688706448"
"hgt"
"162cm"
"iyr"
"2017"
"cid"
"174"
"eyr"
"2025"
"byr"
"1943"
"hcl"
"#733820"
"ecl"
"oth"
"cid"
"124"
"pid"
"111220591"
"iyr"
"2019"
"eyr"
"2001"
"hgt"
"159in"
"byr"
"1933"
"hcl"
"#fffffd"
"ecl"
"oth"
"pid"
"812929897"
"hgt"
"159cm"
"iyr"
"2026"
"cid"
"291"
"eyr"
"2024"
"byr"
"1942"
"hcl"
"#ceb3a1"
"ecl"
"amb"
"cid"
"83"
"pid"
"524032739"
"iyr"
"2013"
"hgt"
"191cm"
"eyr"
"2028"
"byr"
"1974"
"hcl"
"eefed5"
"ecl"
"gry"
"pid"
"88405792"
"hgt"
"183cm"
"cid"
"221"
"eyr"
"2029"
"byr"
"1963"
"hcl"
"#18171d"
"ecl"
"grn"
"pid"
"777881168"
"hgt"
"181cm"
"iyr"
"2018"
"eyr"
"2021"
"byr"
"1923"
"hcl"
"#a5e1b5"
"ecl"
"gry"
"pid"
"062495008"
"hgt"
"178cm"
"iyr"
"2016"
"eyr"
"2027"
"byr"
"1941"
"hcl"
"#efcc98"
"cid"
"56"
"pid"
"649868696"
"iyr"
"2011"
"eyr"
"2025"
"hgt"
"164cm"
"byr"
"1971"
"hcl"
"#888785"
"ecl"
"blu"
"pid"
"117915262"
"hgt"
"188cm"
"iyr"
"2020"
"eyr"
"2023"
"byr"
"1925"
"ecl"
"brn"
"cid"
"174"
"pid"
"143293382"
"iyr"
"2012"
"eyr"
"2024"
"hgt"
"193cm"
"byr"
"1946"
"hcl"
"#602927"
"ecl"
"blu"
"hgt"
"192cm"
"pid"
"251564680"
"iyr"
"2011"
"eyr"
"2021"
"byr"
"1976"
"hcl"
"#b6652a"
"ecl"
"blu"
"hgt"
"164cm"
"pid"
"695538656"
"iyr"
"2010"
"eyr"
"2022"
"cid"
"244"
"byr"
"1973"
"hcl"
"#ceb3a1"
"ecl"
"hzl"
"pid"
"358398181"
"hgt"
"74in"
"iyr"
"2014"
"eyr"
"2027"
"cid"
"329"
"byr"
"1949"
"hcl"
"#623a2f"
"ecl"
"blu"
"cid"
"211"
"hgt"
"172cm"
"iyr"
"2019"
"eyr"
"2023"
"pid"
"657051725"
"byr"
"1954"
"hcl"
"#602927"
"ecl"
"amb"
"pid"
"562699115"
"hgt"
"162cm"
"iyr"
"2018"
"eyr"
"2026"
"byr"
"2000"
"hcl"
"#b6652a"
"ecl"
"brn"
"pid"
"835184859"
"hgt"
"157cm"
"iyr"
"2013"
"eyr"
"2027"
"byr"
"1981"
"hcl"
"#cfa07d"
"ecl"
"brn"
"pid"
"763432667"
"hgt"
"63in"
"iyr"
"2010"
"cid"
"107"
"eyr"
"2027"
"byr"
"1981"
"hcl"
"f55bf8"
"ecl"
"amb"
"hgt"
"177cm"
"cid"
"314"
"pid"
"632519974"
"eyr"
"2025"
"iyr"
"2015"
"byr"
"2009"
"hcl"
"#602927"
"ecl"
"hzl"
"pid"
"614239656"
"hgt"
"169cm"
"iyr"
"2014"
"eyr"
"2024"
"byr"
"1992"
"ecl"
"oth"
"pid"
"136852264"
"cid"
"339"
"iyr"
"2011"
"eyr"
"2024"
"byr"
"1949"
"hcl"
"#6b5442"
"ecl"
"brn"
"pid"
"772739059"
"hgt"
"157cm"
"iyr"
"2020"
"eyr"
"2025"
"byr"
"1945"
"hcl"
"#18171d"
"ecl"
"grn"
"pid"
"053763751"
"iyr"
"2018"
"eyr"
"2022"
"byr"
"1933"
"hcl"
"#18171d"
"ecl"
"oth"
"pid"
"214212776"
"cid"
"122"
"iyr"
"2020"
"eyr"
"2030"
"hgt"
"170cm"
"byr"
"1988"
"ecl"
"brn"
"pid"
"883116919"
"hgt"
"187cm"
"iyr"
"2018"
"eyr"
"2020"
"byr"
"1938"
"hcl"
"#a97842"
"ecl"
"grn"
"cid"
"329"
"pid"
"636649774"
"iyr"
"2020"
"eyr"
"2025"
"hgt"
"158cm"
"byr"
"1946"
"hcl"
"#341e13"
"ecl"
"blu"
"hgt"
"161cm"
"pid"
"461889565"
"iyr"
"2020"
"eyr"
"2023"
"cid"
"97"
"byr"
"1951"
"hcl"
"#cfa07d"
"ecl"
"hzl"
"hgt"
"168cm"
"pid"
"492241189"
"iyr"
"2013"
"eyr"
"2029"
"cid"
"150"
"byr"
"1980"
"hcl"
"#733820"
"ecl"
"gry"
"hgt"
"150cm"
"pid"
"401735295"
"cid"
"153"
"eyr"
"2024"
"iyr"
"2016"
"byr"
"1998"
"hcl"
"#a97842"
"ecl"
"hzl"
"hgt"
"184cm"
"pid"
"453480077"
"iyr"
"2018"
"eyr"
"2025"
"byr"
"2001"
Result for part 1: 264
Result for part 2: 224
Day 5
parse_day5 (generic function with 1 method)xxxxxxxxxxfunction parse_day5(lines) map(lines) do line row = parse(Int, join(replace(split(line[1:7], ""), "F" => "0", "B" => "1")); base = 2) col = parse(Int, join(replace(split(line[8:10], ""), "L" => "0", "R" => "1")); base = 2) row * 8 + col endendTest 1, part 1: true
find_missing_id (generic function with 1 method)xxxxxxxxxxfunction find_missing_id(ids) sorted_ids = sort(ids) for i ∈ 1:length(sorted_ids)-1 if sorted_ids[i] + 1 ≠ sorted_ids[i + 1] return sorted_ids[i] + 1 end endend594
699
683
645
823
452
160
836
459
38
684
152
613
387
335
159
454
246
632
729
220
468
734
644
571
251
797
630
810
638
Result for part 1: 850
Result for part 2: 599
Day 6
parse_day6 (generic function with 1 method)xxxxxxxxxxfunction parse_day6(lines) :: Array{Array{Set{Char}}} groups = [[]] for line ∈ lines if line == "" push!(groups, []) else push!(last(groups), Set(line)) end end groupsendsum_of_group_lengths (generic function with 1 method)xxxxxxxxxxfunction sum_of_group_lengths(groups, f) map(groups) do group length(reduce(f, group)) end |> sum endTest 1, part 1: true
Test 1, part 2: true
Number of groups read from data/day06.txt: 490
Result for part 1: 6735
Result for part 2: 3221
Day 7
xxxxxxxxxxstruct Bags matrix :: Array{Int, 2} names :: Dict{String, Int}endparse_day7 (generic function with 1 method)xxxxxxxxxxfunction parse_day7(lines) l = length(lines) m = zeros(Int, l, l) name_indices = Dict{String, Int}() get_bag_index(name) = get!(name_indices, name, length(name_indices) + 1) for i ∈ 1:l line = lines[i] bag = match(r"^\w+ \w+", line).match bag_index = get_bag_index(bag) for inner_bag ∈ eachmatch(r"(\d+) (\w+ \w+) bag", line) n = parse(Int, inner_bag[1]) m[bag_index, get_bag_index(inner_bag[2])] = n end end Bags(m, name_indices)endbags_that_contain (generic function with 1 method)xxxxxxxxxxfunction bags_that_contain(name, bags) visited = falses(length(bags.names)) to_visit = [bags.names[name]] while !isempty(to_visit) current = pop!(to_visit) visited[current] = true containing = findall(≠(0), bags.matrix[:, current] .* .!visited) append!(to_visit, containing) end findall(visited)endnb_bags_contained (generic function with 1 method)xxxxxxxxxxfunction nb_bags_contained(name, bags) function nb_bags_contained(bag_index) content = bags.matrix[bag_index, :] indexes = findall(≠(0), content) 1 + (isempty(indexes) ? 0 : sum(nb_bags_contained.(indexes) .* filter(≠(0), content))) end nb_bags_contained(bags.names[name]) - 1endTest 1, part 1: true
Test 1, part 2: true
Test 2, part 2: true
594×594 Array{Int64,2}:
0 3 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 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
0 0 0 1 1 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 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 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 0 0 0 0 1 5 2 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 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 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 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 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 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 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 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"posh teal"
213
"clear teal"
277
"faded tomato"
118
"dull indigo"
193
"drab indigo"
17
"mirrored chartreuse"
385
"shiny lime"
66
"dark brown"
429
"dotted fuchsia"
264
"shiny green"
519
"mirrored violet"
157
"posh gray"
529
"bright brown"
493
"drab cyan"
462
"posh brown"
557
"dim aqua"
259
"vibrant violet"
88
"light lime"
325
"shiny silver"
408
"vibrant silver"
518
"muted olive"
523
"dotted bronze"
498
"wavy aqua"
285
"vibrant bronze"
108
"wavy beige"
536
"mirrored olive"
332
"faded crimson"
503
"dull blue"
391
"faded magenta"
588
"posh coral"
172
Result for part 1: 335
Result for part 2: 2431
Day 8
xxxxxxxxxxstruct Instruction operator :: Symbol argument :: Intendparse_day8 (generic function with 1 method)xxxxxxxxxxfunction parse_day8(lines) map(lines) do line splitted = split(line, ' ') Instruction(Symbol(splitted[1]), parse(Int, splitted[2])) endendexecute (generic function with 1 method)xxxxxxxxxx# The returned boolean is true if the execution has finished correctly or false if there is a infinite loop.# The returned integer is the accumulator when the inifinite loop is detected or when the execution has finished correctly.function execute(instructions) :: Tuple{Bool, Int} pos = 1 accumulator = 0 n = length(instructions) visited_positions = falses(n) while pos ≤ n && !visited_positions[pos] visited_positions[pos] = true ins = instructions[pos] if ins.operator == :acc accumulator += ins.argument pos += 1 elseif ins.operator == :jmp pos += ins.argument else # :nop. pos += 1 end end pos > n, accumulatorendfix_to_not_loop (generic function with 1 method)xxxxxxxxxxfunction fix_to_not_loop(instructions) copy = deepcopy(instructions) # To avoid modifying the input. function switch(pos) if copy[pos].operator == :jmp copy[pos] = Instruction(:nop, copy[pos].argument) true elseif copy[pos].operator == :nop copy[pos] = Instruction(:jmp, copy[pos].argument) true else false end end for i ∈ 1:length(copy) if switch(i) finished, accumulator = execute(copy) if finished return accumulator end switch(i) end endendTest 1, part 1: true
Test 1, part 2: true
:acc
-8
:jmp
5
:acc
0
:acc
44
:acc
42
:jmp
324
:acc
-17
:jmp
1
:acc
-17
:jmp
51
:acc
-13
:acc
4
:jmp
1
:nop
608
:jmp
274
:acc
-17
:jmp
169
:acc
28
:nop
508
:jmp
1
:jmp
-112
:jmp
-613
:acc
26
:nop
-151
:jmp
-471
:acc
50
:acc
16
:nop
-119
:acc
46
:jmp
1
Result for part 1: (false, 1928)
Result for part 2: 1319
Day [9]
parse_day9 (generic function with 1 method)xxxxxxxxxxfunction parse_day9(lines) parse.(Int64, lines)endfirst_number_without_valid_pair (generic function with 1 method)xxxxxxxxxxfunction first_number_without_valid_pair(numbers, preamble_size) for i ∈ preamble_size+1:length(numbers) previous = numbers[i-preamble_size:i-1] n = numbers[i] if n ∉ [a + b for a ∈ previous for b ∈ previous if a ≠ b] return n end endendfind_encryption_weakness (generic function with 1 method)xxxxxxxxxxfunction find_encryption_weakness(numbers, target) l = length(numbers) for i ∈ 1:l for j ∈ i+1:l ξ = numbers[i:j] s = sum(ξ) if s == target return maximum(ξ) + minimum(ξ) elseif s > target break end end endendTest 1, part 1: true
Test 1, part 2: true
10
21
30
41
7
31
43
13
18
16
8
27
48
49
19
46
50
37
9
26
81140653782337
134921301295717
81753820513729
89128049157277
110682581369284
86295433501493
100234164113687
115503232106027
108042699036276
182767846428000
Result for part 1: 31161678
Result for part 2: 5453868