diff --git a/src/day22/day22.go b/src/day22/day22.go index ae31c28..89e3140 100644 --- a/src/day22/day22.go +++ b/src/day22/day22.go @@ -241,10 +241,3 @@ func initiateDimension(x int, y int) [][]rune { } return emptyLayer } - -func Abs(x int64) int64 { - if x < 0 { - return -x - } - return x -} diff --git a/src/day23/day23.go b/src/day23/day23.go new file mode 100644 index 0000000..53a34c1 --- /dev/null +++ b/src/day23/day23.go @@ -0,0 +1,255 @@ +package main + +import ( + "AOC2021/src/helper" + "fmt" + "strings" +) + +type board struct { + corridor [11]rune + rooms [4][4]rune + energy int +} + +var costs = map[rune]int{ + 'A': 1, + 'B': 10, + 'C': 100, + 'D': 1000, +} + +var destX = map[rune]int{ + 'A': 0, + 'B': 1, + 'C': 2, + 'D': 3, +} + +var enterableCorridorPos = [7]int{0, 1, 3, 5, 7, 9, 10} + +func main() { + playBoard := board{ + [11]rune{'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, + [4][4]rune{{'D', 'D', 'D', 'B'}, {'D', 'C', 'B', 'A'}, {'C', 'B', 'A', 'A'}, {'B', 'A', 'C', 'C'}}} + currentBoards := []board + endBoards := []board + currentBoards = append(currentBoards, playBoard) + for len(currentBoards) > 0 { + step(¤tBoards, &endBoards) + } + fmt.Println(len(endBoards)) + minEnergy := 9999999 + for _, endBoard := range endBoards { + if checkWinner(endBoard) && endBoard.energy < minEnergy { + if minEnergy > endBoard.energy { + minEnergy = endBoard.energy + } + } + } + fmt.Println(minEnergy) +} + +func checkWinner(board board) bool { + for amphoidType, room := range destX { + for _, val := range board.rooms[room] { + if val != amphoidType && val != '.' { + return false + } + } + } + return true +} + +func step(currentBoards *[]board, endBoards *[]board) { + fmt.Print("hll") + for selectedBoard, selectedEnergy := range *currentBoards { + possibleMoves := getPossibleMoves(selectedBoard) + if len(possibleMoves) == 0 { + if (*endBoards)[selectedBoard] == 0 || selectedEnergy < (*endBoards)[selectedBoard] { + (*endBoards)[selectedBoard] = selectedEnergy + } + } + for start, targets := range possibleMoves { + for _, target := range targets { + tmpNewBoard, tmpNewErnergy := useMove(selectedBoard, [2][2]int{start, target}, selectedEnergy) + if (*currentBoards)[tmpNewBoard] == 0 || tmpNewErnergy < (*currentBoards)[tmpNewBoard] { + (*currentBoards)[tmpNewBoard] = tmpNewErnergy + } + } + } + } + return +} + +func useMove(board board, move [2][2]int, ernergy int) (board, int) { + //Remove moved Amphoid + var amphoidType rune + if move[0][0] == 0 { + amphoidType = board.corridor[move[0][1]] + board.corridor[move[0][1]] = '.' + } else { + amphoidType = board.rooms[move[0][0]-1][move[0][1]] + board.rooms[move[0][0]-1][move[0][1]] = '.' + } + + //Place moved Amphoid + if move[1][0] == 0 { + board.corridor[move[1][1]] = amphoidType + } else { + board.rooms[move[1][0]-1][move[1][1]] = amphoidType + } + + //Calculate cost + traveledDistance := 0 + if move[0][0] == 0 { + traveledDistance += Abs(move[0][1] - (move[1][0]*2 + 2)) + traveledDistance += move[1][1] + 1 + } else { + traveledDistance += Abs(move[1][1] - (move[0][0]*2 + 2)) + traveledDistance += move[0][1] + 1 + } + ernergy += costs[amphoidType] * (traveledDistance) + return board, ernergy +} + +func getPossibleMoves(board board) map[[2]int][][2]int { + possibleMoves := make(map[[2]int][][2]int) + + for i, val := range board.corridor { + if val != '.' { + tmpPossibleMoves := getPossibleMovesFromPos(board, [2]int{0, i}) + if len(tmpPossibleMoves) > 0 { + possibleMoves[[2]int{0, i}] = tmpPossibleMoves + } + } + } + for i, room := range board.rooms { + for j, val := range room { + if val != '.' { + tmpPossibleMoves := getPossibleMovesFromPos(board, [2]int{i + 1, j}) + if len(tmpPossibleMoves) > 0 { + possibleMoves[[2]int{i + 1, j}] = tmpPossibleMoves + } + } + } + } + return possibleMoves +} + +func getPossibleMovesFromPos(board board, position [2]int) [][2]int { + if position[0] == 0 { + enterableRooms := [][2]int{} + for i, _ := range board.rooms { + possiblePos := roomCanEnter(board, i, position[1], board.corridor[position[1]]) + if possiblePos != -1 { + enterableRooms = append(enterableRooms, [2]int{i + 1, possiblePos}) + } + } + return enterableRooms + } else { + if isInCorrectRoom(board, position) || cantLeaveRoom(board, position) { + return [][2]int{} + } + enterableCoordinates := [][2]int{} + for _, pos := range enterableCorridorPos { + if corridorCoordinateCanEnter(board.corridor, position[0]-1, pos) { + enterableCoordinates = append(enterableCoordinates, [2]int{0, pos}) + } + } + //for i, _ := range board.rooms { + // possiblePos := roomCanEnter(board, i, position[1]*2+2, board.rooms[position[0]-1][position[1]]) + // if possiblePos != -1 { + // enterableCoordinates = append(enterableCoordinates, [2]int{i + 1, possiblePos}) + // } + //} + return enterableCoordinates + } +} + +func cantLeaveRoom(board board, position [2]int) bool { + room := board.rooms[position[0]-1] + for i := 0; i < position[1]; i++ { + if room[i] != '.' { + return true + } + } + return false +} + +func isInCorrectRoom(board board, position [2]int) bool { + amphoidType := board.rooms[position[0]-1][position[1]] + if !(destX[amphoidType] == position[0]-1) { + return false + } + otherAmphoidTypes := helper.RemoveCharactersFromString("ABCD", string(amphoidType)) + for _, element := range board.rooms[position[0]-1] { + if strings.ContainsRune(otherAmphoidTypes, element) { + return false + } + } + return true +} + +func roomCanEnter(board board, positionRoom int, positionAmphoid int, amphoidType rune) int { + room := board.rooms[positionRoom] + corridor := board.corridor + if !(destX[amphoidType] == positionRoom) { + return -1 + } + otherAmphoidTypes := helper.RemoveCharactersFromString("ABCD", string(amphoidType)) + for _, element := range room { + if strings.ContainsRune(otherAmphoidTypes, element) { + return -1 + } + } + target := 2 + positionRoom*2 + n := positionAmphoid + if target < positionAmphoid { + n-- + } else { + n++ + } + for n != target { + if corridor[n] != '.' { + return -1 + } + if target < positionAmphoid { + n-- + } else { + n++ + } + } + for i := len(room) - 1; i >= 0; i-- { + if room[i] == '.' { + return i + } + } + return -1 +} + +func corridorCoordinateCanEnter(corridor [11]rune, currentRoom int, target int) bool { + if corridor[target] != '.' { + return false + } + startPos := 2 + currentRoom*2 + i := startPos + for i != target { + if corridor[i] != '.' { + return false + } + if target < startPos { + i-- + } else { + i++ + } + } + return true +} + +func Abs(x int) int { + if x < 0 { + return -x + } + return x +} diff --git a/src/day23/day23Input.txt b/src/day23/day23Input.txt new file mode 100644 index 0000000..6088097 --- /dev/null +++ b/src/day23/day23Input.txt @@ -0,0 +1,5 @@ +############# +#...........# +###D#D#C#B### +###B#A#A#C### +############# \ No newline at end of file diff --git a/src/day23/day23Test.txt b/src/day23/day23Test.txt new file mode 100644 index 0000000..56a84a1 --- /dev/null +++ b/src/day23/day23Test.txt @@ -0,0 +1,5 @@ +############# +#...........# +###B#C#B#D### + #A#D#C#A# + ######### \ No newline at end of file