AoC2021/src/day22/day22.go
2021-12-24 13:10:26 +01:00

244 lines
6.2 KiB
Go

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
}