AoC2020/day20/day20.go
2020-12-20 21:52:13 +01:00

297 lines
7.1 KiB
Go

package main
import (
"AoC2020/helper"
"fmt"
"math"
"os"
"regexp"
"strconv"
"strings"
)
var lineBreak = "\r\n"
type tile struct {
neighbourID [4]int
edges [4]string
picture []string
}
func main() {
args := os.Args[1:]
input, err := helper.GetFile(args[0])
if err != nil {
fmt.Println(err)
}
tileInput := strings.Split(input, lineBreak+lineBreak)
tiles := getTiles(tileInput)
var tilesWithNeighbours = make(map[int]tile)
for id,tile := range tiles {
tilesWithNeighbours[id] = getNeighboursForTile(id,tile,tiles)
}
var corners = make(map[int]tile)
for key, tile := range tilesWithNeighbours {
pictureEdges := 0
for _, val := range tile.neighbourID{
if val == 0 {
pictureEdges++
}
}
if pictureEdges == 2 {
corners[key] = tile
}
}
product := 1
for key,_ := range corners {
product *= key
}
fmt.Println(product)
fmt.Println(tilesWithNeighbours[1951])
var picture = make(map[[2]int]int)
picture = getPictureStep(1951,tilesWithNeighbours,[]int{},picture)
}
func getPicture(corners map[int]tile, allTiles map[int]tile) map[[2]int]int {
var picture = make(map[[2]int]int)
//len := math.Sqrt(float64(len(allTiles)))
currentTileId := 1951
currentTile := corners[currentTileId]
picture[[2]int{0,0}] = currentTileId
printPicture(currentTile.picture)
return picture
}
func getPictureStep(currentTile int,allTiles map[int]tile,visitedTiles []int, picture map[[2]int]int) map[[2]int]int{
lenght := int(math.Sqrt(float64(len(allTiles))))
position := [2]int{0,lenght}
for allTiles[currentTile].neighbourID[1] != 0 || allTiles[currentTile].neighbourID[2] != 0{
allTiles[currentTile] = rotate(allTiles[currentTile])
fmt.Println(allTiles[currentTile])
}
fmt.Println(allTiles[currentTile])
for len(visitedTiles) < 2{
picture[position] = currentTile
visitedTiles = append(visitedTiles,currentTile)
nextPosition, _ := getNextPosition(position,lenght,picture)
//nextTileId, _ := getNextTile(allTiles[currentTile].edges[edge],allTiles,currentTile)
position = nextPosition
}
return picture
}
func getNextPosition(position [2]int, length int, picture map[[2]int]int) ([2]int, int) {
if (position[1]+1) < length && picture[[2]int{position[0],position[1]+1}] == 0 {
return [2]int{position[0],position[1]+1}, 0
}
if (position[0]-1) > 0 && picture[[2]int{position[0]-1,position[1]}] == 0 {
return [2]int{position[0]-1,position[1]}, 3
}
if (position[1]-1) > 0 && picture[[2]int{position[0],position[1]-1}] == 0 {
return [2]int{position[0],position[1]-1}, 2
}
if (position[0]+1) < 0 && picture[[2]int{position[0]+1,position[1]}] == 0 {
return [2]int{position[0]+1,position[1]}, 1
}
return position, -1
}
func getNextTile(edge string, allTiles map[int]tile, currentTile int) (int, tile){
var newTile tile
for id, tile := range allTiles{
if id != currentTile {
if stringContains(edge, tile.edges[:]) {
return id, tile
}
newTile = flip(tile, 0)
if stringContains(edge, newTile.edges[:]) {
return id, tile
}
newTile = flip(tile, 1)
if stringContains(edge, newTile.edges[:]) {
return id, tile
}
}
}
return 0,tile{}
}
func contains(elem int, array []int) bool{
for _, val := range array{
if val == elem{
return true
}
}
return false
}
func stringContains(elem string, array []string) bool{
for _, val := range array{
if val == elem{
return true
}
}
return false
}
func getSomeTile(m map[int]tile) int {
for k := range m {
return k
}
return 0
}
func printPicture(input[]string){
for _, row := range input {
fmt.Println(row)
}
fmt.Println()
}
func rotate(tile tile) tile{
var newPicture [10][10]rune
for i:= 0; i < len(tile.picture); i++ {
for j:= 0; j < len(tile.picture); j++ {
newPicture[i][j] = rune(tile.picture[len(tile.picture)-j-1][i]);
}
}
var newNeighbourId [4]int
newNeighbourId[0] = tile.neighbourID[3]
for i,val := range tile.neighbourID[:2]{
newNeighbourId[i+1] = val
}
tile.neighbourID = newNeighbourId
for i,row := range newPicture {
tile.picture[i] = string(row[:])
}
tile = setEdges(tile)
return tile
}
//0 horizontal
//1 vertical
func flip(tile tile, direction int) tile{
var newPicture []string
if direction == 0{
for i := len(tile.picture)-1; i >= 0; i--{
newPicture = append(newPicture,tile.picture[i])
}
}
if direction == 1{
for _,val := range tile.picture {
newPicture = append(newPicture,reverse(val))
}
}
newEdges := getAllPossibleEdgesForFlippedTile(tile,direction)
for i:= 0; i < len(tile.edges); i++{
tile.edges[i] = newEdges[i]
}
tile.picture = newPicture
return tile
}
func getTiles(input []string) map[int]tile{
var tiles = make(map[int]tile)
for _, val := range input {
id, tile := getTile(val)
tiles[id] = tile
}
return tiles
}
func getTile(input string) (int, tile) {
tilesRow := strings.Split(input, lineBreak)
var edges [4]string
edges[0] = tilesRow[1]
edges[2] = tilesRow[len(tilesRow)-1]
for _, val := range tilesRow[1:] {
edges[3] = edges[3]+val[0:1]
edges[1] = edges[1]+val[len(val)-1:]
}
r, _ := regexp.Compile("[0-9]{4}")
number, _ := strconv.Atoi(r.FindString(tilesRow[0]))
tile := tile{[4]int{},edges, tilesRow[1:]}
return number, setEdges(tile)
}
func setEdges(tile tile)tile{
var newEdges [4]string
newEdges[0] = tile.picture[0]
newEdges[2] = tile.picture[len(tile.picture)-1]
for _, val := range tile.picture {
newEdges[3] = newEdges[3]+val[0:1]
newEdges[1] = newEdges[1]+val[len(val)-1:]
}
tile.edges = newEdges
return tile
}
func getAllPossibleEdgesForTile(tile tile, direction int) []string{
switch direction {
case -1:
var edges [4]string
for i, edge := range tile.edges {
edges[i] = edge
}
return edges[:]
case 0:
return getAllPossibleEdgesForFlippedTile(tile,0)
case 1:
return getAllPossibleEdgesForFlippedTile(tile,1)
}
return []string{}
}
func getAllPossibleEdgesForFlippedTile(tile tile, direction int) []string{
var edges [4]string
for i:= 0; i < len(tile.edges); i ++ {
if i % 2 == direction {
edges[i] = reverse(tile.edges[i])
}else{
edges[i] = reverse(tile.edges[i])
}
}
return edges[:]
}
func getNeighboursForTile(choosenTile int, tile tile, allTiles map[int]tile) tile{
var idToPossibleEdges = make(map[int][]string)
for id,tile := range allTiles {
idToPossibleEdges[id] = getAllPossibleEdgesForTile(tile,-1)
idToPossibleEdges[id] = append(idToPossibleEdges[id],getAllPossibleEdgesForTile(tile,0)...)
idToPossibleEdges[id] = append(idToPossibleEdges[id],getAllPossibleEdgesForTile(tile,1)...)
}
for i, edge := range tile.edges {
tile.neighbourID[i] = getFittingTileForEdge(choosenTile,edge,idToPossibleEdges)
}
return tile
}
func getFittingTileForEdge(choosenTile int, edge string, idToPossibleEdges map[int][]string) int{
for id,edges := range idToPossibleEdges {
if choosenTile != id && hasMatchingEdge(edges,edge){
return id
}
}
return 0
}
func hasMatchingEdge(edges []string, edge string) bool {
for _, val := range edges {
if val == edge{
return true
}
}
return false
}
func reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}