|
| 1 | +import os |
| 2 | + |
| 3 | +struct Position { |
| 4 | +pub mut: |
| 5 | + x i64 @[required] |
| 6 | + y i64 @[required] |
| 7 | +} |
| 8 | + |
| 9 | +struct Velocity { |
| 10 | +pub mut: |
| 11 | + x i64 @[required] |
| 12 | + y i64 @[required] |
| 13 | +} |
| 14 | + |
| 15 | +struct Robot { |
| 16 | +pub mut: |
| 17 | + position Position @[required] |
| 18 | + velocity Velocity @[required] |
| 19 | +} |
| 20 | + |
| 21 | +const width = 101 |
| 22 | +const height = 103 |
| 23 | + |
| 24 | +fn main() { |
| 25 | + mut robots := os.read_file('robots.input')!.split_into_lines().map(fn (line string) Robot { |
| 26 | + split := line.split(' ') |
| 27 | + position := Position{ |
| 28 | + x: i64(split[0].split(',')[0].split('=')[1].int()) |
| 29 | + y: i64(split[0].split(',')[1].int()) |
| 30 | + } |
| 31 | + velocity := Velocity{ |
| 32 | + x: i64(split[1].split(',')[0].split('=')[1].int()) |
| 33 | + y: i64(split[1].split(',')[1].int()) |
| 34 | + } |
| 35 | + return Robot{ |
| 36 | + position: position |
| 37 | + velocity: velocity |
| 38 | + } |
| 39 | + }) |
| 40 | + |
| 41 | + // simulate all robots for 100 seconds |
| 42 | + mut robots1 := robots.clone() |
| 43 | + for _ in 0 .. 100 { |
| 44 | + // apply velocity to all robots and if we hit the edge we teleport to the other side |
| 45 | + for mut robot in robots1 { |
| 46 | + robot.position.x += robot.velocity.x |
| 47 | + robot.position.y += robot.velocity.y |
| 48 | + robot.position.x = (robot.position.x + width) % width |
| 49 | + robot.position.y = (robot.position.y + height) % height |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + // To determine the safest area, count the number of robots in each quadrant after 100 seconds. Robots that are exactly in the middle (horizontally or vertically) don't count as being in any quadrant, so the only relevant robots are: |
| 54 | + mut quadrants := [4]i64{} |
| 55 | + for robot in robots1 { |
| 56 | + if robot.position.x == width / 2 || robot.position.y == height / 2 { |
| 57 | + continue |
| 58 | + } |
| 59 | + if robot.position.x < width / 2 { |
| 60 | + if robot.position.y < height / 2 { |
| 61 | + quadrants[0] += 1 |
| 62 | + } else { |
| 63 | + quadrants[1] += 1 |
| 64 | + } |
| 65 | + } else { |
| 66 | + if robot.position.y < height / 2 { |
| 67 | + quadrants[2] += 1 |
| 68 | + } else { |
| 69 | + quadrants[3] += 1 |
| 70 | + } |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + mut result1 := quadrants[0] * quadrants[1] * quadrants[2] * quadrants[3] |
| 75 | + println('part1: ${result1}') |
| 76 | + |
| 77 | + // simulate all robots for 100 seconds |
| 78 | + mut robots2 := robots.clone() |
| 79 | + mut i := 1 |
| 80 | + for { |
| 81 | + // apply velocity to all robots and if we hit the edge we teleport to the other side |
| 82 | + for mut robot in robots2 { |
| 83 | + robot.position.x += robot.velocity.x |
| 84 | + robot.position.y += robot.velocity.y |
| 85 | + robot.position.x = (robot.position.x + width) % width |
| 86 | + robot.position.y = (robot.position.y + height) % height |
| 87 | + } |
| 88 | + |
| 89 | + mut positions := []Position{} |
| 90 | + mut unique := true |
| 91 | + for robot in robots2 { |
| 92 | + if robot.position in positions { |
| 93 | + unique = false |
| 94 | + break |
| 95 | + } |
| 96 | + positions << robot.position |
| 97 | + } |
| 98 | + if unique { |
| 99 | + target_length := 5 |
| 100 | + mut length := 0 |
| 101 | + for position in positions { |
| 102 | + mut current_position := position |
| 103 | + for positions.contains(current_position) { |
| 104 | + length += 1 |
| 105 | + |
| 106 | + if length == target_length { |
| 107 | + break |
| 108 | + } |
| 109 | + |
| 110 | + current_position.x += 1 |
| 111 | + } |
| 112 | + |
| 113 | + if length == target_length { |
| 114 | + break |
| 115 | + } |
| 116 | + |
| 117 | + length = 0 |
| 118 | + } |
| 119 | + |
| 120 | + if length == target_length { |
| 121 | + break |
| 122 | + } |
| 123 | + } |
| 124 | + i += 1 |
| 125 | + } |
| 126 | + |
| 127 | + println('part2: ${i}') |
| 128 | +} |
0 commit comments