Compare commits

...

9 Commits

Author SHA1 Message Date
Danila Fedorin
c9cc95c447 Clean up day 15 solution a bit more 2022-12-14 23:13:49 -08:00
Danila Fedorin
8b7da0b751 Add day 15 solution 2022-12-14 23:11:45 -08:00
Danila Fedorin
bbaedda944 Add day 14 solution in Chapel 2022-12-13 21:58:59 -08:00
Danila Fedorin
7fed659932 Add day 14 solutions 2022-12-13 21:26:38 -08:00
Danila Fedorin
d8a62d2eb4 Add Crystal solution to day 13 2022-12-12 21:47:00 -08:00
Danila Fedorin
8dda1b5ee2 Add day 11 code 2022-12-12 11:38:59 -08:00
Danila Fedorin
efa81418eb Make tweaks to day 10 code to make it clearer 2022-12-12 10:16:46 -08:00
Danila Fedorin
76705dc6fb Change day 12 from part 1 to part 2 (cleanup later) 2022-12-12 10:15:54 -08:00
Danila Fedorin
5cd1a7f157 Add day 12 part 1 solution 2022-12-12 10:15:32 -08:00
9 changed files with 614 additions and 5 deletions

View File

@@ -13,11 +13,12 @@ iter ops() {
} }
} }
const deltas = ops(); const deltas = ops(),
const states = + scan deltas; cycles = deltas.size,
const indices = 20..220 by 40; states: [1..cycles] int = + scan deltas,
writeln(+ reduce (states[indices-1] * indices)); interesting = 20..220 by 40;
writeln(+ reduce (states[interesting] * interesting));
const pixels = [(x, pc) in zip(states[0..<240], 0..)] const pixels = [(x, pc) in zip(states[1..240], 0..)]
if abs((pc % 40) - x) <= 1 then "#" else " "; if abs((pc % 40) - x) <= 1 then "#" else " ";
writeln(reshape(pixels, {1..6, 1..40})); writeln(reshape(pixels, {1..6, 1..40}));

96
day11.chpl Normal file
View 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
View 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

83
day12.cr Normal file
View File

@@ -0,0 +1,83 @@
require "advent"
INPUT = input(2022, 12).lines.map(&.chars)
EDGES = {} of Tuple(Int32,Int32) => Array(Tuple(Int32, Int32))
def add_at(pos, c, x, y)
return unless y >= 0 && y < INPUT.size
return unless x >= 0 && x < INPUT[0].size
o = INPUT[y][x]
o = 'a' if o == 'S'
o = 'z' if o == 'E'
return if (c.ord-o.ord) > 1
EDGES[pos] << ({x,y});
end
def add_nearby(x, y)
c = INPUT[y][x]
c = 'a' if c == 'S'
c = 'z' if c == 'E'
if !EDGES[{x,y}]?
EDGES[{x,y}] = [] of Tuple(Int32,Int32)
end
add_at({x,y}, c, x+1, y)
add_at({x,y}, c, x-1, y)
add_at({x,y}, c, x, y+1)
add_at({x,y}, c, x, y-1)
end
from = {0,0}
to = {100,100}
INPUT.each_with_index do |row, y|
row.each_with_index do |c, x|
pos = {x, y}
add_nearby(x, y)
from = pos if c == 'E'
end
end
costs = {from => 0}
mins = {} of Tuple(Int32, Int32) => Int32
visited = Set(Tuple(Int32, Int32)).new
while !costs.empty?
k, v = costs.min_by do |k,v|
v
end
if k == to
puts "Found! #{v}"
break
end
costs.delete k
mins[k] = v
visited << k
INPUT[k[1]][k[0]] = INPUT[k[1]][k[0]].upcase
puts k
EDGES[k].each do |edge|
next if visited.includes? edge
if old = costs[edge]?
costs[edge] = v+1 if old > v+1
else
costs[edge] = v+1
end
end
end
lengths = [] of Int32
puts mins
INPUT.each_with_index do |line, y|
line.each_with_index do |c, x|
next unless c == 'A'
if amin = mins[{x,y}]?
lengths << amin
end
print c
end
puts
end
puts lengths.min

110
day13.cr Normal file
View 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
View 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
View 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
View 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
View 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;
}
}
}
}