using System; using System.Drawing; using System.Collections.Generic; using System.Linq; public class GoCounting { public enum Player { None, Black, White } private readonly Player[][] board; public GoCounting(string input) { board = ParseBoard(input); } private static Player CharToPlayer(char c) { switch (c) { case 'B': return Player.Black; case 'W': return Player.White; default: return Player.None; } } private static Player[][] ParseBoard(string input) { var split = input.Split('\n'); var rows = split.Length; var cols = split[0].Length; return split.Select(row => row.Select(CharToPlayer).ToArray()).ToArray(); } private int Cols => board[0].Length; private int Rows => board.Length; private bool IsValidCoordinate(Point coordinate) => coordinate.Y >= 0 && coordinate.Y < Rows && coordinate.X >= 0 && coordinate.X < Cols; private Player GetPlayer(Point coordinate) => board[coordinate.Y][coordinate.X]; private bool IsEmpty(Point coordinate) => GetPlayer(coordinate) == Player.None; private bool IsTaken(Point coordinate) => !IsEmpty(coordinate); private IEnumerable EmptyCoordinates() { return Enumerable.Range(0, Cols).SelectMany(col => Enumerable.Range(0, Rows).Select(row => new Point(col, row))) .Where(IsEmpty); } private IEnumerable NeighborCoordinates(Point coordinate) { var row = coordinate.Y; var col = coordinate.X; var coords = new[] { new Point(col, row - 1), new Point(col-1, row), new Point(col+1, row), new Point(col, row+1) }; return coords.Where(IsValidCoordinate); } private IEnumerable TakenNeighborCoordinates(Point coordinate) => NeighborCoordinates(coordinate).Where(IsTaken); private IEnumerable EmptyNeighborCoordinates(Point coordinate) => NeighborCoordinates(coordinate).Where(IsEmpty); private Player TerritoryOwner(HashSet coords) { var neighborColors = coords.SelectMany(TakenNeighborCoordinates).Select(GetPlayer); var uniqueNeighborColors = ToSet(neighborColors); if (uniqueNeighborColors.Count == 1) return uniqueNeighborColors.First(); return Player.None; } private HashSet TerritoryHelper(HashSet remainder, HashSet acc) { if (!remainder.Any()) return acc; var emptyNeighbors = new HashSet(remainder.SelectMany(EmptyNeighborCoordinates)); emptyNeighbors.ExceptWith(acc); var newAcc = ToSet(acc); newAcc.UnionWith(emptyNeighbors); return TerritoryHelper(emptyNeighbors, newAcc); } private HashSet Territory(Point coordinate) => IsValidCoordinate(coordinate) && IsEmpty(coordinate) ? TerritoryHelper(ToSingletonSet(coordinate), ToSingletonSet(coordinate)) : new HashSet(); public Tuple> TerritoryFor(Point coord) { var coords = Territory(coord); if (!coords.Any()) return null; var owner = TerritoryOwner(coords); return Tuple.Create(owner, coords.AsEnumerable()); } private Dictionary> TerritoriesHelper(HashSet remainder, Dictionary> acc) { if (!remainder.Any()) return acc; var coord = remainder.First(); var coords = Territory(coord); var owner = TerritoryOwner(coords); var newRemainder = ToSet(remainder); newRemainder.ExceptWith(coords); var newAcc = new Dictionary>(acc); newAcc[owner] = coords; return TerritoriesHelper(newRemainder, newAcc); } public Dictionary> Territories() { var emptyCoords = EmptyCoordinates(); return TerritoriesHelper(ToSet(emptyCoords), new Dictionary>()); } private static HashSet ToSet(IEnumerable value) => new HashSet(value); private static HashSet ToSingletonSet(T value) => new HashSet { value }; }