Compare commits

..

No commits in common. "849fc74a1521bbe325d471941b1f3846ab58d923" and "ed95f875ad46c219b39e583bae279e25ca58aa9a" have entirely different histories.

2 changed files with 0 additions and 509 deletions

View File

@ -1,458 +0,0 @@
package main
import (
"fmt"
"log"
"os"
"regexp"
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
)
const (
MATCH_NONE = iota
MATCH_TOP
MATCH_BOTTOM
MATCH_LEFT
MATCH_RIGHT
)
type Tile struct {
id int
data []string
rotation int
flippedX bool
flippedY bool
}
func NewTile() *Tile {
return &Tile{
data: make([]string, 0),
rotation: 0,
flippedX: false,
flippedY: false,
}
}
func (t *Tile) print() {
for _, line := range t.data {
fmt.Println(line)
}
fmt.Println()
}
func (t *Tile) rotate() {
newData := make([]string, len(t.data))
for i := len(t.data) - 1; i >= 0; i-- {
for j, char := range t.data[i] {
newData[j] += string(char)
}
}
t.data = newData
t.rotation++
if t.rotation > 3 {
t.rotation = 0
}
}
func (t *Tile) flipX() {
newData := make([]string, len(t.data))
for i := 0; i < len(newData); i++ {
newData[i] = t.data[len(t.data)-1-i]
}
t.data = newData
t.flippedX = !t.flippedX
}
func (t *Tile) flipY() {
newData := make([]string, len(t.data))
for i := 0; i < len(newData); i++ {
for j := 0; j < len(t.data[i]); j++ {
newData[i] += string(t.data[i][len(t.data)-1-j])
}
}
t.data = newData
t.flippedY = !t.flippedY
}
func (t *Tile) reset() {
for t.rotation != 0 {
t.rotate()
}
if t.flippedX {
t.flipX()
}
if t.flippedY {
t.flipY()
}
}
func parseInput(input []string) map[int]*Tile {
tileMap := make(map[int]*Tile)
re := regexp.MustCompile("^Tile ([0-9]+):$")
id := 0
tile := NewTile()
for _, line := range input {
if re.MatchString(line) {
id = util.MustAtoi(re.FindStringSubmatch(line)[1])
tile.id = id
continue
}
if line == "" {
tileMap[id] = tile
tile = NewTile()
id = 0
continue
}
tile.data = append(tile.data, line)
}
// if needed, add the last one (might be missing our final blank line)
if id != 0 {
tileMap[id] = tile
}
return tileMap
}
func matchTiles(oldTile, newTile *Tile) int {
for i := 0; i < 4; i++ {
check := subMatchTiles(oldTile, newTile)
if check != MATCH_NONE {
return check
}
newTile.rotate()
}
newTile.reset()
newTile.flipX()
for i := 0; i < 4; i++ {
check := subMatchTiles(oldTile, newTile)
if check != MATCH_NONE {
return check
}
newTile.rotate()
}
newTile.reset()
newTile.flipY()
for i := 0; i < 4; i++ {
check := subMatchTiles(oldTile, newTile)
if check != MATCH_NONE {
return check
}
newTile.rotate()
}
newTile.reset()
newTile.flipX()
newTile.flipY()
for i := 0; i < 4; i++ {
check := subMatchTiles(oldTile, newTile)
if check != MATCH_NONE {
return check
}
newTile.rotate()
}
return MATCH_NONE
}
func subMatchTiles(oldTile, newTile *Tile) int {
// check top
if oldTile.data[0] == newTile.data[0] {
return MATCH_TOP
}
// check bottom
if oldTile.data[len(oldTile.data)-1] == newTile.data[len(newTile.data)-1] {
return MATCH_BOTTOM
}
// check left
match := true
for i := 0; i < len(oldTile.data); i++ {
if oldTile.data[i][0] != newTile.data[i][0] {
match = false
break
}
}
if match {
return MATCH_LEFT
}
// check right
match = true
for i := 0; i < len(oldTile.data); i++ {
if oldTile.data[i][len(oldTile.data)-1] != newTile.data[i][len(newTile.data)-1] {
match = false
break
}
}
if match {
return MATCH_RIGHT
}
return MATCH_NONE
}
func arrangeTiles(tiles map[int]*Tile) map[[2]int]*Tile {
grid := make(map[[2]int]*Tile)
looseTiles := make([]*Tile, 0)
for _, v := range tiles {
looseTiles = append(looseTiles, v)
}
// arbitrarily place a first tile
grid[[2]int{0, 0}] = looseTiles[0]
looseTiles = looseTiles[1:]
for len(looseTiles) > 0 {
for coord, tile := range grid {
if _, ok := grid[[2]int{coord[0] + 1, coord[1]}]; ok {
if _, ok := grid[[2]int{coord[0] - 1, coord[1]}]; ok {
if _, ok := grid[[2]int{coord[0], coord[1] + 1}]; ok {
if _, ok := grid[[2]int{coord[0], coord[1] - 1}]; ok {
continue
}
}
}
}
for i, loose := range looseTiles {
matched := matchTiles(tile, loose)
// On a match, flip appropriately and set coords
// check for already present tiles as well - skip if that's the case
var newCoords [2]int
willFlipX := true
switch matched {
case MATCH_TOP:
newCoords = [2]int{coord[0], coord[1] + 1}
case MATCH_BOTTOM:
newCoords = [2]int{coord[0], coord[1] - 1}
case MATCH_LEFT:
newCoords = [2]int{coord[0] - 1, coord[1]}
willFlipX = false
case MATCH_RIGHT:
newCoords = [2]int{coord[0] + 1, coord[1]}
willFlipX = false
}
if matched != MATCH_NONE {
if _, ok := grid[newCoords]; ok {
continue
}
if willFlipX {
loose.flipX()
} else {
loose.flipY()
}
grid[newCoords] = loose
if i == len(looseTiles)-1 {
looseTiles = looseTiles[:i]
} else {
looseTiles = append(looseTiles[:i], looseTiles[i+1:]...)
}
break // to avoid sequencing issues
}
}
}
}
return grid
}
func findCorners(grid map[[2]int]*Tile) []*Tile {
corners := make([]*Tile, 0)
// min and max coord values
minX, minY, maxX, maxY := findLimits(grid)
corners = append(corners, grid[[2]int{minX, minY}])
corners = append(corners, grid[[2]int{maxX, minY}])
corners = append(corners, grid[[2]int{minX, maxY}])
corners = append(corners, grid[[2]int{maxX, maxY}])
return corners
}
func findLimits(grid map[[2]int]*Tile) (int, int, int, int) {
var minX, minY, maxX, maxY int
for coord, _ := range grid {
if coord[0] > maxX {
maxX = coord[0]
}
if coord[0] < minX {
minX = coord[0]
}
if coord[1] > maxY {
maxY = coord[1]
}
if coord[1] < minY {
minY = coord[1]
}
}
return minX, minY, maxX, maxY
}
func stripBorder(tile *Tile) []string {
ret := make([]string, 0)
for i := 1; i < len(tile.data)-1; i++ {
ret = append(ret, tile.data[i][1:len(tile.data)-1])
}
return ret
}
func combineTiles(grid map[[2]int]*Tile) *Tile {
bigTile := NewTile()
minX, minY, maxX, maxY := findLimits(grid)
for j := maxY; j >= minY; j-- {
row := make([]string, 8)
for i := minX; i <= maxX; i++ {
var tile *Tile
tile, ok := grid[[2]int{i, j}]
if !ok {
log.Panicf("Couldn't find tile: %d, %d", i, j)
}
data := stripBorder(tile)
for i, line := range data {
row[i] = row[i] + line
}
}
bigTile.data = append(bigTile.data, row...)
}
return bigTile
}
var monsterPattern = []string{
" # ",
"# ## ## ###",
" # # # # # # ",
}
func subFilterMonsters(image *Tile) int {
numMonsters := 0
for i := 0; i < len(image.data)-2; i++ {
for j := 0; j < len(image.data[0])-19; j++ {
if monsterCheck(image, i, j) {
removeMonster(image, i, j)
numMonsters++
}
}
}
return numMonsters
}
func removeMonster(image *Tile, i, j int) {
for y := 0; y < 3; y++ {
for x := 0; x < 20; x++ {
if monsterPattern[y][x] == '#' {
if j+x == len(image.data[i+y])-1 {
image.data[i+y] = image.data[i+y][:j+x] + "O"
} else {
image.data[i+y] = image.data[i+y][:j+x] + "O" + image.data[i+y][j+x+1:]
}
}
}
}
}
func monsterCheck(image *Tile, i, j int) bool {
data := image.data
for y := 0; y < 3; y++ {
for x := 0; x < 20; x++ {
if data[i+y][j+x] == '.' && monsterPattern[y][x] == '#' {
return false
}
}
}
return true
}
func filterMonsters(image *Tile) int {
numMonsters := 0
for i := 0; i < 4; i++ {
numMonsters = subFilterMonsters(image)
if numMonsters > 0 {
return numMonsters
}
image.rotate()
}
image.reset()
image.flipX()
for i := 0; i < 4; i++ {
numMonsters = subFilterMonsters(image)
if numMonsters > 0 {
return numMonsters
}
}
image.reset()
image.flipY()
for i := 0; i < 4; i++ {
numMonsters = subFilterMonsters(image)
if numMonsters > 0 {
return numMonsters
}
}
image.reset()
image.flipX()
image.flipY()
for i := 0; i < 4; i++ {
numMonsters = subFilterMonsters(image)
if numMonsters > 0 {
return numMonsters
}
}
return numMonsters
}
func main() {
step := os.Args[1]
values := util.InputParserStrings(os.Args[2])
tileMap := parseInput(values)
grid := arrangeTiles(tileMap)
switch step {
case "1":
corners := findCorners(grid)
product := 1
for _, tile := range corners {
product *= tile.id
}
fmt.Println(product)
case "2":
image := combineTiles(grid)
monsters := filterMonsters(image)
if monsters == 0 {
log.Panicf("Found no monsters")
}
count := 0
for _, line := range image.data {
for _, char := range line {
if char == '#' {
count++
}
}
}
fmt.Println(count)
}
}

View File

@ -1,51 +0,0 @@
package main
import (
"fmt"
"os"
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
)
func findLoopSize(pubKey, subject int) int {
value := 1
for i := 0; ; i++ {
value *= subject
value %= 20201227
if value == pubKey {
return i + 1
}
}
}
func transformLoop(pubKey, loopSize int) int {
value := 1
for i := 0; i < loopSize; i++ {
value *= pubKey
value %= 20201227
}
return value
}
func main() {
step := os.Args[1]
values := util.InputParserInts(os.Args[2])
keyPub := values[0]
doorPub := values[1]
keyLoop := findLoopSize(keyPub, 7)
doorLoop := findLoopSize(doorPub, 7)
encryptionKey1 := transformLoop(keyPub, doorLoop)
encryptionKey2 := transformLoop(doorPub, keyLoop)
switch step {
case "1":
fmt.Println(encryptionKey1)
fmt.Println(encryptionKey2)
case "2":
}
}