day12_pt2.java (3655B)
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 7 class day12_pt2 { 8 record Point(int x, int y) { 9 Point add(Vec v) { 10 return new Point(this.x + v.x, this.y + v.y); 11 } 12 } 13 record Vec(int x, int y) {} 14 static Vec[] DIRS = new Vec[]{ 15 new Vec(0, 1), 16 new Vec(1, 0), 17 new Vec(0, -1), 18 new Vec(-1, 0) 19 }; 20 static Vec[][] DIRPAIRS = new Vec[][]{ 21 new Vec[]{new Vec(0, 1), new Vec(1, 0)}, 22 new Vec[]{new Vec(1, 0), new Vec(0, -1)}, 23 new Vec[]{new Vec(0, -1), new Vec(-1, 0)}, 24 new Vec[]{new Vec(-1, 0), new Vec(0, 1)}, 25 }; 26 public static void main(String[] args) throws IOException { 27 var grid = Files.readAllLines(Path.of(args[0])); 28 // iterate the grid. Recursively find regions and their perimeters. 29 var pts = new HashSet<Point>(); 30 var nRegions = 0; 31 var regions = new HashMap<Integer, HashSet<Point>>(); 32 int height = grid.size(); 33 int width = grid.get(0).length(); 34 for (int y=0; y<height; y++) { 35 for (int x=0; x<width; x++) { 36 var pt = new Point(x, y); 37 if (pts.contains(pt)) continue; 38 var region = expandRegion(grid, pt); 39 regions.put(nRegions++, region); 40 pts.addAll(region); 41 } 42 } 43 44 var res = regions.entrySet().stream().mapToLong(e -> { 45 var region = e.getValue(); 46 var ss = sides(grid, region); 47 System.out.printf("Region %d: size: %d sides: %d\n", e.getKey(), e.getValue().size(), ss); 48 return ss * region.size(); 49 }) 50 .sum(); 51 System.out.printf("Day 12, pt1: %d\n", res); 52 } 53 54 static long sides(List<String> grid, HashSet<Point> region) { 55 return region.stream() 56 .mapToLong(p -> { 57 var v = gv(grid, p); 58 // consider pairs of cardinal directions, e.g. N+E. Look at the squares in these directions 59 // if both are not the same as us; then that's definitely a corner. +1; 60 // if one's the same and one's not, we're not a corner 61 // if both are the smae as us, look at the diagnoal. 62 // if it's the same, not a corner 63 // if it's different, we're an inside corner. 64 65 // Oo = 0 corner Ox = 1 corner Ox = 1 corner Ox = 1 corner Oo = 0 corner 66 // oo oo xo xx xx 67 return Arrays.stream(DIRPAIRS).mapToLong(dp -> { 68 var p1 = p.add(dp[0]); 69 var p2 = p.add(dp[1]); 70 var v1_m = gv(grid, p1) == v; 71 var v2_m = gv(grid, p2) == v; 72 if (!v1_m && !v2_m) { 73 return 1l; 74 } else if (v1_m && v2_m){ 75 var p3 = p2.add(dp[0]); 76 var v3_m = gv(grid, p3) == v; 77 if (v3_m) { 78 return 0l; 79 } else { 80 return 1l; 81 } 82 } else { 83 return 0l; 84 } 85 }).sum(); 86 }) 87 .sum(); 88 } 89 static HashSet<Point> expandRegion(List<String> grid, Point p) { 90 var res = new HashSet<Point>(); 91 expandRegionInternal(grid, p, gv(grid, p), res); 92 return res; 93 } 94 static void expandRegionInternal(List<String> grid, Point p, int val, HashSet<Point> region) { 95 if (region.contains(p)) return; 96 region.add(p); 97 Arrays.stream(DIRS).forEach(d -> { 98 var pp = p.add(d); 99 if (gv(grid, pp) == val) { 100 expandRegionInternal(grid, pp, val, region); 101 } 102 }); 103 } 104 static int gv(List<String> grid, Point p) { 105 var height = grid.size(); 106 if (p.y < 0 || p.y >= height) return -1; 107 var width = grid.get(0).length(); 108 if (p.x < 0 || p.x >= width) return -1; 109 return grid.get(p.y).charAt(p.x); 110 } 111 }