409 lines
14 KiB
Java
409 lines
14 KiB
Java
package com.mattrixwv.adventOfCode24.days;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import com.mattrixwv.Stopwatch;
|
|
import com.mattrixwv.Triple;
|
|
|
|
|
|
public class Problem12 extends Problem{
|
|
private static final String inputFileName = "days/Problem11.txt";
|
|
private List<String> map;
|
|
private List<Triple<Integer, Integer, Character>> patrolHistory;
|
|
private List<Triple<Integer, Integer, Character>> loopLocations;
|
|
//private int loopCounter = 0;
|
|
//private int LOOP_MAX = 7;
|
|
//private int LOOP_MAX = 100;
|
|
|
|
|
|
public Problem12(){
|
|
super();
|
|
description = "Find the number of places that a new obstacle could be placed that creates a patrol loop.";
|
|
result = "Unresolved";
|
|
}
|
|
|
|
|
|
public String runSolution(){
|
|
Stopwatch timer = new Stopwatch();
|
|
timer.start();
|
|
|
|
|
|
throw new RuntimeException("This problem is not yet solved");
|
|
|
|
|
|
//Read the file
|
|
/*
|
|
map = new ArrayList<>();
|
|
try(Scanner scanner = new Scanner(this.getClass().getClassLoader().getResourceAsStream(inputFileName))){
|
|
scanner.useDelimiter("\n");
|
|
while(scanner.hasNext()){
|
|
map.add(scanner.next());
|
|
}
|
|
}
|
|
/* */
|
|
//Answer: 6
|
|
/*
|
|
map = new ArrayList<>(List.of(
|
|
"....#.....",
|
|
".........#",
|
|
"..........",
|
|
"..#.......",
|
|
".......#..",
|
|
"..........",
|
|
".#..^.....",
|
|
"........#.",
|
|
"#.........",
|
|
"......#..."
|
|
));
|
|
/* */
|
|
//Answer: 19
|
|
/*
|
|
map = new ArrayList<>(List.of(
|
|
"...........#.....#......",
|
|
"...................#....",
|
|
"...#.....##.............",
|
|
"......................#.",
|
|
"..................#.....",
|
|
"..#.....................",
|
|
"....................#...",
|
|
"........................",
|
|
".#........^.............",
|
|
"..........#..........#..",
|
|
"..#.....#..........#....",
|
|
"........#.....#..#......"
|
|
));
|
|
/* */
|
|
|
|
/*
|
|
//Find the current location of the guard
|
|
Triple<Integer, Integer, Character> currentLocation = findInitialLocation();
|
|
patrolHistory = new ArrayList<>();
|
|
loopLocations = new ArrayList<>();
|
|
//printMap();
|
|
//Loop while the guard is still on the map
|
|
traverseMap(currentLocation, false);
|
|
|
|
//printMap();
|
|
placePotentialLoops();
|
|
//System.out.println("\n\n");
|
|
printMap();
|
|
|
|
|
|
|
|
//Save the results
|
|
timer.stop();
|
|
result = "The number of positions that a new object could be placed to create a patrol loop is " + loopLocations.size() + ".\nIt took " + timer.toString() + " to run the algorithm.";
|
|
return result;
|
|
/* */
|
|
}
|
|
|
|
private Triple<Integer, Integer, Character> findInitialLocation(){
|
|
for(int row = 0;row < map.size();++row){
|
|
String mapLine = map.get(row);
|
|
int startIndex = mapLine.indexOf("^");
|
|
if(startIndex != -1){
|
|
return new Triple<>(row, startIndex, '^');
|
|
}
|
|
}
|
|
|
|
//If it gets this far it was not found
|
|
return new Triple<>(-1, -1, '\0');
|
|
}
|
|
|
|
private void traverseMap(Triple<Integer, Integer, Character> currentLocation, boolean loopCheck){
|
|
boolean inBounds = true;
|
|
while(inBounds){
|
|
if(patrolHistory.contains(currentLocation)){
|
|
patrolHistory.add(currentLocation);
|
|
break;
|
|
}
|
|
else{
|
|
patrolHistory.add(currentLocation);
|
|
}
|
|
|
|
//Move in that direction as far as possible
|
|
if(currentLocation.getC() == '^'){
|
|
currentLocation = moveUp(currentLocation, loopCheck);
|
|
}
|
|
else if(currentLocation.getC() == '>'){
|
|
currentLocation = moveRight(currentLocation, loopCheck);
|
|
}
|
|
else if(currentLocation.getC() == 'v'){
|
|
currentLocation = moveDown(currentLocation, loopCheck);
|
|
}
|
|
else if(currentLocation.getC() == '<'){
|
|
currentLocation = moveLeft(currentLocation, loopCheck);
|
|
}
|
|
else{
|
|
throw new RuntimeException("There was an error in the location: " + currentLocation);
|
|
}
|
|
//Determine if still in bounds
|
|
//if(loopCounter > LOOP_MAX || currentLocation.getC() == '\0'){
|
|
if(currentLocation.getC() == '\0'){
|
|
inBounds = false;
|
|
}
|
|
//++loopCounter;
|
|
}
|
|
}
|
|
|
|
private Triple<Integer, Integer, Character> moveUp(Triple<Integer, Integer, Character> currentLocation, boolean loopCheck){
|
|
while(true){
|
|
String currentMapString = map.get(currentLocation.getA());
|
|
//If the current Y value is == 0 then the guard left the area
|
|
if(currentLocation.getA() == 0){
|
|
currentMapString = currentMapString.replace("^", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(-1, -1, '\0');
|
|
}
|
|
String nextMapString = map.get(currentLocation.getA() - 1);
|
|
//If the next Y value contains a # then the guard needs to move to the next stage
|
|
if(nextMapString.charAt(currentLocation.getB()) == '#'){
|
|
currentMapString = currentMapString.replace("^", ">");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(currentLocation.getA(), currentLocation.getB(), '>');
|
|
}
|
|
//If the next Y value is a . or X then move to the new location and mark the current location with an X
|
|
else{
|
|
currentMapString = currentMapString.replace("^", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
StringBuilder newMapString = new StringBuilder(nextMapString);
|
|
newMapString.setCharAt(currentLocation.getB(), '^');
|
|
map.set(currentLocation.getA() - 1, newMapString.toString());
|
|
currentLocation = new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), '^');
|
|
|
|
//Check for the potential to create a loop
|
|
if(!loopCheck){
|
|
Triple<Integer, Integer, Character> potentialLoop = new Triple<>(currentLocation.getA() - 1, currentLocation.getB(), '>');
|
|
if(createsLoop(potentialLoop) && !loopContains(potentialLoop)){
|
|
loopLocations.add(potentialLoop);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Triple<Integer, Integer, Character> moveRight(Triple<Integer, Integer, Character> currentLocation, boolean loopCheck){
|
|
while(true){
|
|
String currentMapString = map.get(currentLocation.getA());
|
|
//If the current X value is == the length of the string then the guard left the area
|
|
if(currentLocation.getB() == (currentMapString.length() - 1)){
|
|
currentMapString = currentMapString.replace(">", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(-1, -1, '\0');
|
|
}
|
|
String nextMapString = map.get(currentLocation.getA());
|
|
//If the next X value contains a # then the guard needs to move to the next stage
|
|
if(nextMapString.charAt(currentLocation.getB() + 1) == '#'){
|
|
currentMapString = currentMapString.replace(">", "v");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(currentLocation.getA(), currentLocation.getB(), 'v');
|
|
}
|
|
//If the next X value is a . or X then move to the new location and mark the current location with an X
|
|
else{
|
|
currentMapString = currentMapString.replace(">", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
StringBuilder newMapString = new StringBuilder(nextMapString);
|
|
newMapString.setCharAt(currentLocation.getB() + 1, '>');
|
|
map.set(currentLocation.getA(), newMapString.toString());
|
|
currentLocation = new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, '>');
|
|
|
|
//Check for the potential to create a loop
|
|
if(!loopCheck){
|
|
Triple<Integer, Integer, Character> potentialLoop = new Triple<>(currentLocation.getA(), currentLocation.getB() + 1, 'v');
|
|
if(createsLoop(potentialLoop) && !loopContains(potentialLoop)){
|
|
loopLocations.add(potentialLoop);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Triple<Integer, Integer, Character> moveDown(Triple<Integer, Integer, Character> currentLocation, boolean loopCheck){
|
|
while(true){
|
|
String currentMapString = map.get(currentLocation.getA());
|
|
//If the current Y value is == the length of the string then the guard left the area
|
|
if(currentLocation.getA() == (map.size() - 1)){
|
|
currentMapString = currentMapString.replace("v", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(-1, -1, '\0');
|
|
}
|
|
String nextMapString = map.get(currentLocation.getA() + 1);
|
|
//If the next Y value contains a # then the guard needs to move to the next stage
|
|
if(nextMapString.charAt(currentLocation.getB()) == '#'){
|
|
currentMapString = currentMapString.replace("v", "<");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(currentLocation.getA(), currentLocation.getB(), '<');
|
|
}
|
|
//If the next Y value is a . or X then move to the new location and mark the current location with an X
|
|
else{
|
|
currentMapString = currentMapString.replace("v", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
StringBuilder newMapString = new StringBuilder(nextMapString);
|
|
newMapString.setCharAt(currentLocation.getB(), 'v');
|
|
map.set(currentLocation.getA() + 1, newMapString.toString());
|
|
currentLocation = new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), 'v');
|
|
|
|
//Check for the potential to create a loop
|
|
if(!loopCheck){
|
|
Triple<Integer, Integer, Character> potentialLoop = new Triple<>(currentLocation.getA() + 1, currentLocation.getB(), '<');
|
|
if(createsLoop(potentialLoop) && !loopContains(potentialLoop)){
|
|
loopLocations.add(potentialLoop);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Triple<Integer, Integer, Character> moveLeft(Triple<Integer, Integer, Character> currentLocation, boolean loopCheck){
|
|
while(true){
|
|
String currentMapString = map.get(currentLocation.getA());
|
|
//If the current X value is == 0 then the guard left the area
|
|
if(currentLocation.getB() == 0){
|
|
currentMapString = currentMapString.replace("<", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(-1, -1, '\0');
|
|
}
|
|
String nextMapString = map.get(currentLocation.getA());
|
|
//If the next X value contains a # then the guard needs to move to the next stage
|
|
if(nextMapString.charAt(currentLocation.getB() - 1) == '#'){
|
|
currentMapString = currentMapString.replace("<", "^");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
return new Triple<>(currentLocation.getA(), currentLocation.getB(), '^');
|
|
}
|
|
//If the next X value is a . or X then move to the new location and mark the current location with an X
|
|
else{
|
|
currentMapString = currentMapString.replace("<", "X");
|
|
map.set(currentLocation.getA(), currentMapString);
|
|
StringBuilder newMapString = new StringBuilder(nextMapString);
|
|
newMapString.setCharAt(currentLocation.getB() - 1, '<');
|
|
map.set(currentLocation.getA(), newMapString.toString());
|
|
currentLocation = new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, '<');
|
|
|
|
//Check for the potential to create a loop
|
|
if(!loopCheck){
|
|
Triple<Integer, Integer, Character> potentialLoop = new Triple<>(currentLocation.getA(), currentLocation.getB() - 1, '^');
|
|
if(createsLoop(potentialLoop)){
|
|
loopLocations.add(potentialLoop);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean createsLoop(Triple<Integer, Integer, Character> newObstacleLocation){
|
|
if(loopContains(newObstacleLocation)){
|
|
return false;
|
|
}
|
|
if(newObstacleLocation.getA() >= map.size()){
|
|
return false;
|
|
}
|
|
if(newObstacleLocation.getA() < 0){
|
|
return false;
|
|
}
|
|
if(newObstacleLocation.getB() >= map.get(newObstacleLocation.getA()).length()){
|
|
return false;
|
|
}
|
|
if(newObstacleLocation.getB() < 0){
|
|
return false;
|
|
}
|
|
if(map.get(newObstacleLocation.getA()).charAt(newObstacleLocation.getB()) != '.'){
|
|
return false;
|
|
}
|
|
|
|
boolean loop = false;
|
|
List<String> originalMap = new ArrayList<>(map);
|
|
List<Triple<Integer, Integer, Character>> originalHistory = new ArrayList<>(patrolHistory);
|
|
patrolHistory = new ArrayList<>();
|
|
//int orgLoopCnt = loopCounter;
|
|
//loopCounter = 0;
|
|
//int orgLoopMax = LOOP_MAX;
|
|
//LOOP_MAX = 1000;
|
|
|
|
|
|
StringBuilder mapLine = new StringBuilder(map.get(newObstacleLocation.getA()));
|
|
mapLine.setCharAt(newObstacleLocation.getB(), '#');
|
|
map.set(newObstacleLocation.getA(), mapLine.toString());
|
|
|
|
traverseMap(originalHistory.get(0), true);
|
|
|
|
/* */
|
|
if(newObstacleLocation.getC() == '^'){
|
|
//traverseMap(new Triple<>(newObstacleLocation.getA(), newObstacleLocation.getB() + 1, newObstacleLocation.getC()), true);
|
|
}
|
|
else if(newObstacleLocation.getC() == '>'){
|
|
//traverseMap(new Triple<>(newObstacleLocation.getA() + 1, newObstacleLocation.getB(), newObstacleLocation.getC()), true);
|
|
}
|
|
else if(newObstacleLocation.getC() == 'v'){
|
|
//traverseMap(new Triple<>(newObstacleLocation.getA(), newObstacleLocation.getB() - 1, newObstacleLocation.getC()), true);
|
|
}
|
|
else if(newObstacleLocation.getC() == '<'){
|
|
//traverseMap(new Triple<>(newObstacleLocation.getA() - 1, newObstacleLocation.getB(), newObstacleLocation.getC()), true);
|
|
}
|
|
/* */
|
|
|
|
int lastLocation = patrolHistory.indexOf(patrolHistory.get(patrolHistory.size() - 1));
|
|
if((lastLocation != -1) && (lastLocation != patrolHistory.size() - 1)){
|
|
loop = true;
|
|
}
|
|
|
|
|
|
map = originalMap;
|
|
patrolHistory = originalHistory;
|
|
//loopCounter = orgLoopCnt;
|
|
//LOOP_MAX = orgLoopMax;
|
|
|
|
return loop;
|
|
}
|
|
|
|
private boolean loopContains(Triple<Integer, Integer, Character> loopLocation){
|
|
for(Triple<Integer, Integer, Character> location : loopLocations){
|
|
if(location.getA() == loopLocation.getA() && location.getB() == loopLocation.getB()){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void printMap(){
|
|
for(String mapLine : map){
|
|
System.out.println(mapLine);
|
|
}
|
|
}
|
|
|
|
private void placePotentialLoops(){
|
|
for(Triple<Integer, Integer, Character> loopLocation : loopLocations){
|
|
StringBuilder mapLine = new StringBuilder(map.get(loopLocation.getA()));
|
|
mapLine.setCharAt(loopLocation.getB(), 'O');
|
|
map.set(loopLocation.getA(), mapLine.toString());
|
|
}
|
|
}
|
|
}
|
|
|
|
//! Too small
|
|
/*
|
|
360
|
|
*/
|
|
//! Too large
|
|
/*
|
|
1938
|
|
*/
|
|
|
|
//! ?
|
|
/*
|
|
1065
|
|
*/
|
|
|
|
//! ?
|
|
/*
|
|
Find the number of places that a new obstacle could be placed that creates a patrol loop.
|
|
The number of positions that a new object could be placed to create a patrol loop is 1682.
|
|
It took 1.641 seconds to run the algorithm.
|
|
*/
|
|
|
|
//! How?
|
|
/*
|
|
1723
|
|
*/
|