244 lines
6.2 KiB
Go
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
|
|
}
|