|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+import static java.util.Arrays.copyOfRange;
|
|
|
2
|
+import static java.util.Arrays.stream;
|
|
|
3
|
+
|
|
|
4
|
+final class RectangleCounter {
|
|
|
5
|
+
|
|
|
6
|
+ int countRectangles(final String[] rawGrid) {
|
|
|
7
|
+ final int nRows = rawGrid.length;
|
|
|
8
|
+ if (nRows == 0) return 0;
|
|
|
9
|
+
|
|
|
10
|
+ final int nCols = rawGrid[0].length();
|
|
|
11
|
+ if (nCols == 0) return 0;
|
|
|
12
|
+
|
|
|
13
|
+ return new Grid(nRows, nCols, rawGrid).countRectangles();
|
|
|
14
|
+ }
|
|
|
15
|
+
|
|
|
16
|
+ private static final class Grid {
|
|
|
17
|
+
|
|
|
18
|
+ private enum Entry {
|
|
|
19
|
+ CORNER,
|
|
|
20
|
+ HLINE,
|
|
|
21
|
+ VLINE,
|
|
|
22
|
+ SPACE;
|
|
|
23
|
+
|
|
|
24
|
+ private static Entry fromChar(final char rawGridEntry) {
|
|
|
25
|
+ switch (rawGridEntry) {
|
|
|
26
|
+ case '+': return CORNER;
|
|
|
27
|
+ case '-': return HLINE;
|
|
|
28
|
+ case '|': return VLINE;
|
|
|
29
|
+ case ' ': return SPACE;
|
|
|
30
|
+ default: throw new IllegalStateException("Grid entry " + rawGridEntry + " not recognized.");
|
|
|
31
|
+ }
|
|
|
32
|
+ }
|
|
|
33
|
+ }
|
|
|
34
|
+
|
|
|
35
|
+ private int nRows, nCols;
|
|
|
36
|
+ private final Entry[][] entries;
|
|
|
37
|
+
|
|
|
38
|
+ private Grid(final int nRows, final int nCols, final String[] rawGrid) {
|
|
|
39
|
+ this.nRows = nRows;
|
|
|
40
|
+ this.nCols = nCols;
|
|
|
41
|
+ this.entries = new Entry[nRows][nCols];
|
|
|
42
|
+
|
|
|
43
|
+ for (int nRow = 0; nRow < nRows; nRow++) {
|
|
|
44
|
+ for (int nCol = 0; nCol < nCols; nCol++) {
|
|
|
45
|
+ entries[nRow][nCol] = Entry.fromChar(rawGrid[nRow].charAt(nCol));
|
|
|
46
|
+ }
|
|
|
47
|
+ }
|
|
|
48
|
+ }
|
|
|
49
|
+
|
|
|
50
|
+ private int countRectangles() {
|
|
|
51
|
+ int result = 0;
|
|
|
52
|
+
|
|
|
53
|
+ for (int topRow = 0; topRow < nRows - 1; topRow++) {
|
|
|
54
|
+
|
|
|
55
|
+ for (int leftCol = 0; leftCol < nCols - 1; leftCol++) {
|
|
|
56
|
+
|
|
|
57
|
+ // Only check rectangles that lie below/to the right of our current coordinate:
|
|
|
58
|
+ for (int bottomRow = topRow + 1; bottomRow < nRows; bottomRow++) {
|
|
|
59
|
+
|
|
|
60
|
+ for (int rightCol = leftCol + 1; rightCol < nCols; rightCol++) {
|
|
|
61
|
+
|
|
|
62
|
+ if (formsRectangle(topRow, bottomRow, leftCol, rightCol)) {
|
|
|
63
|
+ result++;
|
|
|
64
|
+ }
|
|
|
65
|
+ }
|
|
|
66
|
+ }
|
|
|
67
|
+ }
|
|
|
68
|
+ }
|
|
|
69
|
+
|
|
|
70
|
+ return result;
|
|
|
71
|
+ }
|
|
|
72
|
+
|
|
|
73
|
+ private boolean formsRectangle(
|
|
|
74
|
+ final int topRow,
|
|
|
75
|
+ final int bottomRow,
|
|
|
76
|
+ final int leftCol,
|
|
|
77
|
+ final int rightCol) {
|
|
|
78
|
+
|
|
|
79
|
+ return entries[topRow][leftCol].equals(Entry.CORNER)
|
|
|
80
|
+ && entries[topRow][rightCol].equals(Entry.CORNER)
|
|
|
81
|
+ && entries[bottomRow][leftCol].equals(Entry.CORNER)
|
|
|
82
|
+ && entries[bottomRow][rightCol].equals(Entry.CORNER)
|
|
|
83
|
+ && isHorizontalLineSegment(topRow, leftCol, rightCol)
|
|
|
84
|
+ && isHorizontalLineSegment(bottomRow, leftCol, rightCol)
|
|
|
85
|
+ && isVerticalLineSegment(leftCol, topRow, bottomRow)
|
|
|
86
|
+ && isVerticalLineSegment(rightCol, topRow, bottomRow);
|
|
|
87
|
+ }
|
|
|
88
|
+
|
|
|
89
|
+ private boolean isHorizontalLineSegment(final int row, final int leftCol, final int rightCol) {
|
|
|
90
|
+ return stream(copyOfRange(getRow(row), leftCol, rightCol))
|
|
|
91
|
+ .allMatch(entry -> entry.equals(Entry.HLINE) || entry.equals(Entry.CORNER));
|
|
|
92
|
+ }
|
|
|
93
|
+
|
|
|
94
|
+ private boolean isVerticalLineSegment(final int col, final int topRow, final int bottomRow) {
|
|
|
95
|
+ return stream(copyOfRange(getCol(col), topRow, bottomRow))
|
|
|
96
|
+ .allMatch(entry -> entry.equals(Entry.VLINE) || entry.equals(Entry.CORNER));
|
|
|
97
|
+ }
|
|
|
98
|
+
|
|
|
99
|
+ private Entry[] getRow(final int number) {
|
|
|
100
|
+ return entries[number];
|
|
|
101
|
+ }
|
|
|
102
|
+
|
|
|
103
|
+ private Entry[] getCol(final int number) {
|
|
|
104
|
+ final Entry[] result = new Entry[nRows];
|
|
|
105
|
+
|
|
|
106
|
+ for (int nRow = 0; nRow < nRows; nRow++) {
|
|
|
107
|
+ result[nRow] = entries[nRow][number];
|
|
|
108
|
+ }
|
|
|
109
|
+
|
|
|
110
|
+ return result;
|
|
|
111
|
+ }
|
|
|
112
|
+
|
|
|
113
|
+ }
|
|
|
114
|
+
|
|
|
115
|
+}
|