package main import ( "AOC2021/src/helper" "fmt" "os" "strconv" "strings" ) type cubid struct { xValues [2]int yValues [2]int zValues [2]int cuts []*cubid alreadyUsed []*cubid command string } func main() { args := os.Args[1:] input, err := helper.GetInput(args[0]) if err != nil { fmt.Println(err) } part1(input) cubids := []*cubid{} for _, row := range input { commandSplit := strings.Split(row, " ") valueSplit := strings.Split(helper.RemoveCharactersFromString(commandSplit[1], "yxz,"), "=") xValues := getValuesFromString(valueSplit[1], false) yValues := getValuesFromString(valueSplit[2], false) zValues := getValuesFromString(valueSplit[3], false) cubids = addCubid(cubids, cubid{xValues, yValues, zValues, []*cubid{}, []*cubid{}, commandSplit[0]}) } fmt.Println(countActiveCubids(cubids)) } func part1(input []string) { coreMap := make(map[[3]int]struct{}) for _, row := range input { commandSplit := strings.Split(row, " ") valueSplit := strings.Split(helper.RemoveCharactersFromString(commandSplit[1], "yxz,"), "=") xValues := getValuesFromString(valueSplit[1], true) yValues := getValuesFromString(valueSplit[2], true) zValues := getValuesFromString(valueSplit[3], true) for i := xValues[0]; i <= xValues[1]; i++ { for j := yValues[0]; j <= yValues[1]; j++ { for k := zValues[0]; k <= zValues[1]; k++ { if commandSplit[0] == "on" { coreMap[[3]int{i, j, k}] = struct{}{} } else if commandSplit[0] == "off" { delete(coreMap, [3]int{i, j, k}) } } } } } fmt.Println(int64(len(coreMap))) } func checkOverlap(cubid1 *cubid, cubid2 *cubid) bool { if !overlapLines(cubid1.xValues, cubid2.xValues) { return false } if !overlapLines(cubid1.yValues, cubid2.yValues) { return false } if !overlapLines(cubid1.zValues, cubid2.zValues) { return false } return true } func addCubid(cubids []*cubid, newCubid cubid) []*cubid { newCubids := []*cubid{} if newCubid.command == "off" { for i := range cubids { if checkOverlap(cubids[i], &newCubid) { cut(cubids[i], newCubid) newCubids = append(newCubids, cubids[i]) } else { newCubids = append(newCubids, cubids[i]) } } } if newCubid.command == "on" { newCubids = handleOnCubid(cubids, newCubid, newCubids) } return newCubids } func handleOnCubid(cubids []*cubid, newCubid cubid, newCubids []*cubid) []*cubid { tmpNewCubid := newCubid tmpOffCubid := newCubid tmpOffCubid.command = "off" for i := range cubids { if checkOverlap(cubids[i], &tmpNewCubid) { alreadyUsed(&tmpNewCubid, cubids[i]) addCubid(cubids[i].cuts, tmpOffCubid) } newCubids = append(newCubids, cubids[i]) } newCubids = append(newCubids, &tmpNewCubid) return newCubids } func countActiveCubids(cubids []*cubid) int64 { sum := int64(0) for i := range cubids { allPoints := countActiveCubid(cubids[i]) inactivePoints := countActiveCubids(cubids[i].cuts) alreadyUsedPoints := countActiveCubids(cubids[i].alreadyUsed) sum += allPoints - inactivePoints - alreadyUsedPoints } return sum } func countActiveCubid(cubid *cubid) int64 { lengthX := cubid.xValues[1] - cubid.xValues[0] + 1 lengthY := cubid.yValues[1] - cubid.yValues[0] + 1 lengthZ := cubid.zValues[1] - cubid.zValues[0] + 1 sum := int64(lengthX) * int64(lengthY) * int64(lengthZ) return sum } func cut(cubid1 *cubid, cubid2 cubid) int { cutCubid := cubid{} cutCubid.xValues[0] = max(cubid1.xValues[0], cubid2.xValues[0]) cutCubid.yValues[0] = max(cubid1.yValues[0], cubid2.yValues[0]) cutCubid.zValues[0] = max(cubid1.zValues[0], cubid2.zValues[0]) cutCubid.xValues[1] = min(cubid1.xValues[1], cubid2.xValues[1]) cutCubid.yValues[1] = min(cubid1.yValues[1], cubid2.yValues[1]) cutCubid.zValues[1] = min(cubid1.zValues[1], cubid2.zValues[1]) cutCubid.command = "on" for _, overlapCubid := range cubid1.alreadyUsed { if checkOverlap(&cutCubid, overlapCubid) { alreadyUsed(&cutCubid, overlapCubid) } } cubid1.cuts = addCubid(cubid1.cuts, cutCubid) return 0 } func alreadyUsed(cubid1 *cubid, cubid2 *cubid) int { cutCubid := cubid{} cutCubid.xValues[0] = max(cubid1.xValues[0], cubid2.xValues[0]) cutCubid.yValues[0] = max(cubid1.yValues[0], cubid2.yValues[0]) cutCubid.zValues[0] = max(cubid1.zValues[0], cubid2.zValues[0]) cutCubid.xValues[1] = min(cubid1.xValues[1], cubid2.xValues[1]) cutCubid.yValues[1] = min(cubid1.yValues[1], cubid2.yValues[1]) cutCubid.zValues[1] = min(cubid1.zValues[1], cubid2.zValues[1]) cutCubid.command = "on" cubid1.alreadyUsed = addCubid(cubid1.alreadyUsed, cutCubid) return 0 } func checkSameCoordinates(cubid1 cubid, cubid2 cubid) bool { return cubid1.xValues == cubid2.xValues && cubid1.yValues == cubid2.yValues && cubid1.zValues == cubid2.zValues } func getValuesFromString(input string, part1 bool) (output [2]int) { split := strings.Split(input, "..") output[0], _ = strconv.Atoi(split[0]) if part1 && output[0] < -50 { output[0] = -50 } output[1], _ = strconv.Atoi(split[1]) if part1 && output[1] > 50 { output[1] = 50 } return } func isBetween(x, a, b int) bool { if x >= a && x <= b { return true } return false } func overlapLines(a, b [2]int) bool { for _, aVal := range a { if isBetween(aVal, b[0], b[1]) { return true } } for _, bVal := range b { if isBetween(bVal, a[0], a[1]) { return true } } return false } func min(a, b int) int { if a < b { return a } return b } func max(a, b int) int { if a > b { return a } return b } func printTwoDimensions(cubids []*cubid) { field := initiateDimension(100, 100) offset := 40 for _, cubid := range cubids { for i := cubid.xValues[0] + offset; i <= cubid.xValues[1]+offset; i++ { for j := cubid.yValues[0] + offset; j <= cubid.yValues[1]+offset; j++ { field[j][i] = '#' } } for _, cut := range cubid.cuts { for i := cut.xValues[0] + offset; i <= cut.xValues[1]+offset; i++ { for j := cut.yValues[0] + offset; j <= cut.yValues[1]+offset; j++ { field[j][i] = 'X' } } } } for _, row := range field { fmt.Println(string(row)) } fmt.Printf("Active Points: %d \n", countActiveCubids(cubids)) } func initiateDimension(x int, y int) [][]rune { var emptyLayer [][]rune for i := 0; i < y; i++ { emptyLayer = append(emptyLayer, []rune(strings.Repeat(".", x))) } return emptyLayer }