|
| 1 | +import gleam/int |
| 2 | +import gleam/io |
| 3 | +import gleam/list |
| 4 | +import gleam/order |
| 5 | +import gleam/string |
| 6 | +import internal/aoc_utils |
| 7 | +import internal/point.{type Point} |
| 8 | + |
| 9 | +pub fn main() { |
| 10 | + let filename = "inputs/day21.txt" |
| 11 | + |
| 12 | + let lines_result = aoc_utils.read_lines(from: filename) |
| 13 | + case lines_result { |
| 14 | + Ok(lines) -> { |
| 15 | + // If the file was converting into a list of lines |
| 16 | + // successfully then run each part of the problem |
| 17 | + aoc_utils.run_part_and_print("Part 1", fn() { solve_p1(lines) }) |
| 18 | + aoc_utils.run_part_and_print("Part 2", fn() { solve_p2(lines) }) |
| 19 | + } |
| 20 | + Error(_) -> io.println("Error reading file") |
| 21 | + } |
| 22 | +} |
| 23 | + |
| 24 | +// +---+---+---+ |
| 25 | +// | 7 | 8 | 9 | |
| 26 | +// +---+---+---+ |
| 27 | +// | 4 | 5 | 6 | |
| 28 | +// +---+---+---+ |
| 29 | +// | 1 | 2 | 3 | |
| 30 | +// +---+---+---+ |
| 31 | +// | 0 | A | |
| 32 | +// +---+---+ |
| 33 | +// |
| 34 | +// ^, >, <, v <- order for keypad |
| 35 | +// |
| 36 | +// +---+---+ |
| 37 | +// | ^ | A | |
| 38 | +// +---+---+---+ |
| 39 | +// | < | v | > | |
| 40 | +// +---+---+---+ |
| 41 | +// |
| 42 | +// v, >, <, ^ <- order for directional keypad |
| 43 | +// |
| 44 | +// ^ -> <A>A |
| 45 | +// < -> v<<A>>^A |
| 46 | +// v -> v<A>^A |
| 47 | +// > -> vA^A |
| 48 | + |
| 49 | +// 379A |
| 50 | +// ^A^^<<A>>AvvvA |
| 51 | +// 12345678 1 123456789 1 12345678 |
| 52 | +// ^ A ^ ^ < < A > >A v vvA |
| 53 | +// < A > A < A A v < A A > >^ A v A A^ A v < A AA> ^ A |
| 54 | +// v<<A>>^AvA^A v<<A>>^A A v<A<A>>^A A vAA<^A>A v<A>^AA<A>Av<A<A>>^AAAvA<^A>A |
| 55 | +// <v<A>>^AvA^A <vA<AA>>^A A vA<^A>A A vA^A <vA>^AA<A>A<v<A>A>^AAAvA<^A>A |
| 56 | +// < A > A v < <A A > ^ A A > A v A A^ A < v A AA> ^ A |
| 57 | +// ^ A < < ^ ^ A > >A v vvA |
| 58 | +// 1234567890 1 1234567 1 1234 |
| 59 | +// ^A<<^^A>>AvvvA |
| 60 | + |
| 61 | +// Part 1 |
| 62 | +pub fn solve_p1(lines: List(String)) -> Result(String, String) { |
| 63 | + list.map(lines, fn(line) { |
| 64 | + decode_numeric_sequence(line) |
| 65 | + |> io.debug |
| 66 | + |> decode_directional_sequence |
| 67 | + |> io.debug |
| 68 | + |> decode_directional_sequence |
| 69 | + |> io.debug |
| 70 | + |> string.length |
| 71 | + |> io.debug |
| 72 | + }) |
| 73 | + |
| 74 | + todo |
| 75 | +} |
| 76 | + |
| 77 | +// Part 2 |
| 78 | +pub fn solve_p2(lines: List(String)) -> Result(String, String) { |
| 79 | + Error("Unimplemented") |
| 80 | +} |
| 81 | + |
| 82 | +fn decode_numeric_sequence(sequence: String) -> String { |
| 83 | + string.to_graphemes("A" <> sequence) |
| 84 | + |> list.window_by_2 |
| 85 | + |> list.map(fn(pair) { find_motion_numeric(pair.0, pair.1) }) |
| 86 | + |> string.join("") |
| 87 | +} |
| 88 | + |
| 89 | +fn decode_directional_sequence(sequence: String) -> String { |
| 90 | + string.to_graphemes("A" <> sequence) |
| 91 | + |> list.window_by_2 |
| 92 | + |> list.map(fn(pair) { find_motion_directional(pair.0, pair.1) }) |
| 93 | + |> string.join("") |
| 94 | +} |
| 95 | + |
| 96 | +fn find_motion_directional(start: String, push: String) -> String { |
| 97 | + let assert Ok(start_pos) = get_directional_position(start) |
| 98 | + let assert Ok(push_pos) = get_directional_position(push) |
| 99 | + |
| 100 | + let right_count = push_pos.0 - start_pos.0 |
| 101 | + let up_count = push_pos.1 - start_pos.1 |
| 102 | + |
| 103 | + let horizontal = case int.compare(start_pos.0, push_pos.0) { |
| 104 | + order.Lt -> string.join(list.repeat(">", right_count), "") |
| 105 | + order.Eq -> "" |
| 106 | + order.Gt -> string.join(list.repeat("<", -right_count), "") |
| 107 | + } |
| 108 | + |
| 109 | + case int.compare(start_pos.1, push_pos.1) { |
| 110 | + order.Lt -> { |
| 111 | + // Go up first then left or right |
| 112 | + horizontal <> string.join(list.repeat("^", up_count), "") <> "A" |
| 113 | + } |
| 114 | + order.Eq -> { |
| 115 | + // Go left or right |
| 116 | + horizontal <> "A" |
| 117 | + } |
| 118 | + order.Gt -> { |
| 119 | + // Go left or right first, then down |
| 120 | + string.join(list.repeat("v", -up_count), "") <> horizontal <> "A" |
| 121 | + } |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +fn find_motion_numeric(start: String, push: String) -> String { |
| 126 | + let assert Ok(start_pos) = get_numeric_position(start) |
| 127 | + let assert Ok(push_pos) = get_numeric_position(push) |
| 128 | + |
| 129 | + let right_count = push_pos.0 - start_pos.0 |
| 130 | + let up_count = push_pos.1 - start_pos.1 |
| 131 | + |
| 132 | + let horizontal = case int.compare(start_pos.0, push_pos.0) { |
| 133 | + order.Lt -> string.join(list.repeat(">", right_count), "") |
| 134 | + order.Eq -> "" |
| 135 | + order.Gt -> string.join(list.repeat("<", -right_count), "") |
| 136 | + } |
| 137 | + |
| 138 | + case int.compare(start_pos.1, push_pos.1) { |
| 139 | + order.Lt -> { |
| 140 | + // Go up first then left or right |
| 141 | + string.join(list.repeat("^", up_count), "") <> horizontal <> "A" |
| 142 | + } |
| 143 | + order.Eq -> { |
| 144 | + // Go left or right |
| 145 | + horizontal <> "A" |
| 146 | + } |
| 147 | + order.Gt -> { |
| 148 | + // Go left or right first, then down |
| 149 | + horizontal <> string.join(list.repeat("v", -up_count), "") <> "A" |
| 150 | + } |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +fn get_directional_position(key: String) -> Result(Point, Nil) { |
| 155 | + case key { |
| 156 | + "^" -> Ok(#(1, 1)) |
| 157 | + "A" -> Ok(#(2, 1)) |
| 158 | + "<" -> Ok(#(0, 0)) |
| 159 | + "v" -> Ok(#(1, 0)) |
| 160 | + ">" -> Ok(#(2, 0)) |
| 161 | + _ -> Error(Nil) |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +fn get_numeric_position(key: String) -> Result(Point, Nil) { |
| 166 | + case key { |
| 167 | + "7" -> Ok(#(0, 3)) |
| 168 | + "8" -> Ok(#(1, 3)) |
| 169 | + "9" -> Ok(#(2, 3)) |
| 170 | + "4" -> Ok(#(0, 2)) |
| 171 | + "5" -> Ok(#(1, 2)) |
| 172 | + "6" -> Ok(#(2, 2)) |
| 173 | + "1" -> Ok(#(0, 1)) |
| 174 | + "2" -> Ok(#(1, 1)) |
| 175 | + "3" -> Ok(#(2, 1)) |
| 176 | + "0" -> Ok(#(1, 0)) |
| 177 | + "A" -> Ok(#(2, 0)) |
| 178 | + _ -> Error(Nil) |
| 179 | + } |
| 180 | +} |
0 commit comments