day16_pt1.java (4124B)
1 import java.nio.file.Files; 2 import java.nio.file.Path; 3 import java.io.IOException; 4 import java.util.*; 5 import java.util.stream.*; 6 import java.util.regex.*; 7 8 class day16_pt1 { 9 enum Dir{ 10 North, 11 East, 12 South, 13 West; 14 15 Vec unitVec() { 16 return switch (this) { 17 case North -> new Vec(0, -1); 18 case East -> new Vec(1, 0); 19 case South -> new Vec(0, 1); 20 case West -> new Vec(-1, 0); 21 }; 22 } 23 Dir opp() { 24 return switch(this) { 25 case North -> South; 26 case East -> West; 27 case South -> North; 28 case West -> East; 29 }; 30 } 31 // there's a better way with matrix multiplication 32 // but I'm not going to write it r.n. 33 int nr(Dir other) { 34 return switch (this) { 35 case North -> switch (other) { 36 case North -> 0; 37 case East -> 1; 38 case South -> 2; 39 case West -> 1; 40 }; 41 case East -> switch (other) { 42 case North -> 1; 43 case East -> 0; 44 case South -> 1; 45 case West -> 2; 46 }; 47 case South -> switch (other) { 48 case North -> 2; 49 case East -> 1; 50 case South -> 0; 51 case West -> 1; 52 }; 53 case West -> switch (other) { 54 case North -> 1; 55 case East -> 2; 56 case South -> 1; 57 case West -> 0; 58 }; 59 }; 60 } 61 } 62 record Point(int x, int y) { 63 Point add(Vec v){ 64 return new Point(this.x + v.x, this.y + v.y); 65 } 66 } 67 record Vec(int x, int y){} 68 public static void main(String[] args) throws IOException { 69 var grid = Files.readAllLines(Path.of(args[0])); 70 var height = grid.size(); 71 var width = grid.get(0).length(); 72 var scores = new int[height][width]; 73 Point start = null; 74 Point end = null; 75 for (var y=0; y<height; y++) { 76 for (var x=0; x<width; x++) { 77 scores[y][x] = Integer.MAX_VALUE; 78 var p = new Point(x, y); 79 var ch = gv(grid, p); 80 switch (ch) { 81 case 'S': 82 start = p; 83 break; 84 case 'E': 85 scores[y][x] = 0; 86 end = p; 87 break; 88 } 89 } 90 } 91 92 // From the start, recurse backwards over the whole grid 93 // to find hte scores to each point 94 var dirOut = new Dir[]{null}; // surely there's a neater way 95 for (var dir : Dir.values()) { 96 var pp = end.add(dir.unitVec()); 97 scores[pp.y][pp.x] = 1; 98 markScores(grid, pp, dir.opp(), scores, dirOut); 99 } 100 101 // debug 102 // for (int y=0;y<height;y++) { 103 // for (int x=0;x<width;x++) { 104 // var ss = scores[y][x]; 105 // if (ss < Integer.MAX_VALUE) { 106 // System.out.printf("|%05d", ss); 107 // } else { 108 // System.out.printf("| ", ss); 109 // } 110 111 // } 112 // System.out.print('\n'); 113 // } 114 // Now simply read the score from the start point 115 var res = scores[start.y][start.x]; 116 // and twiddle for any 117 // initial rotation we had to do 118 var dd = dirOut[0]; 119 res += 1000 * dd.nr(Dir.East); 120 System.out.printf("Day 16, pt1: %d\n", res); 121 } 122 123 static void markScores(List<String> grid, Point cur, Dir curDir, int[][] scores, Dir[] dirOut) { 124 var curScore = scores[cur.y][cur.x]; 125 for (var dir : Dir.values()) { 126 var pp = cur.add(dir.unitVec()); 127 var ch = gv(grid, pp); 128 switch (ch) { 129 case '#': break; // Wall, do nothing. 130 case 'S': 131 case '.': 132 int add = 1 + dir.opp().nr(curDir) * 1000; 133 var s = curScore + add; 134 var ss = scores[pp.y][pp.x]; 135 if (s < ss) { 136 if (ch == 'S') 137 dirOut[0] = dir.opp(); 138 scores[pp.y][pp.x] = s; 139 markScores(grid, pp, dir.opp(), scores, dirOut); 140 } 141 break; 142 } 143 } 144 } 145 146 static int gv(List<String> grid, Point p) { 147 var height = grid.size(); 148 if (p.y < 0 || p.y >= height) return -1; 149 var width = grid.get(0).length(); 150 if (p.x < 0 || p.x >= width) return -1; 151 return grid.get(p.y).charAt(p.x); 152 } 153 }