├── LICENSE ├── README.md ├── day1 ├── .gitignore └── main.pony ├── day10 ├── .gitignore ├── input.pony └── main.pony ├── day11 ├── .gitignore ├── elevator.pony ├── foor.pony ├── input.pony ├── main.pony ├── rule.pony └── state.pony ├── day12 ├── .gitignore ├── _test.pony └── input.pony ├── day13 ├── .gitignore └── _test.pony ├── day14 ├── .gitignore └── main.pony ├── day15 ├── .gitignore └── main.pony ├── day16 ├── .gitignore └── _test.pony ├── day17 ├── .gitignore └── _test.pony ├── day18 ├── .gitignore └── _test.pony ├── day19 ├── .gitignore └── _test.pony ├── day19b ├── .gitignore └── _test.pony ├── day2 ├── .gitignore └── main.pony ├── day20 ├── .gitignore ├── _test.pony └── input.pony ├── day21 ├── .gitignore ├── _test.pony └── input.pony ├── day22 ├── .gitignore ├── _test.pony └── input.pony ├── day23 ├── .gitignore ├── _test.pony └── input.pony ├── day24 ├── .gitignore ├── _test.pony ├── bfs.pony └── input.pony ├── day25 ├── .gitignore ├── _test.pony ├── assembunny.pony └── input.pony ├── day3 ├── .gitignore └── main.pony ├── day4 ├── .gitignore └── main.pony ├── day5 ├── .gitignore └── main.pony ├── day6 ├── .gitignore ├── input.pony └── main.pony ├── day7 ├── .gitignore ├── input.pony └── main.pony ├── day8 ├── .gitignore ├── input.pony └── main.pony └── day9 ├── .gitignore ├── input.pony └── main.pony /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pony-advent-2016 2 | 3 | Advent of Code 2016 implemented in the Pony Language 4 | 5 | Each day a new coding challenge comes here: 6 | 7 | http://adventofcode.com/2016 8 | 9 | -------------------------------------------------------------------------------- /day1/.gitignore: -------------------------------------------------------------------------------- 1 | day1 -------------------------------------------------------------------------------- /day1/main.pony: -------------------------------------------------------------------------------- 1 | actor Main 2 | let env: Env 3 | 4 | new create(env': Env) => 5 | env = env' 6 | env.out.print("hello") 7 | let city: CityMap = CityMap(env) 8 | env.out.print("city: " + city.string()) 9 | let i1 = Instruction(RIGHT, 1) 10 | city.apply_move(i1) 11 | env.out.print("city: " + city.string()) 12 | 13 | test_parse() 14 | test_example1() 15 | test_example2() 16 | test_example3() 17 | 18 | print_result_of(""" 19 | R3, L2, L2, R4, L1, R2, R3, R4, L2, R4, L2, L5, L1, R5, R2, R2, L1, R4, R1, L5, L3, R4, R3, R1, L1, L5, L4, L2, R5, L3, L4, R3, R1, L3, R1, L3, R3, L4, R2, R5, L190, R2, L3, R47, R4, L3, R78, L1, R3, R190, R4, L3, R4, R2, R5, R3, R4, R3, L1, L4, R3, L4, R1, L4, L5, R3, L3, L4, R1, R2, L4, L3, R3, R3, L2, L5, R1, L4, L1, R5, L5, R1, R5, L4, R2, L2, R1, L5, L4, R4, R4, R3, R2, R3, L1, R4, R5, L2, L5, L4, L1, R4, L4, R4, L4, R1, R5, L1, R1, L5, R5, R1, R1, L3, L1, R4, L1, L4, L4, L3, R1, R4, R1, R1, R2, L5, L2, R4, L1, R3, L5, L2, R5, L4, R5, L5, R3, R4, L3, L3, L2, R2, L5, L5, R3, R4, R3, R4, R3, R1 20 | """, "puzzle input: ") 21 | 22 | test_part_two() 23 | 24 | fun print_result_of(input: String, msg: String) => 25 | let parser: Parser ref = Parser 26 | try 27 | let instructions = parser.parse(input) 28 | let city: CityMap ref = CityMap(env) 29 | city.apply_moves(instructions) 30 | env.out.print(msg + city.string()) 31 | // for h in city.history.values() do 32 | // env.out.write(" (") 33 | // .write(h._1.string()).write(",") 34 | // .write(h._2.string()).print(")") 35 | // end 36 | else 37 | print_parser_error(parser) 38 | end 39 | 40 | fun print_parser_error(parser: Parser) => 41 | env.out.print("test_parse failed at " 42 | + parser.loc.line().string()) 43 | env.out.print("test_parse messsage " 44 | + parser.err) 45 | 46 | fun test_parse() => 47 | let parser: Parser ref = Parser 48 | try 49 | let instructions = parser.parse("R2, L3") 50 | for i in instructions.values() do 51 | env.out.print("i: " + i.string()) 52 | end 53 | else 54 | print_parser_error(parser) 55 | end 56 | 57 | fun test_example1() => 58 | print_result_of("R2, L3", "example1: ") 59 | 60 | fun test_example2() => 61 | print_result_of("R2, R2, R2", "example2: ") 62 | 63 | fun test_example3() => 64 | print_result_of("R5, L5, R5, R3", "example3: ") 65 | 66 | fun test_part_two() => 67 | print_result_of("R8, R4, R4, R8", "part two: ") 68 | 69 | type TURN is (LEFT|RIGHT) 70 | type FACING is (NORTH|EAST|SOUTH|WEST) 71 | 72 | class Tuples 73 | fun string(t: (I64, I64)): String val => 74 | String.append("(") 75 | .append(t._1.string()).append(",") 76 | .append(t._2.string()).append(")").clone() 77 | 78 | primitive RIGHT 79 | fun string(): String => "R" 80 | primitive LEFT 81 | fun string(): String => "L" 82 | 83 | primitive NORTH 84 | fun string(): String => "N" 85 | fun turn(direction: TURN): FACING ? => 86 | match direction 87 | | LEFT => WEST 88 | | RIGHT => EAST 89 | else 90 | error 91 | end 92 | fun compute_offset(instruction: Instruction): (I64, I64) => 93 | (0, instruction.distance) 94 | fun increment(): (I64, I64) => 95 | (0, 1) 96 | 97 | primitive EAST 98 | fun string(): String => "E" 99 | fun turn(direction: TURN): FACING ? => 100 | match direction 101 | | LEFT => NORTH 102 | | RIGHT => SOUTH 103 | else 104 | error 105 | end 106 | fun compute_offset(instruction: Instruction): (I64, I64) => 107 | (instruction.distance, 0) 108 | fun increment(): (I64, I64) => 109 | (1, 0) 110 | 111 | primitive SOUTH 112 | fun string(): String => "S" 113 | fun turn(direction: TURN): FACING ? => 114 | match direction 115 | | LEFT => EAST 116 | | RIGHT => WEST 117 | else 118 | error 119 | end 120 | fun compute_offset(instruction: Instruction): (I64, I64) => 121 | (0, -instruction.distance) 122 | fun increment(): (I64, I64) => 123 | (0, -1) 124 | 125 | primitive WEST 126 | fun string(): String => "W" 127 | fun turn(direction: TURN): FACING ? => 128 | match direction 129 | | LEFT => SOUTH 130 | | RIGHT => NORTH 131 | else 132 | error 133 | end 134 | fun compute_offset(instruction: Instruction): (I64, I64) => 135 | (-instruction.distance, 0) 136 | fun increment(): (I64, I64) => 137 | (-1, 0) 138 | 139 | class Instruction 140 | let direction: TURN 141 | let distance: I64 142 | new create(direction': TURN, distance': I64) => 143 | direction = direction' 144 | distance = distance' 145 | fun string(): String => 146 | direction.string() + distance.string() 147 | 148 | class CityMap 149 | let env: Env 150 | let tuples: Tuples = Tuples 151 | var facing: FACING = NORTH 152 | // (x, y) 153 | var location: (I64, I64) = (0, 0) 154 | let history: Array[(I64, I64)] = Array[(I64, I64)] 155 | var firstRevisit: (None|(I64, I64)) = None 156 | 157 | new create(env': Env) => 158 | env = env' 159 | 160 | fun ref apply_moves(instructions: Array[Instruction]) => 161 | for i in instructions.values() do 162 | apply_move(i) 163 | end 164 | 165 | fun ref apply_move(instruction: Instruction) => 166 | try 167 | facing = facing.turn(instruction.direction) 168 | let offset: (I64, I64) = facing.compute_offset(instruction) 169 | let increment: (I64, I64) = facing.increment() 170 | let target = (location._1 + offset._1, location._2 + offset._2) 171 | while (location._1 != target._1) or (location._2 != target._2) do 172 | location = (location._1 + increment._1, location._2 + increment._2) 173 | match firstRevisit 174 | | None => 175 | check_revisit() 176 | history.push(location) 177 | end 178 | end 179 | end 180 | 181 | fun ref check_revisit() => 182 | if (history.contains(location, 183 | { (l:(I64,I64), r:(I64, I64)): Bool => 184 | (l._1 == r._1) and (l._2 == r._2) })) 185 | then 186 | firstRevisit = location 187 | end 188 | 189 | fun blocks_away(): U64 => 190 | location._1.abs() + location._2.abs() 191 | 192 | fun revisit_blocks_away(): U64 => 193 | match firstRevisit 194 | | (let t1: I64, let t2: I64) => 195 | t1.abs() + t2.abs() 196 | else 197 | 0 198 | end 199 | 200 | fun revisit(): String => 201 | match firstRevisit 202 | | (let t1:I64, let t2:I64) => 203 | "(" + t1.string() + "," + t2.string() + ")" 204 | else "None" 205 | end 206 | fun string(): String => 207 | "city: facing: " + facing.string() 208 | + " E: " + location._1.string() 209 | + " N: " + location._2.string() 210 | + " blocks away: " + blocks_away().string() 211 | + " revisit: " + revisit() 212 | + " revisit blocks away: " + revisit_blocks_away().string() 213 | 214 | class Parser 215 | var err: String = "" 216 | var loc: SourceLoc = __loc 217 | 218 | fun ref parse(input: String val): Array[Instruction] ? => 219 | let parts: Array[String] = input.split(",") 220 | let r: Array[Instruction] = Array[Instruction] 221 | for str in parts.values() do 222 | r.push(parse_entry(str)) 223 | end 224 | r 225 | 226 | fun ref parse_entry(str: String): Instruction ? => 227 | let str' = str.clone().strip() 228 | let dir': String val = str'.substring(0, 1) 229 | let direction: TURN = match dir' 230 | | "R" => RIGHT 231 | | "L" => LEFT 232 | else 233 | err = "Unknown direction: \"" + str' + "\"(" + dir' + ")" 234 | loc = __loc 235 | error 236 | end 237 | try 238 | let distance: I64 = str'.read_int[I64](1)._1 239 | Instruction(direction, distance) 240 | else 241 | err = "read_int failed: " + str' 242 | loc = __loc 243 | error 244 | end 245 | -------------------------------------------------------------------------------- /day10/.gitignore: -------------------------------------------------------------------------------- 1 | day10 2 | -------------------------------------------------------------------------------- /day10/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | """value 5 goes to bot 2 4 | bot 2 gives low to bot 1 and high to bot 0 5 | value 3 goes to bot 1 6 | bot 1 gives low to output 1 and high to bot 0 7 | bot 0 gives low to output 2 and high to output 0 8 | value 2 goes to bot 2""" 9 | 10 | fun puzzle(): String => 11 | """bot 135 gives low to bot 27 and high to bot 166 12 | bot 57 gives low to bot 4 and high to bot 186 13 | bot 115 gives low to output 2 and high to bot 80 14 | bot 44 gives low to bot 175 and high to bot 88 15 | bot 167 gives low to bot 42 and high to bot 168 16 | bot 18 gives low to bot 32 and high to bot 89 17 | bot 199 gives low to bot 75 and high to bot 40 18 | bot 129 gives low to bot 178 and high to bot 147 19 | bot 163 gives low to bot 49 and high to bot 160 20 | value 2 goes to bot 143 21 | bot 176 gives low to bot 139 and high to bot 117 22 | bot 194 gives low to bot 11 and high to bot 37 23 | bot 99 gives low to bot 163 and high to bot 138 24 | value 53 goes to bot 9 25 | bot 159 gives low to output 1 and high to bot 207 26 | bot 0 gives low to bot 105 and high to bot 13 27 | bot 6 gives low to bot 66 and high to bot 116 28 | bot 81 gives low to bot 54 and high to bot 10 29 | bot 27 gives low to bot 188 and high to bot 199 30 | bot 186 gives low to bot 84 and high to bot 123 31 | bot 154 gives low to bot 21 and high to bot 107 32 | bot 188 gives low to bot 92 and high to bot 75 33 | bot 164 gives low to bot 115 and high to bot 28 34 | bot 106 gives low to bot 48 and high to bot 155 35 | bot 193 gives low to bot 101 and high to bot 110 36 | bot 136 gives low to bot 166 and high to bot 152 37 | bot 7 gives low to bot 156 and high to bot 24 38 | bot 103 gives low to bot 182 and high to bot 0 39 | bot 101 gives low to bot 16 and high to bot 72 40 | bot 86 gives low to bot 102 and high to bot 48 41 | bot 78 gives low to bot 177 and high to bot 113 42 | value 17 goes to bot 198 43 | bot 54 gives low to bot 161 and high to bot 111 44 | bot 46 gives low to bot 74 and high to bot 39 45 | bot 22 gives low to bot 56 and high to bot 161 46 | bot 5 gives low to bot 186 and high to bot 123 47 | bot 137 gives low to bot 202 and high to bot 85 48 | bot 202 gives low to bot 108 and high to bot 118 49 | bot 174 gives low to bot 0 and high to bot 21 50 | bot 119 gives low to bot 68 and high to bot 53 51 | bot 151 gives low to bot 83 and high to bot 164 52 | bot 160 gives low to bot 33 and high to bot 97 53 | bot 76 gives low to bot 40 and high to bot 120 54 | bot 60 gives low to bot 103 and high to bot 174 55 | bot 203 gives low to bot 120 and high to bot 132 56 | bot 157 gives low to bot 116 and high to bot 11 57 | bot 98 gives low to bot 208 and high to bot 16 58 | bot 142 gives low to bot 114 and high to bot 71 59 | bot 143 gives low to bot 198 and high to bot 146 60 | bot 30 gives low to bot 59 and high to bot 135 61 | bot 87 gives low to bot 39 and high to bot 104 62 | bot 161 gives low to bot 173 and high to bot 125 63 | bot 104 gives low to bot 34 and high to bot 68 64 | bot 70 gives low to bot 112 and high to bot 176 65 | bot 92 gives low to bot 122 and high to bot 46 66 | bot 148 gives low to bot 28 and high to bot 58 67 | bot 49 gives low to output 0 and high to bot 33 68 | bot 140 gives low to bot 136 and high to bot 134 69 | bot 16 gives low to bot 170 and high to bot 79 70 | bot 13 gives low to bot 204 and high to bot 22 71 | bot 189 gives low to bot 148 and high to bot 45 72 | bot 89 gives low to bot 73 and high to bot 86 73 | value 31 goes to bot 50 74 | bot 166 gives low to bot 199 and high to bot 76 75 | bot 178 gives low to output 5 and high to bot 159 76 | bot 58 gives low to bot 167 and high to bot 126 77 | bot 149 gives low to bot 180 and high to bot 153 78 | bot 131 gives low to bot 97 and high to bot 66 79 | bot 64 gives low to bot 192 and high to bot 44 80 | bot 117 gives low to bot 140 and high to bot 134 81 | bot 156 gives low to bot 174 and high to bot 154 82 | value 11 goes to bot 19 83 | bot 1 gives low to bot 26 and high to bot 144 84 | bot 171 gives low to output 7 and high to bot 150 85 | bot 31 gives low to bot 110 and high to bot 127 86 | value 5 goes to bot 162 87 | bot 9 gives low to bot 8 and high to bot 128 88 | bot 93 gives low to bot 109 and high to bot 188 89 | value 47 goes to bot 184 90 | bot 80 gives low to output 19 and high to bot 42 91 | bot 155 gives low to bot 149 and high to bot 52 92 | bot 108 gives low to output 14 and high to bot 47 93 | bot 165 gives low to bot 200 and high to bot 141 94 | bot 184 gives low to bot 162 and high to bot 20 95 | bot 50 gives low to bot 143 and high to bot 4 96 | bot 28 gives low to bot 80 and high to bot 167 97 | bot 66 gives low to bot 151 and high to bot 55 98 | bot 201 gives low to bot 124 and high to bot 41 99 | bot 204 gives low to bot 94 and high to bot 56 100 | bot 134 gives low to bot 152 and high to bot 203 101 | bot 51 gives low to bot 36 and high to bot 142 102 | bot 2 gives low to bot 52 and high to bot 201 103 | bot 183 gives low to bot 38 and high to bot 78 104 | bot 26 gives low to bot 142 and high to bot 69 105 | bot 182 gives low to bot 3 and high to bot 105 106 | bot 72 gives low to bot 79 and high to bot 209 107 | bot 8 gives low to bot 185 and high to bot 65 108 | bot 75 gives low to bot 46 and high to bot 87 109 | bot 38 gives low to bot 82 and high to bot 177 110 | bot 147 gives low to bot 159 and high to bot 207 111 | bot 195 gives low to bot 104 and high to bot 119 112 | bot 63 gives low to bot 126 and high to bot 172 113 | bot 144 gives low to bot 69 and high to bot 82 114 | bot 83 gives low to output 3 and high to bot 115 115 | bot 43 gives low to bot 194 and high to bot 91 116 | value 37 goes to bot 8 117 | bot 82 gives low to bot 193 and high to bot 31 118 | bot 150 gives low to output 18 and high to bot 49 119 | value 23 goes to bot 182 120 | bot 67 gives low to bot 61 and high to bot 165 121 | bot 77 gives low to bot 107 and high to bot 122 122 | bot 130 gives low to bot 141 and high to bot 30 123 | value 73 goes to bot 12 124 | bot 41 gives low to bot 99 and high to bot 208 125 | bot 170 gives low to bot 131 and high to bot 6 126 | bot 120 gives low to bot 195 and high to bot 132 127 | bot 118 gives low to bot 47 and high to bot 129 128 | bot 100 gives low to bot 150 and high to bot 163 129 | value 67 goes to bot 185 130 | bot 152 gives low to bot 76 and high to bot 203 131 | bot 162 gives low to bot 67 and high to bot 205 132 | value 7 goes to bot 32 133 | bot 121 gives low to bot 172 and high to bot 158 134 | bot 65 gives low to bot 57 and high to bot 5 135 | bot 122 gives low to bot 81 and high to bot 74 136 | bot 21 gives low to bot 13 and high to bot 17 137 | bot 23 gives low to bot 133 and high to bot 1 138 | bot 36 gives low to bot 201 and high to bot 114 139 | bot 138 gives low to bot 160 and high to bot 131 140 | bot 55 gives low to bot 164 and high to bot 148 141 | bot 123 gives low to bot 70 and high to bot 176 142 | value 61 goes to bot 61 143 | bot 107 gives low to bot 17 and high to bot 81 144 | bot 19 gives low to bot 60 and high to bot 156 145 | value 41 goes to bot 12 146 | value 29 goes to bot 18 147 | value 13 goes to bot 60 148 | bot 62 gives low to bot 20 and high to bot 64 149 | bot 40 gives low to bot 87 and high to bot 195 150 | bot 90 gives low to bot 64 and high to bot 112 151 | bot 69 gives low to bot 71 and high to bot 193 152 | bot 35 gives low to output 4 and high to bot 108 153 | bot 177 gives low to bot 31 and high to bot 113 154 | bot 59 gives low to bot 93 and high to bot 27 155 | bot 187 gives low to bot 89 and high to bot 94 156 | bot 73 gives low to output 9 and high to bot 102 157 | bot 45 gives low to bot 58 and high to bot 63 158 | bot 39 gives low to bot 23 and high to bot 34 159 | bot 110 gives low to bot 72 and high to bot 190 160 | bot 181 gives low to bot 15 and high to bot 93 161 | bot 95 gives low to bot 7 and high to bot 15 162 | bot 33 gives low to output 13 and high to bot 169 163 | bot 20 gives low to bot 205 and high to bot 192 164 | bot 158 gives low to bot 85 and high to bot 29 165 | bot 61 gives low to bot 14 and high to bot 200 166 | value 71 goes to bot 103 167 | bot 192 gives low to bot 130 and high to bot 175 168 | bot 112 gives low to bot 44 and high to bot 139 169 | bot 96 gives low to bot 144 and high to bot 38 170 | bot 32 gives low to output 11 and high to bot 73 171 | bot 180 gives low to output 10 and high to bot 171 172 | value 59 goes to bot 3 173 | bot 208 gives low to bot 138 and high to bot 170 174 | bot 198 gives low to bot 184 and high to bot 62 175 | bot 207 gives low to output 16 and high to output 8 176 | bot 196 gives low to bot 43 and high to bot 91 177 | bot 10 gives low to bot 111 and high to bot 133 178 | bot 168 gives low to bot 35 and high to bot 202 179 | bot 113 gives low to bot 127 and high to bot 196 180 | bot 169 gives low to output 20 and high to bot 83 181 | bot 3 gives low to bot 18 and high to bot 187 182 | bot 52 gives low to bot 153 and high to bot 124 183 | bot 190 gives low to bot 209 and high to bot 43 184 | bot 125 gives low to bot 2 and high to bot 36 185 | bot 173 gives low to bot 155 and high to bot 2 186 | bot 153 gives low to bot 171 and high to bot 100 187 | bot 34 gives low to bot 1 and high to bot 96 188 | bot 84 gives low to bot 90 and high to bot 70 189 | bot 12 gives low to bot 9 and high to bot 128 190 | bot 24 gives low to bot 154 and high to bot 77 191 | bot 179 gives low to bot 63 and high to bot 121 192 | bot 85 gives low to bot 118 and high to bot 29 193 | bot 11 gives low to bot 189 and high to bot 145 194 | bot 116 gives low to bot 55 and high to bot 189 195 | bot 132 gives low to bot 119 and high to bot 53 196 | bot 15 gives low to bot 24 and high to bot 109 197 | bot 102 gives low to output 15 and high to bot 197 198 | value 43 goes to bot 206 199 | bot 37 gives low to bot 145 and high to bot 25 200 | bot 53 gives low to bot 183 and high to bot 78 201 | bot 197 gives low to output 12 and high to bot 180 202 | bot 47 gives low to output 17 and high to bot 178 203 | bot 17 gives low to bot 22 and high to bot 54 204 | bot 56 gives low to bot 106 and high to bot 173 205 | bot 191 gives low to bot 135 and high to bot 136 206 | bot 127 gives low to bot 190 and high to bot 196 207 | bot 172 gives low to bot 137 and high to bot 158 208 | bot 4 gives low to bot 146 and high to bot 84 209 | bot 42 gives low to output 6 and high to bot 35 210 | bot 145 gives low to bot 45 and high to bot 179 211 | bot 133 gives low to bot 51 and high to bot 26 212 | bot 139 gives low to bot 88 and high to bot 117 213 | bot 105 gives low to bot 187 and high to bot 204 214 | bot 126 gives low to bot 168 and high to bot 137 215 | bot 128 gives low to bot 65 and high to bot 5 216 | bot 114 gives low to bot 41 and high to bot 98 217 | bot 14 gives low to bot 206 and high to bot 95 218 | bot 91 gives low to bot 37 and high to bot 25 219 | bot 206 gives low to bot 19 and high to bot 7 220 | value 19 goes to bot 14 221 | bot 185 gives low to bot 50 and high to bot 57 222 | bot 205 gives low to bot 165 and high to bot 130 223 | bot 109 gives low to bot 77 and high to bot 92 224 | bot 175 gives low to bot 30 and high to bot 191 225 | bot 29 gives low to bot 129 and high to bot 147 226 | bot 74 gives low to bot 10 and high to bot 23 227 | bot 94 gives low to bot 86 and high to bot 106 228 | bot 25 gives low to bot 179 and high to bot 121 229 | bot 71 gives low to bot 98 and high to bot 101 230 | bot 209 gives low to bot 157 and high to bot 194 231 | bot 88 gives low to bot 191 and high to bot 140 232 | bot 124 gives low to bot 100 and high to bot 99 233 | bot 97 gives low to bot 169 and high to bot 151 234 | bot 141 gives low to bot 181 and high to bot 59 235 | bot 146 gives low to bot 62 and high to bot 90 236 | bot 200 gives low to bot 95 and high to bot 181 237 | bot 79 gives low to bot 6 and high to bot 157 238 | bot 48 gives low to bot 197 and high to bot 149 239 | value 3 goes to bot 67 240 | bot 68 gives low to bot 96 and high to bot 183 241 | bot 111 gives low to bot 125 and high to bot 51""" 242 | -------------------------------------------------------------------------------- /day10/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "debug" 3 | use "regex" 4 | 5 | actor Main 6 | let env: Env 7 | new create(env': Env) => 8 | env = env' 9 | 10 | simulate_instructions((5, 2), INPUT.sample().split("\n")) 11 | simulate_instructions((61, 17), INPUT.puzzle().split("\n")) 12 | 13 | fun simulate_instructions(watch: (U32, U32), lines: Array[String]) => 14 | let router = Router(watch) 15 | for l in lines.values() do 16 | try 17 | let i = parse(l) 18 | match i 19 | | let take: Take => 20 | router.route(take.bot, take) 21 | | let give: Give => 22 | router.route(give.bot, give) 23 | else 24 | env.err.print("** Bad instruction:") 25 | end 26 | else 27 | env.err.print("** Failed: " + l) 28 | end 29 | end 30 | 31 | fun parse(line: String): Instruction ? => 32 | let take = Regex("value (\\d+) goes to bot (\\d+)") 33 | let gives = Regex("bot (\\d+) gives low to (bot|output) (\\d+) and high to (bot|output) (\\d+)") 34 | if take == line then 35 | let matched = take(line) 36 | let value = matched(1).read_int[U32]()._1 37 | let bot = matched(2).read_int[U32]()._1 38 | let r: Take val = Take(bot, value) 39 | return r 40 | end 41 | if gives == line then 42 | let matched = gives(line) 43 | let bot = matched(1).read_int[U32]()._1 44 | let lowTo: String val = matched(2) 45 | let lowValue = matched(3).read_int[U32]()._1 46 | let highTo: String val = matched(4) 47 | let highValue = matched(5).read_int[U32]()._1 48 | let r: Give val = Give( 49 | bot, 50 | lowTo, lowValue, 51 | highTo, highValue 52 | ) 53 | return r 54 | end 55 | env.err.write("** No match: ").print(line) 56 | error 57 | 58 | type Instruction is (Give | Take ) 59 | 60 | class val Give 61 | let bot: U32 62 | let lowTo: String 63 | let lowValue: U32 64 | let highTo: String 65 | let highValue: U32 66 | new val create( 67 | bot': U32, 68 | lowTo': String, lowValue': U32, 69 | highTo': String, highValue': U32 70 | ) => 71 | bot = bot' 72 | lowTo = lowTo' 73 | lowValue = lowValue' 74 | highTo = highTo' 75 | highValue = highValue' 76 | fun val string(): String => 77 | recover 78 | String.append("bot ").append(bot.string()).append(" gives low to ") 79 | .append(lowTo).append(" ").append(lowValue.string()).append(" and high to ") 80 | .append(highTo).append(" ").append(highValue.string()) 81 | end 82 | 83 | class val Take 84 | let bot: U32 85 | let value: U32 86 | new val create(bot': U32, value': U32) => 87 | bot = bot' 88 | value = value' 89 | fun val string(): String => 90 | recover 91 | String.append("value ").append(value.string()) 92 | .append(" goes to bot ").append(bot.string()) 93 | end 94 | 95 | actor Router 96 | let bots: Map[U32, Bot tag] 97 | let watch: (U32, U32) 98 | new create(watch': (U32, U32)) => 99 | watch = watch' 100 | bots = Map[U32, Bot tag] 101 | 102 | be route(bot: U32, instr: Instruction) => 103 | try 104 | bots(bot).process(instr) 105 | else 106 | let b = Bot(bot, this, watch) 107 | bots(bot) = b 108 | b.process(instr) 109 | end 110 | 111 | be output(output': U32, value: U32) => 112 | Debug.out( 113 | String 114 | .append("output(").append(output'.string()) 115 | .append(")=").append(value.string()) 116 | ) 117 | 118 | actor Bot 119 | let bot: U32 120 | let router: Router tag 121 | let watch: (U32, U32) 122 | let values: Array[U32] = Array[U32] 123 | var give: (Give|None) = None 124 | 125 | new create(bot': U32, router': Router tag, watch': (U32, U32)) => 126 | bot = bot' 127 | router = router' 128 | watch = watch' 129 | 130 | be process(instr: Instruction) => 131 | Debug.out(instr.string()) 132 | match instr 133 | | let take: Take => 134 | if values.size() == 2 then 135 | Debug.err("** Got three values before Give. Losing value!") 136 | end 137 | values.push(take.value) 138 | if values.size() == 2 then 139 | ready_to_give() 140 | end 141 | | let give': Give => 142 | give = give' 143 | if values.size() == 2 then 144 | ready_to_give() 145 | end 146 | end 147 | 148 | fun ref ready_to_give() => 149 | match give 150 | | let give': Give => 151 | try 152 | let low = values(0).min(values(1)) 153 | let hi = values(0).max(values(1)) 154 | match watch 155 | | (low, hi) => 156 | Debug.out("-- Bot: " + bot.string()) 157 | | (hi, low) => 158 | Debug.out("-- Bot: " + bot.string()) 159 | end 160 | match (give'.lowTo, give'.highTo) 161 | | ("output", "output") => 162 | router.output(give'.lowValue, low) 163 | router.output(give'.highValue, hi) 164 | | ("bot", "output") => 165 | router.route(give'.lowValue, Take(give'.lowValue, low)) 166 | router.output(give'.highValue, hi) 167 | | ("output", "bot") => 168 | router.output(give'.lowValue, low) 169 | router.route(give'.highValue, Take(give'.highValue, hi)) 170 | | ("bot", "bot") => 171 | router.route(give'.lowValue, Take(give'.lowValue, low)) 172 | router.route(give'.highValue, Take(give'.highValue, hi)) 173 | end 174 | values.clear() 175 | end 176 | end 177 | -------------------------------------------------------------------------------- /day11/.gitignore: -------------------------------------------------------------------------------- 1 | day11 2 | -------------------------------------------------------------------------------- /day11/elevator.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | class Elevator 4 | let floor: USize 5 | let generators: Set[String] 6 | let microchips: Set[String] 7 | 8 | new create( 9 | floor': USize = 0, 10 | generators': Set[String] = Set[String], 11 | microchips': Set[String] = Set[String] 12 | ) => 13 | floor = floor' 14 | generators = generators' 15 | microchips = microchips' 16 | 17 | fun string(): String => 18 | (1 + floor).string() 19 | -------------------------------------------------------------------------------- /day11/foor.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "debug" 3 | 4 | class Floor 5 | let floor: USize 6 | let _generators: Set[String] 7 | let _microchips: Set[String] 8 | let gen_mic: String ref 9 | 10 | new create( 11 | floor': USize = 0, 12 | generators': Set[String] = Set[String], 13 | microchips': Set[String] = Set[String] 14 | ) => 15 | floor = floor' 16 | _generators = generators' 17 | _microchips = microchips' 18 | gen_mic = "..............".clone() 19 | build() 20 | 21 | fun ref build(): Floor => 22 | gen_mic.clear().append("..............") 23 | try 24 | for g' in _generators.values() do 25 | let idx: USize = match g' 26 | | "promethium" => 0 27 | | "cobalt" => 1 28 | | "curium" => 2 29 | | "ruthenium" => 3 30 | | "plutonium" => 4 31 | | "elerium" => 5 32 | else 33 | 6 34 | end 35 | gen_mic(2 * idx) = 'G' 36 | end 37 | for m' in _microchips.values() do 38 | let idx: USize = match m' 39 | | "promethium" => 0 40 | | "cobalt" => 1 41 | | "curium" => 2 42 | | "ruthenium" => 3 43 | | "plutonium" => 4 44 | | "elerium" => 5 45 | else 46 | 6 47 | end 48 | gen_mic((2 * idx) + 1) = 'M' 49 | end 50 | else 51 | Debug.err("** Fatal") 52 | end 53 | this 54 | 55 | fun clone(): Floor => 56 | Floor(floor, _generators.clone(), _microchips.clone()) 57 | 58 | fun ref g(g': String): Floor => 59 | _generators.set(g') 60 | build() 61 | this 62 | 63 | fun ref rm_g(g': String): Floor => 64 | _generators.unset(g') 65 | build() 66 | this 67 | 68 | fun ref m(m': String): Floor => 69 | _microchips.set(m') 70 | build() 71 | this 72 | 73 | fun generators(): Set[String] box => 74 | _generators 75 | fun microchips(): Set[String] box => 76 | _microchips 77 | 78 | fun ref rm_m(m': String): Floor => 79 | _microchips.unset(m') 80 | build() 81 | this 82 | 83 | fun is_empty(): Bool => 84 | (_generators.size() == 0) and (_microchips.size() == 0) 85 | 86 | fun string(): String => 87 | let gm: String val = gen_mic.clone() 88 | recover val 89 | let r: String ref = String 90 | r.append("|").append((1+floor).string()).append("|").append(gm) 91 | r.clone() 92 | end 93 | -------------------------------------------------------------------------------- /day11/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | """The first floor contains a hydrogen-compatible microchip and a lithium-compatible microchip. 4 | The second floor contains a hydrogen generator. 5 | The third floor contains a lithium generator. 6 | The fourth floor contains nothing relevant.""" 7 | 8 | fun puzzle(): String => 9 | """The first floor contains a promethium generator and a promethium-compatible microchip. 10 | The second floor contains a cobalt generator, a curium generator, a ruthenium generator, and a plutonium generator. 11 | The third floor contains a cobalt-compatible microchip, a curium-compatible microchip, a ruthenium-compatible microchip, and a plutonium-compatible microchip. 12 | The fourth floor contains nothing relevant.""" 13 | 14 | fun types(): Array[String] => 15 | ["promethium", "cobalt", "curium", "ruthenium", "plutonium"] 16 | -------------------------------------------------------------------------------- /day11/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "debug" 3 | use "time" 4 | 5 | class ErrorInfo 6 | var message: String = "" 7 | var source: SourceLoc = __loc 8 | 9 | fun ref throw(message': String, source': SourceLoc = __loc) ? => 10 | message = message' 11 | source = source' 12 | error 13 | 14 | fun string(): String val => 15 | recover 16 | String.append("** ").append(message).append(":") 17 | .append(source.file()).append(",").append(source.method()) 18 | .append("@").append(source.line().string()) 19 | end 20 | 21 | actor Main 22 | let env: Env 23 | let err: ErrorInfo = ErrorInfo 24 | let pending: Array[State] = Array[State] 25 | var lastReport: I64 = 0 26 | 27 | new create(env': Env) => 28 | env = env' 29 | 30 | let seenStates = Set[String] 31 | // let state = State(seenStates, 0, Elevator(0), puzzle()) 32 | let state = State(seenStates, 0, Elevator(0), puzzle_part2()) 33 | // let state = State(seenStates, 0, Elevator(3), puzzle_part2a()) 34 | 35 | // 48 is too low 36 | // based on partial 57 (each extra pair on floor 1 is +12?) 37 | // 59 is too high 38 | 39 | pending.push(state) 40 | search_pending() 41 | 42 | be search_pending() => 43 | try 44 | let state' = pending.shift() 45 | if (state'.is_win()) then 46 | env.out.print("win:" + state'.string() + "moves:" + state'.moves.string()) 47 | end 48 | // Debug.out("from@" + state'.moves.string() + ":" + state'.string()) 49 | let next: Array[State] = state'.compute_next() 50 | pending.concat(next.values()) 51 | 52 | let nowSecs = Time.seconds() 53 | if (lastReport + 10) <= nowSecs then 54 | lastReport = nowSecs 55 | env.out.print("from@" + state'.moves.string() + ":" + state'.string()) 56 | env.out.print("pending: " + pending.size().string()) 57 | end 58 | search_pending() 59 | else 60 | env.out.print("exhausted all") 61 | end 62 | 63 | fun bad_ones(): Array[Floor] => 64 | [ 65 | Floor(0).m("H").g("P"), 66 | Floor(1).g("H").m("Z"), 67 | Floor(2).g("L"), 68 | Floor(3) 69 | ] 70 | 71 | fun sample(): Array[Floor box] => 72 | [ 73 | recover box Floor(0).m("H").m("L") end, 74 | recover box Floor(1).g("H") end, 75 | recover box Floor(2).g("L") end, 76 | recover box Floor(3) end 77 | ] 78 | 79 | /* Assumes we need to pull down all the M's to starte 80 | * and that the G's must be moved up first 81 | */ 82 | fun puzzle_learn(): Array[Floor box] => 83 | [ 84 | // The first floor contains a promethium generator and a promethium-compatible microchip. 85 | recover box Floor(0).build() end, 86 | // The second floor contains a cobalt generator, 87 | // a curium generator, 88 | // a ruthenium generator, and 89 | // a plutonium generator. 90 | recover box Floor(1).g("promethium").g("cobalt").g("curium").g("ruthenium").g("plutonium").build() end, 91 | // The third floor contains a cobalt-compatible microchip, 92 | // a curium-compatible microchip, 93 | // a ruthenium-compatible microchip, and 94 | // a plutonium-compatible microchip. 95 | recover box Floor(2).m("promethium").m("cobalt").m("curium").m("ruthenium").m("plutonium").build() end, 96 | // Empty 97 | recover box Floor(3).build() end 98 | ] 99 | 100 | fun puzzle(): Array[Floor box] => 101 | [ 102 | // The first floor contains a promethium generator and a promethium-compatible microchip. 103 | recover box Floor(0).g("promethium").m("promethium").build() end, 104 | // The second floor contains a cobalt generator, 105 | // a curium generator, 106 | // a ruthenium generator, and 107 | // a plutonium generator. 108 | recover box Floor(1).g("cobalt").g("curium").g("ruthenium").g("plutonium").build() end, 109 | // The third floor contains a cobalt-compatible microchip, 110 | // a curium-compatible microchip, 111 | // a ruthenium-compatible microchip, and 112 | // a plutonium-compatible microchip. 113 | recover box Floor(2).m("cobalt").m("curium").m("ruthenium").m("plutonium").build() end, 114 | // Empty 115 | recover box Floor(3).build() end 116 | ] 117 | 118 | fun puzzle_part2(): Array[Floor box] => 119 | [ 120 | // The first floor contains a promethium generator and a promethium-compatible microchip. 121 | recover box Floor(0) 122 | .g("promethium").m("promethium") 123 | .g("elerium").m("elerium") 124 | .g("dilithium").m("dilithium") 125 | .build() 126 | end, 127 | // The second floor contains a cobalt generator, 128 | // a curium generator, 129 | // a ruthenium generator, and 130 | // a plutonium generator. 131 | recover box Floor(1).g("cobalt").g("curium").g("ruthenium").g("plutonium").build() end, 132 | // The third floor contains a cobalt-compatible microchip, 133 | // a curium-compatible microchip, 134 | // a ruthenium-compatible microchip, and 135 | // a plutonium-compatible microchip. 136 | recover box Floor(2).m("cobalt").m("curium").m("ruthenium").m("plutonium").build() end, 137 | // Empty 138 | recover box Floor(3).build() end 139 | ] 140 | 141 | /* 142 | Sub-problem 143 | E4 GM GM 144 | ........ 145 | ........ 146 | ........GM GM 147 | */ 148 | fun puzzle_part2a(): Array[Floor box] => 149 | [ 150 | // The first floor contains a promethium generator and a promethium-compatible microchip. 151 | recover box Floor(0) 152 | .g("elerium").m("elerium") 153 | .g("dilithium").m("dilithium") 154 | .build() 155 | end, 156 | // The second floor contains a cobalt generator, 157 | // a curium generator, 158 | // a ruthenium generator, and 159 | // a plutonium generator. 160 | recover box Floor(1).build() end, 161 | // The third floor contains a cobalt-compatible microchip, 162 | // a curium-compatible microchip, 163 | // a ruthenium-compatible microchip, and 164 | // a plutonium-compatible microchip. 165 | recover box Floor(2).build() end, 166 | // Empty 167 | recover box Floor(3) 168 | .g("ruthenium").g("plutonium") 169 | .m("ruthenium").m("plutonium") 170 | .build() end 171 | ] 172 | -------------------------------------------------------------------------------- /day11/rule.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "debug" 3 | 4 | primitive Rule 5 | fun is_safe_floor(f: Floor box): Bool => 6 | _is_safe(f.generators(), f.microchips()) 7 | 8 | fun is_safe_state(s: State): Bool => 9 | // Debug.out(" to@" + s.moves.string() + ":" + s.string()) 10 | 11 | for f in s.floors.values() do 12 | if not is_safe_floor(f) then 13 | // Debug.out("--bad-floor--(" + f.string() + ")") 14 | return false 15 | end 16 | end 17 | 18 | if s.moves >= 59 then 19 | // Debug.out("limit reached") 20 | return false 21 | end 22 | 23 | // Don't let the M's get ahead of the G' 24 | // for t in INPUT.types().values() do 25 | // let fOfG: U32 = s.floorOfG(t).u32() 26 | // let fOfM: U32 = s.floorOfM(t).u32() 27 | // if fOfM > fOfG then 28 | // // Debug.out("bad-m-g@" + s.moves.string() + ":" + s.string()) 29 | // return false 30 | // end 31 | // end 32 | // // Don't let elevator go to floor "1" 33 | // if s.elevator.floor == 0 then 34 | // return false 35 | // end 36 | 37 | // TODO might need to do elevator 38 | // Debug.out("good@" + s.moves.string() + ":" + s.string()) 39 | true 40 | 41 | fun _is_safe(generators: Set[String] box, microchips: Set[String] box): Bool => 42 | if generators.size() == 0 then 43 | return true 44 | end 45 | 46 | let unpaired_microchips = microchips.without(generators) 47 | 48 | if unpaired_microchips.size() == 0 then 49 | return true 50 | end 51 | false 52 | -------------------------------------------------------------------------------- /day11/state.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "debug" 3 | 4 | class State 5 | // let seen: Map[String, State] 6 | let seen: Set[String] 7 | var moves: USize 8 | let elevator: Elevator 9 | let floors: Array[Floor box] 10 | 11 | new create( 12 | seen': Set[String], 13 | moves': USize, 14 | e: Elevator, f: Array[Floor box] 15 | ) => 16 | seen = seen' // Must be breadth first search 17 | // seen = Set[String] 18 | moves = moves' 19 | elevator = e 20 | floors = f 21 | 22 | fun ref compute_next(): Array[State] => 23 | match elevator.floor 24 | | 3 => down() 25 | | 2 => down().concat(up().values()) 26 | | 1 => down().concat(up().values()) 27 | | 0 => up() 28 | else 29 | Debug.err("** Fail") 30 | Array[State] 31 | end 32 | 33 | fun ref up(): Array[State] => 34 | compute_move_to(elevator.floor + 1) 35 | 36 | fun ref down(): Array[State] => 37 | compute_move_to(elevator.floor - 1) 38 | 39 | fun floorOfG(g: String): USize => 40 | for f in floors.values() do 41 | if f.generators().contains(g) then 42 | // Debug.out("floorOfG:"+g+f.floor.string()) 43 | return f.floor 44 | end 45 | end 46 | Debug.err("** error1") 47 | 0 48 | 49 | fun floorOfM(m: String): USize => 50 | for f in floors.values() do 51 | if f.microchips().contains(m) then 52 | // Debug.out("floorOfM:"+m+f.floor.string()) 53 | return f.floor 54 | end 55 | end 56 | Debug.err("** error1") 57 | 0 58 | 59 | fun ref compute_move_to(next: USize val): Array[State] => 60 | let res = Array[State] 61 | let moves' = moves + 1 62 | try 63 | let cur = floors(elevator.floor) 64 | // generators 65 | for gi in cur.generators().values() do 66 | let state' = move_generator(moves', elevator.floor, next, gi) 67 | maybe_add_state(res, state') 68 | for gj in cur.generators().values() do 69 | maybe_add_state(res, state'.move_generator(moves', elevator.floor, next, gj)) 70 | end 71 | end 72 | // microchips 73 | for mi in cur.microchips().values() do 74 | let state' = move_microchip(moves', elevator.floor, next, mi) 75 | maybe_add_state(res, state') 76 | for mj in cur.microchips().values() do 77 | maybe_add_state(res, state'.move_microchip(moves', elevator.floor, next, mj)) 78 | end 79 | end 80 | // Cross product 81 | for gi in cur.generators().values() do 82 | for mj in cur.microchips().values() do 83 | maybe_add_state(res, move_both(moves', elevator.floor, next, gi, mj)) 84 | end 85 | end 86 | end 87 | res 88 | 89 | fun ref move_generator( 90 | moves': USize, cur': USize, next': USize val, g: String 91 | ): State ? => 92 | let cur_floor: Floor ref = floors(cur').clone() 93 | let next_floor: Floor ref = floors(next').clone() 94 | // Debug.out("b-" + cur_floor.gen_mic + cur_floor.generators().contains("promethium").string()) 95 | cur_floor.rm_g(g) 96 | // Debug.out("a-" + cur_floor.gen_mic + cur_floor.generators().contains("promethium").string()) 97 | next_floor.g(g) 98 | let floors' = floors.clone() 99 | try 100 | floors'(cur') = cur_floor.build() 101 | floors'(next') = next_floor.build() 102 | else 103 | Debug.err("** Fail") 104 | end 105 | State(seen, moves', Elevator(next'), floors') 106 | 107 | fun ref move_microchip( 108 | moves': USize, cur': USize, next': USize val, m: String 109 | ): State ? => 110 | let cur_floor: Floor ref = floors(cur').clone() 111 | let next_floor: Floor ref = floors(next').clone() 112 | cur_floor.rm_m(m) 113 | next_floor.m(m) 114 | let floors' = floors.clone() 115 | try 116 | floors'(cur') = cur_floor 117 | floors'(next') = next_floor 118 | else 119 | Debug.err("** Fail") 120 | end 121 | State(seen, moves', Elevator(next'), floors') 122 | 123 | fun ref move_both( 124 | moves': USize, cur': USize, next': USize val, g: String, m: String 125 | ): State ? => 126 | let state' = move_generator(moves', cur', next', g) 127 | state'.move_microchip(moves', cur', next', m) 128 | 129 | fun ref maybe_add_state(list: Array[State], state: State) => 130 | if not seen.contains(state.string()) then 131 | seen.set(state.string()) 132 | // if elevator.floor == 1 then 133 | // Debug.out("from: " + string()) 134 | // Debug.out("try: " + state.string()) 135 | // end 136 | if Rule.is_safe_state(state) then 137 | list.push(state) 138 | end 139 | end 140 | // else 141 | // try 142 | // let old = seen(state.string()) 143 | // if old.moves > state.moves then 144 | // // Found a faster way to get here 145 | // Debug.out("Found faster path to " + state.string()) 146 | // seen(state.string()) = state 147 | // if Rule.is_safe_state(state) then 148 | // list.push(state) 149 | // end 150 | // end 151 | // end 152 | // end 153 | 154 | fun is_win(): Bool => 155 | try 156 | for i in Range(0,3) do 157 | if not floors(i).is_empty() then 158 | return false 159 | end 160 | end 161 | true 162 | else 163 | false 164 | end 165 | 166 | fun string(): String => 167 | let r: String ref = String 168 | r.append("E").append(elevator.string()).append("-") 169 | for f in floors.reverse().values() do 170 | r.append(f.string()).append("-") 171 | end 172 | r.clone() 173 | -------------------------------------------------------------------------------- /day12/.gitignore: -------------------------------------------------------------------------------- 1 | day12 2 | -------------------------------------------------------------------------------- /day12/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | use "time" 6 | 7 | actor Main is TestList 8 | new create(env: Env) => PonyTest(env, this) 9 | new make() => None 10 | 11 | fun tag tests(test: PonyTest) => 12 | test(_TestParse) 13 | // test(_TestSample) 14 | // test(_TestPuzzle) 15 | test(_TestPuzzle2) 16 | 17 | class CpyInst 18 | let x: (String|I64) 19 | let y: String 20 | new create(x': (String|I64), y': String) => 21 | x = x' 22 | y = y' 23 | fun apply(bunny: Assembly) ? => 24 | match x 25 | | let reg: String => bunny.registers(y) = bunny.registers(reg) 26 | | let int: I64 => bunny.registers(y) = int 27 | end 28 | bunny.ip = bunny.ip + 1 29 | fun string(): String => 30 | "cpy " + x.string() + " " + y 31 | 32 | class IncInst 33 | let x: String 34 | new create(x': String) => 35 | x = x' 36 | fun apply(bunny: Assembly) ? => 37 | bunny.registers(x) = bunny.registers(x) + 1 38 | bunny.ip = bunny.ip + 1 39 | fun string(): String => 40 | "inc " + x 41 | 42 | class DecInst 43 | let x: String 44 | new create(x': String) => 45 | x = x' 46 | fun apply(bunny: Assembly) ? => 47 | bunny.registers(x) = bunny.registers(x) - 1 48 | bunny.ip = bunny.ip + 1 49 | fun string(): String => 50 | "dec " + x 51 | 52 | class JnzInst 53 | let x: (String|I64) 54 | let y: I64 55 | new create(x': (String|I64), y': I64) => 56 | x = x' 57 | y = y' 58 | fun apply(bunny: Assembly) ? => 59 | let int: I64 = match x 60 | | let reg: String => bunny.registers(reg) 61 | | let v: I64 => v 62 | else 0 end 63 | 64 | if int != 0 then 65 | // Debug.out("jumping by " + y.string()) 66 | bunny.ip = (bunny.ip.i64() + y).usize() 67 | else 68 | bunny.ip = bunny.ip + 1 69 | end 70 | fun string(): String => 71 | "jnz " + x.string() + " " + y.string() 72 | 73 | type Inst is (CpyInst|IncInst|DecInst|JnzInst) 74 | 75 | class Assembly 76 | let registers: Map[String, I64] = Map[String, I64] 77 | var ip: USize = 0 78 | 79 | new create() => 80 | registers("a") = 0 81 | registers("b") = 0 82 | registers("c") = 0 83 | registers("d") = 0 84 | 85 | fun ref exec(instructions: Array[Inst]) => 86 | while ip < instructions.size() do 87 | try 88 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string()) 89 | instructions(ip).apply(this) 90 | else 91 | Debug.err("*** failed") 92 | end 93 | end 94 | try 95 | Debug.out("a = " + registers("a").string()) 96 | end 97 | 98 | fun parse(lines: Array[String]): Array[Inst] => 99 | let instructions = Array[Inst] 100 | try 101 | let cpy = Regex("cpy ([a-d]) ([a-d])") 102 | let cpy' = Regex("cpy (-?\\d+) ([a-d])") 103 | let inc = Regex("inc ([a-d])") 104 | let dec = Regex("dec ([a-d])") 105 | let jnz = Regex("jnz ([a-d]) (-?\\d+)") 106 | let jnz' = Regex("jnz (-?\\d+) (-?\\d+)") 107 | 108 | for line in lines.values() do 109 | if cpy == line then 110 | let matched = cpy(line) 111 | instructions.push(CpyInst(matched(1), matched(2))) 112 | elseif cpy' == line then 113 | let matched = cpy'(line) 114 | instructions.push(CpyInst(matched(1).read_int[I64]()._1, matched(2))) 115 | elseif inc == line then 116 | let matched = inc(line) 117 | instructions.push(IncInst(matched(1))) 118 | elseif dec == line then 119 | let matched = dec(line) 120 | instructions.push(DecInst(matched(1))) 121 | elseif jnz == line then 122 | let matched = jnz(line) 123 | instructions.push(JnzInst(matched(1), matched(2).read_int[I64]()._1)) 124 | elseif jnz' == line then 125 | let matched = jnz'(line) 126 | instructions.push(JnzInst(matched(1).read_int[I64]()._1, matched(2).read_int[I64]()._1)) 127 | else 128 | Debug.err(" ** No match for " + line) 129 | end 130 | end 131 | else 132 | Debug.err("** Parse") 133 | end 134 | instructions 135 | 136 | class iso _TestParse is UnitTest 137 | fun name(): String => "parse" 138 | fun apply(h: TestHelper) ? => 139 | let bunny: Assembly ref = Assembly 140 | let r: Array[Inst] = bunny.parse(INPUT.sample().split("\n")) 141 | match r(0) 142 | | let cpy: CpyInst => 143 | h.assert_eq[I64](41, cpy.x as I64) 144 | h.assert_eq[String]("a", cpy.y) 145 | else 146 | h.fail("not a cpy") 147 | end 148 | match r(1) 149 | | let inc: IncInst => 150 | h.assert_eq[String]("a", inc.x) 151 | else 152 | h.fail("not inc") 153 | end 154 | match r(2) 155 | | let inc: IncInst => 156 | h.assert_eq[String]("a", inc.x) 157 | else 158 | h.fail("not inc") 159 | end 160 | match r(3) 161 | | let dec: DecInst => 162 | h.assert_eq[String]("a", dec.x) 163 | else 164 | h.fail("not dec") 165 | end 166 | match r(4) 167 | | let jnz: JnzInst => 168 | h.assert_eq[String]("a", jnz.x as String) 169 | h.assert_eq[I64](2, jnz.y) 170 | else 171 | h.fail("not jnz") 172 | end 173 | match r(5) 174 | | let dec: DecInst => 175 | h.assert_eq[String]("a", dec.x) 176 | else 177 | h.fail("not dec") 178 | end 179 | 180 | class iso _TestSample is UnitTest 181 | fun name(): String => "sample" 182 | fun apply(h: TestHelper) => 183 | let bunny: Assembly ref = Assembly 184 | let r: Array[Inst] = bunny.parse(INPUT.sample().split("\n")) 185 | bunny.exec(r) 186 | 187 | class iso _TestPuzzle is UnitTest 188 | fun name(): String => "puzzle" 189 | fun apply(h: TestHelper) => 190 | let bunny: Assembly ref = Assembly 191 | let r: Array[Inst] = bunny.parse(INPUT.puzzle().split("\n")) 192 | for i in r.values() do 193 | Debug.out(i.string()) 194 | end 195 | bunny.exec(r) 196 | 197 | class iso _TestPuzzle2 is UnitTest 198 | fun name(): String => "puzzle2" 199 | fun apply(h: TestHelper) => 200 | let bunny: Assembly ref = Assembly 201 | bunny.registers("c") = 1 202 | let r: Array[Inst] = bunny.parse(INPUT.puzzle().split("\n")) 203 | for i in r.values() do 204 | Debug.out(i.string()) 205 | end 206 | bunny.exec(r) 207 | -------------------------------------------------------------------------------- /day12/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | """cpy 41 a 4 | inc a 5 | inc a 6 | dec a 7 | jnz a 2 8 | dec a""" 9 | 10 | fun puzzle(): String => 11 | """cpy 1 a 12 | cpy 1 b 13 | cpy 26 d 14 | jnz c 2 15 | jnz 1 5 16 | cpy 7 c 17 | inc d 18 | dec c 19 | jnz c -2 20 | cpy a c 21 | inc a 22 | dec b 23 | jnz b -2 24 | cpy c b 25 | dec d 26 | jnz d -6 27 | cpy 18 c 28 | cpy 11 d 29 | inc a 30 | dec d 31 | jnz d -2 32 | dec c 33 | jnz c -5""" 34 | -------------------------------------------------------------------------------- /day13/.gitignore: -------------------------------------------------------------------------------- 1 | day13 2 | -------------------------------------------------------------------------------- /day13/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | use "time" 6 | 7 | actor Main is TestList 8 | new create(env: Env) => PonyTest(env, this) 9 | new make() => None 10 | 11 | fun tag tests(test: PonyTest) => 12 | test(_TestBuild) 13 | test(_TestSample) 14 | test(_TestPuzzle) 15 | test(_TestPuzzle2) 16 | 17 | class val State 18 | let moves: USize 19 | let location: (USize, USize) 20 | let maze: String 21 | new val create(moves': USize, location': (USize, USize), maze': String) => 22 | moves = moves' 23 | location = location' 24 | maze = maze' 25 | fun location_string(): String => 26 | "(" + location._1.string() + "," + location._2.string() + ")" 27 | fun string(): String => 28 | "@" + moves.string() + location_string() 29 | 30 | class val Lookup 31 | let width: USize 32 | new val create(width': USize) => 33 | width = width' 34 | fun _index(loc: (USize, USize)): USize => 35 | (let x, let y) = loc 36 | (y * (width + 1)) + x 37 | 38 | actor Router 39 | let env: Env 40 | let visited: String ref 41 | let workers: Array[Worker] = Array[Worker] 42 | var n: USize = 0 43 | let lookup: Lookup 44 | let limit: USize 45 | 46 | new create(env': Env, maze: String, width': USize, limit': USize = 100) => 47 | env = env' 48 | visited = maze.clone() 49 | lookup = Lookup(width') 50 | limit = limit' 51 | 52 | for i in Range(0, 6) do 53 | workers.push(Worker(this, lookup)) 54 | end 55 | 56 | be sum_reached() => 57 | var sum: USize = 0 58 | for c in visited.values() do 59 | if c == '0' then 60 | sum = sum + 1 61 | end 62 | end 63 | env.out.print("Sum reached:" + sum.string()) 64 | 65 | be search(from: State, goal: (USize, USize)) => 66 | if from.moves > limit then 67 | sum_reached() 68 | return 69 | end 70 | if been_there(from.location) then 71 | return 72 | end 73 | try 74 | visited(lookup._index(from.location)) = '0' 75 | if (from.location._1 == goal._1) and (from.location._2 == goal._2) then 76 | env.out.print("win: " + from.moves.string()) 77 | // env.out.print("path: " + visited) 78 | return 79 | end 80 | else 81 | Debug.err("** Err 57") 82 | end 83 | 84 | Debug.out("Searching:" + from.string()) 85 | try 86 | workers(n % workers.size()).search(from, goal) 87 | end 88 | 89 | fun been_there(loc: (USize, USize)): Bool => 90 | try 91 | visited(lookup._index(loc)) == '0' 92 | else 93 | Debug.err("** Err 72") 94 | true 95 | end 96 | 97 | actor Worker 98 | let router: Router 99 | let lookup: Lookup 100 | new create(router': Router, lookup': Lookup) => 101 | router = router' 102 | lookup = lookup' 103 | 104 | be search(from: State, goal: (USize, USize)) => 105 | _search(from, goal, -1, 0) // left 106 | _search(from, goal, 0, -1) // up 107 | _search(from, goal, 1, 0) // right 108 | _search(from, goal, 0, 1) // down 109 | 110 | fun _search(from: State, goal: (USize, USize), dx: ISize, dy: ISize) => 111 | let nx: USize = (from.location._1.isize() + dx).usize() 112 | let ny: USize = (from.location._2.isize() + dy).usize() 113 | let next = (nx, ny) 114 | if available(from, next) then 115 | router.search(make_state(from, next), goal) 116 | end 117 | 118 | fun available(from: State, loc: (USize, USize)): Bool => 119 | try 120 | from.maze(lookup._index(loc)) == '.' 121 | else 122 | false 123 | end 124 | 125 | fun make_state(from: State, next: (USize, USize)): State => 126 | State(from.moves + 1, next, from.maze) 127 | 128 | class Maze 129 | let maze: String ref = String 130 | new create(width: USize, height: USize, c: USize) => 131 | for y in Range(0, height) do 132 | for x in Range(0, width) do 133 | maze.push(if is_odd(count_one_bits(compute_for(x, y, c))) then '#' else '.' end) 134 | end 135 | maze.push('\n') 136 | end 137 | 138 | fun count_one_bits(v: USize): USize => 139 | var c: USize = 0 140 | for i in Range(0, USize.bitwidth()) do 141 | let mask = 1 << i 142 | let check = v and mask 143 | if check > 0 then 144 | c = c + 1 145 | end 146 | end 147 | c 148 | 149 | fun is_odd(v: USize): Bool => 150 | (v % 2) == 1 151 | 152 | fun compute_for(x: USize, y: USize, c: USize): USize => 153 | (x*x) + (3*x) + ((2*x)*y) + y + (y*y) + c 154 | 155 | class iso _TestBuild is UnitTest 156 | fun name(): String => "build" 157 | fun apply(h: TestHelper) => 158 | let maze = Maze(10, 7, 10) 159 | h.assert_eq[USize](0, maze.count_one_bits(0)) 160 | h.assert_eq[USize](1, maze.count_one_bits(1)) 161 | h.assert_eq[USize](1, maze.count_one_bits(2)) 162 | h.assert_eq[USize](2, maze.count_one_bits(3)) 163 | h.assert_eq[USize](1, maze.count_one_bits(4)) 164 | h.assert_eq[USize](3, maze.count_one_bits(7)) 165 | h.assert_eq[USize](64, maze.count_one_bits(0xFFFFFFFFFFFFFFFF)) 166 | h.assert_eq[USize](5, maze.count_one_bits(1364)) 167 | 168 | let exp = """.#.####.## 169 | ..#..#...# 170 | #....##... 171 | ###.#.###. 172 | .##..#..#. 173 | ..##....#. 174 | #...##.### 175 | """ 176 | h.assert_eq[String](exp, maze.maze.clone()) 177 | 178 | Debug.out(maze.maze) 179 | // Debug.out(Maze(62, 78, 1364).maze) 180 | 181 | class iso _TestSample is UnitTest 182 | fun name(): String => "sample" 183 | fun apply(h: TestHelper) => 184 | let maze = Maze(10, 7, 10) 185 | let start = State(0, (1, 1), maze.maze.clone()) 186 | let router = Router(h.env, maze.maze.clone(), 10) 187 | router.search(start, (7, 4)) 188 | 189 | class iso _TestPuzzle is UnitTest 190 | fun name(): String => "puzzle" 191 | fun apply(h: TestHelper) => 192 | let maze = Maze(62, 78, 1364) 193 | let start = State(0, (1, 1), maze.maze.clone()) 194 | let router = Router(h.env, maze.maze.clone(), 62, 86) 195 | router.search(start, (31, 39)) 196 | 197 | class iso _TestPuzzle2 is UnitTest 198 | fun name(): String => "puzzle2" 199 | fun apply(h: TestHelper) => 200 | let maze = Maze(62, 78, 1364) 201 | let start = State(0, (1, 1), maze.maze.clone()) 202 | let router = Router(h.env, maze.maze.clone(), 62, 50) 203 | router.search(start, (31, 39)) 204 | -------------------------------------------------------------------------------- /day14/.gitignore: -------------------------------------------------------------------------------- 1 | day14 2 | -------------------------------------------------------------------------------- /day14/main.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "debug" 3 | use "collections" 4 | use "crypto" 5 | use "time" 6 | 7 | actor Main is TestList 8 | new create(env: Env) => PonyTest(env, this) 9 | new make() => None 10 | 11 | fun tag tests(test: PonyTest) => 12 | test(_TestCollector1) 13 | test(_TestGenerator) 14 | test(_TestStretch) 15 | // test(_TestSample) 16 | // test(_TestSampleActors) 17 | // test(_TestPuzzleActors) 18 | test(_TestPuzzle2Actors) 19 | // test(_TestPuzzle2) 20 | 21 | class iso _TestStretch is UnitTest 22 | fun name(): String => "stretch" 23 | fun apply(h: TestHelper) => 24 | h.assert_eq[String]("577571be4de9dcce85a041ba0410f29f", Generator("abc").apply(0)) 25 | h.assert_eq[String]("a107ff634856bb300138cac6568c0f24", Generator("abc").stretch(0)) 26 | 27 | class iso _TestPuzzle2 is UnitTest 28 | fun name(): String => "puzzle2/iter" 29 | fun apply(h: TestHelper) => 30 | let seed = "zpqevtbw" 31 | let col = CollectorActor(h.env) 32 | let gen = Generator(seed) 33 | for i in Range(0, 10_000_000) do 34 | col.collect(i, gen.stretch(i)) 35 | end 36 | 37 | class iso _TestPuzzle2Actors is UnitTest 38 | fun name(): String => "puzzle2/actors" 39 | 40 | fun apply(h: TestHelper) => 41 | let seed = "zpqevtbw" 42 | let col = CollectorActor(h.env) 43 | let gens = Array[GeneratorActor] 44 | for i in Range(0, 1) do 45 | gens.push(GeneratorActor(seed)) 46 | end 47 | for i in Range(0, 10_000_000) do 48 | try 49 | // Debug.out("i " + i.string()) 50 | let t = i % gens.size() 51 | gens(t).stretch(i, col) 52 | end 53 | end 54 | 55 | class iso _TestPuzzleActors is UnitTest 56 | fun name(): String => "sample/actors" 57 | 58 | fun apply(h: TestHelper) => 59 | let seed = "zpqevtbw" 60 | let col = CollectorActor(h.env) 61 | let gens = Array[GeneratorActor] 62 | for i in Range(0, 8) do 63 | gens.push(GeneratorActor(seed)) 64 | end 65 | for i in Range(0, 10_000_000) do 66 | try 67 | // Debug.out("i " + i.string()) 68 | let t = i % gens.size() 69 | gens(t).generate(i, col) 70 | end 71 | end 72 | 73 | class iso _TestSampleActors is UnitTest 74 | fun name(): String => "sample/actors" 75 | 76 | fun apply(h: TestHelper) => 77 | let seed = "abc" 78 | let col = CollectorActor(h.env) 79 | let gens = Array[GeneratorActor] 80 | for i in Range(0, 8) do 81 | gens.push(GeneratorActor(seed)) 82 | end 83 | for i in Range(0, 23728) do 84 | try 85 | // Debug.out("i " + i.string()) 86 | let t = i % gens.size() 87 | gens(t).generate(i, col) 88 | end 89 | end 90 | 91 | class iso _TestSample is UnitTest 92 | fun name(): String => "sample" 93 | 94 | fun apply(h: TestHelper) => 95 | let col = Collector(h.env) 96 | let gen = Generator("abc") 97 | for i in Range(0, 1040) do 98 | col._collect(i, gen(i)) 99 | end 100 | h.assert_eq[USize](1, col.keys_found) 101 | h.assert_eq[USize](39, col.max_key) 102 | 103 | for i in Range(817, 23728) do 104 | col._collect(i, gen(i)) 105 | end 106 | h.assert_eq[USize](64, col.keys_found) 107 | h.assert_eq[USize](22728, col.max_key) 108 | 109 | class iso _TestGenerator is UnitTest 110 | fun name(): String => "generator" 111 | fun apply(h: TestHelper) => 112 | h.assert_eq[String]("0034e0923cc38887a57bd7b1d4f953df", Generator("abc")(18)) 113 | 114 | class iso _TestCollector1 is UnitTest 115 | fun name(): String => "collector1" 116 | 117 | fun apply(h: TestHelper) => 118 | let col = Collector(h.env) 119 | 120 | col._collect(0, "no") 121 | h.assert_eq[USize](1, col.want) 122 | 123 | col._collect(5, "fffff") 124 | h.assert_eq[USize](1, col.want) 125 | 126 | col._collect(1, "abfffc") 127 | h.assert_eq[USize](1, col.want) 128 | h.assert_eq[USize](0, col.keys_found) 129 | h.assert_eq[USize](0, col.max_key) 130 | 131 | col._collect(2, "xx") 132 | col._collect(3, "yyy") 133 | col._collect(4, "zz") 134 | h.assert_eq[USize](3, col.want) 135 | h.assert_eq[USize](1, col.keys_found) 136 | h.assert_eq[USize](1, col.max_key) 137 | 138 | col._collect(6, "asdfyyyyy134") 139 | h.assert_eq[USize](5, col.want) 140 | h.assert_eq[USize](2, col.keys_found) 141 | h.assert_eq[USize](3, col.max_key) 142 | 143 | actor GeneratorActor 144 | let gen: Generator 145 | 146 | new create(seed': String) => 147 | gen = Generator(seed') 148 | be generate(index: USize, col: CollectorActor) => 149 | col.collect(index, gen(index)) 150 | be stretch(index: USize, col: CollectorActor) => 151 | col.collect(index, gen.stretch(index)) 152 | 153 | actor CollectorActor 154 | let col: Collector 155 | 156 | new create(env': Env) => 157 | col = Collector(env') 158 | 159 | be collect(index: USize, hash: String) => 160 | col._collect(index, hash) 161 | 162 | class Generator 163 | let seed: String 164 | new create(seed': String) => 165 | seed = seed' 166 | 167 | fun apply(index: USize): String => 168 | let attempt = seed + index.string() 169 | _compute(attempt) 170 | 171 | fun _compute(attempt: String): String => 172 | let md5 = Digest.md5() 173 | try 174 | md5.append(attempt) 175 | let sum = md5.final() 176 | ToHexString(sum) 177 | else 178 | Debug.err("**") 179 | "ERROR" 180 | end 181 | 182 | fun stretch(index: USize): String => 183 | let attempt = seed + index.string() 184 | _stretch(_compute(attempt)) 185 | 186 | fun _stretch(old: String): String => 187 | var cur = old 188 | for i in Range(0, 2016) do 189 | cur = _compute(cur) 190 | end 191 | cur 192 | 193 | class Collector 194 | let env: Env 195 | let results: Array[(None|String)] = Array[(None|String)].init(None, 10_000_000) 196 | var want: USize = 0 197 | var keys_found: USize = 0 198 | var max_key: USize = 0 199 | var lastReport: I64 = 0 200 | 201 | new create(env': Env) => 202 | env = env' 203 | 204 | fun ref _collect(index: USize, hash: String) => 205 | try 206 | 207 | let nowSecs = Time.seconds() 208 | if (lastReport + 10) <= nowSecs then 209 | lastReport = nowSecs 210 | env.out.print("want: " + want.string()) 211 | env.out.print("size: " + index.string()) 212 | end 213 | 214 | results(index) = hash 215 | while search_for_key() do 216 | results(want) = None 217 | want = want + 1 218 | if keys_found == 64 then 219 | env.out.print("--64--" + max_key.string()) 220 | end 221 | end 222 | end 223 | 224 | fun ref search_for_key():Bool => 225 | try 226 | match results(want) 227 | | let h: String => 228 | return search_for_three(h) 229 | end 230 | end 231 | false 232 | 233 | fun ref search_for_three(h: String): Bool => 234 | for i in Range(2, h.size()) do 235 | try 236 | let a = h(i - 2) 237 | let b = h(i - 1) 238 | let c = h(i) 239 | 240 | if (a == b) and (b == c) then 241 | // Debug.out("3 was " + h + "@" + want.string()) 242 | return search_for_five(a) 243 | end 244 | else 245 | Debug.err("**") 246 | end 247 | end 248 | true // skip on 249 | 250 | fun ref search_for_five(char: U8): Bool => 251 | for i in Range(want + 1, want + 1 + 1000) do 252 | try 253 | match results(i) 254 | | let h: String => 255 | if is_key(char, h) then 256 | keys_found = keys_found + 1 257 | max_key = max_key.max(want) 258 | env.out.print("5 was " + h + "#" + keys_found.string()) 259 | // Debug.out("5 was " + h + "@" + i.string()) 260 | return true 261 | end 262 | else 263 | return false // still waiting for some hashes 264 | end 265 | end 266 | end 267 | true // no key found 268 | 269 | fun ref is_key(char: U8, h: String): Bool => 270 | for i in Range(4, h.size()) do 271 | try 272 | let a = h(i - 4) 273 | let b = h(i - 3) 274 | let c = h(i - 2) 275 | let d = h(i - 1) 276 | let e = h(i) 277 | match (a, b, c, d, e) 278 | | (char, char, char, char, char) => 279 | return true 280 | end 281 | end 282 | end 283 | false 284 | -------------------------------------------------------------------------------- /day15/.gitignore: -------------------------------------------------------------------------------- 1 | day15 2 | -------------------------------------------------------------------------------- /day15/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | class Disk 4 | let start: USize 5 | let positions: USize 6 | new create(start': USize, positions': USize) => 7 | start = start' 8 | positions = positions' 9 | 10 | fun at_time(t: USize): USize => 11 | (start + t) % positions 12 | 13 | fun string(d: USize): String => 14 | String() 15 | .append("Disc #").append(d.string()) 16 | .append(" has ").append(positions.string()).append(" positions;") 17 | .append(" at time=0, it is at position ").append(start.string()).append(".") 18 | .clone() 19 | 20 | actor Main 21 | let env: Env 22 | new create(env': Env) => 23 | env = env' 24 | 25 | let z = Disk(4, 5).at_time(6) 26 | let x = Disk(1, 2).at_time(7) 27 | env.out.print("z: " + z.string()) 28 | env.out.print("x: " + x.string()) 29 | 30 | let disks = Array[Disk] 31 | disks.push(Disk(1, 13)) 32 | disks.push(Disk(10, 19)) 33 | disks.push(Disk(2, 3)) 34 | disks.push(Disk(1, 7)) 35 | disks.push(Disk(3, 5)) 36 | disks.push(Disk(5, 17)) 37 | disks.push(Disk(0, 11)) 38 | 39 | try 40 | for i in Range(0, disks.size()) do 41 | env.out.print(disks(i).string(i + 1)) 42 | end 43 | 44 | for time in Range(0, 10_000_000) do 45 | var bounce = false 46 | for d in Range(0, disks.size()) do 47 | let dt = time + d + 1 48 | let pt = disks(d).at_time(dt) 49 | if pt != 0 then 50 | bounce = true 51 | continue 52 | end 53 | end 54 | if bounce == false then 55 | env.out.print("win@" + time.string()) 56 | end 57 | end 58 | end 59 | 60 | /* 61 | Disc #1 has 13 positions; at time=0, it is at position 1. 62 | Disc #2 has 19 positions; at time=0, it is at position 10. 63 | Disc #3 has 3 positions; at time=0, it is at position 2. 64 | Disc #4 has 7 positions; at time=0, it is at position 1. 65 | Disc #5 has 5 positions; at time=0, it is at position 3. 66 | Disc #6 has 17 positions; at time=0, it is at position 5. 67 | */ 68 | -------------------------------------------------------------------------------- /day16/.gitignore: -------------------------------------------------------------------------------- 1 | day16 2 | -------------------------------------------------------------------------------- /day16/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | 4 | actor Main is TestList 5 | new create(env: Env) => PonyTest(env, this) 6 | new make() => None 7 | 8 | fun tag tests(test: PonyTest) => 9 | test(_TestDragon1) 10 | test(_TestDragonCk1) 11 | test(_TestDragonFill) 12 | test(_TestPuzzle) 13 | 14 | class DragonCurve 15 | fun apply(a: String): String => 16 | let b = a.clone() 17 | let b' = b.reverse() 18 | try 19 | for i in Range(0, b'.size()) do 20 | match b'(i) 21 | | '0' => b'(i) = '1' 22 | | '1' => b'(i) = '0' 23 | end 24 | end 25 | end 26 | a + "0" + b'.clone() 27 | 28 | fun checksum(s: String, len: USize): String => 29 | recover val 30 | let ck: String ref = String 31 | let w: String ref = (s.clone().truncate(len)) 32 | for i in Range(0, w.size()/2) do 33 | try 34 | let l = w(i * 2) 35 | let r = w( (i * 2) + 1) 36 | match (l, r) 37 | | ('0', '0') => ck.append("1") 38 | | ('1', '1') => ck.append("1") 39 | | ('0', '1') => ck.append("0") 40 | | ('1', '0') => ck.append("0") 41 | end 42 | end 43 | end 44 | if (ck.size() % 2) == 0 then 45 | checksum(ck.clone(), len) 46 | else 47 | ck 48 | end 49 | end 50 | 51 | fun fill(seed: String, len: USize): String => 52 | var f = seed 53 | while f.size() < len do 54 | f = apply(f) 55 | end 56 | checksum(f, len) 57 | 58 | class iso _TestDragon1 is UnitTest 59 | fun name(): String => "dragon1" 60 | 61 | fun apply(h: TestHelper) => 62 | let curve = DragonCurve 63 | 64 | h.assert_eq[String]("100", curve("1")) 65 | h.assert_eq[String]("001", curve("0")) 66 | h.assert_eq[String]("11111000000", curve("11111")) 67 | h.assert_eq[String]("1111000010100101011110000", curve("111100001010")) 68 | 69 | class iso _TestDragonCk1 is UnitTest 70 | fun name(): String => "checksum" 71 | 72 | fun apply(h: TestHelper) => 73 | let curve = DragonCurve 74 | 75 | h.assert_eq[String]("100", curve.checksum("110010110100", 12)) 76 | 77 | class iso _TestDragonFill is UnitTest 78 | fun name(): String => "fill" 79 | 80 | fun apply(h: TestHelper) => 81 | let curve = DragonCurve 82 | 83 | h.assert_eq[String]("01100", curve.fill("10000", 20)) 84 | 85 | class iso _TestPuzzle is UnitTest 86 | fun name(): String => "puzzle" 87 | 88 | fun apply(h: TestHelper) => 89 | let curve = DragonCurve 90 | 91 | h.env.out.print("--1--" + curve.fill("10001110011110000", 272)) 92 | h.env.out.print("--2--" + curve.fill("10001110011110000", 35651584)) 93 | -------------------------------------------------------------------------------- /day17/.gitignore: -------------------------------------------------------------------------------- 1 | day17 2 | -------------------------------------------------------------------------------- /day17/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "debug" 4 | use "crypto" 5 | 6 | actor Main is TestList 7 | new create(env: Env) => PonyTest(env, this) 8 | new make() => None 9 | 10 | fun tag tests(test: PonyTest) => 11 | test(_TestPathSearch) 12 | 13 | primitive INPUT 14 | fun room(): String => 15 | """######### 16 | #S| | | # 17 | #-#-#-#-# 18 | # | | | # 19 | #-#-#-#-# 20 | # | | | # 21 | #-#-#-#-# 22 | # | | | 23 | ####### V""" 24 | 25 | class val State 26 | let location: (USize, USize) 27 | let path: String 28 | new val create(location': (USize, USize), path': String) => 29 | location = location' 30 | path = path' 31 | fun string(): String => 32 | let l = location 33 | "("+ l._1.string() + "," + l._2.string() + ")" + path 34 | 35 | actor Router 36 | let env: Env 37 | let seed: String 38 | let visited: Set[String] = Set[String] 39 | let height: USize = 4 40 | let width: USize = 4 41 | let workers: Array[Worker] 42 | var next: USize = 0 43 | var win: Bool = false 44 | 45 | new create(env': Env, seed': String) => 46 | env = env' 47 | seed = seed' 48 | workers = Array[Worker] 49 | for i in Range(0, 6) do 50 | workers.push(Worker(env, this, width, height, seed)) 51 | end 52 | 53 | be route(state: State) => 54 | // if win then 55 | // return 56 | // end 57 | if visited.contains(state.path) then 58 | return 59 | end 60 | visited.set(state.path) 61 | if (state.location._1 == 3) and (state.location._2 == 3) then 62 | env.out.print( 63 | "win: length: " + state.path.size().string() + 64 | " path: " + state.path) 65 | win = true 66 | return 67 | end 68 | // Debug.out("state: " + state.string()) 69 | try 70 | workers(next % workers.size()).next_states(state) 71 | end 72 | 73 | actor Worker 74 | let env: Env 75 | let router: Router 76 | let width: USize 77 | let height: USize 78 | let seed: String 79 | 80 | new create(env': Env, router': Router, 81 | width': USize, height': USize, seed': String) 82 | => 83 | env = env' 84 | router = router' 85 | width = width' 86 | height = height' 87 | seed = seed' 88 | be next_states(state: State) => 89 | if state.location._1 > 0 then 90 | maybe_route(state, "L") 91 | end 92 | if (state.location._1 + 1) < width then 93 | maybe_route(state, "R") 94 | end 95 | if state.location._2 > 0 then 96 | maybe_route(state, "U") 97 | end 98 | if (state.location._2 + 1) < height then 99 | maybe_route(state, "D") 100 | end 101 | 102 | fun maybe_route(cur: State, move: String) => 103 | try 104 | let next = _next_state(cur, move) 105 | let k = seed + cur.path 106 | let h = _compute(k) 107 | // Debug.out("checking: " + k + "=" + h + " for " + move) 108 | let idx: USize = match move 109 | | "U" => 0 110 | | "D" => 1 111 | | "L" => 2 112 | | "R" => 3 113 | else 114 | env.err.print("** Bad move") 115 | error 116 | end 117 | let c = h(idx) 118 | let open: Bool = match c 119 | | 'b' => true 120 | | 'c' => true 121 | | 'd' => true 122 | | 'e' => true 123 | | 'f' => true 124 | else 125 | false 126 | end 127 | if open then 128 | router.route(next) 129 | end 130 | else 131 | env.err.print("** Error") 132 | end 133 | 134 | fun _next_state(state: State, move: String): State ? => 135 | let location' = match move 136 | | "L" => (state.location._1 - 1, state.location._2) 137 | | "R" => (state.location._1 + 1, state.location._2) 138 | | "U" => (state.location._1, state.location._2 - 1) 139 | | "D" => (state.location._1, state.location._2 + 1) 140 | else 141 | Debug.err("** Bad move") 142 | error 143 | end 144 | State(location', state.path + move) 145 | 146 | fun _compute(attempt: String): String ? => 147 | let md5 = Digest.md5() 148 | try 149 | md5.append(attempt) 150 | let sum = md5.final() 151 | ToHexString(sum) 152 | else 153 | Debug.err("** Digest") 154 | error 155 | end 156 | 157 | class iso _TestPathSearch is UnitTest 158 | fun name(): String => "path" 159 | 160 | fun apply(h: TestHelper) => 161 | let start = State((0,0), "") 162 | // let router = Router(h.env, "hijkl") 163 | // router.route(start) 164 | 165 | // let router = Router(h.env, "ihgpwlah") 166 | // router.route(start) 167 | 168 | // let router = Router(h.env, "kglvqrro") 169 | // router.route(start) 170 | 171 | // let router = Router(h.env, "ulqzkmiv") 172 | // router.route(start) 173 | 174 | let router = Router(h.env, "rrrbmfta") 175 | router.route(start) 176 | -------------------------------------------------------------------------------- /day18/.gitignore: -------------------------------------------------------------------------------- 1 | day18 2 | -------------------------------------------------------------------------------- /day18/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "debug" 4 | use "time" 5 | 6 | actor Main is TestList 7 | new create(env: Env) => PonyTest(env, this) 8 | new make() => None 9 | 10 | fun tag tests(test: PonyTest) => 11 | test(_TestSample) 12 | // test(_TestPuzzle) 13 | // test(_TestSample2) 14 | // test(_TestPuzzle2) 15 | 16 | class Traps 17 | let rows: Array[String] = Array[String] 18 | new create(init: String, total_rows: USize) => 19 | var prior: String ref = init.clone() 20 | rows.push(init) 21 | for i in Range(0, total_rows - 1) do 22 | prior = add_row(prior, init.size()) 23 | rows.push(prior.clone()) 24 | end 25 | 26 | fun print_floor() => 27 | for r in rows.values() do 28 | Debug.out(r) 29 | end 30 | 31 | fun count_safe(): USize => 32 | var n: USize = 0 33 | for r in rows.values() do 34 | for c in r.values() do 35 | if c == '.' then 36 | n = n + 1 37 | end 38 | end 39 | end 40 | n 41 | 42 | fun add_row(floor: String ref, width: USize): String ref => 43 | let result: String ref = String 44 | for i in Range(0, width) do 45 | let left = try floor(i - 1) else '.' end 46 | let center = try floor(i) else '.' end 47 | let right = try floor(i + 1) else '.' end 48 | let tile: U8 = match (left, center, right) 49 | | ('^', '^', '.') => '^' 50 | | ('.', '^', '^') => '^' 51 | | ('^', '.', '.') => '^' 52 | | ('.', '.', '^') => '^' 53 | else 54 | '.' 55 | end 56 | result.push(tile) 57 | end 58 | result 59 | 60 | class iso _TestSample is UnitTest 61 | fun name(): String => "sample" 62 | fun apply(h: TestHelper) => 63 | let floor: String ref = String 64 | let traps: Traps ref = Traps(".", 1) 65 | floor.append("..^^.") 66 | Debug.out(floor) 67 | var r = floor 68 | for i in Range(0, 4) do 69 | r = traps.add_row(r, floor.size()) 70 | Debug.out(r) 71 | end 72 | 73 | r = String.append(".^^.^.^^^^") 74 | Debug.out(r) 75 | for i in Range(0, 9) do 76 | r = traps.add_row(r, r.size()) 77 | Debug.out(r) 78 | end 79 | 80 | Traps("..^^.", 3).print_floor() 81 | Debug.out("---------------") 82 | Traps(".^^.^.^^^^", 10).print_floor() 83 | 84 | h.assert_eq[USize](6, Traps("..^^.", 3).count_safe()) 85 | h.assert_eq[USize](38, Traps(".^^.^.^^^^", 10).count_safe()) 86 | 87 | h.assert_eq[USize](2016, 88 | Traps( 89 | "^..^^.^^^..^^.^...^^^^^....^.^..^^^.^.^.^^...^.^.^.^.^^.....^.^^.^.^.^.^.^.^^..^^^^^...^.....^....^.", 90 | 40 91 | ).count_safe() 92 | ) 93 | h.assert_eq[USize](19998750, 94 | Traps( 95 | "^..^^.^^^..^^.^...^^^^^....^.^..^^^.^.^.^^...^.^.^.^.^^.....^.^^.^.^.^.^.^.^^..^^^^^...^.....^....^.", 96 | 400000 97 | ).count_safe() 98 | ) 99 | 100 | class iso _TestSample2 is UnitTest 101 | fun name(): String => "sample2" 102 | fun apply(h: TestHelper) => 103 | None 104 | 105 | class iso _TestPuzzle is UnitTest 106 | fun name(): String => "puzzle" 107 | fun apply(h: TestHelper) => 108 | None 109 | 110 | class iso _TestPuzzle2 is UnitTest 111 | fun name(): String => "puzzle" 112 | fun apply(h: TestHelper) => 113 | None 114 | -------------------------------------------------------------------------------- /day19/.gitignore: -------------------------------------------------------------------------------- 1 | day19 2 | -------------------------------------------------------------------------------- /day19/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "debug" 4 | use "time" 5 | 6 | actor Main is TestList 7 | new create(env: Env) => PonyTest(env, this) 8 | new make() => None 9 | 10 | fun tag tests(test: PonyTest) => 11 | // test(_TestSample) 12 | // test(_TestPuzzle) 13 | test(_TestSample2) 14 | test(_TestPuzzle2) 15 | 16 | class Elf 17 | let name: USize 18 | var gifts: USize = 1 19 | new create(name': USize) => 20 | name = name' 21 | fun string(): String => 22 | name.string() + "/" + gifts.string() 23 | 24 | class WhiteEl 25 | fun make_circle(n: USize): List[Elf] => 26 | let circle = List[Elf] 27 | for i in Range(1, n + 1) do 28 | circle.push(Elf(i)) 29 | end 30 | circle 31 | 32 | fun print_circle(circle: List[Elf]) => 33 | Debug.out("--------------------") 34 | for v in circle.values() do 35 | Debug.out("Elf:" + v.string()) 36 | end 37 | 38 | fun next(circle: List[Elf], here: ListNode[Elf]): ListNode[Elf] ? => 39 | match here.next() 40 | | let n': ListNode[Elf] => n' 41 | else circle.head() end 42 | 43 | fun forward(circle: List[Elf], from: ListNode[Elf], dist: USize): ListNode[Elf] ? => 44 | var result = from 45 | for i in Range(0, dist) do 46 | result = next(circle, result) 47 | end 48 | result 49 | 50 | fun take(circle: List[Elf], target: USize) => 51 | try 52 | var n = circle.head() 53 | 54 | while n().gifts < target do 55 | let here = n 56 | n = next(circle, here) 57 | 58 | here().gifts = here().gifts + n().gifts 59 | let dead = n 60 | n = next(circle, dead) 61 | dead.remove() 62 | end 63 | else 64 | Debug.err("** Oops") 65 | end 66 | 67 | fun take2(circle: List[Elf], target: USize) => 68 | try 69 | var lastReport: I64 = 0 70 | var n = circle.head() 71 | var remainingElves = target 72 | 73 | while n().gifts < target do 74 | let nowSecs = Time.seconds() 75 | if (lastReport + 10) <= nowSecs then 76 | lastReport = nowSecs 77 | Debug.out("n:" + n().string() + " size:" + remainingElves.string()) 78 | end 79 | let here = n 80 | n = next(circle, here) 81 | 82 | let dloser = remainingElves / 2 83 | let nloser = forward(circle, here, dloser) 84 | 85 | here().gifts = here().gifts + nloser().gifts 86 | if n is nloser then 87 | n = next(circle, n) 88 | end 89 | nloser.remove() 90 | remainingElves = remainingElves - 1 91 | end 92 | else 93 | Debug.err("** Oops") 94 | end 95 | 96 | class iso _TestSample is UnitTest 97 | fun name(): String => "sample" 98 | fun apply(h: TestHelper) => 99 | let white: WhiteEl ref = WhiteEl 100 | let circle = white.make_circle(5) 101 | white.print_circle(circle) 102 | white.take(circle, 5) 103 | white.print_circle(circle) 104 | 105 | class iso _TestSample2 is UnitTest 106 | fun name(): String => "sample2" 107 | fun apply(h: TestHelper) => 108 | let white: WhiteEl ref = WhiteEl 109 | let circle = white.make_circle(5) 110 | white.print_circle(circle) 111 | white.take2(circle, 5) 112 | white.print_circle(circle) 113 | 114 | class iso _TestPuzzle is UnitTest 115 | fun name(): String => "puzzle" 116 | fun apply(h: TestHelper) => 117 | let white: WhiteEl ref = WhiteEl 118 | let size: USize = 3017957 119 | let circle = white.make_circle(size) 120 | white.take(circle, size) 121 | white.print_circle(circle) 122 | 123 | class iso _TestPuzzle2 is UnitTest 124 | fun name(): String => "puzzle" 125 | fun apply(h: TestHelper) => 126 | let white: WhiteEl ref = WhiteEl 127 | let size: USize = 3017957 128 | let circle = white.make_circle(size) 129 | white.take2(circle, size) 130 | white.print_circle(circle) 131 | -------------------------------------------------------------------------------- /day19b/.gitignore: -------------------------------------------------------------------------------- 1 | day19 2 | -------------------------------------------------------------------------------- /day19b/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "debug" 4 | use "time" 5 | 6 | actor Main is TestList 7 | new create(env: Env) => PonyTest(env, this) 8 | new make() => None 9 | 10 | fun tag tests(test: PonyTest) => 11 | // test(_TestSample) 12 | // test(_TestPuzzle) 13 | test(_TestSample2) 14 | test(_TestPuzzle2) 15 | 16 | class Elf 17 | let name: USize 18 | var gifts: USize = 1 19 | new create(name': USize) => 20 | name = name' 21 | fun string(): String => 22 | name.string() + "/" + gifts.string() 23 | 24 | class WhiteEl 25 | let env: Env 26 | new create(env': Env) => 27 | env = env' 28 | 29 | fun make_circle(n: USize): List[Elf] => 30 | let circle = List[Elf] 31 | for i in Range(1, n + 1) do 32 | circle.push(Elf(i)) 33 | end 34 | circle 35 | 36 | fun print_circle(circle: List[Elf]) => 37 | env.out.print("--------------------") 38 | for v in circle.values() do 39 | env.out.print("Elf:" + v.string()) 40 | end 41 | 42 | fun next(circle: List[Elf], here: ListNode[Elf]): ListNode[Elf] ? => 43 | match here.next() 44 | | let n': ListNode[Elf] => n' 45 | else circle.head() end 46 | 47 | fun forward(circle: List[Elf], from: ListNode[Elf], dist: USize): ListNode[Elf] ? => 48 | var result = from 49 | for i in Range(0, dist) do 50 | result = next(circle, result) 51 | end 52 | result 53 | 54 | fun take(circle: List[Elf], target: USize) => 55 | try 56 | var n = circle.head() 57 | 58 | while n().gifts < target do 59 | let here = n 60 | n = next(circle, here) 61 | 62 | here().gifts = here().gifts + n().gifts 63 | let dead = n 64 | n = next(circle, dead) 65 | dead.remove() 66 | end 67 | else 68 | Debug.err("** Oops") 69 | end 70 | 71 | /* 72 | 26583 is too low 73 | */ 74 | fun take2(circle: List[Elf], target: USize) => 75 | try 76 | let elves = Array[Elf] 77 | for i in Range(0, target) do 78 | elves.push(Elf(i + 1)) 79 | end 80 | 81 | var lastReport: I64 = 0 82 | var cur: USize = 0 83 | while elves.size() > 1 do 84 | let nowSecs = Time.seconds() 85 | if (lastReport + 10) <= nowSecs then 86 | lastReport = nowSecs 87 | env.out.print("remain: " + elves.size().string()) 88 | end 89 | 90 | let nxt = (cur + 1) % elves.size() 91 | let across = ((elves.size() / 2) + cur) % elves.size() 92 | Debug.out("dead: " + elves(across).string()) 93 | elves.remove(across, 1) 94 | cur = nxt 95 | end 96 | 97 | env.out.print("win:" + elves(0).string()) 98 | else 99 | Debug.err("** Oops") 100 | end 101 | 102 | class iso _TestSample is UnitTest 103 | fun name(): String => "sample" 104 | fun apply(h: TestHelper) => 105 | let white: WhiteEl ref = WhiteEl(h.env) 106 | let circle = white.make_circle(5) 107 | white.print_circle(circle) 108 | white.take(circle, 5) 109 | white.print_circle(circle) 110 | 111 | class iso _TestSample2 is UnitTest 112 | fun name(): String => "sample2" 113 | fun apply(h: TestHelper) => 114 | let white: WhiteEl ref = WhiteEl(h.env) 115 | let circle = white.make_circle(5) 116 | white.take2(circle, 5) 117 | 118 | class iso _TestPuzzle is UnitTest 119 | fun name(): String => "puzzle" 120 | fun apply(h: TestHelper) => 121 | let white: WhiteEl ref = WhiteEl(h.env) 122 | let size: USize = 3017957 123 | let circle = white.make_circle(size) 124 | white.take(circle, size) 125 | white.print_circle(circle) 126 | 127 | class iso _TestPuzzle2 is UnitTest 128 | fun name(): String => "puzzle" 129 | fun apply(h: TestHelper) => 130 | let white: WhiteEl ref = WhiteEl(h.env) 131 | let size: USize = 3017957 132 | let circle = white.make_circle(size) 133 | white.take2(circle, size) 134 | -------------------------------------------------------------------------------- /day2/.gitignore: -------------------------------------------------------------------------------- 1 | day2 -------------------------------------------------------------------------------- /day2/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | actor Main 4 | new create(env: Env) => 5 | env.out.print("hi") 6 | let keyPad = KeyPad.make1(env) 7 | try 8 | keyPad(demo_input()) 9 | else 10 | env.err.print("Bad input") 11 | end 12 | env.out.print("--") 13 | // env.out.print("input: " + puzzle_input()) 14 | let real = KeyPad.make1(env) 15 | try 16 | real(puzzle_input()) 17 | else 18 | env.err.print("Bad input2") 19 | end 20 | env.out.print("--") 21 | 22 | part2a(env) 23 | part2b(env) 24 | 25 | fun part2a(env: Env) => 26 | let pad = KeyPad.make2(env) 27 | try 28 | pad(demo_input()) 29 | else 30 | env.err.print("Bad input 3") 31 | end 32 | env.out.print("--") 33 | 34 | fun part2b(env: Env) => 35 | let pad = KeyPad.make2(env) 36 | try 37 | pad(puzzle_input()) 38 | else 39 | env.err.print("Bad input 4") 40 | end 41 | env.out.print("--") 42 | 43 | fun demo_input(): String => 44 | """ULL 45 | RRDDD 46 | LURDL 47 | UUUUD 48 | """ 49 | 50 | fun puzzle_input(): String => 51 | """LDUDDRUDRRURRRRDRUUDULDLULRRLLLUDDULRDLDDLRULLDDLRUURRLDUDDDDLUULUUDDDDLLLLLULLRURDRLRLRLLURDLLDDUULUUUUDLULLRLUUDDLRDRRURRLURRLLLRRDLRUDURRLRRRLULRDLUDRDRLUDDUUULDDDDDURLDULLRDDRRUDDDDRRURRULUDDLLRRDRURDLLLLLUUUDLULURLULLDRLRRDDLUDURUDRLRURURLRRDDLDUULURULRRLLLDRURDULRDUURRRLDLDUDDRLURRDRDRRLDLRRRLRURDRLDRUDLURRUURDLDRULULURRLDLLLUURRULUDDDRLDDUDDDRRLRDUDRUUDDULRDDULDDURULUDLUDRUDDDLRRRRRDLULDRLRRRRUULDUUDRRLURDLLUUDUDDDLUUURDRUULRURULRLLDDLLUDLURRLDRLDDDLULULLURLULRDLDRDDDLRDUDUURUUULDLLRDRUDRDURUUDDLRRRRLLLUULURRURLLDDLDDD 52 | DRURURLLUURRRULURRLRULLLURDULRLRRRLRUURRLRRURRRRUURRRLUDRDUDLUUDULURRLDLULURRLDURLUUDLDUDRUURDDRDLLLDDRDDLUUDRDUDDRRDLDUDRLDDDRLLDDLUDRULRLLURLDLURRDRUDUDLDLULLLRDLLRRDULLDRURRDLDRURDURDULUUURURDLUDRRURLRRLDULRRDURRDRDDULLDRRRLDRRURRRRUURDRLLLRRULLUDUDRRDDRURLULLUUDDRLDRRDUDLULUUDRDDDDLRLRULRLRLLDLLRRDDLDRDURRULLRLRRLULRULDDDRDRULDRUUDURDLLRDRURDRLRDDUDLLRUDLURURRULLUDRDRDURLLLDDDRDRURRDDRLRRRDLLDDLDURUULURULRLULRLLURLUDULDRRDDLRDLRRLRLLULLDDDRDRU 53 | URUUDUDRDDRDRRRDLLUDRUDRUUUURDRRDUDUULDUDLLUDRRUDLLRDLLULULDRRDDULDRLDLDDULLDDRDDDLRLLDLLRDUUDUURLUDURDRRRRLRRLDRRUULLDLDLRDURULRURULRRDRRDDUUURDURLLDDUUDLRLDURULURRRDRRUUUDRDDLRLRRLLULUDDRRLRRRRLRDRUDDUULULRRURUURURRLRUDLRRUUURUULLULULRRDDULDRRLLLDLUDRRRLLRDLLRLDUDDRRULULUDLURLDRDRRLULLRRDRDLUURLDDURRLDRLURULDLDRDLURRDRLUUDRUULLDRDURLLDLRUDDULLLLDLDDDLURDDUDUDDRLRDDUDDURURLULLRLUDRDDUDDLDRUURLDLUUURDUULRULLDDDURULDDLLD 54 | LRRLLRURUURRDLURRULDDDLURDUURLLDLRRRRULUUDDLULLDLLRDLUDUULLUDRLLDRULDDURURDUUULRUDRLLRDDDURLRDRRURDDRUDDRRULULLLDLRLULLDLLDRLLLUDLRURLDULRDDRDLDRRDLUUDDLURDLURLUDLRDLDUURLRRUULDLURULUURULLURLDDURRURDRLUULLRRLLLDDDURLURUURLLLLDLLLUDLDLRDULUULRRLUUUUDLURRURRULULULRURDDRRRRDRUDRURDUDDDDUDLURURRDRRDRUDRLDLDDDLURRRURRUDLDURDRLDLDLDDUDURLUDUUDRULLRLLUUDDUURRRUDURDRRUURLUDRRUDLUDDRUUDLULDLLDLRUUDUULLDULRRLDRUDRRDRLUUDDRUDDLLULRLULLDLDUULLDRUUDDUDLLLLDLDDLDLURLDLRUUDDUULLUDUUDRUDLRDDRDLDRUUDUDLLDUURRRLLLLRLLRLLRLUUDULLRLURDLLRUUDRULLULRDRDRRULRDLUDDURRRRURLLRDRLLDRUUULDUDDLRDRD 55 | DDLRRULRDURDURULLLLRLDDRDDRLLURLRDLULUDURRLUDLDUDRDULDDULURDRURLLDRRLDURRLUULLRUUDUUDLDDLRUUDRRDDRLURDRUDRRRDRUUDDRLLUURLURUDLLRRDRDLUUDLUDURUUDDUULUURLUDLLDDULLUURDDRDLLDRLLDDDRRDLDULLURRLDLRRRLRRURUUDRLURURUULDURUDRRLUDUDLRUDDUDDRLLLULUDULRURDRLUURRRRDLLRDRURRRUURULRUDULDULULUULULLURDUDUDRLDULDRDDULRULDLURLRLDDDDDDULDRURRRRDLLRUDDRDDLUUDUDDRLLRLDLUDRUDULDDDRLLLLURURLDLUUULRRRUDLLULUUULLDLRLDLLRLRDLDULLRLUDDDRDRDDLULUUR 56 | """ 57 | 58 | interface HasMove 59 | fun move(old: (USize, USize)): (USize, USize) 60 | 61 | type Moves is (MoveU|MoveD|MoveL|MoveR|ENDOFLINE) 62 | primitive MoveU is HasMove 63 | fun move(old: (USize, USize)): (USize, USize) => 64 | (old._1 - 1, old._2) 65 | primitive MoveD is HasMove 66 | fun move(old: (USize, USize)): (USize, USize) => 67 | (old._1 + 1, old._2) 68 | primitive MoveL is HasMove 69 | fun move(old: (USize, USize)): (USize, USize) => 70 | (old._1, old._2 - 1) 71 | primitive MoveR is HasMove 72 | fun move(old: (USize, USize)): (USize, USize) => 73 | (old._1, old._2 + 1) 74 | 75 | primitive ENDOFLINE 76 | 77 | class KeyPadKey 78 | let label: String 79 | let row: USize 80 | let col: USize 81 | 82 | new create(label': String, row': USize, col': USize) => 83 | label = label' 84 | row = row' 85 | col = col' 86 | fun string(): String => 87 | label 88 | 89 | class KeyPad 90 | let env: Env 91 | let rows: Array[String] = Array[String] 92 | var location: (USize, USize) 93 | 94 | new make1(env': Env) => 95 | env = env' 96 | rows.push(" ") 97 | rows.push(" 123 ") 98 | rows.push(" 456 ") 99 | rows.push(" 789 ") 100 | rows.push(" ") 101 | location = (2, 2) 102 | 103 | new make2(env': Env) => 104 | env = env' 105 | rows.push(" ") 106 | rows.push(" 1 ") 107 | rows.push(" 234 ") 108 | rows.push(" 56789 ") 109 | rows.push(" ABC ") 110 | rows.push(" D ") 111 | rows.push(" ") 112 | location = (3, 1) 113 | 114 | fun ref loc(): String => 115 | try 116 | rows(location._1).substring(location._2.isize(), location._2.isize() + 1) 117 | else 118 | "err" 119 | end 120 | 121 | fun ref parse(input: String): Array[Moves] ? => 122 | let result = Array[Moves] 123 | for r in input.runes() do 124 | result.push( 125 | match r 126 | | 'U' => MoveU 127 | | 'D' => MoveD 128 | | 'L' => MoveL 129 | | 'R' => MoveR 130 | | '\n' => ENDOFLINE 131 | else 132 | error 133 | end 134 | ) 135 | end 136 | result 137 | 138 | fun ref apply(moves: String) ? => 139 | _apply(parse(moves)) 140 | 141 | fun ref _apply(moves: Array[Moves]) => 142 | for m in moves.values() do 143 | // env.out.write("at-").print(at.string()) 144 | move(m) 145 | end 146 | 147 | fun peek(at: (USize, USize)): String => 148 | try 149 | rows(at._1).substring(at._2.isize(), at._2.isize() + 1) 150 | else 151 | "error" 152 | end 153 | 154 | fun ref move(m: Moves): KeyPad => 155 | match m 156 | | let mover: HasMove val if peek(mover.move(location)) != " " => 157 | location = mover.move(location) 158 | | ENDOFLINE => env.out.write(loc()) 159 | end 160 | // env.out.write("->").print(loc()) 161 | this 162 | -------------------------------------------------------------------------------- /day20/.gitignore: -------------------------------------------------------------------------------- 1 | day20 2 | -------------------------------------------------------------------------------- /day20/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | 6 | actor Main is TestList 7 | new create(env: Env) => PonyTest(env, this) 8 | new make() => None 9 | 10 | fun tag tests(test: PonyTest) => 11 | // test(_TestBlacklist) 12 | test(_TestBlacklist2) 13 | 14 | class Blacklist 15 | let list: Array[(U32, U32)] = Array[(U32, U32)] 16 | 17 | new create(lines: Array[String]) => 18 | try 19 | let r = Regex("(\\d+)-(\\d+)") 20 | for line in lines.values() do 21 | let matched = r(line) 22 | var t1 = matched(1).read_int[U32]()._1 23 | var t2 = matched(2).read_int[U32]()._1 24 | list.push((t1, t2)) 25 | end 26 | else 27 | Debug.err("err1") 28 | end 29 | 30 | fun print() => 31 | for e in list.values() do 32 | Debug.out(e._1.string() + "-" + e._2.string()) 33 | end 34 | 35 | fun search(): U32 => 36 | for i in Range(0, U32.max_value().usize()) do 37 | var blocked = false 38 | for p in list.values() do 39 | if (p._1 <= i.u32()) and (i.u32() <= p._2) then 40 | blocked = true 41 | break 42 | end 43 | end 44 | if not blocked then 45 | return i.u32() 46 | end 47 | end 48 | -1 49 | 50 | fun allowed(ip: U32): Bool => 51 | var blocked = false 52 | for p in list.values() do 53 | if (p._1 <= ip.u32()) and (ip.u32() <= p._2) then 54 | blocked = true 55 | break 56 | end 57 | end 58 | not blocked 59 | 60 | actor Checker 61 | let blacklist: Blacklist val 62 | new create(blacklist': Blacklist val) => 63 | blacklist = blacklist' 64 | 65 | be check(ip: U32, col: Collector) => 66 | if blacklist.allowed(ip) then 67 | col.add() 68 | end 69 | be finish(col: Collector) => 70 | col.finish() 71 | 72 | actor Collector 73 | let env: Env 74 | var count: USize = USize 75 | 76 | new create(env': Env) => 77 | env = env' 78 | be add() => 79 | count = count +1 80 | be finish() => 81 | env.out.print("finish: " + count.string()) 82 | 83 | class iso _TestBlacklist is UnitTest 84 | fun name(): String => "blacklist" 85 | 86 | fun apply(h: TestHelper) => 87 | let blacklist = Blacklist(INPUT.sample().split("\n")) 88 | // blacklist.print() 89 | h.assert_eq[U32](3, blacklist.search()) 90 | let b2 = Blacklist(INPUT.puzzle().split("\n")) 91 | // b2.print() 92 | h.assert_eq[U32](0, b2.search()) 93 | 94 | class iso _TestBlacklist2 is UnitTest 95 | fun name(): String => "blacklist/count" 96 | 97 | fun apply(h: TestHelper) => 98 | // let b2: Blacklist val = recover val Blacklist(INPUT.sample().split("\n")) end 99 | let b2: Blacklist val = recover val Blacklist(INPUT.puzzle().split("\n")) end 100 | let checkers = Array[Checker] 101 | for i in Range(0, 4) do 102 | checkers.push(Checker(b2)) 103 | end 104 | let col = Collector(h.env) 105 | 106 | for i in Range(0, U32.max_value().usize()) do 107 | try 108 | let c = checkers(i % checkers.size()) 109 | c.check(i.u32(), col) 110 | end 111 | end 112 | 113 | for c in checkers.values() do 114 | c.finish(col) 115 | end 116 | -------------------------------------------------------------------------------- /day21/.gitignore: -------------------------------------------------------------------------------- 1 | day21 2 | -------------------------------------------------------------------------------- /day21/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | 6 | actor Main is TestList 7 | new create(env: Env) => PonyTest(env, this) 8 | new make() => None 9 | 10 | fun tag tests(test: PonyTest) => 11 | test(_TestParse) 12 | test(_TestApply) 13 | test(_TestPuzzle) 14 | test(_TestUndo) 15 | test(_TestPuzzle2) 16 | 17 | class SwapPosition 18 | let x: USize 19 | let y: USize 20 | new create(x': USize, y': USize) => 21 | x = x' 22 | y = y' 23 | fun apply(s: String): String => 24 | try 25 | let r = s.clone() 26 | r(x) = s(y) 27 | r(y) = s(x) 28 | r 29 | else 30 | Debug.err("** SP") 31 | s 32 | end 33 | fun undo(s: String): String => 34 | apply(s) 35 | fun string(): String => "swap position" 36 | 37 | class SwapLetter 38 | let x: U8 39 | let y: U8 40 | new create(x': U8, y': U8) => 41 | x = x' 42 | y = y' 43 | fun apply(s: String): String => 44 | try 45 | let r = s.clone() 46 | for i in Range(0, s.size()) do 47 | match s(i) 48 | | x => r(i) = y 49 | | y => r(i) = x 50 | end 51 | end 52 | r 53 | else 54 | Debug.err("** SL") 55 | s 56 | end 57 | fun undo(s: String): String => 58 | apply(s) 59 | fun string(): String => "swap letter" 60 | 61 | class RotateLeft 62 | let steps: USize 63 | new create(steps': USize) => 64 | steps = steps' 65 | fun apply(s: String): String => 66 | try 67 | let r = s.clone() 68 | for i in Range(0, s.size()) do 69 | r(i) = s( (i + steps) % s.size() ) 70 | end 71 | r 72 | else 73 | Debug.err("** RL") 74 | s 75 | end 76 | fun undo(s: String): String => 77 | RotateRight(steps).apply(s) 78 | fun string(): String => "rotate left" 79 | 80 | class RotateRight 81 | let steps: USize 82 | new create(steps': USize) => 83 | steps = steps' 84 | fun apply(s: String): String => 85 | try 86 | let r = s.clone() 87 | for i in Range(0, s.size()) do 88 | r( (i + steps) % s.size() ) = s(i) 89 | end 90 | r 91 | else 92 | Debug.err("** RR") 93 | s 94 | end 95 | fun undo(s: String): String => 96 | RotateLeft(steps).apply(s) 97 | fun string(): String => "rotate right" 98 | 99 | class RotateBasedOnLetter 100 | let letter: U8 101 | new create(letter': U8) => 102 | letter = letter' 103 | fun apply(s: String): String => 104 | try 105 | var off: USize = 0 106 | var found = false 107 | for i in Range(0, s.size()) do 108 | if letter == s(i) then 109 | off = i 110 | found = true 111 | break 112 | end 113 | end 114 | if not found then 115 | Debug.err("Not found: " + letter.string()) 116 | end 117 | if off >= 4 then 118 | off = off + 1 119 | end 120 | off = off + 1 121 | RotateRight(off).apply(s) 122 | else 123 | Debug.err("** RB") 124 | s 125 | end 126 | fun undo(s: String): String => 127 | try 128 | var off: USize = 0 129 | var found = false 130 | for i in Range(0, s.size()) do 131 | if letter == s(i) then 132 | off = i 133 | found = true 134 | break 135 | end 136 | end 137 | if not found then 138 | Debug.err("Not found: " + letter.string()) 139 | end 140 | off = match off 141 | | 1 => 1 142 | | 3 => 2 143 | | 5 => 3 144 | | 7 => 4 145 | | 2 => 6 146 | | 4 => 7 147 | | 6 => 8 148 | | 0 => 9 149 | else 150 | error 151 | end 152 | RotateLeft(off).apply(s) 153 | else 154 | Debug.err("** RB") 155 | s 156 | end 157 | fun string(): String => "rotate letter" 158 | 159 | class ReversePositions 160 | let x: USize 161 | let y: USize 162 | new create(x': USize, y': USize) => 163 | x = x' 164 | y = y' 165 | fun apply(s: String): String => 166 | try 167 | let r = s.clone() 168 | for i in Range(x, y + 1) do 169 | let j = x + (y - i) 170 | r(j) = s(i) 171 | end 172 | r 173 | else 174 | Debug.err("** RP") 175 | s 176 | end 177 | fun undo(s: String): String => 178 | apply(s) 179 | fun string(): String => "reverse position " + x.string() + " " + y.string() 180 | 181 | class MovePosition 182 | let x: USize 183 | let y: USize 184 | new create(x': USize, y': USize) => 185 | x = x' 186 | y = y' 187 | fun apply(s: String): String => 188 | try 189 | let r = s.clone() 190 | r.delete(x.isize()) 191 | r.insert_byte(y.isize(), s(x)) 192 | r 193 | else 194 | Debug.err("** MP") 195 | s 196 | end 197 | fun undo(s: String): String => 198 | try 199 | let r = s.clone() 200 | r.delete(y.isize()) 201 | r.insert_byte(x.isize(), s(y)) 202 | r 203 | else 204 | Debug.err("** MP") 205 | s 206 | end 207 | fun string(): String => "move position" 208 | 209 | type Operation is (SwapPosition|SwapLetter 210 | |RotateLeft|RotateRight|RotateBasedOnLetter 211 | |ReversePositions|MovePosition 212 | ) 213 | 214 | class Scrambler 215 | var pass: String 216 | new create(pass': String) => 217 | pass = pass' 218 | 219 | fun ref apply(op: Operation): String => 220 | pass = op.apply(pass) 221 | pass 222 | 223 | fun ref undo(op: Operation): String => 224 | pass = op.undo(pass) 225 | pass 226 | 227 | fun parse(lines: Array[String]): Array[Operation] ? => 228 | let result = Array[Operation] 229 | for line in lines.values() do 230 | result.push(parseLine(line)) 231 | end 232 | result 233 | 234 | fun parseLine(line: String): Operation ? => 235 | let sp = Regex("swap position (\\d+) with position (\\d+)") 236 | let sl = Regex("swap letter (.) with letter (.)") 237 | let rl = Regex("rotate left (\\d+) steps?") 238 | let rr = Regex("rotate right (\\d+) steps?") 239 | let rb = Regex("rotate based on position of letter (.)") 240 | let rp = Regex("reverse positions (\\d+) through (\\d+)") 241 | let mp = Regex("move position (\\d+) to position (\\d+)") 242 | 243 | if sp == line then 244 | let matched = sp(line) 245 | return SwapPosition( 246 | matched(1).read_int[USize]()._1, 247 | matched(2).read_int[USize]()._1 248 | ) 249 | end 250 | if sl == line then 251 | let matched = sl(line) 252 | return SwapLetter( 253 | matched(1)(0), 254 | matched(2)(0) 255 | ) 256 | end 257 | if rl == line then 258 | let matched = rl(line) 259 | return RotateLeft(matched(1).read_int[USize]()._1) 260 | end 261 | if rr == line then 262 | let matched = rr(line) 263 | return RotateRight(matched(1).read_int[USize]()._1) 264 | end 265 | if rb == line then 266 | let matched = rb(line) 267 | return RotateBasedOnLetter(matched(1)(0)) 268 | end 269 | if rp == line then 270 | let matched = rp(line) 271 | return ReversePositions( 272 | matched(1).read_int[USize]()._1, 273 | matched(2).read_int[USize]()._1 274 | ) 275 | end 276 | if mp == line then 277 | let matched = mp(line) 278 | return MovePosition( 279 | matched(1).read_int[USize]()._1, 280 | matched(2).read_int[USize]()._1 281 | ) 282 | end 283 | Debug.err("Unparsed line: [" + line + "]") 284 | error 285 | 286 | class iso _TestParse is UnitTest 287 | fun name(): String => "parse" 288 | fun apply(h: TestHelper) => 289 | let s: Scrambler ref = Scrambler("".clone()) 290 | try 291 | let ops = s.parse(INPUT.sample().split("\n")) 292 | h.assert_eq[USize](4, (ops(0) as SwapPosition).x) 293 | h.assert_eq[USize](0, (ops(0) as SwapPosition).y) 294 | h.assert_eq[U8]('d', (ops(1) as SwapLetter).x) 295 | h.assert_eq[U8]('b', (ops(1) as SwapLetter).y) 296 | h.assert_eq[USize](0, (ops(2) as ReversePositions).x) 297 | h.assert_eq[USize](4, (ops(2) as ReversePositions).y) 298 | h.assert_eq[USize](1, (ops(3) as RotateLeft).steps) 299 | h.assert_eq[USize](1, (ops(4) as MovePosition).x) 300 | h.assert_eq[USize](4, (ops(4) as MovePosition).y) 301 | h.assert_eq[USize](3, (ops(5) as MovePosition).x) 302 | h.assert_eq[USize](0, (ops(5) as MovePosition).y) 303 | h.assert_eq[U8]('b', (ops(6) as RotateBasedOnLetter).letter) 304 | h.assert_eq[U8]('d', (ops(7) as RotateBasedOnLetter).letter) 305 | else 306 | h.fail("** Parse error") 307 | end 308 | 309 | class iso _TestUndo is UnitTest 310 | fun name(): String => "undo" 311 | fun apply(h: TestHelper) => 312 | /* 313 | NOTE: we don't have to do undo perfect 314 | We just need to undo so that redo ends up with same 315 | scrambled password (I think). It appears that rotate based 316 | on letter is a one way scramble. 317 | */ 318 | // 0 -> 1 319 | h.assert_eq[String]("habcdefg", RotateBasedOnLetter('a').apply("abcdefgh")) 320 | // 1 -> left 1 or 6 321 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('a').undo("habcdefg"), "a") 322 | 323 | // 1 -> 2 324 | h.assert_eq[String]("ghabcdef", RotateBasedOnLetter('b').apply("abcdefgh")) 325 | // 3 -> left 2 326 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('b').undo("ghabcdef"), "b") 327 | 328 | // 2 -> 3 329 | h.assert_eq[String]("fghabcde", RotateBasedOnLetter('c').apply("abcdefgh")) 330 | // 5 -> left 3 331 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('c').undo("fghabcde"), "c") 332 | 333 | // 3 -> 4 334 | h.assert_eq[String]("efghabcd", RotateBasedOnLetter('d').apply("abcdefgh")) 335 | // 7 -> left 4 336 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('d').undo("efghabcd"), "d") 337 | 338 | // 4 -> 6 339 | h.assert_eq[String]("cdefghab", RotateBasedOnLetter('e').apply("abcdefgh")) 340 | // 2 -> left 6 341 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('e').undo("cdefghab"), "e") 342 | 343 | // 5 -> 7 344 | h.assert_eq[String]("bcdefgha", RotateBasedOnLetter('f').apply("abcdefgh")) 345 | // 4 -> left 7 346 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('f').undo("bcdefgha"), "f") 347 | // 01234567 348 | 349 | // 6 -> 8 350 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('g').apply("abcdefgh")) 351 | // 6 -> left 8 352 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('g').undo("abcdefgh"), "g") 353 | 354 | // 7 -> 9 355 | h.assert_eq[String]("habcdefg", RotateBasedOnLetter('h').apply("abcdefgh")) 356 | // 0 -> left 9 357 | h.assert_eq[String]("abcdefgh", RotateBasedOnLetter('h').undo("habcdefg"), "h") 358 | // 01234567 359 | 360 | h.assert_eq[String]("abcefghd", MovePosition(3, 7).apply("abcdefgh")) 361 | h.assert_eq[String]("abcdefgh", MovePosition(3, 7).undo("abcefghd")) 362 | h.assert_eq[String]("abgcdefh", MovePosition(6, 2).apply("abcdefgh")) 363 | h.assert_eq[String]("abcdefgh", MovePosition(6, 2).undo("abgcdefh")) 364 | 365 | class iso _TestApply is UnitTest 366 | fun name(): String => "apply" 367 | fun apply(h: TestHelper) => 368 | let s: Scrambler ref = Scrambler("abcde".clone()) 369 | try 370 | let ops = s.parse(INPUT.sample().split("\n")) 371 | h.assert_eq[String]("ebcda", s(ops(0))) 372 | h.assert_eq[String]("edcba", s(ops(1))) 373 | h.assert_eq[String]("abcde", s(ops(2))) 374 | h.assert_eq[String]("bcdea", s(ops(3))) 375 | h.assert_eq[String]("bdeac", s(ops(4))) 376 | h.assert_eq[String]("abdec", s(ops(5))) 377 | h.assert_eq[String]("ecabd", s(ops(6))) 378 | h.assert_eq[String]("decab", s(ops(7))) 379 | 380 | // h.assert_eq[String]("ecabd", s.undo(ops(7))) 381 | // h.assert_eq[String]("abdec", s.undo(ops(6))) 382 | 383 | h.assert_eq[String]("bdehagcf", ReversePositions(3, 7).apply("bdefcgah")) 384 | else 385 | h.fail("** Apply error") 386 | end 387 | 388 | class iso _TestPuzzle is UnitTest 389 | fun name(): String => "puzzle" 390 | fun apply(h: TestHelper) => 391 | let s: Scrambler ref = Scrambler("abcdefgh".clone()) 392 | try 393 | let ops = s.parse(INPUT.puzzle().split("\n")) 394 | for op in ops.values() do 395 | s(op) 396 | // h.assert_eq[String]("", s.pass, op.string()) 397 | end 398 | h.assert_eq[String]("dgfaehcb", s.pass) 399 | for op in ops.reverse().values() do 400 | s.undo(op) 401 | // h.assert_eq[String]("", s.pass, op.string()) 402 | end 403 | h.assert_eq[String]("abcdefgh", s.pass) 404 | else 405 | h.fail("** Apply error") 406 | end 407 | 408 | class iso _TestPuzzle2 is UnitTest 409 | fun name(): String => "puzzle2" 410 | fun apply(h: TestHelper) => 411 | let s: Scrambler ref = Scrambler("fbgdceah".clone()) 412 | try 413 | let ops = s.parse(INPUT.puzzle().split("\n")) 414 | for op in ops.reverse().values() do 415 | s.undo(op) 416 | // h.assert_eq[String]("", s.pass, op.string()) 417 | end 418 | h.assert_eq[String]("fdhgacbe", s.pass) 419 | else 420 | h.fail("** Apply error") 421 | end 422 | -------------------------------------------------------------------------------- /day21/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | """swap position 4 with position 0 4 | swap letter d with letter b 5 | reverse positions 0 through 4 6 | rotate left 1 step 7 | move position 1 to position 4 8 | move position 3 to position 0 9 | rotate based on position of letter b 10 | rotate based on position of letter d""" 11 | 12 | fun puzzle(): String => 13 | """move position 2 to position 6 14 | move position 0 to position 5 15 | move position 6 to position 4 16 | reverse positions 3 through 7 17 | move position 1 to position 7 18 | swap position 6 with position 3 19 | swap letter g with letter b 20 | swap position 2 with position 3 21 | move position 4 to position 3 22 | move position 6 to position 3 23 | swap position 4 with position 1 24 | swap letter b with letter f 25 | reverse positions 3 through 4 26 | swap letter f with letter e 27 | reverse positions 2 through 7 28 | rotate based on position of letter h 29 | rotate based on position of letter a 30 | rotate based on position of letter e 31 | rotate based on position of letter h 32 | rotate based on position of letter c 33 | move position 5 to position 7 34 | swap letter a with letter d 35 | move position 5 to position 6 36 | swap position 4 with position 0 37 | swap position 4 with position 6 38 | rotate left 6 steps 39 | rotate right 4 steps 40 | rotate right 5 steps 41 | swap letter f with letter e 42 | swap position 2 with position 7 43 | rotate based on position of letter e 44 | move position 4 to position 5 45 | swap position 4 with position 2 46 | rotate right 1 step 47 | swap letter b with letter f 48 | rotate based on position of letter b 49 | reverse positions 3 through 5 50 | move position 3 to position 1 51 | rotate based on position of letter g 52 | swap letter c with letter e 53 | swap position 7 with position 3 54 | move position 0 to position 3 55 | rotate right 6 steps 56 | reverse positions 1 through 3 57 | swap letter d with letter e 58 | reverse positions 3 through 5 59 | move position 0 to position 3 60 | swap letter c with letter e 61 | move position 2 to position 7 62 | swap letter g with letter b 63 | rotate right 0 steps 64 | reverse positions 1 through 3 65 | swap letter h with letter d 66 | move position 4 to position 0 67 | move position 6 to position 3 68 | swap letter a with letter c 69 | reverse positions 3 through 6 70 | swap letter h with letter g 71 | move position 7 to position 2 72 | rotate based on position of letter h 73 | swap letter b with letter h 74 | reverse positions 2 through 6 75 | move position 6 to position 7 76 | rotate based on position of letter a 77 | rotate right 7 steps 78 | reverse positions 1 through 6 79 | move position 1 to position 6 80 | rotate based on position of letter g 81 | rotate based on position of letter d 82 | move position 0 to position 4 83 | rotate based on position of letter e 84 | rotate based on position of letter d 85 | rotate based on position of letter a 86 | rotate based on position of letter a 87 | rotate right 4 steps 88 | rotate based on position of letter b 89 | reverse positions 0 through 4 90 | move position 1 to position 7 91 | rotate based on position of letter e 92 | move position 1 to position 7 93 | swap letter f with letter h 94 | move position 5 to position 1 95 | rotate based on position of letter f 96 | reverse positions 0 through 1 97 | move position 2 to position 4 98 | rotate based on position of letter a 99 | swap letter b with letter d 100 | move position 6 to position 0 101 | swap letter e with letter b 102 | rotate right 7 steps 103 | move position 2 to position 7 104 | rotate left 4 steps 105 | swap position 6 with position 1 106 | move position 3 to position 5 107 | rotate right 7 steps 108 | reverse positions 0 through 6 109 | swap position 2 with position 1 110 | reverse positions 4 through 6 111 | rotate based on position of letter g 112 | move position 6 to position 4""" 113 | -------------------------------------------------------------------------------- /day22/.gitignore: -------------------------------------------------------------------------------- 1 | day22 2 | -------------------------------------------------------------------------------- /day22/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | use "time" 6 | 7 | actor Main is TestList 8 | new create(env: Env) => PonyTest(env, this) 9 | new make() => None 10 | 11 | fun tag tests(test: PonyTest) => 12 | test(_TestParse) 13 | test(_TestCountViablePairs) 14 | test(_TestMakeGridString) 15 | // test(_TestSampleSolve) 16 | test(_TestPuzzle2Solve) 17 | 18 | class val Node 19 | let x: USize 20 | let y: USize 21 | let size: USize 22 | let used: USize 23 | let goal: Bool 24 | 25 | new val create(x': USize, y': USize, size': USize, used': USize, goal': Bool = false) => 26 | x = x' 27 | y = y' 28 | size = size' 29 | used = used' 30 | goal = goal' 31 | 32 | new val make_goal(old: Node) => 33 | x = old.x 34 | y = old.y 35 | size = old.size 36 | used = old.used 37 | goal = true 38 | 39 | fun move_to(to: Node): Node val => 40 | Node(to.x, to.y, size, used, goal) 41 | 42 | fun avail(): USize => 43 | size - used 44 | 45 | fun string(): String => 46 | "x" + x.string() + " y" + y.string() 47 | 48 | class val State 49 | let moves: USize 50 | let nodes: Array[Node] val 51 | new val create(moves': USize, nodes': Array[Node] val) => 52 | moves = moves' 53 | nodes = nodes' 54 | 55 | actor Router 56 | let env: Env 57 | var idx: USize = 0 58 | let workers: Array[Worker] = Array[Worker] 59 | let visited: Set[String] = Set[String] 60 | let grid: Grid = Grid 61 | var win: Bool = false 62 | var moves: USize = 0 63 | var lastReport: I64 = 0 64 | 65 | new create(env': Env) => 66 | env = env' 67 | for i in Range(0, 4) do 68 | workers.push(Worker) 69 | end 70 | 71 | be route_work(s: State) => 72 | let gs = grid.make_grid_string(s.nodes) 73 | if visited.contains(gs) then 74 | // Been here, done that 75 | return 76 | end 77 | visited.set(gs) 78 | Debug.out("route: " + s.moves.string() + "\n" + gs) 79 | 80 | let nowSecs = Time.seconds() 81 | if (lastReport + 10) <= nowSecs then 82 | lastReport = nowSecs 83 | env.out.print("-- " + s.moves.string() + "\n" + gs) 84 | end 85 | 86 | try 87 | if gs(0) == 'G' then 88 | win = true 89 | moves = s.moves 90 | env.out.print("!! win: " + s.moves.string()) 91 | end 92 | end 93 | if win then 94 | return 95 | end 96 | 97 | // Prune states that move G down 98 | try 99 | var found = false 100 | for i in Range(0, gs.size()) do 101 | match gs(i) 102 | | '\n' => break 103 | | 'G' => found = true 104 | end 105 | end 106 | if not found then 107 | return 108 | end 109 | end 110 | 111 | try 112 | workers(idx % workers.size()).next_states(s, this) 113 | end 114 | 115 | actor Worker 116 | be next_states(s: State, router: Router) => 117 | if s.moves >= 300 then 118 | Debug.out("Killing off state") 119 | return 120 | end 121 | let pairs = Grid.find_viable_pairs(s.nodes) 122 | for pair in pairs.values() do 123 | (let a, let b) = pair 124 | let ax = a.x.isize() 125 | let ay = a.y.isize() 126 | let bx = b.x.isize() 127 | let by = b.y.isize() 128 | match ( (ax -bx).abs(), (ay - by).abs() ) 129 | | (1, 0) => router.route_work(swap_pair(s, a, b)) 130 | | (0, 1) => router.route_work(swap_pair(s, a, b)) 131 | | (let dx: USize, let dy: USize) => 132 | // Debug.out("*" + dx.string() + "," + dy.string()) 133 | None 134 | end 135 | end 136 | 137 | fun swap_pair(s: State, a: Node, b: Node): State => 138 | let a' = a.move_to(b) 139 | let b' = b.move_to(a) 140 | let nodes: Array[Node] iso = recover iso Array[Node] end 141 | for n in s.nodes.values() do 142 | if n is a then 143 | nodes.push(a') 144 | elseif n is b then 145 | nodes.push(b') 146 | else 147 | nodes.push(n) 148 | end 149 | end 150 | State(s.moves + 1, consume nodes) 151 | 152 | class Grid 153 | fun parse(lines: Array[String]): Array[Node] => 154 | let result = Array[Node] 155 | try 156 | let df = Regex("/dev/grid/node-x(\\d+)-y(\\d+)\\s+(\\d+)T\\s+(\\d+)T\\s+(\\d+)T\\s+(\\d+)%") 157 | 158 | for line in lines.values() do 159 | if df == line then 160 | let matched = df(line) 161 | let x: USize = matched(1).read_int[USize]()._1 162 | let y = matched(2).read_int[USize]()._1 163 | let size = matched(3).read_int[USize]()._1 164 | let used = matched(4).read_int[USize]()._1 165 | let avail = matched(5).read_int[USize]()._1 166 | let percent = matched(6).read_int[USize]()._1 167 | 168 | let node = Node(x, y, size, used) 169 | if avail != node.avail() then 170 | Debug.err("** Error2") 171 | end 172 | result.push(node) 173 | end 174 | end 175 | else 176 | Debug.err("** Error") 177 | end 178 | result 179 | 180 | fun set_goal(nodes: Array[Node] box): Array[Node] val => 181 | let r: Array[Node] iso = recover iso Array[Node] end 182 | (let width, let height) = size_grid(nodes) 183 | for n in nodes.values() do 184 | match (n.x, n.y) 185 | | (width - 1, 0) => r.push(Node.make_goal(n)) 186 | else r.push(n) end 187 | end 188 | r 189 | 190 | fun size_grid(nodes: Array[Node] box): (USize, USize) => 191 | var max_x: USize = 0 192 | var max_y: USize = 0 193 | for n in nodes.values() do 194 | max_x = max_x.max(n.x) 195 | max_y = max_y.max(n.y) 196 | end 197 | let width = max_x + 1 198 | let height = max_y + 1 199 | (width, height) 200 | 201 | fun make_grid_string(nodes: Array[Node] box): String => 202 | (let width, let height) = size_grid(nodes) 203 | _make_grid_string(nodes, width, height) 204 | 205 | fun _make_grid_string(nodes: Array[Node] box, width: USize, height: USize): String => 206 | let result: String iso = recover iso String end 207 | for y in Range(0, height) do 208 | for x in Range(0, width) do 209 | result.push('#') 210 | end 211 | result.push('\n') 212 | end 213 | 214 | let viable = find_viable_pairs(nodes) 215 | for pair in viable.values() do 216 | (let a, let b) = pair 217 | try 218 | result(idx(a.x, a.y, width)) = '.' 219 | else 220 | Debug.err("** Err 197") 221 | end 222 | end 223 | for pair in viable.values() do 224 | (let a, let b) = pair 225 | try 226 | result(idx(b.x, b.y, width)) = '_' 227 | else 228 | Debug.err("** Err 205") 229 | end 230 | end 231 | for n in nodes.values() do 232 | if n.goal then 233 | try 234 | result(idx(n.x, n.y, width)) = 'G' 235 | end 236 | break 237 | end 238 | end 239 | result 240 | 241 | fun idx(x: USize, y: USize, width: USize): USize => 242 | // width + 1 to handle \n 243 | (y * (width + 1)) + x 244 | 245 | fun find_viable_pairs(nodes: Array[Node] box): Array[(Node, Node)] => 246 | let result = Array[(Node, Node)] 247 | for i in Range(0, nodes.size()) do 248 | for j in Range(0, nodes.size()) do 249 | try 250 | let a = nodes(i) 251 | let b = nodes(j) 252 | 253 | if a.used == 0 then 254 | // Node A is not empty (its Used is not zero). 255 | continue 256 | end 257 | if i == j then 258 | // Nodes A and B are not the same node. 259 | continue 260 | end 261 | if a.used > b.avail() then 262 | // The data on node A (its Used) would fit on node B (its Avail). 263 | continue 264 | end 265 | result.push((a, b)) 266 | else 267 | Debug.err("** Out of bounds") 268 | end 269 | end 270 | end 271 | result 272 | 273 | fun count_viable_pairs(nodes: Array[Node]): USize => 274 | var count: USize = 0 275 | for i in Range(0, nodes.size()) do 276 | for j in Range(0, nodes.size()) do 277 | try 278 | let a = nodes(i) 279 | let b = nodes(j) 280 | 281 | if a.used == 0 then 282 | // Node A is not empty (its Used is not zero). 283 | continue 284 | end 285 | if i == j then 286 | // Nodes A and B are not the same node. 287 | continue 288 | end 289 | if a.used > b.avail() then 290 | // The data on node A (its Used) would fit on node B (its Avail). 291 | continue 292 | end 293 | count = count + 1 294 | else 295 | Debug.err("** Out of bounds") 296 | end 297 | end 298 | end 299 | count 300 | 301 | class iso _TestParse is UnitTest 302 | fun name(): String => "parse" 303 | fun apply(h: TestHelper) ? => 304 | let grid: Grid ref = Grid 305 | let r = grid.parse(INPUT.puzzle().split("\n")) 306 | h.assert_eq[USize](1054, r.size()) 307 | h.assert_eq[USize](91, r(0).size) 308 | h.assert_eq[USize](71, r(0).used) 309 | h.assert_eq[USize](20, r(0).avail()) 310 | 311 | let r' = grid.parse(INPUT.sample().split("\n")) 312 | h.assert_eq[USize](9, r'.size()) 313 | h.assert_eq[USize](10, r'(0).size) 314 | h.assert_eq[USize](8, r'(0).used) 315 | h.assert_eq[USize](2, r'(0).avail()) 316 | 317 | class iso _TestCountViablePairs is UnitTest 318 | fun name(): String => "count viable" 319 | fun apply(h: TestHelper) => 320 | let grid: Grid ref = Grid 321 | let r = grid.parse(INPUT.puzzle().split("\n")) 322 | let viable = grid.count_viable_pairs(r) 323 | h.assert_eq[USize](1024, viable) 324 | 325 | class iso _TestMakeGridString is UnitTest 326 | fun name(): String => "make grid string" 327 | fun apply(h: TestHelper) => 328 | let grid: Grid ref = Grid 329 | let nodes = grid.parse(INPUT.sample().split("\n")) 330 | let gs = grid.make_grid_string(nodes) 331 | 332 | class iso _TestSampleSolve is UnitTest 333 | fun name(): String => "sample solve" 334 | fun apply(h: TestHelper) => 335 | let router = Router(h.env) 336 | let nodes = recover val Grid.parse(INPUT.sample().split("\n")) end 337 | let start = State(0, Grid.set_goal(nodes)) 338 | router.route_work(start) 339 | 340 | class iso _TestPuzzle2Solve is UnitTest 341 | fun name(): String => "puzzle part2" 342 | fun apply(h: TestHelper) => 343 | let router = Router(h.env) 344 | let nodes = recover val Grid.parse(INPUT.puzzle().split("\n")) end 345 | let start = State(0, Grid.set_goal(nodes)) 346 | router.route_work(start) 347 | -------------------------------------------------------------------------------- /day23/.gitignore: -------------------------------------------------------------------------------- 1 | day23 2 | -------------------------------------------------------------------------------- /day23/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | use "time" 6 | 7 | actor Main is TestList 8 | new create(env: Env) => PonyTest(env, this) 9 | new make() => None 10 | 11 | fun tag tests(test: PonyTest) => 12 | // test(_TestParse) 13 | // test(_TestSample) 14 | // test(_TestToggle) 15 | // test(_TestPuzzle) 16 | test(_TestPuzzle2) 17 | 18 | class CpyInst 19 | let x: (String|I64) 20 | let y: (String|I64) 21 | new create(x': (String|I64), y': (String|I64)) => 22 | x = x' 23 | y = y' 24 | fun apply(bunny: Assembly) ? => 25 | let v = match x 26 | | let reg: String => bunny.registers(reg) 27 | | let int: I64 => int 28 | else error end 29 | 30 | match y 31 | | let y': String => bunny.registers(y') = v 32 | // Invalid if its a number so we just skip it 33 | end 34 | bunny.ip = bunny.ip + 1 35 | 36 | fun string(): String => 37 | "cpy " + x.string() + " " + y.string() 38 | 39 | class IncInst 40 | let x: String 41 | new create(x': String) => 42 | x = x' 43 | fun apply(bunny: Assembly) ? => 44 | bunny.registers(x) = bunny.registers(x) + 1 45 | bunny.ip = bunny.ip + 1 46 | fun string(): String => 47 | "inc " + x 48 | 49 | class DecInst 50 | let x: String 51 | new create(x': String) => 52 | x = x' 53 | fun apply(bunny: Assembly) ? => 54 | bunny.registers(x) = bunny.registers(x) - 1 55 | bunny.ip = bunny.ip + 1 56 | fun string(): String => 57 | "dec " + x 58 | 59 | class JnzInst 60 | let x: (String|I64) 61 | let y: (String|I64) 62 | new create(x': (String|I64), y': (String|I64)) => 63 | x = x' 64 | y = y' 65 | fun apply(bunny: Assembly) ? => 66 | let int: I64 = match x 67 | | let reg: String => bunny.registers(reg) 68 | | let v: I64 => v 69 | else error end 70 | 71 | let jmp: I64 = match y 72 | | let reg: String => bunny.registers(reg) 73 | | let v: I64 => v 74 | else error end 75 | 76 | if int != 0 then 77 | // Debug.out("jumping by " + jmp.string()) 78 | bunny.ip = (bunny.ip.i64() + jmp).usize() 79 | else 80 | bunny.ip = bunny.ip + 1 81 | end 82 | fun string(): String => 83 | "jnz " + x.string() + " " + y.string() 84 | 85 | class TglInst 86 | let x: String 87 | new create(x': String) => 88 | x = x' 89 | fun apply(bunny: Assembly) => 90 | try 91 | let off = bunny.registers(x) 92 | let tgt = bunny.instructions((bunny.ip.i64() + off).usize()) 93 | // Debug.out("Target: " + tgt.string()) 94 | let chg: Inst = match tgt 95 | | let inc: IncInst => DecInst(inc.x) 96 | | let dec: DecInst => IncInst(dec.x) 97 | | let tgl: TglInst => IncInst(tgl.x) 98 | | let cpy: CpyInst => JnzInst(cpy.x, cpy.y) 99 | | let jnz: JnzInst => CpyInst(jnz.x, jnz.y) 100 | else 101 | Debug.err("** No match!") 102 | error 103 | end 104 | bunny.instructions((bunny.ip.i64() + off).usize()) = chg 105 | then 106 | bunny.ip = bunny.ip + 1 107 | end 108 | 109 | fun string(): String => 110 | "tgl " + x 111 | 112 | type Inst is (CpyInst|IncInst|DecInst|JnzInst|TglInst) 113 | 114 | class Assembly 115 | let registers: Map[String, I64] = Map[String, I64] 116 | var ip: USize = 0 117 | var instructions: Array[Inst] = Array[Inst] 118 | var lastReport: I64 = 0 119 | var i: ISize = 0 120 | 121 | new create() => 122 | registers("a") = 0 123 | registers("b") = 0 124 | registers("c") = 0 125 | registers("d") = 0 126 | 127 | fun ref exec(instructions': Array[Inst]) => 128 | instructions = instructions' 129 | while ip < instructions.size() do 130 | try 131 | let nowSecs = Time.seconds() 132 | if (lastReport + 10) <= nowSecs then 133 | lastReport = nowSecs 134 | // env.out.print("-- " + s.moves.string() + "\n" + gs) 135 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 136 | end 137 | if (i % 1000) == 0 then 138 | Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 139 | end 140 | instructions(ip).apply(this) 141 | else 142 | Debug.err("*** failed") 143 | end 144 | i = i + 1 145 | end 146 | try 147 | Debug.out("a = " + registers("a").string()) 148 | end 149 | 150 | fun ref step(): Bool => 151 | """ 152 | Returns true if we should keep going 153 | """ 154 | if ip < instructions.size() then 155 | try 156 | let nowSecs = Time.seconds() 157 | if (lastReport + 10) <= nowSecs then 158 | lastReport = nowSecs 159 | // env.out.print("-- " + s.moves.string() + "\n" + gs) 160 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 161 | end 162 | // if (i % 10000) == 0 then 163 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 164 | // end 165 | instructions(ip).apply(this) 166 | else 167 | Debug.err("*** failed") 168 | end 169 | i = i + 1 170 | true 171 | else 172 | try 173 | Debug.out("a = " + registers("a").string()) 174 | end 175 | false 176 | end 177 | 178 | fun regs_string(): String => 179 | try 180 | String 181 | .append("[a:").append(registers("a").string()).append("]") 182 | .append("[b:").append(registers("b").string()).append("]") 183 | .append("[c:").append(registers("c").string()).append("]") 184 | .append("[d:").append(registers("d").string()).append("]").clone() 185 | else 186 | "Error" 187 | end 188 | 189 | fun parse(lines: Array[String]): Array[Inst] => 190 | let result = Array[Inst] 191 | try 192 | let cpy = Regex("cpy ([a-d]) ([a-d])") 193 | let cpy' = Regex("cpy (-?\\d+) ([a-d])") 194 | let inc = Regex("inc ([a-d])") 195 | let dec = Regex("dec ([a-d])") 196 | let jnz = Regex("jnz ([a-d]) (-?\\d+)") 197 | let jnz' = Regex("jnz (-?\\d+) (-?\\d+)") 198 | let jnz'' = Regex("jnz (-?\\d+) ([a-d])") 199 | let tgl = Regex("tgl ([a-d])") 200 | 201 | for line in lines.values() do 202 | if cpy == line then 203 | let matched = cpy(line) 204 | result.push(CpyInst(matched(1), matched(2))) 205 | elseif cpy' == line then 206 | let matched = cpy'(line) 207 | result.push(CpyInst(matched(1).read_int[I64]()._1, matched(2))) 208 | elseif inc == line then 209 | let matched = inc(line) 210 | result.push(IncInst(matched(1))) 211 | elseif dec == line then 212 | let matched = dec(line) 213 | result.push(DecInst(matched(1))) 214 | elseif jnz == line then 215 | let matched = jnz(line) 216 | result.push(JnzInst(matched(1), matched(2).read_int[I64]()._1)) 217 | elseif jnz' == line then 218 | let matched = jnz'(line) 219 | result.push(JnzInst(matched(1).read_int[I64]()._1, matched(2).read_int[I64]()._1)) 220 | elseif jnz'' == line then 221 | let matched = jnz''(line) 222 | result.push(JnzInst(matched(1).read_int[I64]()._1, matched(2))) 223 | elseif tgl == line then 224 | let matched = tgl(line) 225 | result.push(TglInst(matched(1))) 226 | else 227 | Debug.err(" ** No match for " + line) 228 | end 229 | end 230 | else 231 | Debug.err("** Parse") 232 | end 233 | result 234 | 235 | class iso _TestParse is UnitTest 236 | fun name(): String => "parse" 237 | fun apply(h: TestHelper) ? => 238 | let bunny: Assembly ref = Assembly 239 | let r: Array[Inst] = bunny.parse(INPUT.sample().split("\n")) 240 | match r(0) 241 | | let cpy: CpyInst => 242 | h.assert_eq[I64](2, cpy.x as I64) 243 | h.assert_eq[String]("a", cpy.y.string()) 244 | else 245 | h.fail("not a cpy") 246 | end 247 | match r(1) 248 | | let tgl: TglInst => 249 | h.assert_eq[String]("a", tgl.x) 250 | else 251 | h.fail("not tgl") 252 | end 253 | match r(2) 254 | | let tgl: TglInst => 255 | h.assert_eq[String]("a", tgl.x) 256 | else 257 | h.fail("not tgl") 258 | end 259 | match r(3) 260 | | let tgl: TglInst => 261 | h.assert_eq[String]("a", tgl.x) 262 | else 263 | h.fail("not tgl") 264 | end 265 | match r(4) 266 | | let cpy: CpyInst => 267 | h.assert_eq[I64](1, cpy.x as I64) 268 | h.assert_eq[String]("a", cpy.y.string()) 269 | else 270 | h.fail("not cpy") 271 | end 272 | match r(5) 273 | | let dec: DecInst => 274 | h.assert_eq[String]("a", dec.x) 275 | else 276 | h.fail("not dec") 277 | end 278 | match r(6) 279 | | let dec: DecInst => 280 | h.assert_eq[String]("a", dec.x) 281 | else 282 | h.fail("not dec") 283 | end 284 | 285 | /* 286 | - For one-argument instructions, inc becomes dec, and all other one-argument instructions become inc. 287 | - For two-argument instructions, jnz becomes cpy, and all other two-instructions become jnz. 288 | - The arguments of a toggled instruction are not affected. 289 | - If an attempt is made to toggle an instruction outside the program, nothing happens. 290 | - If toggling produces an invalid instruction (like cpy 1 2) and an attempt is 291 | later made to execute that instruction, skip it instead. 292 | - If tgl toggles itself (for example, if a is 0, tgl a would target itself and become inc a), 293 | the resulting instruction is not executed until the next time it is reached. 294 | */ 295 | class iso _TestToggle is UnitTest 296 | fun name(): String => "toggle" 297 | fun apply(h: TestHelper) ? => 298 | let instructions = Array[Inst] 299 | instructions.push(TglInst("b")) 300 | instructions.push(IncInst("a")) 301 | instructions.push(DecInst("a")) 302 | instructions.push(TglInst("a")) 303 | instructions.push(CpyInst("a", "b")) 304 | instructions.push(JnzInst("a", 1)) 305 | 306 | let bunny = Assembly 307 | bunny.registers("b") = 1 308 | bunny.instructions = instructions 309 | try 310 | instructions(0).apply(bunny) 311 | else 312 | h.fail("Apply threw") 313 | end 314 | match instructions(1) 315 | | let dec: DecInst => 316 | h.assert_eq[String]("a", dec.x) 317 | else 318 | h.fail("not dec: " + instructions(1).string()) 319 | end 320 | 321 | bunny.registers("b") = 2 322 | bunny.ip = 0 323 | instructions(0).apply(bunny) 324 | match instructions(2) 325 | | let inc: IncInst => 326 | h.assert_eq[String]("a", inc.x) 327 | else 328 | h.fail("not inc: " + instructions(2).string()) 329 | end 330 | 331 | bunny.registers("b") = 3 332 | bunny.ip = 0 333 | instructions(0).apply(bunny) 334 | match instructions(3) 335 | | let inc: IncInst => 336 | h.assert_eq[String]("a", inc.x) 337 | else 338 | h.fail("not inc: " + instructions(3).string()) 339 | end 340 | 341 | bunny.registers("b") = 4 342 | bunny.ip = 0 343 | instructions(0).apply(bunny) 344 | match instructions(4) 345 | | let jnz: JnzInst => 346 | h.assert_eq[String]("a", jnz.x.string()) 347 | h.assert_eq[String]("b", jnz.y.string()) 348 | else 349 | h.fail("not jnz: " + instructions(3).string()) 350 | end 351 | 352 | bunny.registers("b") = 5 353 | bunny.ip = 0 354 | instructions(0).apply(bunny) 355 | match instructions(5) 356 | | let jnz: CpyInst => 357 | h.assert_eq[String]("a", jnz.x.string()) 358 | h.assert_eq[I64](1, jnz.y as I64) 359 | else 360 | h.fail("not cpy: " + instructions(3).string()) 361 | end 362 | // Verify bad instruction is skipped 363 | bunny.ip = 5 364 | instructions(5).apply(bunny) 365 | h.assert_eq[USize](6, bunny.ip) 366 | 367 | bunny.registers("b") = 100 // Out of bounds 368 | bunny.ip = 0 369 | instructions(0).apply(bunny) 370 | h.assert_eq[USize](1, bunny.ip) 371 | 372 | // Toggle self 373 | bunny.registers("b") = 0 374 | bunny.ip = 0 375 | instructions(0).apply(bunny) 376 | h.assert_eq[USize](1, bunny.ip) 377 | 378 | class iso _TestSample is UnitTest 379 | fun name(): String => "sample" 380 | fun apply(h: TestHelper) ? => 381 | let bunny: Assembly ref = Assembly 382 | let r: Array[Inst] = bunny.parse(INPUT.sample().split("\n")) 383 | bunny.exec(r) 384 | h.assert_eq[I64](3, bunny.registers("a")) 385 | 386 | class iso _TestPuzzle is UnitTest 387 | fun name(): String => "puzzle" 388 | fun apply(h: TestHelper) ? => 389 | let bunny: Assembly ref = Assembly 390 | let r: Array[Inst] = bunny.parse(INPUT.puzzle().split("\n")) 391 | for i in r.values() do 392 | Debug.out(i.string()) 393 | end 394 | bunny.registers("a") = 7 395 | bunny.exec(r) 396 | h.assert_eq[I64](12748, bunny.registers("a")) 397 | 398 | actor Runner 399 | let env: Env 400 | let bunny: Assembly = Assembly 401 | new create(env': Env) => 402 | env = env' 403 | let r: Array[Inst] = bunny.parse(INPUT.puzzle().split("\n")) 404 | for i in r.values() do 405 | Debug.out(i.string()) 406 | end 407 | bunny.instructions = r 408 | bunny.registers("a") = 12 409 | 410 | be step() => 411 | if bunny.step() then 412 | this.step() 413 | else 414 | env.out.print(bunny.regs_string()) 415 | end 416 | 417 | class iso _TestPuzzle2 is UnitTest 418 | fun name(): String => "puzzle2" 419 | fun apply(h: TestHelper) => 420 | let runner = Runner(h.env) 421 | runner.step() 422 | -------------------------------------------------------------------------------- /day23/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | """cpy 2 a 4 | tgl a 5 | tgl a 6 | tgl a 7 | cpy 1 a 8 | dec a 9 | dec a""" 10 | 11 | fun puzzle(): String => 12 | """cpy a b 13 | dec b 14 | cpy a d 15 | cpy 0 a 16 | cpy b c 17 | inc a 18 | dec c 19 | jnz c -2 20 | dec d 21 | jnz d -5 22 | dec b 23 | cpy b c 24 | cpy c d 25 | dec d 26 | inc c 27 | jnz d -2 28 | tgl c 29 | cpy -16 c 30 | jnz 1 c 31 | cpy 94 c 32 | jnz 82 d 33 | inc a 34 | inc d 35 | jnz d -2 36 | inc c 37 | jnz c -5""" 38 | -------------------------------------------------------------------------------- /day24/.gitignore: -------------------------------------------------------------------------------- 1 | day24 2 | -------------------------------------------------------------------------------- /day24/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | use "time" 6 | 7 | actor Main is TestList 8 | new create(env: Env) => PonyTest(env, this) 9 | new make() => None 10 | 11 | fun tag tests(test: PonyTest) => 12 | test(_TestFindGoals) 13 | test(_TestFindDists) 14 | 15 | class val Goal is (Hashable & Equatable[Goal] & Comparable[Goal]) 16 | let name: U8 17 | let location: (USize, USize) 18 | new val create(name': U8, location': (USize, USize)) => 19 | name = name' 20 | location = location' 21 | fun string(): String => 22 | let l = location 23 | let v: U8 = name - '0' 24 | "@" + v.string() + "(" + l._1.string() + "," + l._2.string() + ")" 25 | fun eq(other: Goal): Bool => 26 | name == other.name 27 | fun hash(): U64 => 28 | name.hash() 29 | fun lt(other: Goal): Bool => 30 | name < other.name 31 | 32 | class FindGoals 33 | fun search(maze: String): Array[Goal] => 34 | let lines = maze.split("\n") 35 | let result = Array[Goal] 36 | try 37 | for y in Range(0, lines.size()) do 38 | let line = lines(y) 39 | for x in Range(0, line.size()) do 40 | let c = line(x) 41 | if ('0' <= c) and (c <= '9') then 42 | result.push( Goal(c, (x, y)) ) 43 | end 44 | end 45 | end 46 | end 47 | result 48 | 49 | fun remove_goals(maze: String): String => 50 | let result: String ref = maze.clone() 51 | try 52 | for i in Range(0, maze.size()) do 53 | let c = maze(i) 54 | if ('0' <= c) and (c <= '9') then 55 | result(i) = '.' 56 | end 57 | end 58 | result 59 | else 60 | Debug.err("**: Err") 61 | end 62 | result.clone() 63 | 64 | fun tuple_eq(l: (USize, USize), r: (USize, USize)): Bool => 65 | (l._1 == r._1) and (l._2 == r._2) 66 | 67 | fun tuple_string(l: (USize, USize)): String => 68 | "(" + l._1.string() + "," + l._2.string() + ")" 69 | 70 | class iso _TestFindGoals is UnitTest 71 | fun name(): String => "find" 72 | fun apply(h: TestHelper) => 73 | let find: FindGoals val = FindGoals 74 | let goals = find.search(INPUT.sample()) 75 | for g in goals.values() do 76 | Debug.out("g: " + g.string()) 77 | end 78 | Debug.out("--------------------------") 79 | let goals' = find.search(INPUT.puzzle()) 80 | for g in goals'.values() do 81 | Debug.out("g: " + g.string()) 82 | end 83 | 84 | class Solver 85 | fun solve(env: Env, input: String) => 86 | try 87 | let collector = Collector(env) 88 | let find: FindGoals val = FindGoals 89 | let goals = Sort[Array[Goal], Goal](find.search(input)) 90 | let maze = find.remove_goals(input) 91 | Debug.out(maze) 92 | var count: USize = 0 93 | let goals': Array[Goal] trn = recover trn Array[Goal] end 94 | for goal in goals.values() do 95 | goals'.push(goal) 96 | end 97 | collector.set_goals(consume goals') 98 | 99 | for i in Range(0, goals.size()) do 100 | for j in Range(i + 1, goals.size()) do 101 | let src = goals(i) 102 | let dst = goals(j) 103 | if src == dst then 104 | continue 105 | end 106 | // Debug.out("src:" + src.string() + " dst:" + dst.string()) 107 | 108 | let search = SearchMaze 109 | search(env, maze, src.location, dst.location, collector) 110 | count = count + 1 111 | end 112 | end 113 | Debug.out("There are " + count.string() + " pairs") 114 | collector.set_count(count) 115 | else 116 | Debug.err("** Err") 117 | end 118 | 119 | class iso _TestFindDists is UnitTest 120 | fun name(): String => "dists" 121 | fun apply(h: TestHelper) => 122 | // Solver.solve(h.env, INPUT.sample()) 123 | Solver.solve(h.env, INPUT.puzzle()) 124 | // 470 is too high 125 | // got it with 428 126 | 127 | // 470 is too low to return to 0 128 | -------------------------------------------------------------------------------- /day24/bfs.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "regex" 3 | use "debug" 4 | use "time" 5 | 6 | class val State 7 | let moves: USize 8 | let location: (USize, USize) 9 | let maze: String 10 | new val create(moves': USize, location': (USize, USize), maze': String) => 11 | moves = moves' 12 | location = location' 13 | maze = maze' 14 | fun location_string(): String => 15 | "(" + location._1.string() + "," + location._2.string() + ")" 16 | fun string(): String => 17 | "@" + moves.string() + location_string() 18 | 19 | class val Lookup 20 | let width: USize 21 | new val create(width': USize) => 22 | width = width' 23 | fun _index(loc: (USize, USize)): USize => 24 | (let x, let y) = loc 25 | (y * (width + 1)) + x 26 | 27 | actor Router 28 | let env: Env 29 | let collector: Collector 30 | let start: (USize, USize) 31 | let visited: String ref 32 | let workers: Array[Worker] = Array[Worker] 33 | var n: USize = 0 34 | let lookup: Lookup 35 | let limit: USize 36 | var win: Bool = false 37 | var moves: USize = 0 38 | 39 | new create(env': Env, maze: String, 40 | collector': Collector, 41 | start': (USize, USize), 42 | width': USize, limit': USize = 100) 43 | => 44 | env = env' 45 | collector = collector' 46 | start = start' 47 | visited = maze.clone() 48 | lookup = Lookup(width') 49 | limit = limit' 50 | 51 | for i in Range(0, 6) do 52 | workers.push(Worker(this, lookup)) 53 | end 54 | 55 | be sum_reached() => 56 | var sum: USize = 0 57 | for c in visited.values() do 58 | if c == '0' then 59 | sum = sum + 1 60 | end 61 | end 62 | // env.out.print("Sum reached:" + sum.string()) 63 | 64 | fun location_string(l: (USize, USize)): String => 65 | "(" + l._1.string() + "," + l._2.string() + ")" 66 | 67 | be search(from: State, goal: (USize, USize)) => 68 | if from.moves > limit then 69 | sum_reached() 70 | return 71 | end 72 | if been_there(from.location) then 73 | return 74 | end 75 | try 76 | visited(lookup._index(from.location)) = '0' 77 | if (from.location._1 == goal._1) and (from.location._2 == goal._2) then 78 | moves = moves.min(from.moves) 79 | if not win then 80 | // env.out.print("win: " + from.moves.string() + " " 81 | // + location_string(start) + "=>" + from.location_string() 82 | // ) 83 | collector.record(from.moves, start, from.location) 84 | end 85 | win = true 86 | // env.out.print("path: " + visited) 87 | return 88 | end 89 | else 90 | Debug.err("** Err 57") 91 | end 92 | 93 | // Debug.out("--searching:" + from.string()) 94 | try 95 | workers(n % workers.size()).search(from, goal) 96 | end 97 | 98 | fun been_there(loc: (USize, USize)): Bool => 99 | try 100 | visited(lookup._index(loc)) == '0' 101 | else 102 | Debug.err("** Err 72") 103 | true 104 | end 105 | 106 | actor Worker 107 | let router: Router 108 | let lookup: Lookup 109 | new create(router': Router, lookup': Lookup) => 110 | router = router' 111 | lookup = lookup' 112 | 113 | be search(from: State, goal: (USize, USize)) => 114 | _search(from, goal, -1, 0) // left 115 | _search(from, goal, 0, -1) // up 116 | _search(from, goal, 1, 0) // right 117 | _search(from, goal, 0, 1) // down 118 | 119 | fun _search(from: State, goal: (USize, USize), dx: ISize, dy: ISize) => 120 | let nx: USize = (from.location._1.isize() + dx).usize() 121 | let ny: USize = (from.location._2.isize() + dy).usize() 122 | let next = (nx, ny) 123 | if available(from, next) then 124 | router.search(make_state(from, next), goal) 125 | end 126 | 127 | fun available(from: State, loc: (USize, USize)): Bool => 128 | try 129 | from.maze(lookup._index(loc)) == '.' 130 | else 131 | false 132 | end 133 | 134 | fun make_state(from: State, next: (USize, USize)): State => 135 | State(from.moves + 1, next, from.maze) 136 | 137 | class val Pair 138 | let dist: USize 139 | let src: (USize, USize) 140 | let dst: (USize, USize) 141 | new val create(dist': USize, src': (USize, USize), dst': (USize, USize)) => 142 | dist = dist' 143 | src = src' 144 | dst = dst' 145 | 146 | actor Collector 147 | let env: Env 148 | var count: USize = USize.max_value() 149 | var goals: Array[Goal] val = recover val Array[Goal] end 150 | let pairs: Array[Pair] = Array[Pair] 151 | var best: USize = USize.max_value() 152 | let distances: Map[String, USize] = Map[String, USize] 153 | var searched: USize = 0 154 | 155 | new create(env': Env) => 156 | env = env' 157 | be record(dist: USize, src: (USize, USize), dst: (USize, USize)) => 158 | Debug.out("got: " + tupple(src) + "=>" + tupple(dst) + " dist " + dist.string()) 159 | pairs.push(Pair(dist, src, dst)) 160 | distances(encode(src, dst)) = dist 161 | distances(encode(dst, src)) = dist 162 | 163 | if pairs.size() >= count then 164 | find_shortest() 165 | end 166 | 167 | fun encode(src: (USize, USize), dst: (USize, USize)): String => 168 | tupple(src) + "=>" + tupple(dst) 169 | 170 | fun tupple(l: (USize, USize)): String => 171 | "("+ l._1.string() + "," + l._2.string() + ")" 172 | be set_count(count': USize) => 173 | count = count' 174 | if pairs.size() >= count then 175 | find_shortest() 176 | end 177 | be set_goals(goals': Array[Goal] val) => 178 | goals = goals' 179 | fun ref find_shortest() => 180 | Debug.out("ready --" + goals.size().string()) 181 | try 182 | _find_shortest(0, goals, 0) 183 | // for i in Range(0, goals.size()) do 184 | // _find_shortest(i, goals, 0) 185 | // end 186 | env.out.print("best: " + best.string() + " searched: " + searched.string()) 187 | else 188 | Debug.err("** Grr") 189 | end 190 | Debug.out("done --") 191 | 192 | fun ref _find_shortest(at: USize, remain: Array[Goal] val, traveled: USize) ? => 193 | let src = remain(at) 194 | let r' = recover val 195 | remain.clone().remove(at, 1) 196 | end 197 | if r'.size() == 0 then 198 | // Debug.out("done dist=" + traveled.string()) 199 | // now add the distance from here to 0 200 | if true then 201 | let final = traveled + compute_dist(src, goals(0)) 202 | best = best.min(final) 203 | else 204 | best = best.min(traveled) 205 | end 206 | return 207 | end 208 | 209 | for i in Range(0, r'.size()) do 210 | let dst = r'(i) 211 | _find_shortest(i, r', traveled + compute_dist(src, dst)) 212 | end 213 | 214 | fun ref compute_dist(from: Goal, to: Goal): USize ? => 215 | try 216 | searched = searched + 1 217 | let r = distances(encode(from.location, to.location)) 218 | // Debug.out(encode(from.location, to.location) + " is " + r.string()) 219 | r 220 | else 221 | Debug.err("** missing: " + encode(from.location, to.location)) 222 | error 223 | end 224 | 225 | class Maze 226 | let maze: String ref = String 227 | new create(width: USize, height: USize, c: USize) => 228 | for y in Range(0, height) do 229 | for x in Range(0, width) do 230 | maze.push(if is_odd(count_one_bits(compute_for(x, y, c))) then '#' else '.' end) 231 | end 232 | maze.push('\n') 233 | end 234 | 235 | fun count_one_bits(v: USize): USize => 236 | var c: USize = 0 237 | for i in Range(0, USize.bitwidth()) do 238 | let mask = 1 << i 239 | let check = v and mask 240 | if check > 0 then 241 | c = c + 1 242 | end 243 | end 244 | c 245 | 246 | fun is_odd(v: USize): Bool => 247 | (v % 2) == 1 248 | 249 | fun compute_for(x: USize, y: USize, c: USize): USize => 250 | (x*x) + (3*x) + ((2*x)*y) + y + (y*y) + c 251 | 252 | class SearchMaze 253 | fun apply(env: Env, maze: String, 254 | start: (USize, USize), goal: (USize,USize), 255 | collector: Collector) 256 | => 257 | let dims = learn_dimensions(maze) 258 | // Debug.out("width: " + dims._1.string() + "," + "height: " + dims._2.string()) 259 | let state = State(0, start, maze.clone()) 260 | let router = Router(env, maze.clone(), 261 | collector, start, dims._1, 500) 262 | router.search(state, goal) 263 | 264 | fun learn_dimensions(maze: String): (USize, USize) => 265 | let lines = maze.split("\n") 266 | try 267 | (lines(0).size(), lines.size()) 268 | else 269 | Debug.err("** Error") 270 | (0, 0) 271 | end 272 | -------------------------------------------------------------------------------- /day24/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | /* 4 | 01234567891 5 | */ 6 | """########### 7 | #0.1.....2# 8 | #.#######.# 9 | #4.......3# 10 | ###########""" 11 | 12 | fun puzzle(): String => 13 | """##################################################################################################################################################################################### 14 | #...........#...#.....#.....#.....#....7#.................#.............#.....#.#.#...#.#.#.......#.......#.........#.....#.....#...#.....#.#.#.....#.......#.#.....#.....#.#.......# 15 | #.#####.###.#####.###.#.#.#.#.#.#.#.###.###.#.#.#######.###.#.#####.#.#.#.#.###.#.#.#.#.#.#.#####.#.#.###.#.###.#.#.#.###.#.#.###.#.#.#####.#.#.#.#.#####.###.#.#.###.#.#.#.#.#.###.# 16 | #.......#...#...#.#.....#.#.#...#...#...#.....#...#.......#.......#.......#.#.....#.#.....#.........#...#...#.#...#.#.#.....#.....#.......#.#...#.#.......#...#.#...#.#...#.#.#.....# 17 | #.#.#.###.#.#.#.###.###.#.#.###.#.###.#.#.#.###.#.#.#.#.#.#######.#.#####.#.#.###.#.#.###.#.#.#####.#.#.#####.#.#.#.#.#.#.#.#.#.#####.#.#.###.#.#.#.###.###.#.#.#.#.#.#.#.#.#.#.#.#.# 18 | #...........#.#.....#.....#...#...#.#.....#.#.#.........#.....#...#...#...#...#...#.#.....#.#.....#...#.........#...#.........#.#.#...............#.....#.#...#.#...#.#.......#.#...# 19 | #.#####.###.#.###########.#.#.#.#.#.#.#.###.#.#######.#.#.#.#.#.###.#.#.#.#.#.#.#.###.#.#.#.#########.###.#.#####.#.#############.#.#.#.#.#.#.###.#.#.#.#.###.#.#.#.#.#.#####.#.###.# 20 | #...#.#.....#....4#.......#...#.......#.......#...#.......#...#.#...#...#...#.....#.#.#...#.....#...#...#...#...#...#.............#...#...#...#...#.#...#.#...#...#.#...#..0#.....#.# 21 | #.#.#.###.#.#.#.#.###.###.#.###.#####.#.###.#.#.#.#.#####.#.#.###.###.#.###.###.###.###.#.#.#.#.###.#.#.#.#.#.#####.#.#.#####.#.#.###.#.#.#.###.#.#.#.#.###.#.#.#####.#.#.###.#.#.### 22 | #.#...#...........#...#.....#.#...#.#.#.#.#.......#...........#.....#.....#.#.#.#.......#.#...#.....#.#.......#.....#...#.......#.#.....#.#.#.....#.#.#.#.#.#.#.........#.#...#.#.#.# 23 | #.#.#.#.#########.###.#.#.###.#.###.#####.###.#.#.#.###.#.#.###.###.###.#.###.#########.#.###.#.#.#.#.#.#.#.#.#########.#.#####.#.#####.#.#.###.#.#.#.#.#.#####.###.#.#.#.###.#.#.#.# 24 | #.#.....#.....#.......#.#...#.....#...........#.#.#.....#...#.#.........#.#.#.#.........#.#.......#.......#...#...#...#...#.#...........#.#.....#.#.......#...........#...#...#.....# 25 | #.#####.#.#.#.#####.#.#.#.#.#.#.#.#.#.#.#.#.###.###.###.#####.###.###.#.###.#.#.#.###.#######.###.#.#.#.#####.#.#####.#.###.#.#####.#.#.#.#########.#.###.#.#.#.#.#.#.###.#####.###.# 26 | #.#...#.........#.....#...#.......#...#.#...#.......#...#...#.#.......#.......#...#.....#...........#...#.#.....#.................#.#...#.#.........#.#...#.#.#.#.......#.#.....#...# 27 | #.#.#.#.#.###.#.#.###.#.#.#.#####.#.###.#.###.###.###.#######.#.###.###.#.###.#.#.###.#.#.#####.###.#.#.#.#.###.#.###.#######.#.#.#.#.#.#.#.#.#.#######.#.#.#.#.###.#.#.#.###.#.#.### 28 | #.....#.#...#.....#...#.#.#.....#.#.#...#.#.#...........#.....#.#...#.................#.#.#...#.........#.......#.#...#.......#.#.#.....#...#...........#.#...#.........#...........# 29 | ###.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#####.###.###.#.###.#.#.#.#.###.#.#######.#.#####.###.#.#.#.#.#.#.#####.#.#.#.###.#.#.#######.#.#.#.#####.#.###.#.###.###.#.#.###.##### 30 | #.#.#.#.#...#.....#...#...#...#...#.#...#.#.#.......#...#.#...............#...#.....#.....#.....#.....#.#.#.......#...#.#.....#.....#.........#...#...#.#.......#...#.....#.....#...# 31 | #.#.#.#.###.###.#.#.#.#########.#.#.#########.#.#.###.#.#.#.###.#####.###.#.#.#.#.###.#.#.#.#.###.#.#.#.#.#.#.#####.###.#.#.#.###.#.#.#.#.#.#.###.#.#.#.###.#.###.#####.###.#.#.#.#.# 32 | #.....#.....#.....#.......#...........#...#...#.#.....#.#.......#.......#.#.#.........#.............#...#.#.#.....#.....#...#...#.......#...#.......#...#...#...#....1#.....#...#.#.# 33 | ###.#.#.#######.#.#.#.###.#.#.###.###.#.###.#.#.#.#.#.#.###.###.###.#.#.#.#.#.#.#.#.#####.#####.###.#.###.#.#.#.#.###.###.#.#####.###.#.#.###.###.#######.#.###.###.#.###.#.#.#.###.# 34 | #...#...#5......#.#...#.......#...#.........#.....#...........#...#.#.......#.#...........#...#.......#.....#.#.......#...#.....#.......#...#.#.................#.....#...#...#.....# 35 | #.###.#.#.#.#####.#####.#####.###.#.#########.###.###.#.#.#####.#.#.###.#.###.###.#.#.#.#.#.###.#.#######.#.#.#.#.#.###.#.#.###.#.#####.###.#.#.#.###.#.#.###.#.###.#########.#####.# 36 | #.#.#...#...#.....#.....#.#.....#.#.....#.........#...#...#.....#.#.#.......#.......#.......#...#.........#...#...#.....#.#.#...#.........#.#.#.#.#.....#.#.....#.........#.....#...# 37 | ###.###.###.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#####.#.#.#.#.###.#.#####.#.###.#.#.###.#.#.#.#.#.###.#.#.###.#.#########.#.#####.###.#.###.#####.#.#.#.#.#.#.###.#.#.#.#.#.###.#.#.#.#.#.# 38 | #.#.#.#.......#...#.#...#.....#.#.................#.#.........#.....#...#...#.#.....#.....#.....#...#...#.....#...#...#...#.#.#...#...#...#...#...#...#.#...#.......................# 39 | #.###.#############.#.#######.#.###.###########.#.#.###.###.#.#.###.###.#.###.###.#.#.###.#.#.###.#.#.#.###.#.###.#.#.#.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.###.###.#.#.#.#.#.#.#.#.#.# 40 | #.....#.#.......#...............#.....#...........#...#.#.#...#...#...#.#.#...#.......#...#...#.....#.....#.#.#...............#.#...#.....#.....#.#.#.#.......#...#.#...#...#.....#.# 41 | #.#.###.#.###.#.#.#######.#.###.#.###.#.#.#.#.#####.#.#.#.#.#.#.#.###.#######.#.#.###.###.#.#.#.#######.#.###.#.#.###########.###.#########.#.#####.#.#.#.#.#.#.#.#.#.#####.###.#.### 42 | #...#...#.#...............#.#.......#.#...#.#.......#.#...#.#.....#.....#.#.......#.........#.#.#...#.#...................#...#...#.............#.......#.......#.#...#...#.....#.#.# 43 | #.#.#####.#.#######.#.###.#.#####.#.#.#.#.###.#.#.#.###.#.#.#####.###.###.#.#.#.#.#.#####.#.###.#.#.#.#.###.#.#####.#######.#.###.#.#.#.#.#####.#.#####.###.#######.#.#.#.#.###.#.#.# 44 | #.........#.#...#.#.......#...#...#...........#.....#.....#.......#.....#.....#.#.#...#.#...#.....#.....#.....#...#.#.........#.....#.....#.#.#.....#...#...#.......#.#.#.....#...#.# 45 | ###.#######.#.#.#.#.###.#.###.#.###.###.#.###.#.#.#.#.#.#.###.#.###.#.#.#.###.###.#.#.#.#.###.#.#.###.#.#.#.#.#.#.#.#.#.#.#####.#####.###.#.#.#.#####.###.###.#.#.#####.#.#####.#.### 46 | #...#.......#.......#...#...#.........#.....#...#...#...#.#...#.........#...#.....#...#.#.#.#.#...#.....#.#.....#.....#.#.........#.....#.#.#.....#...#...#.......#.#3....#...#.....# 47 | #.###.###.#####.###.###.###.#.###.#.###.###.#.###.###.#.#.#######.#.#.#.#.###.#.#.#.###.###.#.#.###.#.#.#.#####.###.###.###.#.###.#.#.###.#.#.#####.###.#.#.###.#.#.###.#.#.#.###.#.# 48 | #.#...#.....#.#...#...#.#...........#...#.#...#.#.#.....#.#.......#.#.....#...#...#.....#...#.......#.........#...#.#...#.#.#.#.....#.....#.......#.........#.....#.....#.#...#.#...# 49 | #.#.#.#####.#.###########.###.#.#####.###.###.#.###.###.#.#.#####.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.###.#.###.#.#.#.#.###.#.#.#.#.#####################.###.###.###.#.#.#.#.#.# 50 | #.#...#.#...#.....#...#...#.....#.......#.......#.....#.#...#.....#...#.....#...#.......#...#.#...#.#...#.#...........#...#.#...#.#.......#.........#.#.......#...........#...#...#.# 51 | ###.###.#.#.#.#.#.#.#####.#.#.#.###.#.#######.#.###.#.#####.#.###.###.#.#.###.#.#.#.###.#.#######.#.#.#.###.###.#.#######.#.#.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#.###.#.#.###.###.#.#.### 52 | #.#...#.......#.#...#.#.........#.........#...#.#...#.........#.#...#...#.........#...#.....#.......#...#.....#.....#...........#..2#.....#.#.....#...#.#.....#.......#...#...#...#.# 53 | #.#.#.#.#.#.#.#.###.#.###.#.###.#.#.###.#.#.#.#.#.#.###.#.#####.#.###.###.#.###.#.#.#.#####.#.#.###.#.###.###.###.#.#####.#.#####.#####.#.#.#.#.#.###.#.#.#####.#.#.#.#.###.#.#.###.# 54 | #.#..6#.........#...#.#.......#.#.......#.........#...#.....#.#...#...#.#.#.....#.....#.#.........................#.......#...#.#.........#.#...#...........#...#.....#.....#...#...# 55 | #####################################################################################################################################################################################""" 56 | -------------------------------------------------------------------------------- /day25/.gitignore: -------------------------------------------------------------------------------- 1 | day25 2 | -------------------------------------------------------------------------------- /day25/_test.pony: -------------------------------------------------------------------------------- 1 | use "ponytest" 2 | use "collections" 3 | use "regex" 4 | use "debug" 5 | use "time" 6 | 7 | actor Main is TestList 8 | new create(env: Env) => PonyTest(env, this) 9 | new make() => None 10 | 11 | fun tag tests(test: PonyTest) => 12 | test(_TestLowest) 13 | 14 | actor Router 15 | let env: Env 16 | let workers: Array[Worker] 17 | var next: USize = 0 18 | var count: USize = 0 19 | new create(env': Env, asm: String) => 20 | env = env' 21 | workers = Array[Worker] 22 | for i in Range(0, 6) do 23 | workers.push(Worker(env', asm, this)) 24 | end 25 | 26 | be begin() => 27 | while count < 1000 do 28 | try 29 | workers(next % workers.size()).check(next.i64()) 30 | end 31 | next = next + 1 32 | count = count + 1 33 | end 34 | 35 | be completed(win: Bool) => 36 | if win then 37 | return 38 | end 39 | try 40 | if (next % 1000) == 0 then 41 | env.out.print("trying: " + next.string()) 42 | end 43 | workers(next % workers.size()).check(next.i64()) 44 | end 45 | next = next + 1 46 | 47 | actor Worker 48 | let env: Env 49 | let bunny: Assembly 50 | let instructions: Array[Inst] 51 | let router: Router 52 | 53 | new create(env': Env, asm': String, router': Router) => 54 | env = env' 55 | bunny = Assembly 56 | instructions = bunny.parse(asm'.split("\n")) 57 | router = router' 58 | 59 | be check(value: I64) => 60 | bunny.reset() 61 | bunny.registers("a") = value 62 | bunny.exec(instructions) 63 | if bunny.success then 64 | env.out.print("win: " + value.string()) 65 | end 66 | router.completed(bunny.success) 67 | 68 | class iso _TestLowest is UnitTest 69 | fun name(): String => "lowest" 70 | fun apply(h: TestHelper) => 71 | let router = Router(h.env, INPUT.puzzle()) 72 | router.begin() 73 | -------------------------------------------------------------------------------- /day25/assembunny.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "debug" 3 | use "time" 4 | use "regex" 5 | 6 | class CpyInst 7 | let x: (String|I64) 8 | let y: (String|I64) 9 | new create(x': (String|I64), y': (String|I64)) => 10 | x = x' 11 | y = y' 12 | fun apply(bunny: Assembly) ? => 13 | let v = match x 14 | | let reg: String => bunny.registers(reg) 15 | | let int: I64 => int 16 | else error end 17 | 18 | match y 19 | | let y': String => bunny.registers(y') = v 20 | // Invalid if its a number so we just skip it 21 | end 22 | bunny.ip = bunny.ip + 1 23 | 24 | fun string(): String => 25 | "cpy " + x.string() + " " + y.string() 26 | 27 | class IncInst 28 | let x: String 29 | new create(x': String) => 30 | x = x' 31 | fun apply(bunny: Assembly) ? => 32 | bunny.registers(x) = bunny.registers(x) + 1 33 | bunny.ip = bunny.ip + 1 34 | fun string(): String => 35 | "inc " + x 36 | 37 | class DecInst 38 | let x: String 39 | new create(x': String) => 40 | x = x' 41 | fun apply(bunny: Assembly) ? => 42 | bunny.registers(x) = bunny.registers(x) - 1 43 | bunny.ip = bunny.ip + 1 44 | fun string(): String => 45 | "dec " + x 46 | 47 | class JnzInst 48 | let x: (String|I64) 49 | let y: (String|I64) 50 | new create(x': (String|I64), y': (String|I64)) => 51 | x = x' 52 | y = y' 53 | fun apply(bunny: Assembly) ? => 54 | let int: I64 = match x 55 | | let reg: String => bunny.registers(reg) 56 | | let v: I64 => v 57 | else error end 58 | 59 | let jmp: I64 = match y 60 | | let reg: String => bunny.registers(reg) 61 | | let v: I64 => v 62 | else error end 63 | 64 | if int != 0 then 65 | // Debug.out("jumping by " + jmp.string()) 66 | bunny.ip = (bunny.ip.i64() + jmp).usize() 67 | else 68 | bunny.ip = bunny.ip + 1 69 | end 70 | fun string(): String => 71 | "jnz " + x.string() + " " + y.string() 72 | 73 | class TglInst 74 | let x: String 75 | new create(x': String) => 76 | x = x' 77 | fun apply(bunny: Assembly) => 78 | try 79 | let off = bunny.registers(x) 80 | let tgt = bunny.instructions((bunny.ip.i64() + off).usize()) 81 | // Debug.out("Target: " + tgt.string()) 82 | let chg: Inst = match tgt 83 | | let inc: IncInst => DecInst(inc.x) 84 | | let dec: DecInst => IncInst(dec.x) 85 | | let tgl: TglInst => IncInst(tgl.x) 86 | | let cpy: CpyInst => JnzInst(cpy.x, cpy.y) 87 | | let jnz: JnzInst => CpyInst(jnz.x, jnz.y) 88 | else 89 | Debug.err("** No match!") 90 | error 91 | end 92 | bunny.instructions((bunny.ip.i64() + off).usize()) = chg 93 | then 94 | bunny.ip = bunny.ip + 1 95 | end 96 | 97 | fun string(): String => 98 | "tgl " + x 99 | 100 | class OutInst 101 | let x: (String|I64) 102 | new create(x': (String|I64)) => 103 | x = x' 104 | fun apply(bunny: Assembly) ? => 105 | match x 106 | | let reg: String => bunny.out(bunny.registers(reg)) 107 | | let v: I64 => bunny.out(v) 108 | end 109 | bunny.ip = bunny.ip + 1 110 | fun string(): String => 111 | "out " + x.string() 112 | 113 | type Inst is (CpyInst|IncInst|DecInst|JnzInst|TglInst|OutInst) 114 | 115 | class Assembly 116 | let registers: Map[String, I64] = Map[String, I64] 117 | var ip: USize = 0 118 | var instructions: Array[Inst] = Array[Inst] 119 | var lastReport: I64 = 0 120 | var i: ISize = 0 121 | var lastOut: I64 = -1 122 | var goodCount: USize = 0 123 | var fail: Bool = false 124 | var success: Bool = false 125 | 126 | new create() => 127 | registers("a") = 0 128 | registers("b") = 0 129 | registers("c") = 0 130 | registers("d") = 0 131 | 132 | fun ref exec(instructions': Array[Inst]) => 133 | instructions = instructions' 134 | while ip < instructions.size() do 135 | if fail then break end 136 | if success then break end 137 | try 138 | let nowSecs = Time.seconds() 139 | if (lastReport + 10) <= nowSecs then 140 | lastReport = nowSecs 141 | // env.out.print("-- " + s.moves.string() + "\n" + gs) 142 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 143 | end 144 | // if (i % 1000) == 0 then 145 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 146 | // end 147 | instructions(ip).apply(this) 148 | else 149 | Debug.err("*** failed") 150 | end 151 | i = i + 1 152 | end 153 | 154 | fun ref step(): Bool => 155 | """ 156 | Returns true if we should keep going 157 | """ 158 | if ip < instructions.size() then 159 | try 160 | let nowSecs = Time.seconds() 161 | if (lastReport + 10) <= nowSecs then 162 | lastReport = nowSecs 163 | // env.out.print("-- " + s.moves.string() + "\n" + gs) 164 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 165 | end 166 | // if (i % 10000) == 0 then 167 | // Debug.out("ip: " + ip.string() + "|" + instructions(ip).string() + "\t" + regs_string()) 168 | // end 169 | instructions(ip).apply(this) 170 | else 171 | Debug.err("*** failed") 172 | end 173 | i = i + 1 174 | true 175 | else 176 | try 177 | Debug.out("a = " + registers("a").string()) 178 | end 179 | false 180 | end 181 | 182 | fun regs_string(): String => 183 | try 184 | String 185 | .append("[a:").append(registers("a").string()).append("]") 186 | .append("[b:").append(registers("b").string()).append("]") 187 | .append("[c:").append(registers("c").string()).append("]") 188 | .append("[d:").append(registers("d").string()).append("]").clone() 189 | else 190 | "Error" 191 | end 192 | 193 | // asmout 194 | fun ref reset() => 195 | registers("a") = 0 196 | registers("b") = 0 197 | registers("c") = 0 198 | registers("d") = 0 199 | ip = 0 200 | lastOut = -1 201 | goodCount = 0 202 | fail = false 203 | success = false 204 | fun ref out(v: I64) => 205 | if lastOut != v then 206 | lastOut = v 207 | goodCount = goodCount + 1 208 | else 209 | fail = true 210 | end 211 | if goodCount > 100 then 212 | success = true 213 | end 214 | 215 | fun parse(lines: Array[String]): Array[Inst] => 216 | let result = Array[Inst] 217 | try 218 | let cpy = Regex("cpy ([a-d]) ([a-d])") 219 | let cpy' = Regex("cpy (-?\\d+) ([a-d])") 220 | let inc = Regex("inc ([a-d])") 221 | let dec = Regex("dec ([a-d])") 222 | let jnz = Regex("jnz ([a-d]) (-?\\d+)") 223 | let jnz' = Regex("jnz (-?\\d+) (-?\\d+)") 224 | let jnz'' = Regex("jnz (-?\\d+) ([a-d])") 225 | let tgl = Regex("tgl ([a-d])") 226 | let out_regex = Regex("out ([a-d])") 227 | 228 | for line in lines.values() do 229 | if cpy == line then 230 | let matched = cpy(line) 231 | result.push(CpyInst(matched(1), matched(2))) 232 | elseif cpy' == line then 233 | let matched = cpy'(line) 234 | result.push(CpyInst(matched(1).read_int[I64]()._1, matched(2))) 235 | elseif inc == line then 236 | let matched = inc(line) 237 | result.push(IncInst(matched(1))) 238 | elseif dec == line then 239 | let matched = dec(line) 240 | result.push(DecInst(matched(1))) 241 | elseif jnz == line then 242 | let matched = jnz(line) 243 | result.push(JnzInst(matched(1), matched(2).read_int[I64]()._1)) 244 | elseif jnz' == line then 245 | let matched = jnz'(line) 246 | result.push(JnzInst(matched(1).read_int[I64]()._1, matched(2).read_int[I64]()._1)) 247 | elseif jnz'' == line then 248 | let matched = jnz''(line) 249 | result.push(JnzInst(matched(1).read_int[I64]()._1, matched(2))) 250 | elseif tgl == line then 251 | let matched = tgl(line) 252 | result.push(TglInst(matched(1))) 253 | elseif out_regex == line then 254 | let matched = out_regex(line) 255 | result.push(OutInst(matched(1))) 256 | else 257 | Debug.err(" ** No match for " + line) 258 | end 259 | end 260 | else 261 | Debug.err("** Parse") 262 | end 263 | result 264 | -------------------------------------------------------------------------------- /day25/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | /* 4 | 01234567891 5 | */ 6 | """########### 7 | #0.1.....2# 8 | #.#######.# 9 | #4.......3# 10 | ###########""" 11 | 12 | fun puzzle(): String => 13 | """cpy a d 14 | cpy 9 c 15 | cpy 282 b 16 | inc d 17 | dec b 18 | jnz b -2 19 | dec c 20 | jnz c -5 21 | cpy d a 22 | jnz 0 0 23 | cpy a b 24 | cpy 0 a 25 | cpy 2 c 26 | jnz b 2 27 | jnz 1 6 28 | dec b 29 | dec c 30 | jnz c -4 31 | inc a 32 | jnz 1 -7 33 | cpy 2 b 34 | jnz c 2 35 | jnz 1 4 36 | dec b 37 | dec c 38 | jnz 1 -4 39 | jnz 0 0 40 | out b 41 | jnz a -19 42 | jnz 1 -21""" 43 | -------------------------------------------------------------------------------- /day3/.gitignore: -------------------------------------------------------------------------------- 1 | day3 -------------------------------------------------------------------------------- /day4/.gitignore: -------------------------------------------------------------------------------- 1 | day4 -------------------------------------------------------------------------------- /day5/.gitignore: -------------------------------------------------------------------------------- 1 | day5 2 | -------------------------------------------------------------------------------- /day5/main.pony: -------------------------------------------------------------------------------- 1 | use "crypto" 2 | use "format" 3 | 4 | actor Main 5 | let env: Env 6 | 7 | new create(env': Env) => 8 | env = env' 9 | 10 | let input = "cxdnnyjw" 11 | 12 | crack("abc") 13 | crack(input) 14 | 15 | fun crack(input: String) => 16 | var index: U64 = 0 17 | let result: String ref = String 18 | let result': String ref = " ".clone() 19 | 20 | env.out.print("hashing: " + input) 21 | while (index < 100_000_000) 22 | and ((result.size() < 8) or (result'.contains(" "))) 23 | do 24 | let attempt = input + index.string() 25 | let md5 = Digest.md5() 26 | try 27 | md5.append(attempt) 28 | let sum = md5.final() 29 | match (sum(0), sum(1), sum(2)) 30 | | (0, 0, let x: U8) if (x and 0xF0) == 0=> 31 | result.append(ToHexString(sum).substring(5, 6)) 32 | update_crack(result', sum) 33 | env.out.print("result: " + result) 34 | env.out.print("result': " + result') 35 | end 36 | end 37 | index = index + 1 38 | end 39 | 40 | fun update_crack(result': String ref, sum: Array[U8] val) => 41 | try 42 | let left = (sum(2) and 0xF).usize() 43 | if result'(left) == ' ' then 44 | result'(left) = ToHexString(sum).substring(6, 7)(0) 45 | else 46 | env.out.print("already filled: " + left.string()) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /day6/.gitignore: -------------------------------------------------------------------------------- 1 | day6 2 | -------------------------------------------------------------------------------- /day6/input.pony: -------------------------------------------------------------------------------- 1 | primitive MESSAGE 2 | fun sample(): String => 3 | """eedadn 4 | drvtee 5 | eandsr 6 | raavrd 7 | atevrs 8 | tsrnev 9 | sdttsa 10 | rasrtv 11 | nssdts 12 | ntnada 13 | svetve 14 | tesnvt 15 | vntsnd 16 | vrdear 17 | dvrsen 18 | enarar""" 19 | 20 | fun input(): String => 21 | """bztzdacg 22 | xyjtwqap 23 | arsiwubu 24 | cjwvfwtp 25 | dpdymenf 26 | kbedgnri 27 | gsrrprxn 28 | ojdxafjb 29 | umujtcwg 30 | fcpqbkti 31 | hfhxzhdt 32 | oradqnqo 33 | pjfgpkgz 34 | fagrqjrn 35 | xjkujuks 36 | iisbsyvl 37 | narthccx 38 | sjbnbbxp 39 | ljaemgip 40 | sdlenzfu 41 | zhzlsmgw 42 | sbdndyku 43 | ekcktelc 44 | vxgoapax 45 | bhepszpx 46 | hozlfbdm 47 | fkjgygrj 48 | keutuund 49 | agzrwrzb 50 | mgcucvkn 51 | wiguuvtm 52 | bnyviixq 53 | ybsozbss 54 | cxaqckwv 55 | ulnksnjj 56 | dsrvvmbs 57 | azfnwcdk 58 | hwtwbilm 59 | lieglyxh 60 | vpqfjxcv 61 | sfwxiyqr 62 | hqifjldw 63 | icnsplkz 64 | oxnqizfs 65 | nzfwhwyu 66 | ygaoadfd 67 | dctauvvs 68 | zmtgvtxg 69 | wwzpvoym 70 | cwhcqxvu 71 | rmcvjkzu 72 | yhpwofcb 73 | nulkmdbi 74 | kdppiqlw 75 | awwysfhc 76 | wutwcxvv 77 | haivrowg 78 | mfmsgbsl 79 | fwmphkmm 80 | mjzwenbv 81 | fkvyebad 82 | sprgbbet 83 | mvndpyjx 84 | azwiuvxc 85 | jysrvsaa 86 | dbdhmylh 87 | bgtahasz 88 | rxvnuzdh 89 | abuhtxpr 90 | sicbkalw 91 | ivrdycpj 92 | zhnmrmhl 93 | wauhlrzq 94 | qvdvzigy 95 | exaihdzw 96 | enmyjluj 97 | pzbmvacm 98 | kwiiicwu 99 | caxviljd 100 | fnpjelcd 101 | sekexsoz 102 | yjpdqfte 103 | lbscrmze 104 | hczfunor 105 | hdvlprev 106 | muyeuczq 107 | eyfcvwhv 108 | wnajxlxv 109 | qovjvytl 110 | nrbzwhsf 111 | qgwbxlqh 112 | djvueone 113 | tjbxisce 114 | fwrbhzrk 115 | wesdwdmd 116 | ssumqhxi 117 | kkbxbgyg 118 | ghlmwlkn 119 | nwqprhnc 120 | zothmtwq 121 | xlxhmpvb 122 | wlyckxvt 123 | bmgdhtoc 124 | zkysylxx 125 | paoxzqpo 126 | dpufpfkq 127 | rehmrtqi 128 | zpwyfvdk 129 | kwdpimya 130 | ipnjkoso 131 | mxqxkokf 132 | rsczwsfd 133 | rqrpctlq 134 | geozhplt 135 | ajyatmjk 136 | vkbycpap 137 | pmoftkvg 138 | tzjsvaiy 139 | shoghugz 140 | zbkifgyr 141 | pbkpbmev 142 | mlodbiog 143 | ceemnpgc 144 | rnhmanzi 145 | mkbwwvbx 146 | iwgnsett 147 | utbnohwb 148 | ddxtrdje 149 | mcpjzqws 150 | nrixbssl 151 | tdwjqjgc 152 | pyjyaost 153 | ktslndcw 154 | jseutzlp 155 | aipejffr 156 | iwcjyacs 157 | lshhpbdq 158 | gpenffaf 159 | cukufmfp 160 | ghwjsabp 161 | tmxtxsmw 162 | dhyfbhne 163 | pngepnxe 164 | pojchoea 165 | gtgiogrp 166 | xydkeazh 167 | vqwnnjvx 168 | azjcxxbj 169 | iteaqkgn 170 | nnfhcbhc 171 | oqrlizro 172 | nexqvoak 173 | rglnpjny 174 | ygzhhlqc 175 | mikoaotl 176 | jrhixpef 177 | eikwdvag 178 | wjinncla 179 | ldkfliro 180 | vkmadbkm 181 | loxctpok 182 | iicuxdes 183 | utkriebm 184 | mohvgmkt 185 | fgsaycsy 186 | xmvkgduq 187 | rqhboixq 188 | pgvrtlnh 189 | ztahypot 190 | vmiwyimf 191 | jcgwncls 192 | yiyusdvo 193 | ucqjaxze 194 | bxjgpahy 195 | uginqzlk 196 | nlaxigbi 197 | fpgrsfym 198 | bnanuhpw 199 | uapzqpix 200 | ntebfqhr 201 | defunben 202 | ructvovh 203 | aqhymxge 204 | gdzxxnvd 205 | xauqzcfd 206 | fhrqlybl 207 | erlyajtu 208 | xsqdriep 209 | tjkoykqt 210 | osjeelqi 211 | clofyxny 212 | lhwssjlj 213 | fhaqhrki 214 | cxgocyms 215 | dbfqhwbk 216 | fqpxxtdc 217 | drxiflgp 218 | athtumkv 219 | wpdjptpu 220 | ofqtdaja 221 | fapibvfg 222 | icohxeds 223 | jgmgzzsd 224 | vogagqfx 225 | qelzldjl 226 | qrdlgaqb 227 | woncwuof 228 | sdltdgrl 229 | hwwvgjoz 230 | itrqkyhw 231 | slmehuaw 232 | uxhtcxyc 233 | lsrgmwcr 234 | ligjqlcx 235 | unzkbdhh 236 | vmssbxos 237 | plkfxaqr 238 | zmmeokxo 239 | rgupyiig 240 | psqalimc 241 | zkpdxmny 242 | ctkzxvob 243 | eumydwul 244 | zmzfsjwx 245 | vsdqjfwn 246 | xywlcgzx 247 | yfxinykj 248 | xzfmavcq 249 | uotgqrnu 250 | mhgclvyn 251 | qqetjpeo 252 | bjvmylzy 253 | iruxfcrz 254 | jvldgohm 255 | qvevmjjb 256 | gbobtgrq 257 | iwesuoas 258 | wqkdnzpt 259 | iqhlvjyk 260 | gyqyoolp 261 | wvacvumq 262 | caqzoruh 263 | ftpxpkpr 264 | wvcztqyk 265 | qfqjtgey 266 | croanejb 267 | cbqjdcyz 268 | kxewlwwi 269 | fqarbziw 270 | pepzgqha 271 | cqaeejem 272 | rzezjxhr 273 | ouzyjmdj 274 | sxkmzmqg 275 | txdyoycu 276 | shuzdzke 277 | tyblgetz 278 | troqvtbc 279 | vtkjnqzf 280 | qkzksiui 281 | yvitrrnb 282 | orustrih 283 | dckmcabj 284 | rzkgzwwa 285 | stqdalzw 286 | qlfrvdfx 287 | tbbywjpk 288 | rgmptpyt 289 | oywgrgnf 290 | mczqsszo 291 | bqcllnsw 292 | ryungzti 293 | hsdhzcsq 294 | qlwwnjao 295 | gebhrhss 296 | auelxsel 297 | ooibpinr 298 | hvbwkafc 299 | wyxniwnp 300 | yuniddtp 301 | lkfmtxet 302 | uzvwegaf 303 | mooyfrwz 304 | zbzziowo 305 | udyxjlih 306 | husurpur 307 | oufjezde 308 | dhhqhhvu 309 | ggpiyvdj 310 | pnwosfne 311 | dydoaomg 312 | jigdybwi 313 | jrezqnyp 314 | uqhjltum 315 | mqtfqsez 316 | yebfabmm 317 | vvvvbrta 318 | uvppafsf 319 | sllgpeix 320 | ulgeznra 321 | ifpvbsql 322 | mzdrgkrt 323 | xolsjkcy 324 | azusnhor 325 | hyfnelhw 326 | becqefpj 327 | epyokhod 328 | tqojzdgz 329 | ckjqztth 330 | aweeqxmd 331 | fehhuhve 332 | bjrgsmrc 333 | zmqofcvf 334 | zfjfaomq 335 | bssvmrde 336 | xfdblalt 337 | qhywbzba 338 | mtgsvemd 339 | wvberfyb 340 | mjxkmqul 341 | aytkyusz 342 | sabuotpk 343 | uacviqis 344 | jolhhusp 345 | xbjvogig 346 | gatwogxo 347 | taxbkfxi 348 | fhvejhkr 349 | mlmbhjis 350 | zuezkkhq 351 | cdwcwuvv 352 | jmlprdmv 353 | ydwyooiu 354 | exqatqjs 355 | eunwnucj 356 | hkrnsana 357 | tmfeymay 358 | tcnogxpv 359 | lnlrpnzt 360 | vavbgplk 361 | kjymlakj 362 | tmlseyul 363 | zfowvrum 364 | yzvwvrmw 365 | qntgqett 366 | vwwqkqdt 367 | xlfedyzg 368 | ehxpxwjn 369 | wmijbqgj 370 | idftxkgo 371 | mymigedt 372 | bmouaruq 373 | bxnbmvxz 374 | jqmgqwta 375 | idawdbub 376 | opxennsn 377 | jeotjdhx 378 | sojzqnpa 379 | xouarvap 380 | yjuoninr 381 | vqjogzjl 382 | khzkueji 383 | ndoiuxtm 384 | wifnoizv 385 | afzkeddd 386 | pfyyvihg 387 | pcsrligt 388 | xnsxcyrz 389 | gzququlr 390 | vihfqqdo 391 | lsbsitur 392 | kqrkamdr 393 | peludmha 394 | dfvkfbyu 395 | zscdzqua 396 | lumijqbx 397 | hzkwiitz 398 | yatolkoh 399 | ikbbpwdh 400 | emamjtmc 401 | eqioawcx 402 | bfkrcrfp 403 | ksntxvee 404 | bnslkpji 405 | tblktbpn 406 | gvqfksyi 407 | caplwhtr 408 | jtcllupx 409 | ployzvxi 410 | gygpdyfb 411 | twdijfma 412 | yrzmyoza 413 | gymlehrc 414 | bppycuib 415 | uftzoycx 416 | uxokapsw 417 | jpiwwboy 418 | eciicuyo 419 | hgyuxrfj 420 | hjdhthqg 421 | cexcqher 422 | vsjolhue 423 | odqcfrkk 424 | gkypgguj 425 | xuthrpos 426 | nkzpsbqv 427 | erofbehb 428 | pnxcwqyk 429 | gcwhkxjo 430 | npbnukjp 431 | qmshmgej 432 | txrcdgeo 433 | xttdifgz 434 | vkqihmqf 435 | rlaqduzu 436 | hcjjkhxu 437 | qctdznju 438 | yvekncrn 439 | cajupqki 440 | nccbcgcq 441 | byxxgvjk 442 | zidpfckc 443 | bzeawgwe 444 | omyegefy 445 | ythcjpbj 446 | kcxohucy 447 | wkigkolb 448 | ntvrrpqn 449 | qxcxwtuc 450 | idxsnspd 451 | nvivszfy 452 | tkqlznph 453 | vxnsojrk 454 | kralcfwl 455 | hfkgjwds 456 | wuzgluwn 457 | jwltajll 458 | vpcbpboa 459 | bnrrdjry 460 | uurpkisf 461 | qbjniyrw 462 | einiyjjk 463 | gwmmewnm 464 | erxoycqf 465 | uwdvnnwd 466 | rjqfozcv 467 | nvnjlmum 468 | kuirunnm 469 | moguesgh 470 | luiabxha 471 | xeuaetvy 472 | zcijrciq 473 | dxyawjfe 474 | bxxaytah 475 | firlwpxz 476 | akepeyho 477 | xneohwpu 478 | wrhemsyg 479 | gbafuemn 480 | kzrlkkdd 481 | xsgupnkf 482 | xbqaoosg 483 | dlkuzeqc 484 | hidzsgot 485 | emftjwln 486 | tvwbrngp 487 | habctvij 488 | idzmgcue 489 | flyyevlb 490 | orhdasvb 491 | qwgsvokg 492 | rgpcvtee 493 | jvwyfziw 494 | lzikmdqh 495 | dsyvnfaj 496 | inrlcdst 497 | ehzxjtin 498 | pdnhilac 499 | cvfbcuyz 500 | vtcmfsbh 501 | lnmgmfzw 502 | vovbxstv 503 | opvfvcnx 504 | zlyaoifj 505 | ziumzwqh 506 | phtmspff 507 | jijqudod 508 | jtistrvr 509 | oucmojll 510 | lfjckzhn 511 | fkaodyev 512 | qgspkigk 513 | ypstmrav 514 | kxmxsxrg 515 | egmkleby 516 | ogralaup 517 | klguxwmz 518 | sdpqwdcl 519 | pctkiaws 520 | tvsrfgix 521 | myyrujrq 522 | lzluftpg 523 | rbvscsuk 524 | jfjfdstb 525 | lexiumav 526 | nyvrxexy 527 | jioktbzf 528 | arubkmmm 529 | fnvimawa 530 | dwncnkfi 531 | hyfpywbn 532 | wootqtvb 533 | ktlnzuyh 534 | qpbackvb 535 | reaqetoi 536 | edmnonic 537 | nlpdmqfu 538 | osfsybtk 539 | asnfzlnn 540 | lzsspajo 541 | qanbwzel 542 | lblvbkof 543 | uvurrekd 544 | kshqoiqw 545 | oosxudql 546 | orakdrgn 547 | yotzryse 548 | rpuhmeau 549 | cqchkvbo 550 | ajcaluhy 551 | sabvtxiq 552 | sctoapgf 553 | ihhznfmd 554 | yenlgcmo 555 | dihxrbos 556 | tfusfxad 557 | sdmdfhxa 558 | kodcikxm 559 | cfvvcfum 560 | ynnrmqiw 561 | rbsepvwv 562 | npmdblpf 563 | jgltfwgq 564 | guitdsvy 565 | nfyzuhgv 566 | dgjghspu""" 567 | -------------------------------------------------------------------------------- /day6/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | actor Main 4 | let env: Env 5 | 6 | new create(env': Env) => 7 | env = env' 8 | 9 | decode(MESSAGE.sample().split("\n")) 10 | decode(MESSAGE.input().split("\n")) 11 | 12 | fun decode(lines: Array[String] val) => 13 | var last: USize = try lines(0).size() else 0 end 14 | let result: String ref = String 15 | let result': String ref = String 16 | for col in Range(0, last) do 17 | let freq = Array[USize].init(0, 26) 18 | try 19 | for line in lines.values() do 20 | let offset = (line(col) - 'a').usize() 21 | freq(offset) = freq(offset) + 1 22 | end 23 | else 24 | env.out.print("** error 1") 25 | end 26 | let char = find_max(freq) + 'a' 27 | result.push(char.u8()) 28 | let char' = find_min(freq) + 'a' 29 | result'.push(char'.u8()) 30 | // print_freq(freq) 31 | end 32 | env.out.print("result: " + result) 33 | env.out.print("result': " + result') 34 | 35 | fun print_freq(counts: Array[USize]) => 36 | env.out.print("{") 37 | for i in Range(0, counts.size()) do 38 | let char: String ref = String 39 | char.push((i + 'a').u8()) 40 | env.out.write(char.clone()) 41 | .write("->").write(try counts(i).string() else "oops" end) 42 | .write(" ") 43 | end 44 | env.out.print("}") 45 | 46 | fun find_max(counts: Array[USize]): USize => 47 | var maxIndex: USize = 0 48 | var maxValue: USize = 0 49 | for i in Range(0, counts.size()) do 50 | try 51 | if counts(i) > maxValue then 52 | maxIndex = i 53 | maxValue = counts(i) 54 | end 55 | else 56 | env.out.print("** error 4") 57 | end 58 | end 59 | maxIndex 60 | 61 | fun find_min(counts: Array[USize]): USize => 62 | var minIndex: USize = 0 63 | var minValue: USize = USize.max_value() 64 | for i in Range(0, counts.size()) do 65 | try 66 | if (counts(i) > 0) and (counts(i) < minValue) then 67 | minIndex = i 68 | minValue = counts(i) 69 | end 70 | else 71 | env.out.print("** error 4") 72 | end 73 | end 74 | minIndex 75 | -------------------------------------------------------------------------------- /day7/.gitignore: -------------------------------------------------------------------------------- 1 | day7 2 | -------------------------------------------------------------------------------- /day7/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | primitive OUTSIDE 4 | primitive INSIDE 5 | 6 | type LexState is (OUTSIDE|INSIDE) 7 | 8 | primitive EOL 9 | 10 | actor Main 11 | let env: Env 12 | new create(env': Env) => 13 | env = env' 14 | 15 | count_types(INPUT.sample().split("\n")) 16 | count_types(INPUT.sample2().split("\n")) 17 | count_types(INPUT.sample3().split("\n")) 18 | count_types(INPUT.puzzle().split("\n")) 19 | 20 | fun count_types(lines: Array[String] box) => 21 | env.out.print("lines: " + lines.size().string()) 22 | var count: USize = 0 23 | var count': USize = 0 24 | for line in lines.values() do 25 | let res = is_tls_or_ssl(line) 26 | if res._1 then 27 | // env.out.write("supports TLS:").print(line) 28 | count = count + 1 29 | end 30 | if res._2 then 31 | // env.out.write("supports SSL:").print(line) 32 | count' = count' + 1 33 | end 34 | end 35 | env.out.print("count: " + count.string()) 36 | env.out.print("count': " + count'.string()) 37 | 38 | fun char_or_eol(line: String, index: USize): (EOL|U8) ? => 39 | if index >= line.size() then 40 | EOL 41 | else 42 | line(index) 43 | end 44 | 45 | fun is_tls_or_ssl(line: String): (Bool,Bool) => 46 | var abba_outside: USize = 0 47 | var abba_inside: USize = 0 48 | var collecting: String ref = String 49 | var state: LexState = OUTSIDE 50 | let abaSet = Set[String] 51 | let babSet = Set[String] 52 | 53 | for i in Range(0, line.size() + 1) do // + gets us EOL 54 | try 55 | let char = char_or_eol(line, i) 56 | state = match state 57 | | OUTSIDE => 58 | match char 59 | | '[' => 60 | abba_outside = abba_outside + is_abba(collecting.clone()) 61 | add_to_aba_set(abaSet, collecting.clone()) 62 | collecting = String 63 | INSIDE 64 | | EOL => 65 | abba_outside = abba_outside + is_abba(collecting.clone()) 66 | add_to_aba_set(abaSet, collecting.clone()) 67 | OUTSIDE 68 | else 69 | collecting.push(char as U8) 70 | OUTSIDE 71 | end 72 | | INSIDE => 73 | match char 74 | | ']' => 75 | abba_inside = abba_inside + is_abba(collecting.clone()) 76 | add_to_bab_set(babSet, collecting.clone()) 77 | collecting = String 78 | OUTSIDE 79 | | EOL => 80 | abba_outside = abba_outside + is_abba(collecting.clone()) 81 | add_to_bab_set(babSet, collecting.clone()) 82 | OUTSIDE 83 | else 84 | collecting.push(char as U8) 85 | INSIDE 86 | end 87 | else 88 | env.out.print("** error 1") 89 | error 90 | end 91 | end 92 | end 93 | let tls: Bool = if abba_inside > 0 then 94 | false 95 | else 96 | abba_outside > 0 97 | end 98 | let both = abaSet and babSet 99 | let ssl: Bool = if both.size() > 0 then 100 | true 101 | else 102 | false 103 | end 104 | (tls, ssl) 105 | 106 | fun print_set(msg: String, set: Set[String]) => 107 | env.out.print("{" + msg) 108 | for v in set.values() do 109 | env.out.print("--" + v) 110 | end 111 | 112 | fun add_to_aba_set(set: Set[String], token: String) => 113 | try 114 | var window: String ref = String 115 | for i in Range(0, 2) do 116 | window.push(token(i)) 117 | end 118 | 119 | for i in Range(2, token.size()) do 120 | window.push(token(i)) 121 | if is_window_aba(window) then 122 | set.set(window.clone()) 123 | end 124 | window.shift() 125 | end 126 | else 127 | env.out.print("** error 2") 128 | end 129 | 130 | fun add_to_bab_set(set: Set[String], token: String) => 131 | try 132 | var window: String ref = String 133 | for i in Range(0, 2) do 134 | window.push(token(i)) 135 | end 136 | 137 | for i in Range(2, token.size()) do 138 | window.push(token(i)) 139 | if is_window_aba(window) then 140 | set.set(invert_aba(window)) 141 | end 142 | window.shift() 143 | end 144 | else 145 | env.out.print("** error 2") 146 | end 147 | 148 | fun invert_aba(window: String box): String => 149 | let result: String ref = String 150 | try 151 | result.push(window(1)) 152 | result.push(window(0)) 153 | result.push(window(1)) 154 | else 155 | env.out.print("** window broken") 156 | end 157 | result.clone() 158 | 159 | fun is_window_aba(window: String box): Bool ? => 160 | (window(0) == window(2)) 161 | and 162 | (window(0) != window(1)) 163 | 164 | fun is_abba(token: String): USize => 165 | try 166 | var window: String ref = String 167 | for i in Range(0, 3) do 168 | window.push(token(i)) 169 | end 170 | 171 | for i in Range(3, token.size()) do 172 | window.push(token(i)) 173 | if is_window_abba(window) then 174 | return 1 175 | end 176 | window.shift() 177 | end 178 | else 179 | env.out.print("** error 2") 180 | end 181 | 0 182 | 183 | fun is_window_abba(window: String box): Bool ? => 184 | // env.out.print("window: " + window) 185 | if window(0) == window(1) then 186 | return false 187 | end 188 | if (window(0) == window(3)) and (window(1) == window(2)) then 189 | return true 190 | end 191 | false 192 | -------------------------------------------------------------------------------- /day8/.gitignore: -------------------------------------------------------------------------------- 1 | day8 -------------------------------------------------------------------------------- /day8/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | """rect 3x2 4 | rotate column x=1 by 1 5 | rotate row y=0 by 4 6 | rotate row x=1 by 1""" 7 | 8 | fun puzzle(): String => 9 | """rect 1x1 10 | rotate row y=0 by 6 11 | rect 1x1 12 | rotate row y=0 by 3 13 | rect 1x1 14 | rotate row y=0 by 5 15 | rect 1x1 16 | rotate row y=0 by 4 17 | rect 2x1 18 | rotate row y=0 by 5 19 | rect 2x1 20 | rotate row y=0 by 2 21 | rect 1x1 22 | rotate row y=0 by 5 23 | rect 4x1 24 | rotate row y=0 by 2 25 | rect 1x1 26 | rotate row y=0 by 3 27 | rect 1x1 28 | rotate row y=0 by 3 29 | rect 1x1 30 | rotate row y=0 by 2 31 | rect 1x1 32 | rotate row y=0 by 6 33 | rect 4x1 34 | rotate row y=0 by 4 35 | rotate column x=0 by 1 36 | rect 3x1 37 | rotate row y=0 by 6 38 | rotate column x=0 by 1 39 | rect 4x1 40 | rotate column x=10 by 1 41 | rotate row y=2 by 16 42 | rotate row y=0 by 8 43 | rotate column x=5 by 1 44 | rotate column x=0 by 1 45 | rect 7x1 46 | rotate column x=37 by 1 47 | rotate column x=21 by 2 48 | rotate column x=15 by 1 49 | rotate column x=11 by 2 50 | rotate row y=2 by 39 51 | rotate row y=0 by 36 52 | rotate column x=33 by 2 53 | rotate column x=32 by 1 54 | rotate column x=28 by 2 55 | rotate column x=27 by 1 56 | rotate column x=25 by 1 57 | rotate column x=22 by 1 58 | rotate column x=21 by 2 59 | rotate column x=20 by 3 60 | rotate column x=18 by 1 61 | rotate column x=15 by 2 62 | rotate column x=12 by 1 63 | rotate column x=10 by 1 64 | rotate column x=6 by 2 65 | rotate column x=5 by 1 66 | rotate column x=2 by 1 67 | rotate column x=0 by 1 68 | rect 35x1 69 | rotate column x=45 by 1 70 | rotate row y=1 by 28 71 | rotate column x=38 by 2 72 | rotate column x=33 by 1 73 | rotate column x=28 by 1 74 | rotate column x=23 by 1 75 | rotate column x=18 by 1 76 | rotate column x=13 by 2 77 | rotate column x=8 by 1 78 | rotate column x=3 by 1 79 | rotate row y=3 by 2 80 | rotate row y=2 by 2 81 | rotate row y=1 by 5 82 | rotate row y=0 by 1 83 | rect 1x5 84 | rotate column x=43 by 1 85 | rotate column x=31 by 1 86 | rotate row y=4 by 35 87 | rotate row y=3 by 20 88 | rotate row y=1 by 27 89 | rotate row y=0 by 20 90 | rotate column x=17 by 1 91 | rotate column x=15 by 1 92 | rotate column x=12 by 1 93 | rotate column x=11 by 2 94 | rotate column x=10 by 1 95 | rotate column x=8 by 1 96 | rotate column x=7 by 1 97 | rotate column x=5 by 1 98 | rotate column x=3 by 2 99 | rotate column x=2 by 1 100 | rotate column x=0 by 1 101 | rect 19x1 102 | rotate column x=20 by 3 103 | rotate column x=14 by 1 104 | rotate column x=9 by 1 105 | rotate row y=4 by 15 106 | rotate row y=3 by 13 107 | rotate row y=2 by 15 108 | rotate row y=1 by 18 109 | rotate row y=0 by 15 110 | rotate column x=13 by 1 111 | rotate column x=12 by 1 112 | rotate column x=11 by 3 113 | rotate column x=10 by 1 114 | rotate column x=8 by 1 115 | rotate column x=7 by 1 116 | rotate column x=6 by 1 117 | rotate column x=5 by 1 118 | rotate column x=3 by 2 119 | rotate column x=2 by 1 120 | rotate column x=1 by 1 121 | rotate column x=0 by 1 122 | rect 14x1 123 | rotate row y=3 by 47 124 | rotate column x=19 by 3 125 | rotate column x=9 by 3 126 | rotate column x=4 by 3 127 | rotate row y=5 by 5 128 | rotate row y=4 by 5 129 | rotate row y=3 by 8 130 | rotate row y=1 by 5 131 | rotate column x=3 by 2 132 | rotate column x=2 by 3 133 | rotate column x=1 by 2 134 | rotate column x=0 by 2 135 | rect 4x2 136 | rotate column x=35 by 5 137 | rotate column x=20 by 3 138 | rotate column x=10 by 5 139 | rotate column x=3 by 2 140 | rotate row y=5 by 20 141 | rotate row y=3 by 30 142 | rotate row y=2 by 45 143 | rotate row y=1 by 30 144 | rotate column x=48 by 5 145 | rotate column x=47 by 5 146 | rotate column x=46 by 3 147 | rotate column x=45 by 4 148 | rotate column x=43 by 5 149 | rotate column x=42 by 5 150 | rotate column x=41 by 5 151 | rotate column x=38 by 1 152 | rotate column x=37 by 5 153 | rotate column x=36 by 5 154 | rotate column x=35 by 1 155 | rotate column x=33 by 1 156 | rotate column x=32 by 5 157 | rotate column x=31 by 5 158 | rotate column x=28 by 5 159 | rotate column x=27 by 5 160 | rotate column x=26 by 5 161 | rotate column x=17 by 5 162 | rotate column x=16 by 5 163 | rotate column x=15 by 4 164 | rotate column x=13 by 1 165 | rotate column x=12 by 5 166 | rotate column x=11 by 5 167 | rotate column x=10 by 1 168 | rotate column x=8 by 1 169 | rotate column x=2 by 5 170 | rotate column x=1 by 5""" 171 | -------------------------------------------------------------------------------- /day8/main.pony: -------------------------------------------------------------------------------- 1 | use "regex" 2 | use "collections" 3 | use "debug" 4 | 5 | class RECT 6 | let w: U32 7 | let h: U32 8 | new create(width: U32, height: U32) => 9 | w = width 10 | h = height 11 | fun string(): String => 12 | String.append("rect ").append(w.string()).append("x").append(h.string()).clone() 13 | 14 | class RotateROW 15 | let y: U32 16 | let d: U32 17 | new create(y': U32, d': U32) => 18 | y = y' 19 | d = d' 20 | fun string(): String => 21 | "y = " + y.string() +" by " + d.string() 22 | 23 | class RotateCOLUMN 24 | let x: U32 25 | let d: U32 26 | new create(x': U32, d': U32) => 27 | x = x' 28 | d = d' 29 | fun string(): String => 30 | "x = " + x.string() +" by " + d.string() 31 | 32 | type Operation is (RECT|RotateROW|RotateCOLUMN) 33 | 34 | class Screen 35 | let width: USize 36 | let height: USize 37 | let rows: Array[String ref] = Array[String ref] 38 | 39 | new create(width': USize, height': USize) => 40 | width = width' 41 | height = height' 42 | for r in Range(0, height) do 43 | let str: String ref = String 44 | for c in Range(0, width) do 45 | str.push('.') 46 | end 47 | rows.push(str.clone()) 48 | end 49 | fun print(env: Env) => 50 | for r in rows.values() do 51 | env.out.print(r.clone()) 52 | end 53 | fun ref apply(op: Operation) ? => 54 | // Debug.out(op.string()) 55 | match op 56 | | let rect: RECT => 57 | for y in Range(0, rect.h.usize()) do 58 | for x in Range(0, rect.w.usize()) do 59 | rows(y)(x) = '#' 60 | end 61 | end 62 | | let rr: RotateROW => 63 | let oldRow = rows(rr.y.usize()).clone() 64 | for c in Range(0, width) do 65 | let tc = (c + rr.d.usize()) % width 66 | rows(rr.y.usize())(tc) = oldRow(c) 67 | end 68 | | let rc: RotateCOLUMN => 69 | let oldCol: String ref = String 70 | for r in Range(0, height) do 71 | oldCol.push(rows(r)(rc.x.usize())) 72 | end 73 | for r in Range(0, height) do 74 | let tr = (r + rc.d.usize()) % height 75 | rows(tr.usize())(rc.x.usize()) = oldCol(r) 76 | end 77 | end 78 | fun count(): USize => 79 | var cnt: USize = 0 80 | for r in Range(0, height) do 81 | for c in Range(0, width) do 82 | try 83 | let char = rows(r)(c) 84 | if char == '#' then 85 | cnt = cnt + 1 86 | end 87 | end 88 | end 89 | end 90 | cnt 91 | 92 | actor Main 93 | let env: Env 94 | new create(env': Env) => 95 | env = env' 96 | 97 | do_sample() 98 | do_puzzle() 99 | 100 | fun do_sample() => 101 | let ops = parse_input(INPUT.sample().split("\n")) 102 | let screen = Screen(7,3) 103 | for o in ops.values() do 104 | try 105 | screen(o) 106 | else 107 | env.err.print("** error 1") 108 | end 109 | end 110 | screen.print(env) 111 | env.out.write("n: ").print(screen.count().string()) 112 | 113 | fun do_puzzle() => 114 | let ops = parse_input(INPUT.puzzle().split("\n")) 115 | let screen = Screen(50, 6) 116 | for o in ops.values() do 117 | try 118 | screen(o) 119 | else 120 | env.err.print("** error 2") 121 | end 122 | end 123 | screen.print(env) 124 | env.out.write("n: ").print(screen.count().string()) 125 | 126 | fun parse_input(lines: Array[String]): Array[Operation] => 127 | let result = Array[Operation] 128 | for line in lines.values() do 129 | try 130 | result.push(parse_line(line)) 131 | else 132 | env.err.print("** Failed on " + line) 133 | end 134 | end 135 | result 136 | 137 | fun parse_line(line: String): Operation ? => 138 | let r = Regex("rect (\\d+)x(\\d+)") 139 | let cr = Regex("rotate (column|row) x=(\\d+) by (\\d+)") 140 | let rr = Regex("rotate (column|row) y=(\\d+) by (\\d+)") 141 | 142 | if r == line then 143 | let matched = r(line) 144 | return RECT( 145 | matched(1).read_int[U32]()._1, 146 | matched(2).read_int[U32]()._1) 147 | end 148 | if cr == line then 149 | let matched = cr(line) 150 | return RotateCOLUMN( 151 | matched(2).read_int[U32]()._1, 152 | matched(3).read_int[U32]()._1) 153 | end 154 | if rr == line then 155 | let matched = rr(line) 156 | return RotateROW( 157 | matched(2).read_int[U32]()._1, 158 | matched(3).read_int[U32]()._1) 159 | end 160 | env.err.write("** No match: ").print(line) 161 | error 162 | -------------------------------------------------------------------------------- /day9/.gitignore: -------------------------------------------------------------------------------- 1 | day9 2 | -------------------------------------------------------------------------------- /day9/input.pony: -------------------------------------------------------------------------------- 1 | primitive INPUT 2 | fun sample(): String => 3 | """ 4 | ADVENT 5 | A(1x5)BC 6 | (3x3)XYZ 7 | A(2x2)BCD(2x2)EFG 8 | (6x1)(1x3)A 9 | X(8x2)(3x3)ABCY 10 | """ 11 | 12 | fun puzzle(): String => 13 | """(143x8)(22x7)(4x15)XOPG(7x9)JDPAKGM(8x8)ALGCJRZQ(38x1)(4x10)VNSW(12x10)BZPAZABYKIDJ(3x14)IHF(40x15)(34x8)UGTIHCTVONZPPIWUAEGHGFJUNTIMIELOLW(6x1)XLMMKD(19x1)CLTHZNGCSMZITKBOZBZ(16x10)VALWVLALGUCXHAJT(121x14)(33x14)PXYJATIWOWRSCORYAPBWJSFOOXURQGUPE(56x5)(10x3)DQINJUWAMT(16x5)FSEYWRHWTGLEANIZ(12x4)ISBCDNXTOTIC(1x15)B(6x10)(1x7)CSBHNVBBNQPUFVSPODCHALPI(6851x14)(1837x7)(353x11)(7x4)(2x4)YQ(7x15)MOBFPOM(320x14)(272x2)(9x10)YBHVXLRDX(5x10)XJRJL(65x8)(1x1)T(21x2)XMPKSAQBHNXFSIGDQKXBT(2x7)HP(19x3)OVTOKRSBKJAVBIOUEOL(89x11)(8x5)WDUCSQFE(5x3)TUGKX(16x11)XTJETBLUHHKPKKAJ(7x13)RZAQFQM(24x7)DAVMEYZXPMQWKRKQDRDMYWZK(73x9)(5x1)CMJQZ(6x7)ZGGEFE(1x13)M(11x4)MOVLJYGTUUO(22x4)QZLZYJTLBGKNWCBQEVPPVE(35x9)(21x8)ZJZWFKGZJVRBTMGUUVLMD(2x14)HH(223x4)(63x8)(18x10)LOCHLWKDEDHYHDOVDB(32x9)DRUTZMMGSMRGGMTKBCKYLKCRHENSVICE(3x12)VQE(30x10)FVBATVKKQMVCURXCYZPZNVVRMCIKLU(100x12)(30x6)(23x15)(17x1)XVZNYVGWAZTXMPFQK(2x5)OD(12x14)DIBMBTMLPJKQ(32x6)(12x3)QHTMLKVXWQZK(8x14)GJCLEEAU(389x1)(226x8)(3x8)FBD(25x3)(18x14)KMVYMVSRAXIWSCECNW(170x8)(49x5)(9x4)ULEYLYNJY(18x7)CLTXDTVORLXUOTFCLJ(5x11)PTURS(53x12)(5x8)OBOYG(15x8)SKAEMEEBXJUJUWW(16x2)MCFKLYSMPEAEQFBA(32x6)(7x3)RHAXCPE(8x15)LAMFEDAW(1x9)I(11x5)FSPLMOCWRZK(4x14)WGCQ(149x1)(84x10)(38x13)(18x10)JVWJTCUNDKLYLIFNAK(1x13)O(1x9)G(13x10)(7x14)PGQAEDM(13x6)SLWXIJOMADJLP(3x10)VPI(43x3)(36x11)(1x14)T(4x10)SKRX(5x2)OMCYG(4x6)DQRQ(835x11)(174x10)(81x12)(67x9)(2x13)NR(18x12)RAJKIINYGUXLOUYENK(13x13)OZIWQKWWTUJXF(8x11)EMKSLPRX(3x1)AGE(80x4)(68x4)(2x1)UX(22x12)SMBEEPGHUNJAQZKAWVLLMT(8x4)PFJOHXRV(1x6)X(8x6)SEIMXVVM(1x1)J(69x2)(8x4)FURIFHFB(40x13)(21x5)(5x4)LNZZY(6x2)QFGLMR(7x12)(2x8)XS(3x13)OWJ(571x6)(174x6)(14x2)BSADXDDLJLEVBB(54x8)(5x13)XDYHG(8x2)RZNUYFXX(1x7)G(10x8)ZZWDGZTDKN(3x4)OFG(87x11)(27x6)IKAHWVVLATFUIMJOTCZMIOPAFCI(6x4)WXDRJN(16x3)VHKSZEABZLZJSCEP(14x13)NFTURHBVVUHXTP(96x15)(56x15)(2x6)SG(3x15)MJH(33x12)RIWEVKXHXGWSJOMLFQPNJILPTNYOCKPOK(11x7)(5x11)JBZRA(2x5)UC(3x10)OMB(6x13)UYKLMI(75x8)(5x7)RNUEO(59x4)(16x8)ISRGFLEIVCWUHMXM(2x10)XJ(1x2)F(16x12)XVTXZKCKMPXCRZKE(186x10)(13x15)OOKJFSXSSGOKX(56x6)(16x15)GOGUQYXMCUOYIZAS(13x3)XDXFDHEEKCXSD(9x8)LNBOQQDVV(55x11)(2x15)OR(1x15)F(13x10)IDEHWRDIWEKSW(14x9)KYLMLJMZIEPMEZ(3x3)ETX(28x1)(3x4)JFL(14x8)MWDXXMSIFHRGOT(2x2)ZF(2764x12)(429x11)(149x7)(7x7)UVPIIIH(33x10)CMDUQOXWGOIYJPXMDJSVBSBTKZCNWSZEP(90x13)(84x1)(6x4)ZVCUNP(2x6)SF(23x2)VTWDHVYQEWTIHUWIKIUOKKR(9x13)CTXDYHPTH(15x15)NAHZFZHMSJCPDZD(266x3)(11x15)SADHZVETNOX(241x6)(14x5)YUVPESDLQTIKTV(46x1)ZIMMCIPFXSZJNSQUPRPFNAOCIFINUDOCSGYYYTWOPFKBGK(66x13)(28x3)CMZWUBZEIKULJWDWVPYFTZKTRXBG(5x8)HYKCE(4x14)KQQH(7x5)PMPUJYI(74x1)(12x13)ABUKTEQSSDJY(1x15)R(9x9)OVZPKGCLK(2x11)TG(19x13)TAJXSLMQKEAXQRXEPRP(10x4)VMOGPHQCOE(498x10)(21x5)(5x3)PUUYR(5x10)RNLRC(19x2)WSXCBBUHPRTTDLVVCTW(225x8)(7x3)AZCJJGH(194x12)(21x12)PGXOCMGUAPORUREJXOZVV(1x10)E(12x11)MYUUCXKMOGOW(59x8)(24x6)OVCPKGYHILZMSRUKLSNEXYWS(6x10)YXSZQF(10x11)RJCURKGVSA(69x2)(8x6)MUBPJIEW(2x1)YV(13x4)EYQREONZMEQGI(14x7)KRAJKLWPQUOHAF(5x1)IINXC(6x5)QCFNCP(207x5)(162x8)(21x1)(6x6)URWVXQ(5x7)NTTNO(51x10)(3x9)KTX(15x10)KIDPFFJOMAKFGEP(8x3)EDQKQGDQ(2x11)XP(9x9)YPVKLXABX(28x4)(10x8)ZPOJTXYCWK(1x6)H(1x9)V(22x13)(1x11)D(2x14)IB(1x14)R(8x1)IMNVABZA(18x10)AYYHMMTVCTALMDRTTY(1186x4)(426x12)(10x12)(5x7)COTFY(185x11)(26x3)(3x9)MBB(7x7)LBMDHKJ(1x9)L(23x13)QGMBUZUVDVCVLEYADPLMWVQ(3x11)XAP(83x5)(25x12)EKVTQEDEQXIFIGMJNUKZJTQYT(36x4)DEQXETWJMAUEOWHEZNHWGDEWJERBWZMLIBDR(3x15)UDI(19x8)JKCQYDKDITVWBXULCAK(208x11)(84x3)(1x5)N(18x15)TSKZQXYIUVKGKMKLGT(13x6)UEONLUHISGWPT(28x2)MTYEJXWLSDNOVKAAEDDTGLLTGBHR(76x11)(19x8)HNKLLAKBLOSVSDMFOLE(9x3)ERDRBAHWP(8x11)KCOHRRBA(7x5)GCVHIKI(6x9)OVOUKW(11x11)ZLMSNQQTTLW(11x1)(6x9)QBZQNW(376x8)(256x14)(24x6)(6x8)XXKOAV(8x4)YERUBDOP(21x2)VSYQGMMOAQNFSZNKEJMXL(97x12)(20x4)ELTZIBCGEFVJHPETQZHO(3x8)FQG(1x15)Z(37x9)CDWVBANWVKKNVSJMMJPGONUFLDKHUDVIOBXUF(7x14)HOKGPLC(39x10)(19x13)AUHRABETDCLCQIDLQTO(8x7)IHLJMIAM(43x1)(22x3)WHQKLPTHFSHNGCEYYFVAJZ(9x14)IQGSXZIFB(6x9)PQZUZM(81x12)(12x7)RVDAWIZOLVQX(46x1)(5x5)ZZUAP(9x7)TUBIKHAVF(1x4)C(3x5)ZDW(3x2)GZR(5x13)ZTKCX(8x5)RUIPWQKS(139x12)(4x9)ZQRF(52x15)(37x1)(12x14)BWDQNPBEHHUW(4x11)OCUO(2x11)SP(4x2)OFAA(65x1)(18x10)(12x2)CFRFJOBRRAHZ(34x7)(1x1)G(14x4)VOAXQXVGUMVINO(2x15)SW(191x11)(183x14)(100x14)(1x9)U(12x15)VTUYYRSODESQ(31x15)TGSDRMNTWWYHZDTMTZKWIPJMEXCIKMY(18x5)HYFYNJYBHAIDDHFNNL(8x5)YBYZYEJR(8x2)RTBHYMQI(42x12)(10x10)IYEPKYGTOB(3x15)KAM(1x9)F(5x4)LEWBO(8x4)FMFOTKAU(17x8)KNDZJJLCNMGUTBYNS(467x13)(209x6)(148x14)(3x5)XSE(6x1)XJNQKW(74x11)(30x2)OYEEFTIUNLLCTKZHSMUOEBGAJUKLHR(20x2)NVGBWMJWWDPSOHSDVLJD(7x7)QJRZAUF(42x8)YKPGEOXLZMJOLRJTUNOXAYDJKMTXQGDNRVINDLBPTD(12x1)SHAGOOFKKBXE(29x4)(16x13)(1x2)C(5x3)QJMEV(1x5)H(244x4)(110x10)(103x5)(4x12)ZVJM(28x10)JLHDJYLAPCPDLHOZURARRTJTOYXI(13x3)LWRNIXINNQMSJ(20x2)YCYAHDNQLLBKZKVUNRUJ(8x7)WHXSOQVK(71x10)(14x12)(9x3)SUTUFTGLH(1x5)X(37x13)ZDZQBIKRACVXLTTBPIWLVVOXTQUMWMBGHRPLM(41x11)(15x10)(9x13)IKUYTOKNU(12x10)YBTNEIPFBPYQ(144x13)(118x13)(94x8)(3x14)HBL(51x10)(16x14)GJIIPYAQSJSZOAYG(22x2)LSCXUGELCOUDODAXICVDKM(4x15)ZJOT(10x12)MDMYANLMSJ(12x2)SFNEHAVVNRVA(12x1)KORQJVTAAYCM(2204x11)(341x8)(334x5)(125x3)(51x6)(7x11)JSIXUKZ(5x3)ZRFCB(7x6)BCAGHEM(10x1)XAKGJBAFVH(62x5)(23x15)EJCYSGOHVWYIXJVZAGONCUU(5x4)PFOZW(16x1)ZRQQLBUIILWQVERI(113x15)(2x8)PZ(99x12)(14x5)WIHCMMGPTYRSYU(14x7)UQWHOZRLTGQBAD(4x15)TMGY(27x11)NQOSQKJNZETHKKBEQQFRAZXANUJ(9x15)EJQYPZTSF(75x4)(3x12)JEV(22x8)MKXYJKAGYTGCIUZMFMYFXG(31x15)(13x15)AICLOBFSVABCW(6x5)RMVEDR(570x12)(191x8)(21x8)(15x8)(2x14)RA(2x2)RP(18x3)DLYMJPSBGPDEJPSWTD(132x12)(27x11)MALDYBRFSBALZSSKXGDEJHRMPEY(6x15)HDGAOT(80x8)(21x15)RPMHZBMKVBKVYFAKGBUOG(11x7)JDMRMBXYXFJ(3x3)PGK(9x15)XHGWFEKMS(6x12)OBDMXN(10x13)VZTXDPKEOJ(221x14)(136x5)(7x7)KOFBQMH(17x8)AXGVRRRVIYUTVLXYK(6x7)OCQVND(43x7)FQYXCUOIVOVLVQCVQUWANKEOKBNTWBRYDBRXDOORGYV(34x10)(28x4)EAYEMPUGGCQXXPYOUBNYDTWDKIIB(7x15)UVXKQLG(3x1)TKN(39x15)LHMQXTHAUBOBCOKWNNRBEHMHNAEZMXSYIRULNNX(6x8)UHNQYQ(42x12)YCCBHBGNBQWQITDZHCIWDQGBPJDWVSZLXBHFBZTNXX(70x13)(64x1)(3x6)IMA(50x1)(11x5)ZJWXZPRYZMS(3x6)DTK(8x2)HSRWFPBE(7x3)NQITYAF(550x15)(157x12)(4x15)CULH(63x7)(20x9)JKSLXREZWWMMUNGSFKKE(5x2)UHYAE(10x12)EVNMHFLJVG(4x14)LHLJ(72x1)(8x9)FHBNWEDX(2x7)LS(46x7)(8x5)BTBGGCGA(20x11)CMBXJXXVASRCEITYBBDS(1x6)I(5x13)WEXNR(367x2)(258x8)(59x4)(5x9)CGQVE(2x12)JU(23x5)ENUOLZGSAKUMZDPLUZJNORF(7x7)RWIMSVN(1x8)D(65x6)(22x11)LYMRFKDYRWHSPEFGZSSYAS(4x5)AOMJ(12x11)SJOTUWOGLFCP(3x5)PMB(108x15)(8x5)SFVFZKSV(3x3)URR(12x1)FLSFLNYPJWTL(32x12)KUBKDLJFAOCRQYHGGBQOLOLIKPYRFDDF(24x7)KYGCXSDUGCXKMEVUGKLUNZAT(95x11)(89x8)(12x9)BTUGSRSILKBV(18x6)EMUSAMBOMOYHVVSUEF(35x4)ZRVMFQWFDYPBYQXDOIIUMJQHAEDCZMYMPIW(1x9)H(713x7)(100x9)(2x5)EF(9x12)INJPHZJCG(72x2)(44x6)(4x15)XXWI(6x5)AKHVXV(1x12)F(3x2)KVK(2x12)NY(7x4)(1x12)S(5x2)NEPVZ(51x3)(34x1)(28x6)NLMEUVGWHSYSYVDMEGANJVPEZXXA(6x2)JZAWJK(173x9)(102x12)(6x3)(1x5)B(13x3)(7x13)NOJZEUQ(31x8)(3x10)CPP(15x10)XAMXQGQDXTMFFFJ(22x2)KXEPHSRHLAXWVTHUYYUOTQ(2x2)KI(24x14)(9x6)(4x8)CKZS(5x8)BGFNE(25x13)(8x3)IAZDNLPS(7x5)(1x13)V(345x1)(120x3)(61x12)(7x2)OEXPXRI(8x9)ARTERVYM(5x15)SVVHZ(8x9)KQKRQEQK(6x15)YPHUXP(13x7)(8x1)NYSDSLED(18x11)CBFTYQPXNDDMUSKBWA(2x12)AG(28x13)WNMFOTJZKSECVJNQGELGGFOVFXLH(138x8)(4x3)PAHR(29x15)(3x5)WVI(6x6)RBHYPB(5x8)XJGYF(68x7)(6x1)DKUUZV(3x10)FSZ(15x15)VBVSBJQQAMVQOFL(20x6)WXKJNUAQTMIWBFKEQBRG(12x11)WCUUSCREKMDI(7x15)(2x3)EU(18x10)(12x5)CIWKIUYZVFYC(11x1)(6x1)YTFEVP(14x3)AMZRUYKIEJEWGQ(2935x2)(747x7)(740x3)(152x6)(113x14)(63x7)(6x10)AROZFB(14x13)EEJUWNZBXBSJZB(7x7)ZTEZZAY(11x10)BZWJRMKJJXA(38x8)(1x8)M(26x7)ROFAUWBSJYYVFIZDCSULELNRMS(2x4)BM(7x11)XIMWVUI(6x4)(1x3)X(519x6)(92x9)(8x4)LWXAMAZO(2x6)HV(8x11)EZGATUUO(51x12)(4x4)NUQH(11x9)OYVORNQUUSY(6x12)LIYPIM(7x10)SBRMRZG(25x15)GMQEAMMROFEFMFCVBCDEDYCUK(103x1)(9x13)ZOPUZDBTZ(74x5)(33x3)HYGWJEAOUSOKTLFRDEWQYBSUUXTOZYEBW(11x12)FJKKFKWXZHI(3x2)WUK(4x4)UJSL(3x1)HTZ(147x12)(35x14)(9x3)DFLUOQIYB(15x7)ZSPVSVKOJIPWUNV(35x1)(4x4)QRXE(6x11)UFEDJL(9x6)ETFEROGHR(2x2)TT(50x13)(6x2)NBRGKE(14x1)FXYCOCFDTZXIEB(3x12)CPZ(5x3)YMGBR(116x13)(8x4)JYLJKJKO(52x5)(1x11)I(6x12)YTILES(2x13)XS(12x13)XIPTOZBANYYW(1x5)H(39x7)(12x15)IXXTDKZGZRIK(5x10)YGRYH(3x11)XGE(49x3)(43x9)(14x7)CBYKYWLCYCUISY(16x10)(3x8)NCB(2x14)ZJ(2173x9)(349x1)(198x12)(61x9)(42x3)(14x9)RXWYSJPPXVPEMH(2x2)CL(9x15)QLRYLZMJN(7x12)IVFTFHV(123x13)(11x2)RIGKDVWVFCK(15x13)KHGADJXLFQFVCID(43x14)JGKCHVWUFQPGCKOCSCEEDREVYKZUQOJYIYHMTBFTWKB(17x5)(2x10)RF(4x8)AAJL(5x10)KMGNT(61x4)(55x6)(8x11)RFUVGZGW(6x8)CWTPUZ(2x11)OI(15x14)IUUASQAUMTWLMYY(23x10)OTJBICKKDRZTLPMZSAGSKHE(6x13)KIDQQB(27x11)(9x7)ITZNVFMOM(7x12)KRJUTYV(481x10)(1x14)O(234x13)(19x14)VXFRZPOBQEPHZWUVPZA(194x15)(55x3)(23x2)OBUKIGZARPOUCKQKOCEWMNK(20x4)VHQCGAAJZBPDSAIKEVKU(13x13)WKSTPDBGYDIYI(24x4)(18x3)HYAFTYSAAOZACFKQNF(77x8)(3x9)IKC(26x8)MPLJVLHPCBCLQRKKSQVJUWLNPO(1x1)Y(13x3)ACIQYDRERJQPZ(7x7)BFZRAMT(1x2)V(224x12)(114x9)(16x14)(10x6)JGTPXHCKNM(10x12)XFSPPJPNLZ(4x9)MOQE(6x7)YIJANW(47x12)(21x7)XXXITCBDMXQALYVBIJZVD(14x9)BQEJZGPFQCLASY(26x2)(20x5)ZOIORXWFPWHOCUBYHLVH(57x14)(7x7)(1x14)S(2x14)LO(1x10)E(24x5)JRUQQVXLYMRJKEKCBUHHAXJB(1x11)B(1319x13)(533x3)(60x8)(12x5)CRSDECKETUKT(24x11)(9x12)EPAZHOCCB(3x11)YPV(5x12)RKIZQ(32x14)(13x11)(8x7)OBFWCEWY(7x8)LVXUCHZ(112x4)(86x14)(35x10)UAUAKCVFVWFUTVIMZKJVJSDLDKVVEHHEWES(10x15)GWMVEHCXRJ(15x6)ZOMXFSGCSMDQADO(1x4)D(12x11)YHYROORNKOOT(185x2)(44x1)(1x13)R(22x3)PECPELESXBNKNJYONHXKDW(3x15)BCZ(46x8)(31x15)EYMKMMRCNKAEXTOVHXYJGYRZSBZGTBR(3x3)YPE(17x4)AWZSWBGSORXCEDWEA(9x9)EOVQMSRLK(39x13)(2x14)FO(2x9)ZL(17x10)RDKXMAIWMJRNZCDNQ(110x9)(26x13)(4x5)AUXG(4x1)NKYZ(2x11)HM(12x2)(7x1)UYBISPR(21x12)WZFRACCFTYJYNYEBYDMWJ(25x3)(6x14)JQZIPJ(8x7)RYDRUQXE(9x14)WOIJUCMLC(62x1)(29x4)(13x1)PVZJAFZHCMKAD(4x14)DAAY(20x15)VXKSLRVAYJMDUAPZORZK(247x2)(1x12)C(146x13)(96x2)(20x5)MEXWMGWRESSUQLUNSKTQ(25x1)ENSINNLBWLXNKIVALELWWNLKT(4x11)EJAG(16x6)YFSVCDTGLMPBBVHH(2x5)IN(13x6)(8x9)JDSKGYVZ(11x3)(6x1)CWRMKZ(3x6)QGW(79x15)(8x9)JPMDKSUM(9x2)IEYSLSGHL(3x15)RJI(23x3)YBANOYRBOSDTLUSVTOPIASQ(8x10)WYAERLOF(434x15)(3x6)EED(10x5)(5x4)HZYMT(102x6)(87x15)(20x14)IYERDTUWPOBLAXBINHIS(27x6)YOQYWTHZYGFABTICETEEMLNNJPD(13x8)CXMOKWRXGAZZU(3x3)JXC(3x9)MVV(271x7)(20x6)IIHYPRNXHIVBYHWDOFZV(131x4)(2x15)TQ(40x3)EQOBUJXYUKNXRGHLRTKRYOHJNIWMAGNQDZIZCWZD(8x4)DFBSWLKP(28x12)XWOBMJVXWJAXIKOJDTVEPCHYJFBF(23x9)PCPQKRUGQNAZKIALGLVLJPE(1x8)I(14x5)YNKFVNTIGYUUEY(75x6)(1x15)L(15x5)CGTMUYBZXQZWKQX(21x7)YWCFVFFMZKXYGVEEPRVHT(6x6)AUFAKV(3x14)AFE(16x11)(3x15)XZR(2x5)FW(15x6)(9x12)JQUXZGTYC(102x5)(33x6)(4x14)VAKD(5x1)UFHXC(8x6)WYVCFYNW(4x7)VHWF(9x12)ZAFCJQEBF(4x4)GFAE(24x1)TTWSFNEPHVIFUZTSVGYVEHQU(156x2)(86x11)(10x4)JBGAPKEXGN(22x11)FVCUNKIMMVGDMYJKNMAZBP(14x2)QASMZHHHAQFIGR(15x8)WPZLJSRULHJVVFP(32x2)(4x15)PBUR(6x3)DMQCLZ(6x1)MHKQTY(18x15)SDIZPLVBRGOXNOKXMS(21x8)(8x4)CJVQZEBK(3x4)ARX(11x3)EVRICTWKIDT(6x1)BJLPZP(78x14)(9x8)(4x9)FFUW(14x15)CEWZNPRCESFWHZ(36x11)ITXHTYZRAPVDXJEZHBWMPIFNZUDTMVEGRMIC""" 14 | -------------------------------------------------------------------------------- /day9/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | class Plain 4 | let env: Env 5 | var _size: USize = 0 6 | let result: Array[State] ref 7 | var _data: String ref = String 8 | 9 | new create(env': Env, result': Array[State] ref) => 10 | env = env' 11 | result = result' 12 | fun ref transition(char: U8): State => 13 | match char 14 | | '(' => 15 | result.push(this) 16 | Instruction(env, result) 17 | else 18 | _data.push(char) 19 | _size = _size + 1 20 | this 21 | end 22 | fun ref eof() => 23 | result.push(this) 24 | fun size(): USize => 25 | _size 26 | fun size2(): USize => 27 | _size 28 | 29 | class Instruction 30 | let env: Env 31 | let result: Array[State] ref 32 | let _instr: String ref = String 33 | 34 | new create(env': Env, result': Array[State] ref) => 35 | env = env' 36 | result = result' 37 | fun ref transition(char: U8): State => 38 | try 39 | match char 40 | | ')' => 41 | let parts = _instr.split("x") 42 | let size' = parts(0).read_int[USize]()._1 43 | let times = parts(1).read_int[USize]()._1 44 | ReadingData(env, result, size', times) 45 | else 46 | _instr.push(char) 47 | this 48 | end 49 | else 50 | env.err.print("** Unparsable " + _instr) 51 | this 52 | end 53 | fun ref eof() => 54 | env.err.print("** End of file: " + _instr) 55 | fun size(): USize => 0 56 | fun size2(): USize => 0 57 | 58 | class ReadingData 59 | let env: Env 60 | let result: Array[State] ref 61 | let _size: USize 62 | let times: USize 63 | var _data: String ref = String 64 | 65 | new create(env': Env, result': Array[State] ref, size': USize, times': USize) => 66 | env = env' 67 | result = result' 68 | _size = size' 69 | times = times' 70 | fun ref transition(char: U8): State => 71 | _data.push(char) 72 | if _data.size() == _size then 73 | // for i in Range(0, times) do 74 | // result.append(_data) 75 | // end 76 | result.push(this) 77 | Plain(env, result) 78 | else 79 | this 80 | end 81 | fun ref eof() => 82 | if _data.size() == _size then 83 | result.push(this) 84 | else 85 | env.err.print("** End of file? ") 86 | end 87 | 88 | fun size(): USize => 89 | _size * times 90 | fun size2(): USize => 91 | var flag: Bool = _data == "A" 92 | var len: USize = 0 93 | let decompress = DECOMP.decompress(env, _data) 94 | for s in decompress.values() do 95 | if flag then 96 | match s 97 | | let s': ReadingData => env.out.print("data") 98 | | let s': Instruction => env.out.print("instruction") 99 | | let s': Plain => env.out.print("plain") 100 | end 101 | end 102 | len = len + s.size2() 103 | end 104 | if flag then 105 | env.out 106 | .write("nested: " + _data) 107 | .write(", len: " + len.string()) 108 | .print(", d.size: " + decompress.size().string()) 109 | end 110 | len * times 111 | 112 | type State is (Plain|Instruction|ReadingData) 113 | 114 | primitive DECOMP 115 | fun decompress(env: Env, input: String box): Array[State] ref => 116 | let result: Array[State] ref = Array[State] 117 | var state: State ref = Plain(env, result) 118 | for rune in input.values() do 119 | state = match state 120 | | let s: Plain => s.transition(rune) 121 | | let s: Instruction => s.transition(rune) 122 | | let s: ReadingData => s.transition(rune) 123 | else 124 | state 125 | end 126 | end 127 | state.eof() 128 | result 129 | 130 | actor Main 131 | let env: Env 132 | new create(env': Env) => 133 | env = env' 134 | 135 | print_result(DECOMP.decompress(env, INPUT.sample())) 136 | print_result2(DECOMP.decompress(env, "(27x12)(20x12)(13x14)(7x10)(1x12)A")) 137 | print_result(DECOMP.decompress(env, INPUT.puzzle())) 138 | print_result2(DECOMP.decompress(env, INPUT.puzzle())) 139 | 140 | fun print_result(result: Array[State]) => 141 | var len: USize = 0 142 | for s in result.values() do 143 | len = len + s.size() 144 | end 145 | env.out.print("length: " + len.string()) 146 | 147 | fun print_result2(result: Array[State]) => 148 | var len: USize = 0 149 | for s in result.values() do 150 | len = len + s.size2() 151 | end 152 | env.out.print("length2: " + len.string()) 153 | --------------------------------------------------------------------------------