Complete day 13

This commit is contained in:
2024-12-21 12:12:31 -05:00
parent 741aae4f5e
commit c02dc3ce44
5 changed files with 1611 additions and 1 deletions

View File

@@ -34,6 +34,12 @@
<artifactId>myClasses</artifactId>
<version>1.3.6</version>
</dependency>
<dependency>
<groupId>com.mattrixwv</groupId>
<artifactId>matrix</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
<build>

View File

@@ -24,6 +24,8 @@ import com.mattrixwv.adventOfCode24.days.Problem21;
import com.mattrixwv.adventOfCode24.days.Problem22;
import com.mattrixwv.adventOfCode24.days.Problem23;
import com.mattrixwv.adventOfCode24.days.Problem24;
import com.mattrixwv.adventOfCode24.days.Problem25;
import com.mattrixwv.adventOfCode24.days.Problem26;
import com.mattrixwv.adventOfCode24.days.Problem3;
import com.mattrixwv.adventOfCode24.days.Problem4;
import com.mattrixwv.adventOfCode24.days.Problem5;
@@ -39,7 +41,7 @@ public class ProblemSelector{
protected static final List<Integer> PROBLEM_NUMBERS = List.of(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24
20, 21, 22, 23, 24, 25, 26
);
@@ -76,6 +78,8 @@ public class ProblemSelector{
case 22 : day = new Problem22(); break;
case 23 : day = new Problem23(); break;
case 24 : day = new Problem24(); break;
case 25 : day = new Problem25(); break;
case 26 : day = new Problem26(); break;
default: throw new InvalidParameterException();
}
return day;

View File

@@ -0,0 +1,184 @@
package com.mattrixwv.adventOfCode24.days;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.mattrixwv.Stopwatch;
import com.mattrixwv.Triple;
public class Problem25 extends Problem{
private static final String inputFileName = "days/Problem25.txt";
private static final int A_VALUE = 3;
private static final int B_VALUE = 1;
private static final int MAX_PRESSES = 100;
//games = Triple<A, B, Prize>
//A & B = Triple<X, Y, Token>
//Prize = Triple<X, Y, smallestValue>
private List<Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>>> games;
private List<Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>>> results;
public Problem25(){
super();
description = "What is the sum of the minimum number of tokens that can be used to win each solvable game.";
result = "Unresolved";
}
public String runSolution(){
Stopwatch timer = new Stopwatch();
timer.start();
//Read the file
games = new ArrayList<>();
try(Scanner scanner = new Scanner(this.getClass().getClassLoader().getResourceAsStream(inputFileName))){
scanner.useDelimiter("\n\n");
while(scanner.hasNext()){
String machineSetup = scanner.next();
String[] elements = machineSetup.split("\n");
int xMovementA = 0;
int yMovementA = 0;
int xMovementB = 0;
int yMovementB = 0;
int xLocation = 0;
int yLocation = 0;
for(String element : elements){
if(element.startsWith("Button A")){
String buttonAParams = element.split(": ")[1];
String xParam = buttonAParams.split(", ")[0];
String yParam = buttonAParams.split(", ")[1];
xMovementA = Integer.parseInt(xParam.split("X")[1]);
yMovementA = Integer.parseInt(yParam.split("Y")[1]);
}
else if(element.startsWith("Button B")){
String buttonAParams = element.split(": ")[1];
String xParam = buttonAParams.split(", ")[0];
String yParam = buttonAParams.split(", ")[1];
xMovementB = Integer.parseInt(xParam.split("X")[1]);
yMovementB = Integer.parseInt(yParam.split("Y")[1]);
}
else if(element.startsWith("Prize")){
String prizeParams = element.split(": ")[1];
String xParam = prizeParams.split(", ")[0];
String yParam = prizeParams.split(", ")[1];
xLocation = Integer.parseInt(xParam.split("X=")[1]);
yLocation = Integer.parseInt(yParam.split("Y=")[1]);
}
}
Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>> game = new Triple<>(new Triple<>(xMovementA, yMovementA, 3), new Triple<>(xMovementB, yMovementB, 1), new Triple<>(xLocation, yLocation, 0));
games.add(game);
}
}
results = new ArrayList<>();
for(Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>> game : games){
Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>> result = findSmallestValue(game);
results.add(result);
}
int sum = 0;
for(Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>> result : results){
sum += result.getC().getC();
}
//Save the result
timer.stop();
result = "The sum of the minimum tokens needed to win each winnable game is " + sum + ".\nIt took " + timer.toString() + " to run this algorithm.";
return result;
}
private Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>> findSmallestValue(Triple<Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>, Triple<Integer, Integer, Integer>> game){
int smallestTokens = 0;
List<Character> buttonPresses = new ArrayList<>();
final int xValueA = game.getA().getA();
final int yValueA = game.getA().getB();
final int xValueB = game.getB().getA();
final int yValueB = game.getB().getB();
final int xLoc = game.getC().getA();
final int yLoc = game.getC().getB();
//Add A's until X or Y are >= the prize or MAX is reached.
Triple<Integer, Integer, Integer> curLoc = new Triple<>(0, 0, 1);
int aCnt = 0;
while((curLoc.getA() < xLoc) && (curLoc.getB() < yLoc) && (aCnt < MAX_PRESSES)){
buttonPresses.add('A');
++aCnt;
curLoc = calcLocation(buttonPresses, xValueA, yValueA, xValueB, yValueB);
}
//If X and Y match check if the number of tokens is < current solution (or solution is 0) and save if appropriate
if((curLoc.getA() == xLoc) && (curLoc.getB() == yLoc)){
int currentTokens = calculateTokens(buttonPresses);
if((smallestTokens == 0) || (currentTokens < smallestTokens)){
smallestTokens = currentTokens;
}
}
//Remove A's and add B's until X or Y are >= the prize or MAX is reached.
int bCnt = 0;
while(buttonPresses.contains('A')){
buttonPresses.remove((Character)'A');
--aCnt;
curLoc = calcLocation(buttonPresses, xValueA, yValueA, xValueB, yValueB);
while((curLoc.getA() < xLoc) && (curLoc.getB() < yLoc) && (bCnt < MAX_PRESSES)){
buttonPresses.add('B');
++bCnt;
curLoc = calcLocation(buttonPresses, xValueA, yValueA, xValueB, yValueB);
}
//If X and Y match check if the number of tokens is < current solution (or solution is 0) and save if appropriate
if((curLoc.getA() == xLoc) && (curLoc.getB() == yLoc)){
int currentTokens = calculateTokens(buttonPresses);
if((smallestTokens == 0) || (currentTokens < smallestTokens)){
smallestTokens = currentTokens;
}
}
}
//Return a new object with the new token value
return new Triple<>(game.getA(), game.getB(), new Triple<>(game.getC().getA(), game.getC().getB(), smallestTokens));
}
private int calculateTokens(List<Character> buttonPresses){
int tokens = 0;
for(Character ch : buttonPresses){
if(ch == 'A'){
tokens += A_VALUE;
}
else if(ch == 'B'){
tokens += B_VALUE;
}
}
return tokens;
}
private Triple<Integer, Integer, Integer> calcLocation(List<Character> buttonPresses, int xValueA, int yValueA, int xValueB, int yValueB){
int xLoc = 0;
int yLoc = 0;
for(Character ch : buttonPresses){
if(ch == 'A'){
xLoc += xValueA;
yLoc += yValueA;
}
else if(ch == 'B'){
xLoc += xValueB;
yLoc += yValueB;
}
}
return new Triple<Integer, Integer, Integer>(xLoc, yLoc, 1);
}
}
/*
What is the sum of the minimum number of tokens that can be used to win each solvable game.
The sum of the minimum tokens needed to win each winnable game is 31623.
It took 65.497 milliseconds to run this algorithm.
*/

View File

@@ -0,0 +1,137 @@
package com.mattrixwv.adventOfCode24.days;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.mattrixwv.Stopwatch;
import com.mattrixwv.Triple;
import com.mattrixwv.matrix.DoubleMatrix;
public class Problem26 extends Problem{
private static final String inputFileName = "days/Problem25.txt";
private static final int A_VALUE = 3;
private static final int B_VALUE = 1;
private static final double DOUBLE_MARGIN = 0.001D;
//games = Triple<A, B, Prize>
//A & B = Triple<X, Y, Token>
//Prize = Triple<X, Y, smallestValue>
private List<Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>>> games;
private List<Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>>> results;
public Problem26(){
super();
description = "What is the sum of the minimum number of tokens that can be used to win each solvable game.";
result = "Unresolved";
}
public String runSolution(){
Stopwatch timer = new Stopwatch();
timer.start();
//Read the file
games = new ArrayList<>();
try(Scanner scanner = new Scanner(this.getClass().getClassLoader().getResourceAsStream(inputFileName))){
scanner.useDelimiter("\n\n");
while(scanner.hasNext()){
String machineSetup = scanner.next();
String[] elements = machineSetup.split("\n");
long xMovementA = 0;
long yMovementA = 0;
long xMovementB = 0;
long yMovementB = 0;
long xLocation = 0;
long yLocation = 0;
for(String element : elements){
if(element.startsWith("Button A")){
String buttonAParams = element.split(": ")[1];
String xParam = buttonAParams.split(", ")[0];
String yParam = buttonAParams.split(", ")[1];
xMovementA = Long.parseLong(xParam.split("X")[1]);
yMovementA = Long.parseLong(yParam.split("Y")[1]);
}
else if(element.startsWith("Button B")){
String buttonAParams = element.split(": ")[1];
String xParam = buttonAParams.split(", ")[0];
String yParam = buttonAParams.split(", ")[1];
xMovementB = Long.parseLong(xParam.split("X")[1]);
yMovementB = Long.parseLong(yParam.split("Y")[1]);
}
else if(element.startsWith("Prize")){
String prizeParams = element.split(": ")[1];
String xParam = prizeParams.split(", ")[0];
String yParam = prizeParams.split(", ")[1];
xLocation = Long.parseLong(xParam.split("X=")[1]) + 10000000000000L;
yLocation = Long.parseLong(yParam.split("Y=")[1]) + 10000000000000L;
}
}
Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>> game = new Triple<>(new Triple<>(xMovementA, yMovementA, 3L), new Triple<>(xMovementB, yMovementB, 1L), new Triple<>(xLocation, yLocation, 0L));
games.add(game);
}
}
results = new ArrayList<>();
for(Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>> game : games){
Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>> result = findSmallestValue(game);
if(result.getC().getC() > 0L){
results.add(result);
}
}
long sum = 0;
for(Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>> result : results){
sum += result.getC().getC();
}
//Save the result
timer.stop();
result = "The sum of the minimum tokens needed to win each winnable game is " + sum + ".\nIt took " + timer.toString() + " to run this algorithm.";
return result;
}
private Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>> findSmallestValue(Triple<Triple<Long, Long, Long>, Triple<Long, Long, Long>, Triple<Long, Long, Long>> game){
long tokens = 0L;
final Long xValueA = game.getA().getA();
final Long yValueA = game.getA().getB();
final Long xValueB = game.getB().getA();
final Long yValueB = game.getB().getB();
final Long xLoc = game.getC().getA();
final Long yLoc = game.getC().getB();
final DoubleMatrix Ad = new DoubleMatrix(new double[][]{{xValueA.doubleValue(), xValueB.doubleValue()}, {yValueA.doubleValue(), yValueB.doubleValue()}});
final DoubleMatrix bd = new DoubleMatrix(new double[][]{{xLoc.doubleValue()}, {yLoc.doubleValue()}});
if(Ad.det() != 0){
final DoubleMatrix solution = Ad.inverse().multiply(bd);
final Double aTimes = solution.get(0, 0);
final Double bTimes = solution.get(1, 0);
if(((aTimes % 1 < DOUBLE_MARGIN) || (aTimes % 1 > 1 - DOUBLE_MARGIN)) && ((bTimes % 1 < DOUBLE_MARGIN) || (bTimes % 1 > 1 - DOUBLE_MARGIN))){
tokens = calculateTokens(Math.round(solution.get(0, 0)), Math.round(solution.get(1, 0)));
}
}
//Return a new object with the new token value
return new Triple<>(game.getA(), game.getB(), new Triple<>(game.getC().getA(), game.getC().getB(), tokens));
}
private long calculateTokens(long aCnt, long bCnt){
long tokens = 0;
tokens += (aCnt * A_VALUE);
tokens += (bCnt * B_VALUE);
return tokens;
}
}
/*
What is the sum of the minimum number of tokens that can be used to win each solvable game.
The sum of the minimum tokens needed to win each winnable game is 93209116744825.
It took 22.761 milliseconds to run this algorithm.
*/

File diff suppressed because it is too large Load Diff