internal static long Part1(string input) { string[] lines = input.Split('\n'); List <ImageTile> tileList = new List <ImageTile>(); for (int l = 0; l < lines.Length; l++) { string line = lines[l]; if (line.Contains("Tile")) { int i = Array.IndexOf(lines, line); int j = FindNextEmpty(i, lines); char[,] grid = new char[lines[l + 1].Length, j - i - 1]; for (int q = 0; q < grid.GetLength(0); q++) { for (int w = 0; w < grid.GetLength(1); w++) { grid[w, q] = lines[i + q + 1][w]; } } string nn = line.Substring(5, line.Length - 6); int id = int.Parse(nn); ImageTile tile = new ImageTile(grid, id); tileList.Add(tile); } } List <Tuple <ImageTile, int> > possibilities = FindPossibleCorners(tileList); long a = possibilities[0].Item1.id; long b = possibilities[1].Item1.id; long c = possibilities[2].Item1.id; long d = possibilities[3].Item1.id; return(a * b * c * d); }
private static bool TryToFill(ImageTile[,] fullImage, Vector2Int pos, List <ImageTile> list) { int size = fullImage.GetLength(0); List <Tuple <ImageTile, Orrientation> > allowed = new List <Tuple <ImageTile, Orrientation> >(); foreach (ImageTile img in list) { img.rotation = ImageTile.Rotation.NORTH; img.flipped = false; foreach (bool fl in flips) { foreach (ImageTile.Rotation rot in rots) { bool doesFit = true; img.rotation = rot; img.flipped = fl; Orrientation o = new Orrientation { rot = img.rotation, fl = img.flipped }; foreach (Vector2Int offset in dirs) { if (pos.x + offset.x < 0 || pos.y + offset.y < 0) { continue; } if (pos.x + offset.x >= size || pos.y + offset.y >= size) { continue; } if (fullImage[pos.x + offset.x, pos.y + offset.y] == null) { continue; } ImageTile e = fullImage[pos.x + offset.x, pos.y + offset.y]; doesFit &= CheckPlacementWithOrrientation(e, img, offset); } if (doesFit) { allowed.Add(new Tuple <ImageTile, Orrientation>(img, o)); } } } } if (allowed.Count == 1) { Tuple <ImageTile, Orrientation> tt = allowed[0]; tt.Item1.rotation = tt.Item2.rot; tt.Item1.flipped = tt.Item2.fl; fullImage[pos.x, pos.y] = tt.Item1; return(true); } return(false); }
private static bool CheckPlacementWithOrrientation(ImageTile existing, ImageTile newTile, Vector2Int dir) { char[] edge1 = newTile.GetEdge(dir.x, dir.y, newTile.rotation, newTile.flipped); char[] edge2 = existing.GetEdge(-dir.x, -dir.y, existing.rotation, existing.flipped); for (int i = 0; i < edge1.Length; i++) { if (edge1[i] != edge2[i]) { return(false); } } return(true); }
private static bool CheckPlacement(ImageTile existing, ImageTile newTile, Vector2Int dir) { foreach (ImageTile.Rotation rot in rots) { foreach (Vector2Int dir2 in dirs) { foreach (bool fl in flips) { char[] edge1 = newTile.GetEdge(dir2.x, dir2.y, rot, fl); if (existing.MatchEdge(edge1, dir.x, dir.y)) { return(true); } } } } return(false); }
private static ImageTile GetSingleOption(ImageTile start, List <ImageTile> list) { foreach (Vector2Int dir in dirs) { List <ImageTile> neighbors = new List <ImageTile>(); foreach (ImageTile t2 in list) { if (start == t2) { continue; } if (CheckPlacement(start, t2, dir)) { neighbors.Add(t2); } } if (neighbors.Count == 1) { return(neighbors[0]); } } return(null); }
internal static long Part2(string input) { string[] lines = input.Split('\n'); List <ImageTile> tileList = new List <ImageTile>(); for (int l = 0; l < lines.Length; l++) { string line = lines[l]; if (line.Contains("Tile")) { int i = Array.IndexOf(lines, line); int j = FindNextEmpty(i, lines); char[,] grid = new char[lines[l + 1].Length, j - i - 1]; for (int q = 0; q < grid.GetLength(0); q++) { for (int w = 0; w < grid.GetLength(1); w++) { grid[w, q] = lines[i + q + 1][w]; } } string nn = line.Substring(5, line.Length - 6); int id = int.Parse(nn); ImageTile tile = new ImageTile(grid, id); tileList.Add(tile); } } ImageTile starting = null; List <Tuple <ImageTile, int> > possibilities = FindPossibleCorners(tileList); starting = possibilities[0].Item1; int size = (int)Math.Sqrt(tileList.Count); ImageTile[,] fullImage = new ImageTile[size, size]; List <Vector2Int> possibleDirs = new List <Vector2Int>(); Vector2Int cell = new Vector2Int(0, 0); foreach (Vector2Int dir in dirs) { Vector2Int off = new Vector2Int(cell.x + dir.x, cell.y + dir.y); foreach (ImageTile t2 in tileList) { if (t2 == starting) { continue; } if (CheckPlacement(starting, t2, new Vector2Int(-dir.x, -dir.y))) { possibleDirs.Add(dir); } } } int ax = possibleDirs[0].x + possibleDirs[1].x; int ay = possibleDirs[0].y + possibleDirs[1].y; Vector2Int startPos = new Vector2Int((ax == 1 ? size - 1 : 0), (ay == 1 ? size - 1 : 0)); fullImage[startPos.x, startPos.y] = starting; tileList.Remove(starting); while (tileList.Count > 0) { List <Tuple <Vector2Int, int> > expansions = FindOpenNeighbors(fullImage); bool changed = false; do { Tuple <Vector2Int, int> npos = expansions.OrderByDescending(a => a.Item2 * 1000 - a.Item1.y - a.Item1.x).First(); expansions.Remove(npos); if (TryToFill(fullImage, npos.Item1, tileList)) { changed = true; tileList.Remove(fullImage[npos.Item1.x, npos.Item1.y]); break; } } while(expansions.Count > 0); if (!changed) { return(-1); } } // make the pattern look nice in code string pattern = @" # # ## ## ### # # # # # # "; //strip off the \r\n at the front... pattern = pattern.Substring(2, pattern.Length - 2); int s = fullImage[0, 0].grid.GetLength(0); char[,] renderedImage = new char[fullImage.GetLength(0) * (s - 2), fullImage.GetLength(1) * (s - 2)]; for (int y = renderedImage.GetLength(0) - 1; y >= 0; y--) { for (int x = 0; x < renderedImage.GetLength(0); x++) { renderedImage[x, y] = GetCharFromFull(fullImage, x, y, s - 2); } } string[] patterns = GeneratePatterns(pattern); int answer = SearchForSeaMonster(patterns, renderedImage); return(answer); }