2025-12-08 11:30:50 -06:00
|
|
|
import "dart:convert";
|
|
|
|
|
import "dart:io";
|
|
|
|
|
|
|
|
|
|
import "package:args/command_runner.dart";
|
|
|
|
|
|
2025-12-09 14:27:01 -06:00
|
|
|
List getAdjacent(List<List<bool>> map, int idx, int idy) {
|
|
|
|
|
var adjacentValues = [];
|
|
|
|
|
for (int x in [-1, 0, 1]) {
|
|
|
|
|
for (int y in [-1, 0, 1]) {
|
|
|
|
|
if (x == 0 && y == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var xSlewed = idx + x;
|
|
|
|
|
var ySlewed = idy + y;
|
|
|
|
|
//print("$xSlewed, $ySlewed");
|
|
|
|
|
try {
|
|
|
|
|
//print(map[ySlewed][xSlewed]);
|
2025-12-09 15:09:42 -06:00
|
|
|
adjacentValues.add(map[ySlewed][xSlewed]);
|
2025-12-09 14:27:01 -06:00
|
|
|
} on RangeError {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return adjacentValues;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-09 15:09:42 -06:00
|
|
|
(int, List<List<bool>>) removeRolls(List<List<bool>> rollMap) {
|
|
|
|
|
int rollsRemoved = 0;
|
|
|
|
|
List<List<bool>> newRollMap = List.from(
|
|
|
|
|
rollMap.map((e) => List<bool>.from(e, growable: false)),
|
|
|
|
|
growable: false,
|
|
|
|
|
);
|
|
|
|
|
for (var (y, row) in rollMap.indexed) {
|
|
|
|
|
for (var (x, columnValue) in row.indexed) {
|
|
|
|
|
if (columnValue == true) {
|
|
|
|
|
var numAdjacent = getAdjacent(
|
|
|
|
|
rollMap,
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
).where((value) => value).length;
|
|
|
|
|
if (numAdjacent < 4) {
|
|
|
|
|
rollsRemoved++;
|
|
|
|
|
newRollMap[y][x] = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (rollsRemoved, newRollMap);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-08 11:30:50 -06:00
|
|
|
class Day4Command extends Command {
|
|
|
|
|
// The [name] and [description] properties must be defined by every
|
|
|
|
|
// subclass.
|
|
|
|
|
@override
|
|
|
|
|
final name = "day4";
|
|
|
|
|
|
|
|
|
|
@override
|
2025-12-09 15:18:20 -06:00
|
|
|
final description = "Run Advent of Code 2025 Day 4";
|
2025-12-08 11:30:50 -06:00
|
|
|
|
|
|
|
|
Day4Command() {
|
|
|
|
|
// we can add command specific arguments here.
|
|
|
|
|
// [argParser] is automatically created by the parent class.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// [run] may also return a Future.
|
|
|
|
|
@override
|
|
|
|
|
Future<void> run() async {
|
|
|
|
|
// [argResults] is set before [run()] is called and contains the flags/options
|
|
|
|
|
// passed to this command.
|
|
|
|
|
|
|
|
|
|
if (argResults!.rest.length != 1) {
|
|
|
|
|
print(
|
|
|
|
|
"Expected 1 positional arguments, found ${argResults!.rest.length}",
|
|
|
|
|
);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
var filePath = argResults!.rest[0];
|
|
|
|
|
|
|
|
|
|
print("Parsing file: $filePath");
|
2025-12-09 14:27:01 -06:00
|
|
|
var inputFile = File(filePath);
|
|
|
|
|
var paperRollMap = await inputFile
|
|
|
|
|
.openRead()
|
|
|
|
|
.transform(utf8.decoder)
|
|
|
|
|
.transform(LineSplitter())
|
|
|
|
|
.map((line) {
|
|
|
|
|
return line
|
|
|
|
|
.split('')
|
|
|
|
|
.map((ch) => (ch == "@") ? true : false)
|
|
|
|
|
.toList(growable: false);
|
|
|
|
|
})
|
|
|
|
|
.toList();
|
|
|
|
|
//print(paperRollMap);
|
|
|
|
|
//print(getAdjacent(paperRollMap, 0, 0));
|
|
|
|
|
|
2025-12-09 15:09:42 -06:00
|
|
|
int round = 1;
|
|
|
|
|
int totalRollsRemoved = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
int rollsRemoved;
|
|
|
|
|
(rollsRemoved, paperRollMap) = removeRolls(paperRollMap);
|
|
|
|
|
print("Rolls Removed During Round $round: $rollsRemoved");
|
|
|
|
|
if (rollsRemoved == 0) {
|
|
|
|
|
break;
|
2025-12-09 14:27:01 -06:00
|
|
|
}
|
2025-12-09 15:09:42 -06:00
|
|
|
totalRollsRemoved += rollsRemoved;
|
|
|
|
|
round++;
|
2025-12-09 14:27:01 -06:00
|
|
|
}
|
2025-12-09 15:09:42 -06:00
|
|
|
print("Total Rolls Removed: $totalRollsRemoved");
|
2025-12-08 11:30:50 -06:00
|
|
|
}
|
|
|
|
|
}
|