Compare commits
6 Commits
efa81418eb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9cc95c447 | ||
|
|
8b7da0b751 | ||
|
|
bbaedda944 | ||
|
|
7fed659932 | ||
|
|
d8a62d2eb4 | ||
|
|
8dda1b5ee2 |
96
day11.chpl
Normal file
96
day11.chpl
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
use IO, List;
|
||||||
|
|
||||||
|
var modulus = 1;
|
||||||
|
|
||||||
|
record DivByThree {
|
||||||
|
var underlying: int;
|
||||||
|
operator +(lhs: DivByThree, rhs: DivByThree) {
|
||||||
|
return new DivByThree((lhs.underlying + rhs.underlying) / 3);
|
||||||
|
}
|
||||||
|
operator *(lhs: DivByThree, rhs: DivByThree) {
|
||||||
|
return new DivByThree((lhs.underlying * rhs.underlying) / 3);
|
||||||
|
}
|
||||||
|
proc divBy(x: int) return underlying % x == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
record Modulo {
|
||||||
|
var underlying: int;
|
||||||
|
|
||||||
|
operator +(lhs: Modulo, rhs: Modulo) {
|
||||||
|
return new Modulo((lhs.underlying + rhs.underlying) % modulus);
|
||||||
|
}
|
||||||
|
operator *(lhs: Modulo, rhs: Modulo) {
|
||||||
|
return new Modulo((lhs.underlying * rhs.underlying) % modulus);
|
||||||
|
}
|
||||||
|
proc divBy(x: int) return underlying % x == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
config type numtype = DivByThree;
|
||||||
|
config const steps = 20;
|
||||||
|
|
||||||
|
class Op {
|
||||||
|
proc apply(x: ?t) return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SquareOp : Op {
|
||||||
|
override proc apply(x) return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddOp : Op {
|
||||||
|
var toAdd;
|
||||||
|
override proc apply(x) return x + toAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MulOp : Op {
|
||||||
|
var toMul;
|
||||||
|
override proc apply(x) return x * toMul;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc parse(op: string): owned Op {
|
||||||
|
if op == "old * old" then return new SquareOp();
|
||||||
|
if op.startsWith("old + ") then return new AddOp(new numtype(op[6..] : int));
|
||||||
|
return new MulOp(new numtype(op[6..] : int));
|
||||||
|
}
|
||||||
|
|
||||||
|
record Monkey {
|
||||||
|
var op : owned Op;
|
||||||
|
var divBy, ifTrue, ifFalse : int;
|
||||||
|
var items: list(numtype);
|
||||||
|
var count: int = 0;
|
||||||
|
|
||||||
|
iter tossItems() {
|
||||||
|
while !items.isEmpty() {
|
||||||
|
var item = items.pop(0);
|
||||||
|
var changed = op.apply(item);
|
||||||
|
var nextIdx = if changed.divBy(divBy) then ifTrue else ifFalse;
|
||||||
|
count += 1;
|
||||||
|
yield (changed, nextIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var monkeys = new list(Monkey);
|
||||||
|
var line: string;
|
||||||
|
while readLine(line) {
|
||||||
|
proc toNum(x: string) return new numtype(x : int);
|
||||||
|
readLine(line, stripNewline=true);
|
||||||
|
var items = new list(toNum(line[" Starting items: ".size..].split(", ")));
|
||||||
|
readLine(line, stripNewline=true);
|
||||||
|
var op = parse(line[" Operation: new = ".size..]);
|
||||||
|
var divBy, ifTrue, ifFalse: int;
|
||||||
|
readf(" Test: divisible by %i\n", divBy);
|
||||||
|
readf(" If true: throw to monkey %i\n", ifTrue);
|
||||||
|
readf(" If false: throw to monkey %i\n", ifFalse);
|
||||||
|
monkeys.append(new Monkey(op, divBy, ifTrue, ifFalse, items));
|
||||||
|
modulus *= divBy;
|
||||||
|
if (!readln()) then break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for 1..steps {
|
||||||
|
for monkey in monkeys {
|
||||||
|
for (item, nextIdx) in monkey.tossItems() {
|
||||||
|
monkeys[nextIdx].items.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln(monkeys.these().count);
|
||||||
58
day11.cr
Normal file
58
day11.cr
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
require "advent"
|
||||||
|
require "big"
|
||||||
|
|
||||||
|
class Monkey
|
||||||
|
property items : Array(Int64)
|
||||||
|
property op : String
|
||||||
|
property divBy : Int64
|
||||||
|
property ifTrue : Int64
|
||||||
|
property ifFalse : Int64
|
||||||
|
|
||||||
|
def initialize(@items, @op, @divBy, @ifTrue, @ifFalse)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
INSTS = {
|
||||||
|
"*" => ->(x: Int64, y: Int64) { x * y },
|
||||||
|
"+" => ->(x: Int64, y: Int64) { x + y }
|
||||||
|
}
|
||||||
|
|
||||||
|
def execute(inst, old, mod)
|
||||||
|
inst = inst.gsub("old", old.to_s);
|
||||||
|
l, op, r = inst.split(" ")
|
||||||
|
l = l.to_i64 % mod
|
||||||
|
r = r.to_i64 % mod
|
||||||
|
INSTS[op].call(l,r)
|
||||||
|
end
|
||||||
|
|
||||||
|
monkeys = [] of Monkey
|
||||||
|
input(2022, 11).split("\n\n").each do |it|
|
||||||
|
it = it.lines
|
||||||
|
items = it[1].split(": ")[1].split(", ").map(&.to_i64).reverse
|
||||||
|
op = it[2].split("Operation: new = ")[1]
|
||||||
|
divBy = it[3].split("Test: divisible by ")[1].to_i64
|
||||||
|
ifTrue = it[4].split(" If true: throw to monkey ")[1].to_i64
|
||||||
|
ifFalse = it[5].split(" If false: throw to monkey ")[1].to_i64
|
||||||
|
monkeys << Monkey.new(items, op, divBy, ifTrue, ifFalse)
|
||||||
|
end
|
||||||
|
|
||||||
|
counts = [0] * monkeys.size
|
||||||
|
modulus = monkeys.map(&.divBy).product
|
||||||
|
10000.times do
|
||||||
|
monkeys.each_with_index do |m, i|
|
||||||
|
while !m.items.empty?
|
||||||
|
counts[i] += 1
|
||||||
|
item = m.items.pop
|
||||||
|
item = execute(m.op, item, modulus)
|
||||||
|
item = item % modulus
|
||||||
|
if item % m.divBy == 0
|
||||||
|
monkeys[m.ifTrue].items.insert(0, item)
|
||||||
|
else
|
||||||
|
monkeys[m.ifFalse].items.insert(0, item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
counts.sort!
|
||||||
|
puts counts[-1].to_big_i * counts[-2].to_big_i
|
||||||
110
day13.cr
Normal file
110
day13.cr
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
require "advent"
|
||||||
|
INPUT = input(2022, 13).lines
|
||||||
|
|
||||||
|
class Tree
|
||||||
|
property value : Int32?
|
||||||
|
property values : Array(Tree)?
|
||||||
|
|
||||||
|
def initialize(@value, @values)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s(io)
|
||||||
|
if mine = value
|
||||||
|
io << "value: " << mine
|
||||||
|
elsif mine = values
|
||||||
|
io << "values: "
|
||||||
|
mine.each do |v|
|
||||||
|
io << "("
|
||||||
|
v.to_s io
|
||||||
|
io << ")"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def compare(other : Tree)
|
||||||
|
if mine = value
|
||||||
|
if yours = other.value
|
||||||
|
return (mine - yours).sign
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if mine = values
|
||||||
|
if yours = other.values
|
||||||
|
mine.size.times do |i|
|
||||||
|
return 1 unless i < yours.size # Shorter list smaller
|
||||||
|
comp = mine[i].compare yours[i]
|
||||||
|
return comp if comp != 0
|
||||||
|
end
|
||||||
|
return mine.size == yours.size ? 0 : -1 # Shorter list smaller
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if mine = value
|
||||||
|
return Tree.new(nil, [self]).compare(other)
|
||||||
|
elsif yours = other.value
|
||||||
|
return compare(Tree.new(nil, [other]))
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def tree(i)
|
||||||
|
Tree.new(i, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list(is : Array(Int32))
|
||||||
|
Tree.new(nil, is.map { |it| tree(it) })
|
||||||
|
end
|
||||||
|
|
||||||
|
def list(is : Array(Tree))
|
||||||
|
Tree.new(nil, is)
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(string)
|
||||||
|
stack = [[] of Tree]
|
||||||
|
current = nil
|
||||||
|
string.as(String).each_char do |c|
|
||||||
|
if c == '['
|
||||||
|
stack << [] of Tree
|
||||||
|
elsif c.alphanumeric?
|
||||||
|
if current.nil?
|
||||||
|
current = c.to_i32
|
||||||
|
else
|
||||||
|
current = current * 10 + c.to_i32
|
||||||
|
end
|
||||||
|
elsif c == ','
|
||||||
|
if num = current
|
||||||
|
stack.last << tree(num)
|
||||||
|
current = nil
|
||||||
|
end
|
||||||
|
elsif c == ']'
|
||||||
|
if num = current
|
||||||
|
stack.last << tree(num)
|
||||||
|
current = nil
|
||||||
|
end
|
||||||
|
new_tree = Tree.new(nil, stack.pop)
|
||||||
|
stack.last << new_tree
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return stack[0][0]
|
||||||
|
end
|
||||||
|
|
||||||
|
puts parse("[[10,1,2],[],[]]")
|
||||||
|
total = 0
|
||||||
|
INPUT.in_groups_of(3).each_with_index do |group, i|
|
||||||
|
t1 = parse(group[0])
|
||||||
|
t2 = parse(group[1])
|
||||||
|
cmp = t1.compare t2
|
||||||
|
total += (i+1) if cmp != 1
|
||||||
|
end
|
||||||
|
puts total
|
||||||
|
|
||||||
|
trees = INPUT.reject { |it| it.empty? }.map { |it| parse(it) }
|
||||||
|
d1 = parse("[[2]]")
|
||||||
|
d2 = parse("[[6]]")
|
||||||
|
trees << d1
|
||||||
|
trees << d2
|
||||||
|
trees.sort! do |l, r|
|
||||||
|
l.compare r
|
||||||
|
end
|
||||||
|
puts (trees.index!(d1)+1)*(trees.index!(d2)+1)
|
||||||
67
day14.chpl
Normal file
67
day14.chpl
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use IO, Set;
|
||||||
|
|
||||||
|
proc parseCoord(s: string) {
|
||||||
|
const (x, _, y) = s.partition(",");
|
||||||
|
return (x : int, y : int);
|
||||||
|
}
|
||||||
|
|
||||||
|
proc (set((int,int))).draw((x1, y1), (x2, y2)) {
|
||||||
|
for x in (min(x1,x2)..max(x1,x2)) {
|
||||||
|
for y in (min(y1,y2)..max(y1,y2)) {
|
||||||
|
this.add((x,y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iter ((int,int)).nextPositions() {
|
||||||
|
yield this + (0,1);
|
||||||
|
yield this + (-1,1);
|
||||||
|
yield this + (1,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var occupied = new set((int, int));
|
||||||
|
for line in stdin.lines().strip() {
|
||||||
|
const coords = parseCoord(line.split(" -> "));
|
||||||
|
for idx in 0..#(coords.size-1) {
|
||||||
|
occupied.draw(coords[idx], coords[idx+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxHeight = max reduce [(x, y) in occupied] y;
|
||||||
|
const initialPos = (500, 0);
|
||||||
|
config const hasWall = false;
|
||||||
|
var grainCount = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Start a new grain of sand, but give up if there's already one there.
|
||||||
|
var pos = initialPos;
|
||||||
|
if occupied.contains(pos) then break;
|
||||||
|
|
||||||
|
// Make the grain fall
|
||||||
|
var abyss = false;
|
||||||
|
do {
|
||||||
|
var moved = false;
|
||||||
|
for checkPos in pos.nextPositions() {
|
||||||
|
// Check for falling past the floor
|
||||||
|
if checkPos[1] > maxHeight + 10 {
|
||||||
|
abyss = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Try moving, but only if the position is clear and not on the floor.
|
||||||
|
if !occupied.contains(checkPos) &&
|
||||||
|
!(hasWall && checkPos[1] == maxHeight + 2) {
|
||||||
|
pos = checkPos;
|
||||||
|
moved = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while moved;
|
||||||
|
|
||||||
|
// If we stopped because we fell off, don't count the last grain.
|
||||||
|
if !abyss {
|
||||||
|
grainCount += 1;
|
||||||
|
occupied.add(pos);
|
||||||
|
}
|
||||||
|
} while !abyss;
|
||||||
|
|
||||||
|
writeln(grainCount);
|
||||||
57
day14a.cr
Normal file
57
day14a.cr
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
require "advent"
|
||||||
|
INPUT = input(2022, 14).lines
|
||||||
|
|
||||||
|
occupied = {} of Tuple(Int32, Int32) => Bool
|
||||||
|
INPUT.each do |line|
|
||||||
|
points = line.split("->").map &.split(",").map(&.to_i32)
|
||||||
|
points.each_cons_pair do |p1,p2|
|
||||||
|
x1, y1 = p1
|
||||||
|
x2, y2 = p2
|
||||||
|
dx = (x2-x1).sign
|
||||||
|
dy = (y2-y1).sign
|
||||||
|
((x2-x1).abs+1).times do |nx|
|
||||||
|
((y2-y1).abs+1).times do |ny|
|
||||||
|
pos = {x1 + nx*dx, y1 + ny*dy}
|
||||||
|
occupied[pos] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
max_height = occupied.max_of do |k,v|
|
||||||
|
x, y = k
|
||||||
|
y
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Max height: #{max_height}"
|
||||||
|
|
||||||
|
def each_place(pos, &block)
|
||||||
|
x, y = pos
|
||||||
|
yield ({x+1, y+1})
|
||||||
|
yield ({x-1, y+1})
|
||||||
|
yield ({x, y+1})
|
||||||
|
end
|
||||||
|
|
||||||
|
puts occupied
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
overflow = false
|
||||||
|
until overflow
|
||||||
|
pos = {500, 0}
|
||||||
|
moved = false
|
||||||
|
loop do
|
||||||
|
moved = false
|
||||||
|
each_place(pos) do |check|
|
||||||
|
next if occupied[check]?
|
||||||
|
pos = check
|
||||||
|
moved = true
|
||||||
|
end
|
||||||
|
overflow = true if pos[1] > max_height
|
||||||
|
break unless moved
|
||||||
|
break if overflow
|
||||||
|
end
|
||||||
|
occupied[pos] = true
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
puts count-1
|
||||||
54
day14b.cr
Normal file
54
day14b.cr
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
require "advent"
|
||||||
|
INPUT = input(2022, 14).lines
|
||||||
|
|
||||||
|
occupied = {} of Tuple(Int32, Int32) => Bool
|
||||||
|
INPUT.each do |line|
|
||||||
|
points = line.split("->").map &.split(",").map(&.to_i32)
|
||||||
|
points.each_cons_pair do |p1,p2|
|
||||||
|
x1, y1 = p1
|
||||||
|
x2, y2 = p2
|
||||||
|
dx = (x2-x1).sign
|
||||||
|
dy = (y2-y1).sign
|
||||||
|
((x2-x1).abs+1).times do |nx|
|
||||||
|
((y2-y1).abs+1).times do |ny|
|
||||||
|
pos = {x1 + nx*dx, y1 + ny*dy}
|
||||||
|
occupied[pos] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
max_height = occupied.max_of do |k,v|
|
||||||
|
x, y = k
|
||||||
|
y
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Max height: #{max_height}"
|
||||||
|
|
||||||
|
def each_place(pos, &block)
|
||||||
|
x, y = pos
|
||||||
|
yield ({x+1, y+1})
|
||||||
|
yield ({x-1, y+1})
|
||||||
|
yield ({x, y+1})
|
||||||
|
end
|
||||||
|
|
||||||
|
puts occupied
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
until occupied[{500,0}]?
|
||||||
|
pos = {500, 0}
|
||||||
|
moved = false
|
||||||
|
loop do
|
||||||
|
moved = false
|
||||||
|
each_place(pos) do |check|
|
||||||
|
next if occupied[check]? || check[1] == max_height+2
|
||||||
|
pos = check
|
||||||
|
moved = true
|
||||||
|
end
|
||||||
|
break unless moved
|
||||||
|
end
|
||||||
|
occupied[pos] = true
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
puts count
|
||||||
83
day15.chpl
Normal file
83
day15.chpl
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
use IO, Set, List;
|
||||||
|
|
||||||
|
iter data() {
|
||||||
|
var x1, y1, x2, y2 = 0;
|
||||||
|
while readf("Sensor at x=%i, y=%i: closest beacon is at x=%i, y=%i\n", x1, y1, x2, y2) {
|
||||||
|
yield ((x1, y1), (x2, y2), abs(x1-x2) + abs(y1-y2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record overlapping {
|
||||||
|
var disjoint: list(range(int));
|
||||||
|
|
||||||
|
proc add(arg: range(int)) {
|
||||||
|
// Don't pollute `disjoint`.
|
||||||
|
if arg.isEmpty() then return;
|
||||||
|
|
||||||
|
var newRng = arg;
|
||||||
|
do {
|
||||||
|
var merged = false;
|
||||||
|
for (rng, i) in zip(disjoint, 0..) {
|
||||||
|
if newRng[rng].isEmpty() then continue;
|
||||||
|
newRng = min(rng.lowBound, newRng.lowBound)..max(rng.highBound, newRng.highBound);
|
||||||
|
disjoint.pop(i);
|
||||||
|
merged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while merged;
|
||||||
|
disjoint.append(newRng);
|
||||||
|
}
|
||||||
|
|
||||||
|
iter these() { for rng in disjoint do yield rng; }
|
||||||
|
proc size { return + [rng in this] rng.size; }
|
||||||
|
proc boundedSize(bound) { return + reduce [rng in this] rng[bound].size; }
|
||||||
|
proc contains(x) { return || reduce [rng in this] rng.contains(x); }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum axis { xAxis = 0, yAxis = 1 };
|
||||||
|
proc ((int, int)).rangeAlong(axs: axis, reach: int, theXOrY: int) {
|
||||||
|
const dim = axs : int;
|
||||||
|
const dist = abs(this[dim]-theXOrY);
|
||||||
|
|
||||||
|
// Too far
|
||||||
|
if dist > reach then return 0..<0;
|
||||||
|
|
||||||
|
// Get the range
|
||||||
|
const remDist = max(0, reach-dist);
|
||||||
|
return (this[1-dim]-remDist)..(this[1-dim]+remDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
config const theY = 10;
|
||||||
|
const searchSpace = 0..theY * 2;
|
||||||
|
const input = data();
|
||||||
|
|
||||||
|
// Solve part 1
|
||||||
|
var overlaps: overlapping;
|
||||||
|
var occupied: set((int, int));
|
||||||
|
for (sensor, beacon, reach) in input {
|
||||||
|
occupied.add(sensor);
|
||||||
|
occupied.add(beacon);
|
||||||
|
overlaps.add(sensor.rangeAlong(axis.yAxis, reach, theY));
|
||||||
|
}
|
||||||
|
writeln(overlaps.size - (+ reduce [(x,y) in occupied] if y == theY then 1));
|
||||||
|
|
||||||
|
// Solve part 2
|
||||||
|
forall checkY in searchSpace {
|
||||||
|
var overlaps: overlapping;
|
||||||
|
for (sensor, _, reach) in input {
|
||||||
|
overlaps.add(sensor.rangeAlong(axis.yAxis, reach, checkY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if overlaps.boundedSize(searchSpace) != searchSpace.size {
|
||||||
|
// Found the y-cordinate. Now find the x-coordinate.
|
||||||
|
for checkX in searchSpace {
|
||||||
|
if !overlaps.contains(checkX) {
|
||||||
|
// x-coord isn't in the interval, so we found our answer.
|
||||||
|
writeln("x = ", checkX, ", y = ", checkY, ", frequency = ", checkX * 4000000 + checkY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user