public static string Run(List <Tile> input) { Console.WindowWidth = 80; Console.WindowHeight = 50; _memo = new Dictionary <int, char[, ]>(); _board = new char[96, 96]; _mapIds = new int[12, 12]; var connections = new Dictionary <int, List <Connection> >(); var memo = new Dictionary <int, List <MatchInfo> >(); var tiles = new Dictionary <int, Tile>(); tiles = input.ToDictionary(t => t.Id); _seaMonster = new string[] { " # ", "# ## ## ###", " # # # # # # " }; var cornersAndEdges = FindCornersAndEdges(input); var masterCorner = cornersAndEdges.MasterCornerId; var masterCornerMatch = cornersAndEdges.MasterCornerMatch; int x = 0; int y = 0; int mapIdY = 0; int mapIdX = 0; if (masterCornerMatch.Up) { y += _board.GetLength(0) - 10; mapIdY += 10; } if (masterCornerMatch.Left) { x += _board.GetLength(1) - 10; mapIdX += 10; } DrawMapToBoard(tiles[masterCorner].Map, x, y); int nextTileId = masterCorner; bool connecting = true; var links = new HashSet <int>(); Func <List <int>, bool> check = new Func <List <int>, bool>(ces => { var combinations = new List <MatchInfo>(); foreach (var scoutId in ces) { if (scoutId == nextTileId) { continue; } var hash = nextTileId > scoutId ? HashCode.Combine(scoutId, nextTileId) : HashCode.Combine(nextTileId, scoutId); if (links.Contains(hash)) { continue; } combinations.AddRange( TileMatcher.CheckAllCombinations(tiles[nextTileId], tiles[scoutId], _memo) ); if (combinations.Count > 0) { links.Add(hash); if (combinations.Count > 1) { System.Diagnostics.Debug.WriteLine($"{nextTileId} -> {scoutId}, Combinations: {combinations.Count}"); } var key = HashCode.Combine(combinations[0].Target, combinations[0].Permutation); var direction = combinations[0].Direction; var map = _memo[key]; switch (direction) { case Direction.Up: (y, mapIdY) = (y - 8, mapIdY - 1); break; case Direction.Down: (y, mapIdY) = (y + 8, mapIdY + 1); break; case Direction.Left: (x, mapIdX) = (x - 8, mapIdX - 1); break; case Direction.Right: (x, mapIdX) = (x + 8, mapIdX + 1); break; } _mapIds[mapIdY, mapIdX] = scoutId; tiles[scoutId] = new Tile { Id = scoutId, Map = map }; DrawMapToBoard(map, x, y); nextTileId = scoutId; return(true); } } return(false); }); while (connecting) { var isCorner = cornersAndEdges.Corners.Contains(nextTileId); var isEdge = cornersAndEdges.Edges.Contains(nextTileId); var foundEdge = check(cornersAndEdges.Edges); if (foundEdge) { continue; } bool foundCorner = false; if (!foundEdge && isEdge) { foundCorner = check(cornersAndEdges.Corners); } if (!foundEdge && !foundCorner) { break; } } var restOfTiles = new Dictionary <int, Tile>(); foreach (var keyValuePair in tiles) { if (!cornersAndEdges.Corners.Contains(keyValuePair.Key) && !cornersAndEdges.Edges.Contains(keyValuePair.Key)) { restOfTiles.Add(keyValuePair.Key, keyValuePair.Value); } } for (int middleY = 1; middleY < _mapIds.GetLength(0) - 1; middleY++) { for (int middleX = 1; middleX < _mapIds.GetLength(1) - 1; middleX++) { int aboveTileId = _mapIds[middleY - 1, middleX]; var tileKeysToRemove = new HashSet <int>(); foreach (var tile in restOfTiles) { var combinations = TileMatcher.CheckAllCombinations(tiles[aboveTileId], tile.Value, _memo); if (combinations.Count > 0) { var match = combinations.First(c => c.Direction == Direction.Down); var key = HashCode.Combine(combinations[0].Target, combinations[0].Permutation); var direction = combinations[0].Direction; var map = _memo[key]; _mapIds[middleY, middleX] = tile.Key; tiles[tile.Key] = new Tile { Id = tile.Key, Map = map }; DrawMapToBoard(map, middleX * 8, middleY * 8); tileKeysToRemove.Add(tile.Key); } } foreach (var tileKeyToRemove in tileKeysToRemove) { restOfTiles.Remove(tileKeyToRemove); } tileKeysToRemove.Clear(); } } var boards = new Dictionary <int, char[, ]>(); boards.Add(0, _board.Copy()); boards.Add(1, _board.Flip()); for (int permutation = 2; permutation < 8; permutation++) { if (permutation % 2 == 0) { boards.Add(permutation, boards[permutation - 2].Rotate()); } else { boards.Add(permutation, boards[permutation - 1].Flip()); } } foreach (var board in boards) { if (FindSeamonsters(board.Value) > 0) { return(CountRoughSea(board.Value)); } } return("Failed to find any seamonsters! This ofcourse, NEVER happens! :)"); }