diff --git a/2018/day03-1.go b/2018/day03-1.go new file mode 100644 index 0000000..bc853bf --- /dev/null +++ b/2018/day03-1.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + + "internal/fabric" + "internal/util" +) + +func main() { + data := util.ReadInput() + claims, maxX, maxY := fabric.ParseClaims(data) + grid := fabric.PopulateGrid(claims, maxX, maxY) + + count := 0 + for y := 0; y < len(grid); y++ { + for x := 0; x < len(grid[y]); x++ { + if grid[y][x] == -1 { + count++ + } + } + } + + fmt.Println(count) +} diff --git a/2018/day03-2.go b/2018/day03-2.go new file mode 100644 index 0000000..ea6858c --- /dev/null +++ b/2018/day03-2.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + + "internal/fabric" + "internal/util" +) + +func main() { + data := util.ReadInput() + claims, maxX, maxY := fabric.ParseClaims(data) + fabric.PopulateGrid(claims, maxX, maxY) // ignoring return value because we only want the side effect here + + id := -1 + count := 0 + for _, claim := range claims { + if !claim.Overlaps { + id = claim.ID + count++ + } + } + + if count > 1 { + fmt.Printf("%d claims detected no overlap. :(\n", count) + return + } + if count == 0 { + fmt.Println("All claims overlapped. :(") + return + } + + fmt.Println(id) +} diff --git a/2018/internal/fabric/fabric_claims.go b/2018/internal/fabric/fabric_claims.go new file mode 100644 index 0000000..0388c0e --- /dev/null +++ b/2018/internal/fabric/fabric_claims.go @@ -0,0 +1,89 @@ +// Used by both parts of day 03 +package fabric + +import ( + "strconv" + "strings" +) + +type Claim struct { + ID int + Overlaps bool + x1 int + y1 int + x2 int + y2 int +} + +// PopulateGrid takes a series of claims and 'draws' them on a 2d +// array, writing the claim ID to each cell. If an overlap happens, +// the value -1 is written instead. +// It also flags the claim object as 'overwritten' when this happens. +func PopulateGrid(data map[int]*Claim, maxX, maxY int) [][]int { + grid := make([][]int, maxY) + for i := 0; i < maxY; i++ { + grid[i] = make([]int, maxX) + } + + for _, claim := range data { + for y := claim.y1; y < claim.y2; y++ { + for x := claim.x1; x < claim.x2; x++ { + if grid[y][x] != 0 { + if grid[y][x] != -1 { + data[grid[y][x]].Overlaps = true + } + + grid[y][x] = -1 + data[claim.ID].Overlaps = true + } else { + grid[y][x] = claim.ID + } + } + } + } + return grid +} + +// ParseClaims takes our input data and creates some usable, structured data from it. +// Unfortunately the input data is ugly, and so this function reflects that. +// Returns a list of Claim objects, the highest seen X value, and the highest seen Y value. +func ParseClaims(rawData []string) (map[int]*Claim, int, int) { + claims := make(map[int]*Claim) + maxX := 0 + maxY := 0 + + for _, line := range rawData { + // Split the data on spaces, since that's the top-order delimiter. + data := strings.Split(line, " ") + id, _ := strconv.Atoi(data[0][1:]) + + // The coordinate chunk (data[2]) needs the last character chopped off, since it is an unused ':' + // That's what [:len(data[2])-1] is doing. + coords := strings.Split(data[2][:len(data[2])-1], ",") + x1, _ := strconv.Atoi(coords[0]) + y1, _ := strconv.Atoi(coords[1]) + + size := strings.Split(data[3], "x") + width, _ := strconv.Atoi(size[0]) + height, _ := strconv.Atoi(size[1]) + + claim := &Claim{ + ID: id, + x1: x1, + x2: x1 + width, + y1: y1, + y2: y1 + height, + Overlaps: false, + } + claims[id] = claim + + if claim.y2 > maxY { + maxY = claim.y2 + } + if claim.x2 > maxX { + maxX = claim.x2 + } + } + + return claims, maxX, maxY +}