2020-12-20 17:09:40 +01:00
package main
import (
"AoC2020/helper"
"fmt"
2020-12-20 21:52:13 +01:00
"math"
2020-12-20 17:09:40 +01:00
"os"
"regexp"
"strconv"
"strings"
)
2020-12-20 20:19:05 +01:00
var lineBreak = "\r\n"
2020-12-20 17:09:40 +01:00
type tile struct {
neighbourID [ 4 ] int
edges [ 4 ] string
2020-12-20 20:19:05 +01:00
picture [ ] string
2020-12-20 17:09:40 +01:00
}
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 )
2020-12-20 20:19:05 +01:00
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
2020-12-20 17:09:40 +01:00
}
fmt . Println ( product )
2020-12-20 21:52:13 +01:00
fmt . Println ( tilesWithNeighbours [ 1951 ] )
2020-12-20 20:19:05 +01:00
var picture = make ( map [ [ 2 ] int ] int )
2020-12-20 21:52:13 +01:00
picture = getPictureStep ( 1951 , tilesWithNeighbours , [ ] int { } , picture )
2020-12-20 20:19:05 +01:00
}
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
}
2020-12-20 21:52:13 +01:00
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 {
2020-12-20 20:19:05 +01:00
picture [ position ] = currentTile
visitedTiles = append ( visitedTiles , currentTile )
2020-12-20 21:52:13 +01:00
nextPosition , _ := getNextPosition ( position , lenght , picture )
//nextTileId, _ := getNextTile(allTiles[currentTile].edges[edge],allTiles,currentTile)
position = nextPosition
2020-12-20 20:19:05 +01:00
}
return picture
2020-12-20 17:09:40 +01:00
}
2020-12-20 21:52:13 +01:00
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 { }
}
2020-12-20 20:19:05 +01:00
func contains ( elem int , array [ ] int ) bool {
for _ , val := range array {
if val == elem {
return true
}
}
return false
}
2020-12-20 21:52:13 +01:00
func stringContains ( elem string , array [ ] string ) bool {
for _ , val := range array {
if val == elem {
return true
}
}
return false
}
2020-12-20 20:19:05 +01:00
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 [ : ] )
}
2020-12-20 21:52:13 +01:00
tile = setEdges ( tile )
2020-12-20 20:19:05 +01:00
return tile
}
//0 horizontal
//1 vertical
func flip ( tile tile , direction int ) tile {
var newPicture [ ] string
if direction == 0 {
2020-12-20 21:52:13 +01:00
for i := len ( tile . picture ) - 1 ; i >= 0 ; i -- {
2020-12-20 20:19:05 +01:00
newPicture = append ( newPicture , tile . picture [ i ] )
}
}
if direction == 1 {
for _ , val := range tile . picture {
newPicture = append ( newPicture , reverse ( val ) )
}
}
2020-12-20 21:52:13 +01:00
newEdges := getAllPossibleEdgesForFlippedTile ( tile , direction )
for i := 0 ; i < len ( tile . edges ) ; i ++ {
tile . edges [ i ] = newEdges [ i ]
}
2020-12-20 20:19:05 +01:00
tile . picture = newPicture
return tile
}
func getTiles ( input [ ] string ) map [ int ] tile {
var tiles = make ( map [ int ] tile )
2020-12-20 17:09:40 +01:00
for _ , val := range input {
2020-12-20 20:19:05 +01:00
id , tile := getTile ( val )
tiles [ id ] = tile
2020-12-20 17:09:40 +01:00
}
return tiles
}
2020-12-20 20:19:05 +01:00
func getTile ( input string ) ( int , tile ) {
2020-12-20 17:09:40 +01:00
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 ] ) )
2020-12-20 21:52:13 +01:00
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
2020-12-20 17:09:40 +01:00
}
2020-12-20 20:19:05 +01:00
func getAllPossibleEdgesForTile ( tile tile , direction int ) [ ] string {
switch direction {
case - 1 :
var edges [ 4 ] string
for i , edge := range tile . edges {
edges [ i ] = edge
2020-12-20 17:09:40 +01:00
}
2020-12-20 20:19:05 +01:00
return edges [ : ]
case 0 :
return getAllPossibleEdgesForFlippedTile ( tile , 0 )
case 1 :
return getAllPossibleEdgesForFlippedTile ( tile , 1 )
2020-12-20 17:09:40 +01:00
}
2020-12-20 20:19:05 +01:00
return [ ] string { }
2020-12-20 17:09:40 +01:00
}
2020-12-20 20:19:05 +01:00
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 ] )
2020-12-20 17:09:40 +01:00
}
}
2020-12-20 20:19:05 +01:00
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
2020-12-20 17:09:40 +01:00
}
2020-12-20 20:19:05 +01:00
func getFittingTileForEdge ( choosenTile int , edge string , idToPossibleEdges map [ int ] [ ] string ) int {
for id , edges := range idToPossibleEdges {
if choosenTile != id && hasMatchingEdge ( edges , edge ) {
return id
2020-12-20 17:09:40 +01:00
}
}
2020-12-20 20:19:05 +01:00
return 0
2020-12-20 17:09:40 +01:00
}
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 )
}
2020-12-20 20:19:05 +01:00