using System; using System.Linq; public static class Rectangles { public static int Count(string[] rows) { var grid = ParseGrid(rows); var corners = FindCorners(grid); return corners.Sum(corner => RectangleForCorner(corner, corners, grid)); } private static CellType[][] ParseGrid(string[] rows) => rows.Select(row => row.Select(ParseCell).ToArray()).ToArray(); private static CellType ParseCell(char cell) { switch (cell) { case '+': return CellType.Corner; case '-': return CellType.HorizontalLine; case '|': return CellType.VerticalLine; case ' ': return CellType.Empty; default: throw new ArgumentException(); } } private static int Rows(CellType[][] grid) => grid.Length; private static int Cols(CellType[][] grid) => grid[0].Length; private static CellType Cell(Tuple point, CellType[][] grid) => grid[point.Item2][point.Item1]; private static Tuple[] FindCorners(CellType[][] grid) => Enumerable.Range(0, Rows(grid)).SelectMany(y => Enumerable.Range(0, Cols(grid)).Select(x => new Tuple(x, y))) .Where(point => Cell(point, grid) == CellType.Corner) .ToArray(); private static bool ConnectsVertically(Tuple point, CellType[][] grid) => (Cell(point, grid) == CellType.VerticalLine) || (Cell(point, grid) == CellType.Corner); private static bool ConnectedVertically(Tuple top, Tuple bottom, CellType[][] grid) => Enumerable.Range(top.Item2 + 1, bottom.Item2 - top.Item2 - 1).All(y => ConnectsVertically(new Tuple(top.Item1, y), grid)); private static bool ConnectsHorizontally(Tuple point, CellType[][] grid) => (Cell(point, grid) == CellType.HorizontalLine) || (Cell(point, grid) == CellType.Corner); private static bool ConnectedHorizontally(Tuple left, Tuple right, CellType[][] grid) => Enumerable.Range(left.Item1 + 1, right.Item1 - left.Item1 - 1).All(x => ConnectsHorizontally(new Tuple(x, left.Item2), grid)); private static bool IsTopLineOfRectangle(Tuple topLeft, Tuple topRight, CellType[][] grid) => (topRight.Item1 > topLeft.Item1) && (topRight.Item2 == topLeft.Item2) && ConnectedHorizontally(topLeft, topRight, grid); private static bool IsRightLineOfRectangle(Tuple topRight, Tuple bottomRight, CellType[][] grid) => (bottomRight.Item1 == topRight.Item1) && (bottomRight.Item2 > topRight.Item2) && ConnectedVertically(topRight, bottomRight, grid); private static bool IsBottomLineOfRectangle(Tuple bottomLeft, Tuple bottomRight, CellType[][] grid) => (bottomRight.Item1 > bottomLeft.Item1) && (bottomRight.Item2 == bottomLeft.Item2) && ConnectedHorizontally(bottomLeft, bottomRight, grid); private static bool IsLeftLineOfRectangle(Tuple topLeft, Tuple bottomLeft, CellType[][] grid) => (bottomLeft.Item1 == topLeft.Item1) && (bottomLeft.Item2 > topLeft.Item2) && ConnectedVertically(topLeft, bottomLeft, grid); private static int RectangleForCorner(Tuple topLeft, Tuple[] corners, CellType[][] grid) { return (from topRight in corners.Where(corner => IsTopLineOfRectangle(topLeft, corner, grid)) from bottomLeft in corners.Where(corner => IsLeftLineOfRectangle(topLeft, corner, grid)) from bottomRight in corners.Where(corner => IsRightLineOfRectangle(topRight, corner, grid) && IsBottomLineOfRectangle(bottomLeft, corner, grid)) select 1) .Count(); } private enum CellType { Empty, Corner, HorizontalLine, VerticalLine } }