diff --git a/bin/day7.dart b/bin/day7.dart index 42f5bd5..1ab4187 100644 --- a/bin/day7.dart +++ b/bin/day7.dart @@ -1,10 +1,11 @@ import 'package:aoc_2024/lib.dart'; import 'package:aoc_2024/day7/part_1.dart' as part1; +import 'package:aoc_2024/day7/part_2.dart' as part2; Future main(List arguments) async { await runDay( day: 7, part1: part1.calculate, - part2: (r) => Future.value(0), + part2: part2.calculate, ); } diff --git a/lib/day7/part_1.dart b/lib/day7/part_1.dart index 45bf7c0..0be59ff 100644 --- a/lib/day7/part_1.dart +++ b/lib/day7/part_1.dart @@ -12,4 +12,7 @@ Future calculate(Resources resources) async { } bool _canEquationBeTrue(final AmbiguousEquation equation) => - equation.potentialEquations.any((e) => e.isValid()); + equation.potentialEquations([ + Add(), + Multiply(), + ]).any((e) => e.isValid()); diff --git a/lib/day7/part_2.dart b/lib/day7/part_2.dart new file mode 100644 index 0000000..70de0c9 --- /dev/null +++ b/lib/day7/part_2.dart @@ -0,0 +1,19 @@ +import 'package:aoc_2024/lib.dart'; + +import 'shared.dart'; + +Future calculate(Resources resources) async { + final equations = await loadData(resources); + + final result = equations + .where((e) => _canEquationBeTrue(e)) + .fold(0, (v, e) => v + e.result); + return result; +} + +bool _canEquationBeTrue(final AmbiguousEquation equation) => + equation.potentialEquations([ + Add(), + Multiply(), + Concatenation(), + ]).any((e) => e.isValid()); diff --git a/lib/day7/shared.dart b/lib/day7/shared.dart index 295d0df..2b17ea8 100644 --- a/lib/day7/shared.dart +++ b/lib/day7/shared.dart @@ -2,27 +2,36 @@ import 'dart:math'; import 'package:aoc_2024/lib.dart'; -enum Operators { - add, - multiply; -} - -class Component {} +/// Represents an arbitrary equation component. +abstract class Component {} +/// Represents an operator within an equation. abstract class Operator extends Component {} +/// Addition operator. class Add extends Operator { @override String toString() => '+'; } +/// Multiplication operator. class Multiply extends Operator { @override String toString() => '*'; } +/// Concatenation operator (concatenates the numbers on +/// the left and right side to make a new number). +class Concatenation extends Operator { + @override + String toString() => '||'; +} + +/// Identity operator, which just copies the next number in +/// the equation. class Identity extends Operator {} +/// Represents a numerical value operand. class Value extends Component { final int num; @@ -32,12 +41,15 @@ class Value extends Component { String toString() => num.toString(); } +/// Represents an equation, which may or may not be valid. final class Equation { final int result; final List components; Equation({required this.result, required this.components}); + /// Computes the result of the equation, and returns true if the value + /// matches the equations stated result. bool isValid() { var computedResult = 0; Operator operator = Identity(); @@ -53,6 +65,8 @@ final class Equation { computedResult += component.num; case == Multiply: computedResult *= component.num; + case == Concatenation: + computedResult = int.parse('$computedResult${component.num}'); } } } @@ -65,32 +79,24 @@ final class Equation { '$result: ${components.map((c) => c.toString()).join(' ')}'; } +/// Represents an ambiguous equation, which has a list of operands +/// but no operators. final class AmbiguousEquation { final int result; final List operands; AmbiguousEquation({required this.result, required this.operands}); - List get potentialEquations { - // 1 2 3 4 - // 3 operators - // + + + - // + + * - // + * * - // * * * - // * + + - // * * + - // * + * - // + * + - List> operatorOptions = []; + /// Generates a list of all potential equations from the operands + /// in this equation, based on the given list of operators. + Iterable potentialEquations(List operators) { + List> operatorCombinatorial = []; _generateOperators( - operands.length - 1, [Add(), Multiply()], operatorOptions, 0, []); - assert(operatorOptions.length == pow(2, operands.length - 1)); + operands.length - 1, operators, operatorCombinatorial, 0, []); + assert(operatorCombinatorial.length == + pow(operators.length, operands.length - 1)); - //for (final operatorList in operatorOptions) { - // print(operatorList); - //} - return operatorOptions.map((operators) { + return operatorCombinatorial.map((operators) { var components = []; for (int i = 0; i < operands.length; i++) { components.add(Value(operands[i])); @@ -99,9 +105,10 @@ final class AmbiguousEquation { } } return Equation(result: result, components: components); - }).toList(); + }); } + /// Recursively generates a list of operator combinations. void _generateOperators(int length, List operators, List> result, int depth, List current) { if (depth == length) { @@ -118,7 +125,7 @@ final class AmbiguousEquation { /// Loads data from file, with each line represents as /// an equation. -Future> loadData(Resources resources) async { +Future> loadData(Resources resources) async { final file = resources.file(Day.day7); final lines = await file.readAsLines(); @@ -131,5 +138,5 @@ Future> loadData(Resources resources) async { components[1].trim().split(' ').map((s) => int.parse(s)).toList(); return AmbiguousEquation(result: result, operands: operands); - }).toList(); + }); } diff --git a/test/day7_test.dart b/test/day7_test.dart index 79d0949..8935381 100644 --- a/test/day7_test.dart +++ b/test/day7_test.dart @@ -1,5 +1,6 @@ import 'package:aoc_2024/lib.dart'; import 'package:aoc_2024/day7/part_1.dart' as part1; +import 'package:aoc_2024/day7/part_2.dart' as part2; import 'package:test/test.dart'; void main() { @@ -9,6 +10,10 @@ void main() { test('part1', () async { expect(await part1.calculate(resources), 3749); }); + + test('part2', () async { + expect(await part2.calculate(resources), 11387); + }); }); group('real data', tags: 'real-data', () { @@ -17,5 +22,9 @@ void main() { test('part1', () async { expect(await part1.calculate(resources), 4998764814652); }); + + test('part2', () async { + expect(await part2.calculate(resources), 37598910447546); + }); }); }