DEV Community

Cover image for DAY 11 - Advent of Code 2020 w/ GoLang
Edvin
Edvin

Posted on

1 1

DAY 11 - Advent of Code 2020 w/ GoLang

This took me longer than I'd care to admit. I feel like I've built this kind of neighbor-visiting matrix traverser many times back in college. The only advice I can really give is to dust off some of those college CS notes, haha.

My code for this is kind of messy, and I thought about cleaning it up and reducing some of the duplication... but I really didn't want to after solving it. But if you have questions, I'm happy to answer!

package days

import (
    "fmt"
    "reflect"

    inputs "../inputs"
)

// https://adventofcode.com/2020/day/11
// Eleven : advent of code, day eleven part1 and 2.
func Eleven() {
    seatGridAsSlices := inputs.Day11

    seatGrid := [][]rune{}
    for seatRow := range seatGridAsSlices {
        asRunes := []rune(seatGridAsSlices[seatRow])
        seatGrid = append(seatGrid, asRunes)
    }

    snapshot := deepCopy2dSlice(seatGrid)
    scannedGrid := seatWalker(seatGrid)
    for !reflect.DeepEqual(snapshot, scannedGrid) {
        snapshot = deepCopy2dSlice(scannedGrid)
        tmp := deepCopy2dSlice(scannedGrid)
        scannedGrid = seatWalker(tmp)
    }

    fmt.Print("(Part1) - Final seat grid with ")
    fmt.Print(walkOccupied(scannedGrid))
    fmt.Println(" occupied.")

    snapshot2 := deepCopy2dSlice(seatGrid)
    scannedGrid2 := seatWalker2(seatGrid)
    for !reflect.DeepEqual(snapshot2, scannedGrid2) {
        snapshot2 = deepCopy2dSlice(scannedGrid2)
        tmp := deepCopy2dSlice(scannedGrid2)
        scannedGrid2 = seatWalker2(tmp)
    }

    fmt.Print("(Part2) - Final seat grid with ")
    fmt.Print(walkOccupied(scannedGrid2))
    fmt.Println(" occupied.")
}

func seatWalker(grid [][]rune) [][]rune {
    newGrid := deepCopy2dSlice(grid)

    for row, cols := range grid {
        for seat := range cols {
            if cols[seat] == 'L' && checkOccupied(row, seat, grid) == 0 {
                newGrid[row][seat] = '#'
            }

            if cols[seat] == '#' && checkOccupied(row, seat, grid) >= 4 {
                newGrid[row][seat] = 'L'
            }
        }
    }

    return newGrid
}

func seatWalker2(grid [][]rune) [][]rune {
    newGrid := deepCopy2dSlice(grid)

    for row, cols := range grid {
        for seat := range cols {
            if cols[seat] == 'L' && checkOccupied2(row, seat, grid) == 0 {
                newGrid[row][seat] = '#'
            }

            if cols[seat] == '#' && checkOccupied2(row, seat, grid) >= 5 {
                newGrid[row][seat] = 'L'
            }
        }
    }

    return newGrid
}

func walkOccupied(grid [][]rune) int {
    occupied := 0

    for _, cols := range grid {
        for seat := range cols {
            if cols[seat] == '#' {
                occupied++
            }
        }
    }

    return occupied
}

func checkOccupied(row int, seat int, grid [][]rune) int {
    occupied := 0
    /*
        col-1,row-1     col,row-1       col+1, row-1
        col-1,row           X           col+1, row
        col-1,row+1     col,row+1       col+1,row+1
    */

    for x := Max(0, row-1); x <= Min(row+1, len(grid)-1); x++ {
        for y := Max(0, seat-1); y <= Min(seat+1, len(grid[0])-1); y++ {
            if !(x == row && y == seat) {
                if grid[x][y] == '#' {
                    occupied++
                }
            }
        }
    }
    return occupied
}

func checkOccupied2(row int, seat int, grid [][]rune) int {
    occupied := 0
    /*
        col-1,row-1     col,row-1       col+1, row-1
        col-1,row           X           col+1, row
        col-1,row+1     col,row+1       col+1,row+1
    */

    for x := Max(0, row-1); x <= Min(row+1, len(grid)-1); x++ {
        for y := Max(0, seat-1); y <= Min(seat+1, len(grid[0])-1); y++ {
            if !(x == row && y == seat) {
                if grid[x][y] == '#' {
                    occupied++
                } else if grid[x][y] == '.' {
                    occupied = occupied + checkNextNeighbor(grid, x, y, getDir(row, seat, x, y))
                }
            }
        }
    }

    return occupied
}

func getDir(row int, seat int, x int, y int) string {

    if row == x && seat > y {
        return "left"
    }

    if row == x && seat < y {
        return "right"
    }

    if row > x && seat == y {
        return "up"
    }

    if row < x && seat == y {
        return "down"
    }

    if row > x && seat > y {
        return "diagUpLeft"
    }

    if row < x && seat > y {
        return "diagDownLeft"
    }

    if row > x && seat < y {
        return "diagUpRight"
    }

    if row < x && seat < y {
        return "diagDownRight"
    }

    return ""
}

func checkNextNeighbor(grid [][]rune, x int, y int, dir string) int {
    switch dir {
    case "left":
        if y-1 >= 0 {
            if grid[x][y-1] == '.' {
                return checkNextNeighbor(grid, x, y-1, "left")
            } else if grid[x][y-1] == '#' {
                return 1
            }
        }
    case "right":
        if y+1 < len(grid[x]) {
            if grid[x][y+1] == '.' {
                return checkNextNeighbor(grid, x, y+1, "right")
            } else if grid[x][y+1] == '#' {
                return 1
            }
        }
    case "up":
        if x-1 >= 0 {
            if grid[x-1][y] == '.' {
                return checkNextNeighbor(grid, x-1, y, "up")
            } else if grid[x-1][y] == '#' {
                return 1
            }
        }
    case "down":
        if x+1 < len(grid) {
            if grid[x+1][y] == '.' {
                return checkNextNeighbor(grid, x+1, y, "down")
            } else if grid[x+1][y] == '#' {
                return 1
            }
        }
    case "diagUpLeft":
        if x-1 >= 0 && y-1 >= 0 {
            if grid[x-1][y-1] == '.' {
                return checkNextNeighbor(grid, x-1, y-1, "diagUpLeft")
            } else if grid[x-1][y-1] == '#' {
                return 1
            }
        }
    case "diagDownLeft":
        if x+1 < len(grid) && y-1 >= 0 {
            if grid[x+1][y-1] == '.' {
                return checkNextNeighbor(grid, x+1, y-1, "diagDownLeft")
            } else if grid[x+1][y-1] == '#' {
                return 1
            }
        }
    case "diagUpRight":
        if x-1 >= 0 && y+1 < len(grid[x]) {
            if grid[x-1][y+1] == '.' {
                return checkNextNeighbor(grid, x-1, y+1, "diagUpRight")
            } else if grid[x-1][y+1] == '#' {
                return 1
            }
        }
    case "diagDownRight":
        if x+1 < len(grid) && y+1 < len(grid[x]) {
            if grid[x+1][y+1] == '.' {
                return checkNextNeighbor(grid, x+1, y+1, "diagDownRight")
            } else if grid[x+1][y+1] == '#' {
                return 1
            }
        }
    default:
        return 0
    }

    return 0
}

// Max returns the larger of x or y.
func Max(x, y int) int {
    if x < y {
        return y
    }
    return x
}

// Min returns the smaller of x or y.
func Min(x, y int) int {
    if x > y {
        return y
    }
    return x
}

func prettyGrid(seatGrid [][]rune) {
    for runes := range seatGrid {
        for rune := range seatGrid[runes] {
            fmt.Print(string(seatGrid[runes][rune]))
        }
        fmt.Println()
    }
}

func deepCopy2dSlice(twoDimensionalSlice [][]rune) [][]rune {
    copySlice := make([][]rune, len(twoDimensionalSlice))
    for i := range twoDimensionalSlice {
        copySlice[i] = make([]rune, len(twoDimensionalSlice[i]))
        copy(copySlice[i], twoDimensionalSlice[i])
    }

    return copySlice
}

Enter fullscreen mode Exit fullscreen mode

Link to Github source file

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (6)

Collapse
 
gubesch profile image
Christian Gubesch

Hey that looks curios I gotta look at it later on my pc ;) I made this one in go as well😅

Collapse
 
dizveloper profile image
Edvin

Nice!

Yeah I don't think my solution is the most elegant but also pretty wordy because of Go's lack of generics. I am enjoying it though!

Collapse
 
gubesch profile image
Christian Gubesch

yeah thats the beauty you always know what your code will do😅 wanna see my version?

Thread Thread
 
dizveloper profile image
Edvin

Link it!

Thread Thread
 
gubesch profile image
Christian Gubesch

dev.to/gubesch/comment/194en

posted it here yesterday ;)
how did you do today ;)

Thread Thread
 
dizveloper profile image
Edvin

Been a little busy, but got part1 done! I know what I want to do for part 2. Just gotta get to it 😬

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay