Skip to content

Instantly share code, notes, and snippets.

@mikezs
Last active December 23, 2018 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikezs/cd17e9f647c64189d065050263d01a10 to your computer and use it in GitHub Desktop.
Save mikezs/cd17e9f647c64189d065050263d01a10 to your computer and use it in GitHub Desktop.
Advent Of Code 2018
main() async {
int frequency = 0;
List<String> numberArray = input.split("\n");
for (int i = 0; i < numberArray.length; ++i) {
int number = int.parse(numberArray[i]);
frequency += number;
}
print("Frequency: $frequency");
}
main() async {
List<int> seen = [0];
int frequency = 0;
List<int> numberArray = input.split("\n").map((string) => int.parse(string)).toList();
for (int i = 0; i < numberArray.length; ++i) {
int current = numberArray[i];
frequency += current;
if (seen.contains(frequency)) {
print("Twice: $frequency");
break;
} else {
seen.add(frequency);
}
if (i == numberArray.length - 1) {
i = -1;
}
}
}
main() async {
print(part1(input));
print(part2(input));
}
String part2(String input) {
List<String> strings = input.split("\n");
for (int i = 0; i < strings.length; ++i) {
String current = strings[i];
for (int j = i + 1; j < strings.length; ++j) {
String compare = strings[j];
int difference = 0;
String word = "";
for (int k = 0; k < compare.length; ++k) {
List<String> currentLetters = current.split('');
List<String> compareLetters = compare.split('');
if (currentLetters[k] != compareLetters[k]) {
difference++;
} else {
word += currentLetters[k];
}
}
if (difference == 1) {
return word;
}
}
}
return "";
}
int part1(String input) {
int twoTimes = 0;
int threeTimes = 0;
List<String> ids = input.split("\n");
for (int i = 0; i < ids.length; ++i) {
String currentString = ids[i];
if (hasLetter(currentString, 2)) twoTimes++;
if (hasLetter(currentString, 3)) threeTimes++;
}
return twoTimes * threeTimes;
}
bool hasLetter(String input, int exactlyTimes) {
Map letterCounts = Map();
input.runes.forEach((rune) {
if (letterCounts[rune] == null) letterCounts[rune] = 1;
else letterCounts[rune]++;
});
return letterCounts.values.toList().contains(exactlyTimes);
}
main() async {
print(part1(input));
print(part2(input));
}
int part2(String input) {
List<List<int>> grid = generateGrid(input);
int id = 0;
input
.split("\n")
.map((string) => Claim.fromString(string))
.toList()
.forEach((claim) {
for (int i = claim.left; i < claim.left + claim.width; ++i) {
for (int j = claim.top; j < claim.top + claim.height; ++j) {
if (grid[i][j] != 1) {
return;
}
}
}
id = claim.id;
});
return id;
}
class Claim {
int id;
int left;
int top;
int width;
int height;
static Claim fromString(String input) {
Claim c = Claim();
List<String> parts = input.split(" ");
c.id = int.parse(parts[0].substring(1));
List<String> position = parts[2].split(",");
c.left = int.parse(position[0]);
c.top = int.parse(position[1].replaceAll(":", ""));
List<String> size = parts[3].split("x");
c.width = int.parse(size[0]);
c.height = int.parse(size[1]);
return c;
}
}
List<List<int>> generateGrid(String input) {
List<List<int>> grid = List<List<int>>();
for (int i = 0; i < 1000; ++i) {
grid.add(List<int>());
for (int j = 0; j < 1000; ++j) {
grid[i].add(0);
}
}
input
.split("\n")
.map((string) => Claim.fromString(string))
.toList()
.forEach((claim) {
for (int i = claim.left; i < claim.left + claim.width; ++i) {
for (int j = claim.top; j < claim.top + claim.height; ++j) {
grid[i][j]++;
}
}
});
return grid;
}
int part1(String input) {
List<List<int>> grid = generateGrid(input);
int overlapping = 0;
for (int i = 0; i < 1000; ++i) {
for (int j = 0; j < 1000; ++j) {
if (grid[i][j] >= 2) {
overlapping++;
}
}
}
return overlapping;
}
main() async {
List<Entry> entries = input.split("\n").map((entry) {
List<String> parts = entry.split("]");
Entry e = Entry();
String dateTime = parts[0].replaceFirst("[", "");
e.date = DateTime.parse("${dateTime}:00");
e.description = parts[1].substring(1);
return e;
}).toList();
entries.sort((a,b) => a.date.compareTo(b.date));
// entries.forEach((entry) => print("${entry.date} ${entry.description}"));
Map guards = Map();
int gid;
int sleepMinute = 0;
entries.forEach((entry) {
if (entry.sleep()) {
sleepMinute = entry.min();
} else if (entry.wake()) {
int wakeMinute = entry.min();
(guards["$gid"] as Guard).totalAsleep += wakeMinute - sleepMinute;
for (int i = sleepMinute; i < wakeMinute; ++i) {
(guards["$gid"] as Guard).minutesAsleepList[i] += 1;
}
} else {
gid = entry.id();
if (guards["$gid"] == null) {
guards["$gid"] = Guard(id: gid);
}
}
});
List<Guard> sortedGuards = guards.values.map((value) => value as Guard).toList();
sortedGuards.sort((a, b) => a.totalAsleep.compareTo(b.totalAsleep));
// sortedGuards.forEach((g) {
// print("${g.id} -> ${g.totalAsleep}");
// print(g.minutesAsleepList);
// });
Guard highestGuard = sortedGuards.first;
sortedGuards.forEach((guard) {
int current = guard.minutesAsleepList[guard.mostFrequentMinIndex()];
int highest = highestGuard.minutesAsleepList[highestGuard.mostFrequentMinIndex()];
if (current > highest) {
highestGuard = guard;
}
});
int part1 = sortedGuards.last.mostFrequentMinIndex() * sortedGuards.last.id;
print("Part 1: $part1");
int part2 = highestGuard.mostFrequentMinIndex() * highestGuard.id;
print("Part 2: $part2");
}
class Guard {
int id;
List<int> minutesAsleepList;
int totalAsleep;
Guard({
this.id
}) {
this.minutesAsleepList = List<int>(60);
for(int i = 0; i < 60; ++i) {
this.minutesAsleepList[i] = 0;
}
this.totalAsleep = 0;
}
int mostFrequentMinIndex() {
int highestIndex = 0;
int highestValue = 0;
for (int i = 0; i < 60; i++) {
if (this.minutesAsleepList[i] > highestValue) {
highestIndex = i;
highestValue = this.minutesAsleepList[i];
}
}
return highestIndex;
}
}
class Entry {
DateTime date;
String description;
int min() {
return this.date.minute;
}
bool wake() {
return this.description == "wakes up";
}
bool sleep() {
return this.description == "falls asleep";
}
int id() {
return int.parse(this.description.split("#")[1].split(" ")[0]);
}
}
main() async {
List<String> letters = input.split('').toList();
int part1 = reacted(letters).length;
print("Part 1: $part1");
int length = letters.length;
for (int c = 97; c < 97+26; c++) {
List<String> letters = input.split('');
int i = 0;
while (i < letters.length) {
if (letters[i].toLowerCase() == String.fromCharCode(c)) {
letters.removeAt(i);
} else {
++i;
}
}
int len = reacted(letters).length;
if (len < length) {
length = len;
}
}
print("Part 2: $length");
}
List<String> reacted(List<String> letters) {
int index = 0;
while (index < letters.length - 1) {
if (letters[index] != letters[index+1] &&
letters[index].toLowerCase() == letters[index+1].toLowerCase()) {
letters.removeAt(index+1);
letters.removeAt(index);
if (index != 0) --index;
} else {
++index;
}
}
return letters;
}
main() async {
part1();
part2();
}
void part2() {
List<String> coords = input.split('\n');
int maxX = 0;
int maxY = 0;
coords.forEach((coord) {
List<int> parts = coord.split(", ").map((number) => int.parse(number)).toList();
if (parts[0] > maxX) maxX = parts[0];
if (parts[1] > maxY) maxY = parts[1];
});
List<List<int>> grid = List<List<int>>(maxX);
for(int i = 0; i < maxX; ++i) {
grid[i] = List<int>(maxY);
for(int j = 0; j < maxY; ++j) {
for (int k = 0; k < coords.length; ++k) {
String coord = coords[k];
List<int> parts = coord.split(", ").map((number) => int.parse(number)).toList();
int taxiDist = taxiDistance(i, j, parts[0], parts[1]);
if (grid[i][j] == null) grid[i][j] = 0;
grid[i][j] += taxiDist;
}
}
}
int total = 0;
for(int i = 0; i < maxX; ++i) {
for(int j = 0; j < maxY; ++j) {
int currentCount = grid[i][j];
if (currentCount <= 10000) ++total;
}
}
print(total);
}
void part1() {
List<String> coords = input.split('\n');
int maxX = 0;
int maxY = 0;
coords.forEach((coord) {
List<int> parts = coord.split(", ").map((number) => int.parse(number)).toList();
if (parts[0] > maxX) maxX = parts[0];
if (parts[1] > maxY) maxY = parts[1];
});
List<List<int>> grid = List<List<int>>(maxX);
for(int i = 0; i < maxX; ++i) {
grid[i] = List<int>(maxY);
for(int j = 0; j < maxY; ++j) {
int closestIndex = -1;
int closestValue = maxX+maxY;
// Calculate distance to each coord
for (int k = 0; k < coords.length; ++k) {
String coord = coords[k];
List<int> parts = coord.split(", ").map((number) => int.parse(number)).toList();
int taxiDist = taxiDistance(i, j, parts[0], parts[1]);
// If it's equal to 2, set to -1
if (taxiDist == closestValue) {
closestIndex = -1;
} else if (taxiDist < closestValue) {
closestValue = taxiDist;
closestIndex = k;
}
}
grid[i][j] = closestIndex;
}
}
//print(grid);
// Anything on the first or last x or y is infinite
List<int> infiniteNumbers = List<int>();
Map<int, int> counts = Map<int, int>();
for(int i = 0; i < maxX; ++i) {
for(int j = 0; j < maxY; ++j) {
if (i == 0 || j == 0 || i == maxX - 1 || j == maxY - 1) {
int infiniteIndex = grid[i][j];
if (!infiniteNumbers.contains(infiniteIndex)) {
infiniteNumbers.add(infiniteIndex);
}
}
int currentIndex = grid[i][j];
if (counts[currentIndex] == null) counts[currentIndex] = 0;
++counts[currentIndex];
}
}
print(counts);
infiniteNumbers.forEach((infinite) => counts.remove(infinite));
print(infiniteNumbers);
List<int> indexes = counts.keys.toList();
indexes.sort((a, b) => counts[a].compareTo(counts[b]));
int largest = counts[indexes.last];
print("Part 1: $largest");
}
int taxiDistance(int sx, int sy, int dx, int dy) {
return (sx - dx).abs() + (sy - dy).abs();
}
main() async {
part1();
part2();
}
void part2() {
List<String> steps = input.split("\n");
List<String> letters = List<String>();
Map<String, List<String>> map = Map<String, List<String>>();
steps.forEach((step) {
List<String> parts = step.split(" ");
String first = parts[1];
String second = parts[7];
if (map[first] == null) map[first] = List<String>();
map[first].add(second);
if (!letters.contains(first)) letters.add(first);
if (!letters.contains(second)) letters.add(second);
});
List<String> order = List<String>();
int time = 0;
int numWorkers = 5;
List<Worker> workers = List<Worker>();
for(int i = 0; i < numWorkers; ++i) {
workers.add(Worker());
}
bool finished = false;
while (!finished) {
// Check if there's any available workers
// If yes, assign them a letter if ones available
// Tick time and check if anyone finished, add that letter to the order, make them available
List<Worker> availableWorkers = workers.where((worker) => worker.available()).toList();
List<String> lettersAvailable = List<String>();
letters.forEach((letter) {
bool depended = false;
//print("Checking $letter");
map.values.forEach((list) {
if (!depended &&
(list.contains(letter) ||
workers.where((w) => w.letter == letter).length > 0))
depended = true;
});
// Success this letter is available
if (!depended) lettersAvailable.add(letter);
});
//print(lettersAvailable);
// If there's an available worker and available letters
while (availableWorkers.length > 0 && lettersAvailable.length > 0) {
lettersAvailable.sort();
availableWorkers[0].setNewLetter(lettersAvailable[0]);
letters.remove(lettersAvailable[0]);
lettersAvailable.removeAt(0);
availableWorkers = workers.where((worker) => worker.available()).toList();
}
bool workerFinished = false;
workers.forEach((worker) {
String result = worker.tick();
if (result != null) {
order.add(result);
map.remove(result);
letters.remove(result);
workerFinished = true;
}
});
// If every worker is available we're finished
if (workers.where((w) => w.available()).toList().length == numWorkers &&
!workerFinished)
finished = true;
else
++time;
}
print("Order: ${order.join()}");
print("Time (Part 2): $time");
//print(lettersAvailable);
}
class Worker {
String letter;
int remaining;
Worker() {
this.remaining = 0;
}
bool available() {
return this.remaining == 0;
}
void setNewLetter(String letter) {
this.remaining = letter.codeUnitAt(0) - 4;
this.letter = letter;
}
String tick() {
if (!this.available()) {
--this.remaining;
if (this.available()) {
String value = this.letter;
this.letter = null;
return value;
}
}
return null;
}
}
void part1() {
List<String> steps = input.split("\n");
List<String> letters = List<String>();
Map<String, List<String>> map = Map<String, List<String>>();
steps.forEach((step) {
List<String> parts = step.split(" ");
String first = parts[1];
String second = parts[7];
if (map[first] == null) map[first] = List<String>();
map[first].add(second);
if (!letters.contains(first)) letters.add(first);
if (!letters.contains(second)) letters.add(second);
});
//print(map);
List<String> currentlyAvailable = List<String>();
List<String> order = List<String>();
// Find letters that aren't depended on
while (map.length > 0) {
letters.forEach((letter) {
bool depended = false;
map.values.forEach((list) {
if (!depended && list.contains(letter)) depended = true;
});
// Success this letter is available
if (!depended) currentlyAvailable.add(letter);
});
currentlyAvailable.sort();
String currentLetter = currentlyAvailable[0];
order.add(currentLetter);
List<String> newCurrentlyAvailable = List<String>();
map[currentLetter].forEach((newLetter) {
if (!newCurrentlyAvailable.contains(newLetter)) newCurrentlyAvailable.add(newLetter);
});
newCurrentlyAvailable.addAll(map[currentLetter]);
map.remove(currentLetter);
letters.remove(currentLetter);
currentlyAvailable = newCurrentlyAvailable;
newCurrentlyAvailable.clear();
}
letters.sort();
order.addAll(letters);
print("Order (Part 1): ${order.join()}");
}
main() async {
Node head = buildTree(input.split(" ").map((value) => int.parse(value)).toList());
part1(head);
part2(head);
}
void part2(Node head) {
print(head.value());
}
void part1(Node head) {
print(head.metaTotal());
}
class Node {
List<Node> children;
List<int> metadata;
Node parent;
Node({
this.children,
this.metadata,
this.parent
});
int metaTotal() {
int total = 0;
this.children.forEach((c) => total += c.metaTotal());
this.metadata.forEach((m) => total += m);
return total;
}
int value() {
if (this.children.length == 0) {
return this.metaTotal();
} else {
int total = 0;
for (int i = 0; i < this.metadata.length; ++i) {
int index = this.metadata[i] - 1;
if (index >= 0 && this.children.length > index) {
total += this.children[index].value();
}
}
return total;
}
}
}
class ProcessResult {
int offset;
List<Node> children;
ProcessResult({this.offset, this.children});
}
Node buildTree(List<int> values) {
return processValues(0, 1, values, null).children[0];
}
ProcessResult processValues(int offset, int children, List<int> values, Node parent) {
// Return early if we're expecting no children, at the same offset
if (children == 0) {
ProcessResult result = ProcessResult();
result.offset = offset;
result.children = List<Node>();
return result;
}
List<Node> childrenResult = List<Node>();
int currentOffset = offset;
// If we're expecting children, loop until we've got the correct number
for (int i = 0; i < children; ++i) {
int numChildren = values[currentOffset];
int numMeta = values[currentOffset+1];
Node node = Node();
ProcessResult result = processValues(currentOffset+2, numChildren, values, node);
node.children = result.children;
node.metadata = List<int>();
for(int j = 0; j < numMeta; ++j) {
node.metadata.add(values[result.offset+j]);
}
childrenResult.add(node);
currentOffset = result.offset+numMeta;
}
return ProcessResult(offset: currentOffset, children: childrenResult);
}
class LoopListItem {
int value;
LoopListItem next;
LoopListItem prev;
LoopListItem({this.value});
String itemValue(bool current) {
if (current) return "(${this.value})";
return "${this.value}";
}
}
class LoopList {
LoopListItem firstMarble;
LoopListItem currentMarble;
int play(int marble) {
LoopListItem newItem = LoopListItem(value: marble);
if (currentMarble == null) {
newItem.next = newItem;
newItem.prev = newItem;
this.currentMarble = newItem;
this.firstMarble = newItem;
return 0;
}
if (marble % 23 == 0) {
for (int i = 0; i < 7; ++i) {
this.currentMarble = currentMarble.prev;
}
LoopListItem remove = this.currentMarble;
LoopListItem beforeRemove = remove.prev;
LoopListItem afterRemove = remove.next;
beforeRemove.next = afterRemove;
afterRemove.prev = beforeRemove;
this.currentMarble = afterRemove;
return marble + remove.value;
} else {
LoopListItem insertAfter = this.currentMarble.next;
LoopListItem insertBefore = insertAfter.next;
newItem.prev = insertAfter;
newItem.next = insertBefore;
insertBefore.prev = newItem;
insertAfter.next = newItem;
this.currentMarble = newItem;
}
return 0;
}
void printList(int player) {
List<String> list = List<String>();
LoopListItem current = this.firstMarble;
do {
list.add(current.itemValue(current == this.currentMarble));
current = current.next;
}
while (current != this.firstMarble);
print("[$player] ${list.join(" ")}");
}
}
int game(int players, int lastMarble, {bool printGame = false}) {
LoopList game = LoopList();
int currentPlayer = 1;
Map<int, int> scores = Map<int, int>();
for (int i = 1; i <= players; ++i) {
scores[i] = 0;
}
// 0 is added at the start
game.play(0);
for (int i = 1; i <= lastMarble; ++i) {
scores[currentPlayer] += game.play(i);
if (printGame) game.printList(currentPlayer);
if (currentPlayer == players) currentPlayer = 1;
else ++currentPlayer;
}
var sortedScores = scores.values.toList()..sort();
return sortedScores.last;
}
void main() {
List<Point> points = input.split("\n").map((line) {
List<String> parts = line.split("> velocity=<");
List<int> position = parts[0].split("position=<")[1].split(",").map((i) => int.parse(i)).toList();
List<int> velocity = parts[1].split(">")[0].split(",").map((i) => int.parse(i)).toList();
return Point(Vector(position[0], position[1]), Vector(velocity[0], velocity[1]));
}).toList();
int xDistance;
int yDistance;
int minX;
int minY;
int maxX;
int maxY;
int time = 0;
List<Vector> timeVector;
do {
++time;
timeVector = pointsAt(time, points);
minX = null;
minY = null;
maxX = null;
maxY = null;
timeVector.forEach((pos) {
if (minX == null || pos.x < minX) minX = pos.x;
if (maxX == null || pos.x > maxX) maxX = pos.x;
if (minY == null || pos.y < minY) minY = pos.y;
if (maxY == null || pos.y > maxY) maxY = pos.y;
});
xDistance = maxX - minX;
yDistance = maxY - minY;
} while (yDistance > 18);
for (int y = 0; y <= yDistance; ++y) {
String line = "";
for (int x = 0; x <= xDistance; ++x) {
bool match = false;
timeVector.forEach((v) {
if (v.x - minX == x && v.y - minY == y) {
match = true;
}
});
if (match) line = "$line#";
else line = "$line.";
}
print(line);
}
print("$time = x $xDistance y: $yDistance ($minX, $minY)x($maxX, $maxY)");
}
List<Vector> pointsAt(int time, List<Point> points) {
return points.map((p) => p.positionAt(time)).toList();
}
class Vector {
int x;
int y;
Vector(int x, int y) {
this.x = x;
this.y = y;
}
Vector copy() {
return Vector(this.x, this.y);
}
}
class Point {
Vector position;
Vector velocity;
Point(Vector position, Vector velocity) {
this.position = position;
this.velocity = velocity;
}
Vector positionAt(int time) {
return Vector(this.position.x + (this.velocity.x * time), this.position.y + (this.velocity.y * time));
}
String toString() {
return "position=<${position.x}, ${position.y}> velocity=<${velocity.x}, ${velocity.y}>";
}
}
void main() {
// print(Cell(3, 5, 8).powerLevel); // 4
// print(Cell(122, 79, 57).powerLevel); // -5
// print(Cell(217, 196, 39).powerLevel); // 0
// print(Cell(101, 153, 71).powerLevel); // 4
// print(largestCell(18, 3)); //33,45@29
// print(largestCell(42, 3)); //21,61@30
// print(largestSquare(18));
// print(largestSquare(42));
}
Square largestSquare(int serial) {
Square largest;
List<List<Cell>> grid = generateGrid(serial);
for (int i = 1; i < 300; ++i) {
for (int y = 0; y < 300 - i - 1; ++y) {
for (int x = 0; x < 300 - i - 1; ++x) {
int total = 0;
for (int dy = 0; dy < i; ++dy) {
for (int dx = 0; dx < i; ++dx) {
total += grid[y+dy][x+dx].powerLevel;
}
}
if (largest == null || total > largest.power)
largest = Square(grid[y][x], i, total);
}
}
}
return largest;
}
Cell largestCell(int serial, int gridSize) {
List<List<Cell>> grid = generateGrid(serial, gridSize: gridSize, precalculate: true);
Cell largestCell;
Cell cell;
for (int y = 0; y < 300 - gridSize - 1; ++y) {
for (int x = 0; x < 300 - gridSize - 1; ++x) {
cell = grid[y][x];
if (largestCell == null || cell.gridLevel > largestCell.gridLevel)
largestCell = cell;
}
}
return largestCell;
}
List<List<Cell>> generateGrid(int serial, {int gridSize = 3, bool precalculate = false}) {
List<List<Cell>> grid = List<List<Cell>>();
for (int y = 0; y < 300; ++y) {
grid.add(List<Cell>());
for (int x = 0; x < 300; ++x) {
Cell newCell = Cell(x+1, y+1, serial);
grid[y].add(newCell);
if (precalculate) {
int xIndex, yIndex;
for (int ny = 0; ny < gridSize; ++ny) {
for (int nx = 0; nx < gridSize; ++nx) {
xIndex = x - nx;
yIndex = y - ny;
if (xIndex >= 0 && yIndex >= 0)
grid[yIndex][xIndex].gridLevel += newCell.powerLevel;
}
}
}
}
}
return grid;
}
class Square {
Cell cell;
int size;
int power;
Square(Cell cell, int size, int power) {
this.cell = cell;
this.size = size;
this.power = power;
}
String toString() {
return "${this.cell.x},${this.cell.y},${this.size} [${this.power}]";
}
}
class Cell {
int x;
int y;
int powerLevel;
int gridLevel;
Map<int, int> powerLevels;
int _serial;
int _rackID;
Cell(int x, int y, int serial) {
this.x = x;
this.y = y;
this._serial = serial;
this._rackID = x + 10;
this.powerLevel = this._calculatePowerLevel();
this.gridLevel = 0;
this.powerLevels = Map<int, int>();
}
int _calculatePowerLevel() {
int powerLevel = this._rackID * this.y;
powerLevel += this._serial;
powerLevel *= this._rackID;
powerLevel %= 1000;
powerLevel ~/= 100;
powerLevel -= 5;
return powerLevel;
}
String toString() {
return "${this.x},${this.y}@${this.gridLevel}";
}
}
void main() {
Stopwatch stopwatch = Stopwatch()..start();
List<Rule> rules = List<Rule>();
input.split("\n").forEach((r) {
Rule rule = Rule(r);
if (rule.alive) rules.add(rule);
});
Map<int, bool> plants = Map<int, bool>();
int i = 0;
initial.split("").forEach((p) {
plants[i++] = p == "#";
});
paddedPots(plants);
//printPlants(plants, 0);
for (int i = 1; i <= 150; ++i) {
nextGeneration(plants, rules);
printPlants(plants, i);
}
Map<int, bool> finalGeneration = Map<int, bool>();
plants.forEach((k, v) => finalGeneration[k+(50000000000-150)] = v);
int total = 0;
finalGeneration.forEach((index, occupied) {
if (occupied) total += index;
});
print(total);
print('executed in ${stopwatch.elapsed}');
}
void nextGeneration(Map<int, bool> current, List<Rule> rules) {
Map<int, bool> nextGeneration = Map<int, bool>();
current.forEach((index, value) {
Rule rule = rules.firstWhere((r) {
int matches = 0;
r.test.forEach((i, t) {
if (current[index + i] != null && current[index + i] == t)
++matches;
});
return matches == 5;
}, orElse: () {
return null;
});
if (rule != null) {
nextGeneration[index] = rule.alive;
}
});
current.forEach((k, v) {
if (nextGeneration[k] != null) current[k] = nextGeneration[k];
else current[k] = false;
});
//nextGeneration.forEach((k, v) => current[k] = v);
paddedPots(current);
//return nextGeneration;
}
void paddedPots(Map<int, bool> plants) {
for (int i = 0; i < 5; ++i) {
if (needsPadding(plants, start: true)) {
List<int> keys = plants.keys.toList()..sort();
plants[keys.first - 1] = false;
} else {
break;
}
}
for (int i = 0; i < 5; ++i) {
if (needsPadding(plants, start: false)) {
List<int> keys = plants.keys.toList()..sort((a, b) => b.compareTo(a));
plants[keys.first + 1] = false;
} else {
break;
}
}
if (overPadded(plants, start: true)) {
List<int> keys = plants.keys.toList()..sort();
plants.remove(keys.first);
}
if (overPadded(plants, start: false)) {
List<int> keys = plants.keys.toList()..sort((a, b) => b.compareTo(a));
plants.remove(keys.first);
}
}
bool needsPadding(Map<int, bool> plants, {bool start}) {
List<int> keys = plants.keys.toList()..sort((a, b) => start ? a.compareTo(b) : b.compareTo(a));
for (int i = 0; i < 5; ++i) {
if (plants[keys[i]] == true) return true;
}
return false;
}
bool overPadded(Map<int, bool> plants, {bool start}) {
List<int> keys = plants.keys.toList()..sort((a, b) => start ? a.compareTo(b) : b.compareTo(a));
for (int i = 0; i < 6; ++i) {
if (plants[keys[i]] == true) return false;
}
return true;
}
void printPlants(Map<int, bool> plants, int generation) {
List<int> keys = plants.keys.toList();
keys.sort();
String output = "";
keys.forEach((k) => output += plants[k] ? "#" : ".");
print("$generation: $output");
}
class Rule {
Map<int, bool> test;
bool alive;
String line;
Rule(String line) {
this.line = line;
List<String> parts = line.split(" => ");
int i = -2;
this.test = Map<int, bool>();
parts[0].split("").forEach((l) {
this.test[i++] = l == "#";
});
this.alive = parts[1] == "#";
}
}
void main() {
part1();
part2();
}
void part2() {
Stopwatch timer = Stopwatch()..start();
List<List<String>> track = parseTrack(input);
//List<List<String>> track = parseTrack(testInput2);
List<Car> cars = findCars(track);
print("there are ${cars.length} cars");
//printState(track, cars, null);
List<Car> collision;
for (int i = 0; i < 100000; ++i) {
collision = tick(track, cars);
if (collision != null) {
collision.forEach((c) => cars.remove(c));
//print(collision);
}
//printState(track, cars, null);
if (cars.length <= 1) {
print(cars.toList()[0]);
break;
}
}
print(timer.elapsed);
}
void part1() {
Stopwatch timer = Stopwatch()..start();
List<List<String>> track = parseTrack(input);
//List<List<String>> track = parseTrack(testInput);
List<Car> cars = findCars(track);
//printState(track, cars, null);
List<Car> collision;
for (int i = 0; i < 10000; ++i) {
collision = tick(track, cars);
//printState(track, cars, collision);
if (collision != null) {
print("Collision at ${collision[0]} [$i iterations]");
break;
}
}
print(timer.elapsed);
}
List<Car> tick(List<List<String>> track, List<Car> cars) {
List<Car> collision;
cars.sort((a, b) {
if (a.y != b.y)
return a.y.compareTo(b.y);
return a.x.compareTo(b.x);
});
for (int i = 0; i < cars.length; ++i) {
Car c = cars[i];
// Change direction or move
if (c.direction == ">") {
String nextPos = track[c.y][c.x+1];
if (nextPos == "\\") {
c.direction = "v";
} else if (nextPos == "/") {
c.direction = "^";
} else if (nextPos == "+") {
c.nextDirection();
}
c.x += 1;
} else if (c.direction == "<") {
String nextPos = track[c.y][c.x-1];
if (nextPos == "\\") {
c.direction = "^";
} else if (nextPos == "/") {
c.direction = "v";
} else if (nextPos == "+") {
c.nextDirection();
}
c.x -= 1;
} else if (c.direction == "v") {
String nextPos = track[c.y+1][c.x];
if (nextPos == "\\") {
c.direction = ">";
} else if (nextPos == "/") {
c.direction = "<";
} else if (nextPos == "+") {
c.nextDirection();
}
c.y += 1;
} else if (c.direction == "^") {
String nextPos = track[c.y-1][c.x];
if (nextPos == "\\") {
c.direction = "<";
} else if (nextPos == "/") {
c.direction = ">";
} else if (nextPos == "+") {
c.nextDirection();
}
c.y -= 1;
}
cars.forEach((c) => cars.forEach((t) {
if (c != t && c.x == t.x && c.y == t.y) {
//print("collision at $c");
if (collision == null) {
collision = [c, t];
} else {
if (!collision.contains(c)) {
collision.addAll([c, t]);
}
}
//print(collision);
}
}));
}
if (collision != null)
return collision;
return null;
}
void printState(List<List<String>> track, List<Car> cars, List<Car> collision) {
for (int y = 0; y < track.length; ++y) {
String line = "";
for (int x = 0; x < track[y].length; ++x) {
bool replaced = false;
if (collision != null && collision[0].x == x && collision[0].y == y) {
line += "X";
replaced = true;
}
if (!replaced)
cars.forEach((c) {
if (c.x == x && c.y == y){
line += c.direction;
replaced = true;
}
});
if (!replaced) line += track[y][x];
}
print(line);
}
}
List<Car> findCars(List<List<String>> track) {
List<Car> cars = List<Car>();
for (int y = 0; y < track.length; ++y) {
for (int x = 0; x < track[y].length; ++x) {
String direction = track[y][x];
if (direction == "<" ||
direction == "^" ||
direction == ">" ||
direction == "v") {
// Repair the track (remove the car)
if (direction == ">" || direction == "<") {
track[y][x] = "-";
} else if (direction == "v" || direction == "^") {
track[y][x] = "|";
}
// Add our car
cars.add(Car(x, y, direction));
}
}
}
return cars;
}
List<List<String>> parseTrack(String trackInput) {
List<List<String>> track = List<List<String>>();
trackInput.split("\n").forEach((line) {
track.add(line.split(""));
});
return track;
}
class Car {
int x;
int y;
String direction;
int currentDirection = 2;
Car(int x, int y, String direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
String toString() {
return "${this.x},${this.y}";
}
void nextDirection() {
if (this.currentDirection == 2)
this.currentDirection = 0;
else
++this.currentDirection;
if (this.direction == ">") {
if (this.currentDirection == 0) {
this.direction = "^";
} else if (this.currentDirection == 2) {
this.direction = "v";
}
} else if (this.direction == "<") {
if (this.currentDirection == 0) {
this.direction = "v";
} else if (this.currentDirection == 2) {
this.direction = "^";
}
} else if (this.direction == "v") {
if (this.currentDirection == 0) {
this.direction = ">";
} else if (this.currentDirection == 2) {
this.direction = "<";
}
} else if (this.direction == "^") {
if (this.currentDirection == 0) {
this.direction = "<";
} else if (this.currentDirection == 2) {
this.direction = ">";
}
}
}
}
void part2(String input) {
Stopwatch timer = Stopwatch()..start();
List<int> elves = [0, 1];
List<int> recipes = List<int>();
recipes.addAll([3, 7]);
int index = -1;
for (int i = 0; i < 100000000 && index == -1; ++i) {
recipes.addAll(sumOfElves(recipes, elves));
moveElves(recipes, elves);
if (i % 1000000 == 0) {
index = recipes.join("").indexOf(input);
}
}
//print(recipes.join(""));
print(index);
print(timer.elapsed);
}
void part1(int input) {
Stopwatch timer = Stopwatch()..start();
List<int> elves = [0, 1];
List<int> recipes = List<int>();
recipes.addAll([3, 7]);
//printRecipes(recipes, elves);
while (recipes.length < input + 10) {
recipes.addAll(sumOfElves(recipes, elves));
moveElves(recipes, elves);
//printRecipes(recipes, elves);
}
print(recipes.sublist(input, input + 10).join(""));
print(timer.elapsed);
}
void moveElves(List<int> recipes, List<int> elves) {
for (int i = 0; i < elves.length; ++i) {
int moves = recipes[elves[i]] + 1;
elves[i] = (elves[i] + moves) % recipes.length;
}
}
List<int> sumOfElves(List<int> recipes, List<int> elves) {
int total = 0;
for (int e = 0; e < elves.length; ++e) {
total += recipes[elves[e]];
}
return "$total".split("").map((s) => int.parse(s)).toList();
}
void printRecipes(List<int> recipes, List<int> elves) {
List<String> result = List<String>();
bool added;
for (int i = 0; i < recipes.length; ++i) {
added = false;
for (int e = 0; e < elves.length; ++e) {
if (elves[e] == i) {
if (e == 0) result.add("(${recipes[i]})");
else if (e == 1) result.add("[${recipes[i]}]");
added = true;
}
}
if (!added) result.add("${recipes[i]}");
}
print(result.join(" "));
}
void main() {
part1();
//part2();
}
class Player {
int x;
int y;
int hp = 200;
Player(int x, int y) {
this.x = x;
this.y = y;
}
}
class Elf extends Player {
Elf(int x, int y) : super(x, y);
}
class Goblin extends Player {
Goblin(int x, int y) : super(x, y);
}
void part1() {
Stopwatch timer = Stopwatch()..start();
List<List<bool>> grid = List<List<bool>>();
List<Player> players = List<Player>();
List<String> inputList = testInput.split("\n");
for (int y = 0; y < inputList.length; ++y) {
List<bool> row = List<bool>();
grid.add(row);
List<String> line = inputList[y].split("");
for (int x = 0; x < line.length; ++x) {
String char = line[x];
if (char == "#") row.add(true);
else row.add(false);
if (char == "G") players.add(Elf(x, y));
if (char == "E") players.add(Goblin(x, y));
}
}
print(timer.elapsed);
}
void round(List<List<bool>> grid, List<Player> players) {
players.sort((a, b) => a.y == b.y ? a.x.compareTo(b.x) : a.y.compareTo(b.y));
players.forEach((p) {
});
}
void part2(String input) {
Stopwatch timer = Stopwatch()..start();
print(timer.elapsed);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment