Last active
December 23, 2018 14:10
-
-
Save mikezs/cd17e9f647c64189d065050263d01a10 to your computer and use it in GitHub Desktop.
Advent Of Code 2018
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()}"); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}>"; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}"; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] == "#"; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = ">"; | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(" ")); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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