-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday12.java
112 lines (98 loc) · 3.43 KB
/
day12.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import java.io.*;
import java.util.*;
import static java.lang.System.in;
import static java.lang.System.out;
import static java.util.Collections.emptySet;
public class day12 {
public static void main(String[] args) {
var map = new BufferedReader(new InputStreamReader(in)).lines().map(String::toCharArray).toList().toArray(new char[][]{});
var processed = new HashSet<Pos>();
long sum1 = 0, sum2 = 0;
for (int row = 0; row < map.length; row++) {
for (int col = 0; col < map[row].length; col++) {
var p = new Pos(row, col);
if (processed.contains(p)) { continue; }
var region = new Region(map, p, processed);
sum1 += region.area() * region.perimeter();
sum2 += region.area() * region.sides();
}
}
out.println(sum1 + " " + sum2);
}
}
class Region {
final Set<Pos> region =new HashSet<>();
final char[][] map;
long perimeter;
char type;
Region(char[][] map, Pos p, Set<Pos> processed) {
this.map = map;
this.type = map[p.row()][p.col()];
expand(type, p, processed);
}
long area() { return region.size(); }
long perimeter() { return perimeter; }
long sides() {
var sides = 0;
var outDirections = new HashMap<Pos, Set<Direction>>();
for (int row = 0; row < map.length; row++) {
for (int col = 0; col < map[row].length; col++) {
var pp = new Pos(row, col);
if (!region.contains(pp)) { continue; }
for (var d : Direction.values()) {
var np = pp.move(d);
if (inside(np) && map[np.row()][np.col()] == type) { continue; }
var left = pp.move(d.turnLeft());
var right = pp.move(d.turnRight());
if (!outDirections.getOrDefault(left, emptySet()).contains(d) &&
!outDirections.getOrDefault(right, emptySet()).contains(d)) {
sides++;
}
if (!outDirections.containsKey(pp)) {
outDirections.put(pp, new HashSet<>());
}
outDirections.get(pp).add(d);
}
}
}
return sides;
}
void expand(char type, Pos p, Set<Pos> processed) {
if (!inside(p) || map[p.row()][p.col()] != type) {
perimeter++;
return;
}
if (!processed.add(p)) { return; }
region.add(p);
for (var d : Direction.values()) {
expand(type, p.move(d), processed);
}
}
boolean inside(Pos p) {
return p.row() >= 0 && p.row() < map.length && p.col() >= 0 && p.col() < map[p.row()].length;
}
}
record Pos(int row, int col) {
Pos move(Direction d) { return new Pos(row + d.dr, col + d.dc); }
}
enum Direction {
UP(-1, 0), RIGHT(0, 1), DOWN(1, 0), LEFT(0, -1);
final int dr, dc;
Direction(int dr, int dc) { this.dr = dr; this.dc = dc; }
Direction turnRight() {
return switch (this) {
case UP -> RIGHT;
case RIGHT -> DOWN;
case DOWN -> LEFT;
case LEFT -> UP;
};
}
Direction turnLeft() {
return switch (this) {
case UP -> LEFT;
case RIGHT -> UP;
case DOWN -> RIGHT;
case LEFT -> DOWN;
};
}
}