advent2022

Advent of Code 2022 Solutions
git clone git://bsandro.tech/advent2022
Log | Files | Refs | README | LICENSE

main.go (4385B)


      1 package main
      2 
      3 import (
      4 	"fmt"
      5 	"log"
      6 	"os"
      7 )
      8 
      9 func main() {
     10 	if len(os.Args) > 1 {
     11 		day17(os.Args[1])
     12 	} else if len(os.Args) == 1 {
     13 		fmt.Printf("usage: %s inputfile.txt\n", os.Args[0])
     14 	} else {
     15 		fmt.Println("No input data")
     16 	}
     17 }
     18 
     19 func day17(input_file string) {
     20 	fmt.Printf("day 17 input filename: %s\n", input_file)
     21 	dirs, err := os.ReadFile(input_file)
     22 	if err != nil {
     23 		log.Fatal(err)
     24 	}
     25 
     26 	shapes := []Shape{
     27 		CreateLine(),
     28 		CreateCross(),
     29 		CreateL(),
     30 		CreateBeam(),
     31 		CreateBox(),
     32 	}
     33 
     34 	dsum := 0
     35 	for _, d := range dirs {
     36 		if d == '<' {
     37 			dsum--
     38 		} else if d == '>' {
     39 			dsum++
     40 		}
     41 	}
     42 
     43 	field := Field{width: 7, points: make(map[Pos]bool)}
     44 	var di int64 = -1
     45 	var si int64 = -1
     46 	var oy int64 = 0 // old max y
     47 	var i int64 = 0
     48 	cache := make(map[string]Pos)
     49 	getCacheSum := func() Pos {
     50 		var ret Pos
     51 		for _, v := range cache {
     52 			ret.x += v.x
     53 			ret.y += v.y
     54 		}
     55 		return ret
     56 	}
     57 	var cachesum Pos
     58 	for {
     59 		if i == 2022 {
     60 			fmt.Println("Part 1:", field.maxY)
     61 		}
     62 		if i == 1000000000000 {
     63 			fmt.Println("Part 2:", field.maxY)
     64 			break
     65 		}
     66 		si++
     67 		if si >= int64(len(shapes)) {
     68 			si %= int64(len(shapes))
     69 		}
     70 		odi := di
     71 
     72 		if i > int64(len(dirs)*2) && i > 20220 {
     73 			if cachesum.x == 0 || cachesum.y == 0 {
     74 				cachesum = getCacheSum()
     75 			}
     76 			var mul int64 = (1000000000000 - i) / int64(len(cache))
     77 			var ii int64 = i + int64(len(cache))*mul + 1
     78 			if mul > 0 {
     79 				field.maxY += cachesum.x * mul
     80 				i = ii
     81 				cpos1 := fmt.Sprintf("%d-%d", si, odi)
     82 				di = cache[cpos1].y
     83 				field.maxY += cache[cpos1].x
     84 				continue
     85 			} else {
     86 				cpos1 := fmt.Sprintf("%d-%d", si, odi)
     87 				if c1, e1 := cache[cpos1]; e1 {
     88 					field.maxY += c1.x
     89 					di = c1.y
     90 					i++
     91 					continue
     92 				} else {
     93 					log.Fatal("missing cache:", cpos1)
     94 				}
     95 			}
     96 		}
     97 
     98 		// spawning new block
     99 		p := Pos{x: 2, y: field.maxY + 3}
    100 		for {
    101 			// wind
    102 			di++
    103 			if di >= int64(len(dirs)-1) {
    104 				di %= int64(len(dirs) - 1)
    105 			}
    106 			d := dirs[di]
    107 			if d == '<' && p.x > 0 {
    108 				p1 := Pos{x: p.x - 1, y: p.y}
    109 				occ := shapes[si].GetOccupied(p1)
    110 				if !field.Has(occ) {
    111 					p.x--
    112 				}
    113 			} else if d == '>' && p.x+shapes[si].width < field.width {
    114 				p1 := Pos{x: p.x + 1, y: p.y}
    115 				occ := shapes[si].GetOccupied(p1)
    116 				if !field.Has(occ) {
    117 					p.x++
    118 				}
    119 			}
    120 
    121 			// try moving down
    122 			p1 := Pos{x: p.x, y: p.y - 1}
    123 			occ := shapes[si].GetOccupied(p1)
    124 			if p1.y < 0 || field.Has(occ) {
    125 				// can't move further, gotta stop
    126 				field.Add(shapes[si].GetOccupied(p))
    127 				my := p.y + shapes[si].height
    128 				if my > field.maxY {
    129 					field.maxY = my
    130 				}
    131 				if i > int64(len(dirs)) {
    132 					tp := fmt.Sprintf("%d-%d", si, odi)
    133 					cache[tp] = Pos{x: field.maxY - oy, y: di}
    134 				}
    135 				oy = field.maxY
    136 				break
    137 			} else {
    138 				p = p1
    139 			}
    140 		}
    141 		i++
    142 	}
    143 }
    144 
    145 type Pos struct {
    146 	x, y int64
    147 }
    148 type Points []Pos
    149 
    150 func (pts Points) Has(p Pos) bool {
    151 	for _, p1 := range pts {
    152 		if p1.x == p.x && p1.y == p.y {
    153 			return true
    154 		}
    155 	}
    156 	return false
    157 }
    158 
    159 type Field struct {
    160 	width  int64
    161 	points map[Pos]bool
    162 	maxY   int64
    163 }
    164 
    165 func (f Field) Has(pts Points) bool {
    166 	for _, p := range pts {
    167 		_, has := f.points[p]
    168 		if has {
    169 			return true
    170 		}
    171 	}
    172 	return false
    173 }
    174 func (f Field) Add(pts Points) {
    175 	for _, p := range pts {
    176 		f.points[p] = true
    177 	}
    178 }
    179 
    180 type Shape struct {
    181 	width, height int64
    182 	occupied      Points
    183 }
    184 
    185 func (s Shape) GetOccupied(p Pos) Points {
    186 	var res Points
    187 	for _, o := range s.occupied {
    188 		res = append(res, Pos{p.x + o.x, p.y + o.y})
    189 	}
    190 	return res
    191 }
    192 
    193 func CreateLine() Shape {
    194 	var s Shape
    195 	s.occupied = Points{
    196 		Pos{x: 0, y: 0},
    197 		Pos{x: 1, y: 0},
    198 		Pos{x: 2, y: 0},
    199 		Pos{x: 3, y: 0},
    200 	}
    201 	s.width = 4
    202 	s.height = 1
    203 	return s
    204 }
    205 func CreateCross() Shape {
    206 	var s Shape
    207 	s.occupied = Points{
    208 		Pos{x: 1, y: 0},
    209 		Pos{x: 0, y: 1},
    210 		Pos{x: 1, y: 1},
    211 		Pos{x: 2, y: 1},
    212 		Pos{x: 1, y: 2},
    213 	}
    214 	s.width = 3
    215 	s.height = 3
    216 	return s
    217 }
    218 func CreateL() Shape {
    219 	var s Shape
    220 	s.occupied = Points{
    221 		Pos{x: 0, y: 0},
    222 		Pos{x: 1, y: 0},
    223 		Pos{x: 2, y: 0},
    224 		Pos{x: 2, y: 1},
    225 		Pos{x: 2, y: 2},
    226 	}
    227 	s.width = 3
    228 	s.height = 3
    229 	return s
    230 }
    231 func CreateBeam() Shape {
    232 	var s Shape
    233 	s.occupied = Points{
    234 		Pos{x: 0, y: 0},
    235 		Pos{x: 0, y: 1},
    236 		Pos{x: 0, y: 2},
    237 		Pos{x: 0, y: 3},
    238 	}
    239 	s.width = 1
    240 	s.height = 4
    241 	return s
    242 }
    243 func CreateBox() Shape {
    244 	var s Shape
    245 	s.occupied = Points{
    246 		Pos{x: 0, y: 0},
    247 		Pos{x: 1, y: 0},
    248 		Pos{x: 0, y: 1},
    249 		Pos{x: 1, y: 1},
    250 	}
    251 	s.width = 2
    252 	s.height = 2
    253 	return s
    254 }