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 }