main.go (4354B)
1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "log" 7 "os" 8 "strconv" 9 "strings" 10 ) 11 12 type Pos struct { 13 x, y int 14 } 15 16 type Shape []Pos 17 type Shapes []Shape 18 19 func (ss Shapes) GetLeftmost() Pos { 20 p := Pos{x: -1} 21 for _, s := range ss { 22 for _, e := range s { 23 if p.x == -1 || e.x < p.x { 24 p = e 25 } 26 } 27 } 28 return p 29 } 30 func (ss Shapes) GetRightmost() Pos { 31 var p Pos 32 for _, s := range ss { 33 for _, e := range s { 34 if e.x > p.x { 35 p = e 36 } 37 } 38 } 39 return p 40 } 41 func (ss Shapes) GetMaxY() int { 42 y := 0 43 for _, s := range ss { 44 for _, e := range s { 45 if e.y > y { 46 y = e.y 47 } 48 } 49 } 50 return y 51 } 52 53 type Grid [][]byte 54 55 func (grid Grid) String() string { 56 var s string 57 for y := 0; y < len(grid); y++ { 58 for x := 0; x < len(grid[y]); x++ { 59 switch grid[y][x] { 60 case 0: 61 s += " " 62 case 1: 63 s += "#" 64 case 2: 65 s += "o" 66 default: 67 s += " " 68 } 69 } 70 s += "\n" 71 } 72 return s 73 } 74 func (grid *Grid) Init(width, height int) { 75 *grid = make(Grid, height) 76 for y := 0; y < height; y++ { 77 (*grid)[y] = make([]byte, width) 78 } 79 } 80 func (grid *Grid) AddShape(s Shape, offset int) { 81 for i := 1; i < len(s); i++ { 82 x1, y1 := s[i-1].x-offset, s[i-1].y 83 x2, y2 := s[i].x-offset, s[i].y 84 if x1 > x2 { 85 x1, x2 = x2, x1 86 } 87 if y1 > y2 { 88 y1, y2 = y2, y1 89 } 90 for x := x1; x <= x2; x++ { 91 for y := y1; y <= y2; y++ { 92 (*grid)[y][x] = 1 93 } 94 } 95 } 96 } 97 98 func main() { 99 if len(os.Args) > 1 { 100 day14(os.Args[1]) 101 } else if len(os.Args) == 1 { 102 fmt.Printf("usage: %s inputfile.txt\n", os.Args[0]) 103 } else { 104 fmt.Println("No input data") 105 } 106 } 107 108 func day14(input_file string) { 109 fmt.Printf("day 14 input filename: %s\n", input_file) 110 input, err := os.Open(input_file) 111 if err != nil { 112 log.Fatal(err) 113 } 114 defer input.Close() 115 scanner := bufio.NewScanner(input) 116 var shapes Shapes 117 for scanner.Scan() { 118 in := scanner.Text() 119 edges := strings.Split(in, " -> ") 120 var s Shape 121 for _, edge := range edges { 122 var p Pos 123 xs, ys, found := strings.Cut(edge, ",") 124 if !found { 125 log.Fatal("invalid input") 126 } 127 p.x, err = strconv.Atoi(xs) 128 if err != nil { 129 log.Fatal(err) 130 } 131 p.y, err = strconv.Atoi(ys) 132 if err != nil { 133 log.Fatal(err) 134 } 135 s = append(s, p) 136 } 137 if len(s) <= 1 { 138 log.Fatal("invalid shape", s) 139 } 140 shapes = append(shapes, s) 141 } 142 if err = scanner.Err(); err != nil { 143 log.Fatal(err) 144 } 145 146 height := shapes.GetMaxY() + 1 147 offsetX := shapes.GetLeftmost().x 148 width := shapes.GetRightmost().x - offsetX + 2 149 var grid Grid 150 grid.Init(width, height) 151 for _, s := range shapes { 152 grid.AddShape(s, offsetX) 153 } 154 //fmt.Printf("%v\n", grid) 155 156 i := 0 157 for { 158 p := Pos{x: 500 - offsetX, y: 1} 159 for p.x > 0 && p.x < width-1 && p.y < height-1 { 160 if grid[p.y+1][p.x] == 0 { 161 p.y += 1 162 } else if grid[p.y+1][p.x-1] == 0 { 163 p.y += 1 164 p.x -= 1 165 } else if grid[p.y+1][p.x+1] == 0 { 166 p.y += 1 167 p.x += 1 168 } else { 169 break 170 } 171 } 172 if p.x > 0 && p.x < width-1 && p.y < height-1 && grid[p.y][p.x] == 0 { 173 grid[p.y][p.x] = 2 174 } else { 175 break 176 } 177 i++ 178 //fmt.Printf("%v\n", grid) 179 } 180 //fmt.Printf("%v\n", grid) 181 fmt.Println("grains of sand 1:", i) 182 183 var grid2 Grid 184 height += 2 185 leftmost := shapes.GetLeftmost() 186 rightmost := shapes.GetRightmost() 187 minx := leftmost.x - (height - leftmost.y) 188 maxx := rightmost.x + (height - rightmost.y) 189 if minx > 500-height { 190 minx = 500 - height 191 } 192 if maxx < 500+height { 193 maxx = 500 + height 194 } 195 offsetX = minx 196 width = maxx - minx + 2 197 ///fmt.Printf("minx:%d, maxx:%d,offsetx:%d,width:%d,height:%d\n",minx,maxx,offsetX,width,height) 198 if offsetX < 0 { 199 offsetX = 0 200 } 201 grid2.Init(width, height) 202 for _, s := range shapes { 203 grid2.AddShape(s, offsetX) 204 } 205 floor := Shape{} 206 floor = append(floor, Pos{x: 0, y: height - 1}) 207 floor = append(floor, Pos{x: width - 1, y: height - 1}) 208 grid2.AddShape(floor, 0) 209 //fmt.Printf("%v\n", grid2) 210 i = 0 211 for { 212 p := Pos{x: 500 - offsetX, y: 0} 213 for p.x > 0 && p.x < width-1 && p.y < height-1 { 214 if grid2[p.y+1][p.x] == 0 { 215 p.y += 1 216 } else if grid2[p.y+1][p.x-1] == 0 { 217 p.y += 1 218 p.x -= 1 219 } else if grid2[p.y+1][p.x+1] == 0 { 220 p.y += 1 221 p.x += 1 222 } else { 223 break 224 } 225 } 226 if p.y < height-1 && grid2[p.y][p.x] == 0 { 227 grid2[p.y][p.x] = 2 228 } else { 229 break 230 } 231 i++ 232 //fmt.Printf("%v\n", grid2) 233 } 234 //fmt.Printf("%v\n", grid2) 235 fmt.Println("grains of sand 2:", i) 236 }