Compare commits
7 Commits
3aa911a1ad
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e416a50231 | |||
| 8b771666f3 | |||
| 4a0846a625 | |||
| 5fe6870069 | |||
| 1ca80ba6d2 | |||
| 52dfdcc4bb | |||
| 64040259cb |
@@ -0,0 +1,53 @@
|
||||
import "aoc" for AoC
|
||||
|
||||
class CPU {
|
||||
construct new() {
|
||||
_cycle = 0
|
||||
_x = 1
|
||||
|
||||
_every20 = 0
|
||||
_str = ""
|
||||
}
|
||||
|
||||
every20 { _every20 }
|
||||
str { _str }
|
||||
|
||||
tick() {
|
||||
_cycle = _cycle + 1
|
||||
if(_cycle % 40 == 20) {
|
||||
_every20 = _every20 + _x * _cycle
|
||||
}
|
||||
var px = _cycle % 40
|
||||
if(px == _x || px == _x + 1 || px == _x + 2) {
|
||||
_str = _str + "#"
|
||||
} else {
|
||||
_str = _str + "."
|
||||
}
|
||||
if(_cycle % 40 == 0) {
|
||||
_str = _str + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
noop() {
|
||||
tick()
|
||||
}
|
||||
|
||||
addx(x) {
|
||||
tick()
|
||||
tick()
|
||||
_x = _x + x
|
||||
}
|
||||
}
|
||||
|
||||
var cpu = CPU.new()
|
||||
|
||||
for(line in AoC.input.split("\n").where {|l| l != ""}) {
|
||||
if(line == "noop") {
|
||||
cpu.noop()
|
||||
} else {
|
||||
cpu.addx(Num.fromString(line.split(" ")[1]))
|
||||
}
|
||||
}
|
||||
|
||||
System.print(cpu.every20)
|
||||
System.print(cpu.str)
|
||||
@@ -0,0 +1,74 @@
|
||||
import "aoc" for AoC
|
||||
|
||||
class Entry {
|
||||
construct dir(parent) {
|
||||
_parent = parent
|
||||
_files = {}
|
||||
}
|
||||
construct file(parent, size) {
|
||||
_parent = parent
|
||||
_size = size
|
||||
}
|
||||
|
||||
size { _size }
|
||||
files { _files }
|
||||
parent { _parent }
|
||||
|
||||
total_size {
|
||||
if(_size) {
|
||||
return _size
|
||||
} else {
|
||||
return _files.map {|entry| entry.value.total_size}.reduce {|a, b| a+b}
|
||||
}
|
||||
}
|
||||
|
||||
iter_dirs(fn) {
|
||||
if(_files) {
|
||||
fn.call(this)
|
||||
for(file in _files) {
|
||||
file.value.iter_dirs(fn)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lines = AoC.input.split("\n").where {|x| x != ""}
|
||||
|
||||
var root = Entry.dir(null)
|
||||
|
||||
var current = root
|
||||
for(line in lines) {
|
||||
if(line.startsWith("$ cd")) {
|
||||
var path = line.replace("$ cd ", "")
|
||||
if(path == "/") {
|
||||
current = root
|
||||
} else if(path == "..") {
|
||||
current = current.parent
|
||||
} else {
|
||||
current = current.files[path]
|
||||
}
|
||||
} else if(line == "$ ls") {
|
||||
// ignore
|
||||
} else if(line.startsWith("dir ")) {
|
||||
var path = line.replace("dir ", "")
|
||||
if(!current.files[path]) current.files[path] = Entry.dir(current)
|
||||
} else {
|
||||
var split = line.split(" ")
|
||||
var size = Num.fromString(split[0])
|
||||
var path = split[1]
|
||||
if(!current.files[path]) current.files[path] = Entry.file(current, size)
|
||||
}
|
||||
}
|
||||
|
||||
var sum_p1 = 0
|
||||
var smallest_p2 = Num.infinity
|
||||
|
||||
var to_free = 30000000 - (70000000 - root.total_size)
|
||||
root.iter_dirs {|dir|
|
||||
var size = dir.total_size
|
||||
if(size <= 100000) sum_p1 = sum_p1 + size
|
||||
if(size >= to_free && size <= smallest_p2) smallest_p2 = size
|
||||
}
|
||||
|
||||
System.print(sum_p1)
|
||||
System.print(smallest_p2)
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "d7"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "d7"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
use std::{cell::RefCell, collections::HashMap, fs::read_to_string, io::Result, rc::Rc};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Entry {
|
||||
Dir(Option<RME>, HashMap<String, RME>),
|
||||
File(usize),
|
||||
}
|
||||
|
||||
type RME = Rc<RefCell<Entry>>;
|
||||
|
||||
impl Entry {
|
||||
pub fn new_dir<S: AsRef<str>>(parent: &Option<RME>, name: S) -> RME {
|
||||
let this = Rc::new(RefCell::new(Entry::Dir(parent.clone(), HashMap::new())));
|
||||
let this_clone = this.clone();
|
||||
match parent {
|
||||
Some(parent) => match &mut *parent.borrow_mut() {
|
||||
Entry::Dir(_, ref mut children) => {
|
||||
children.insert(name.as_ref().to_owned(), this_clone);
|
||||
}
|
||||
_ => panic!("Attaching a child to a file"),
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn new_file<S: AsRef<str>>(parent: RME, name: S, size: usize) -> RME {
|
||||
let this = Rc::new(RefCell::new(Entry::File(size)));
|
||||
let this_clone = this.clone();
|
||||
match &mut *parent.borrow_mut() {
|
||||
Entry::Dir(_, ref mut children) => {
|
||||
children.insert(name.as_ref().to_owned(), this_clone);
|
||||
}
|
||||
_ => panic!("Attaching a child to a file"),
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
match self {
|
||||
Entry::File(size) => *size,
|
||||
Entry::Dir(_, ref children) => children.values().map(|f| f.borrow().size()).sum(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> RME {
|
||||
match self {
|
||||
Entry::Dir(parent, _) => parent.as_ref().unwrap().clone(),
|
||||
_ => panic!("Get parent for file"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file<S: AsRef<str>>(&self, name: S) -> RME {
|
||||
match self {
|
||||
Entry::Dir(_, ref children) => children.get(name.as_ref()).unwrap().clone(),
|
||||
_ => panic!("Get file for file"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_dirs<F: FnMut(&Self)>(&self, f: &mut F) {
|
||||
match self {
|
||||
Entry::Dir(_, ref children) => {
|
||||
f(self);
|
||||
for child in children.values() {
|
||||
child.borrow().iter_dirs(f);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let none = None;
|
||||
let root = Entry::new_dir(&none, "/");
|
||||
|
||||
let mut current = root.clone();
|
||||
|
||||
for line in read_to_string("input.txt")?
|
||||
.split("\n")
|
||||
.filter(|x| !x.is_empty())
|
||||
{
|
||||
if line.starts_with("$ cd ") {
|
||||
let path = line.split_at(5).1;
|
||||
|
||||
if path == "/" {
|
||||
current = root.clone();
|
||||
} else if path == ".." {
|
||||
let next = current.borrow().parent();
|
||||
current = next;
|
||||
} else {
|
||||
let next = current.borrow().file(path);
|
||||
current = next;
|
||||
}
|
||||
} else if line == "$ ls" {
|
||||
// ignore
|
||||
} else if line.starts_with("dir ") {
|
||||
let path = line.split_at(4).1;
|
||||
Entry::new_dir(&Some(current.clone()), path);
|
||||
} else {
|
||||
let split = line.split(" ").collect::<Vec<_>>();
|
||||
let size = split[0].parse::<usize>().unwrap();
|
||||
let path = split[1];
|
||||
Entry::new_file(current.clone(), path, size);
|
||||
}
|
||||
}
|
||||
|
||||
let mut sum_p1 = 0;
|
||||
let mut smallest_p2 = usize::MAX;
|
||||
|
||||
let to_free = 30000000usize - (70000000usize - root.borrow().size());
|
||||
root.borrow().iter_dirs(&mut |dir| {
|
||||
let size = dir.size();
|
||||
if size <= 100000 {
|
||||
sum_p1 += size
|
||||
}
|
||||
if size >= to_free && size <= smallest_p2 {
|
||||
smallest_p2 = size
|
||||
}
|
||||
});
|
||||
|
||||
println!("Part 1: {}", sum_p1);
|
||||
println!("Part 2: {}", smallest_p2);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import "aoc" for AoC
|
||||
|
||||
class Forest {
|
||||
construct new(w, h) {
|
||||
_w = w
|
||||
_h = h
|
||||
_trees = List.filled(w*h, 0)
|
||||
}
|
||||
|
||||
w { _w }
|
||||
h { _h }
|
||||
|
||||
get(x, y) { _trees[x+_w*y] }
|
||||
set(x, y, t) { _trees[x+_w*y] = t }
|
||||
|
||||
visible_cardinal(x, y) {
|
||||
if(x == 0 || y == 0 || x == w-1 || y == h-1) {
|
||||
return true
|
||||
}
|
||||
|
||||
var t = get(x, y)
|
||||
|
||||
var vis = true
|
||||
for(xi in 0...x) {
|
||||
if(get(xi, y) >= t) {
|
||||
vis = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if(vis) return true
|
||||
|
||||
vis = true
|
||||
for(yi in 0...y) {
|
||||
if(get(x, yi) >= t) {
|
||||
vis = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if(vis) return true
|
||||
|
||||
vis = true
|
||||
for(xi in (x+1)...w) {
|
||||
if(get(xi, y) >= t) {
|
||||
vis = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if(vis) return true
|
||||
|
||||
vis = true
|
||||
for(yi in (y+1)...h) {
|
||||
if(get(x, yi) >= t) {
|
||||
vis = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if(vis) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
score(x, y) {
|
||||
if(x == 0 || y == 0 || x == w-1 || y == h-1) {
|
||||
return 0
|
||||
}
|
||||
|
||||
var t = get(x, y)
|
||||
|
||||
var score_left = 0
|
||||
for(xi in (x-1)..0) {
|
||||
score_left = score_left + 1
|
||||
if(get(xi, y) >= t) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var score_up = 0
|
||||
for(yi in (y-1)..0) {
|
||||
score_up = score_up + 1
|
||||
if(get(x, yi) >= t) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var score_right = 0
|
||||
for(xi in (x+1)...(_w)) {
|
||||
score_right = score_right + 1
|
||||
if(get(xi, y) >= t) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var score_down = 0
|
||||
for(yi in (y+1)...(_h)) {
|
||||
score_down = score_down + 1
|
||||
if(get(x, yi) >= t) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return score_left * score_up * score_right * score_down
|
||||
}
|
||||
}
|
||||
|
||||
var input = AoC.input
|
||||
var row_count = input.where {|x| x == "\n"}.count
|
||||
var lines = input.split("\n").where {|x| x != ""}
|
||||
|
||||
var forest = null
|
||||
var x = 0
|
||||
for(line in lines) {
|
||||
if(!forest) forest = Forest.new(line.count, row_count)
|
||||
var y = 0
|
||||
for(tree in line) {
|
||||
forest.set(x, y, Num.fromString(tree))
|
||||
y = y + 1
|
||||
}
|
||||
x = x + 1
|
||||
}
|
||||
|
||||
var total_visible = 0
|
||||
var best_score = 0
|
||||
for(x in 0...forest.w) {
|
||||
for(y in 0...forest.h) {
|
||||
if(forest.visible_cardinal(x, y)) {
|
||||
total_visible = total_visible + 1
|
||||
}
|
||||
var score = forest.score(x, y)
|
||||
if(score > best_score) {
|
||||
best_score = score
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.print(total_visible)
|
||||
System.print(best_score)
|
||||
@@ -0,0 +1,95 @@
|
||||
import "aoc" for AoC
|
||||
|
||||
class Pos {
|
||||
construct new() {
|
||||
_x = 0
|
||||
_y = 0
|
||||
}
|
||||
|
||||
x { _x }
|
||||
y { _y }
|
||||
|
||||
touches(other) {
|
||||
var dx = (_x - other.x).abs
|
||||
var dy = (_y - other.y).abs
|
||||
|
||||
return dx <= 1 && dy <= 1
|
||||
}
|
||||
|
||||
static movement(h, t) {
|
||||
if(h.touches(t)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
var dx = h.x - t.x
|
||||
var dy = h.y - t.y
|
||||
|
||||
if(dx < 0 && dy < 0) {
|
||||
return "LD"
|
||||
}
|
||||
if(dx < 0 && dy > 0) {
|
||||
return "LU"
|
||||
}
|
||||
if(dx > 0 && dy < 0) {
|
||||
return "RD"
|
||||
}
|
||||
if(dx > 0 && dy > 0) {
|
||||
return "RU"
|
||||
}
|
||||
if(dx < 0 ) {
|
||||
return "L"
|
||||
}
|
||||
if(dx > 0 ) {
|
||||
return "R"
|
||||
}
|
||||
if(dy < 0 ) {
|
||||
return "D"
|
||||
}
|
||||
if(dy > 0 ) {
|
||||
return "U"
|
||||
}
|
||||
}
|
||||
|
||||
u() { _y = _y + 1 }
|
||||
d() { _y = _y - 1 }
|
||||
l() { _x = _x - 1 }
|
||||
r() { _x = _x + 1 }
|
||||
|
||||
move(direction) {
|
||||
for(c in direction) {
|
||||
if(c == "U") this.u()
|
||||
if(c == "D") this.d()
|
||||
if(c == "L") this.l()
|
||||
if(c == "R") this.r()
|
||||
}
|
||||
}
|
||||
|
||||
xy { _x.toString + "," + _y.toString }
|
||||
}
|
||||
|
||||
var h = Pos.new()
|
||||
var t = Pos.new()
|
||||
|
||||
var rope = []
|
||||
for(i in 0...10) { rope.add(Pos.new()) }
|
||||
|
||||
var seen_p1 = {}
|
||||
var seen_p2 = {}
|
||||
|
||||
for(line in AoC.input.split("\n").where {|l| l != ""}) {
|
||||
var split = line.split(" ")
|
||||
var direction = split[0]
|
||||
var count = Num.fromString(split[1])
|
||||
for(i in 0...count) {
|
||||
h.move(direction)
|
||||
t.move(Pos.movement(h, t))
|
||||
seen_p1[t.xy] = true
|
||||
|
||||
rope[0].move(direction)
|
||||
for(i in 1...10) { rope[i].move(Pos.movement(rope[i-1], rope[i])) }
|
||||
seen_p2[rope[9].xy] = true
|
||||
}
|
||||
}
|
||||
|
||||
System.print(seen_p1.count)
|
||||
System.print(seen_p2.count)
|
||||
@@ -0,0 +1,5 @@
|
||||
*.a
|
||||
*.o
|
||||
aoc.c
|
||||
wren_aoc
|
||||
wren.h
|
||||
@@ -0,0 +1,24 @@
|
||||
var CC: 'gcc'
|
||||
var CFLAGS: '-Wall', '-Wextra', '-Werror'
|
||||
var LDFLAGS: '-lm'
|
||||
|
||||
with public default target 'all'
|
||||
\depends 'wren_aoc'
|
||||
|
||||
with public target 'wren_aoc'
|
||||
\depends 'main.o', 'aoc.o', 'libwren.a'
|
||||
\produces '%'
|
||||
\fn => _.cmd CC, CFLAGS, @infiles, '-o', @outfile, LDFLAGS
|
||||
|
||||
with target {'main.o', 'aoc.o'}, pattern: '%.o'
|
||||
\depends '%.c'
|
||||
\produces '%.o'
|
||||
\fn => _.cmd CC, CFLAGS, @infile, '-o', @outfile, '-c'
|
||||
|
||||
with target 'aoc.c'
|
||||
\depends 'aoc.wren'
|
||||
\produces '%'
|
||||
\fn =>
|
||||
code = _.readfile @infile
|
||||
c_code = "extern const char* aoc_mod = \"#{code\gsub('"', '\\"')\gsub('\n', '\\n')}\";\n"
|
||||
_.writefile @outfile, c_code
|
||||
@@ -0,0 +1,3 @@
|
||||
class AoC {
|
||||
foreign static input
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
extern char* aoc_mod;
|
||||
|
||||
char* read_file(const char* path) {
|
||||
FILE* fp = fopen(path, "rb");
|
||||
if(fp == NULL) return NULL;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t len = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
char* out = calloc(len + 1, 1);
|
||||
if(out == NULL) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(len != fread(out, 1, len, fp)) {
|
||||
fclose(fp);
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return out;
|
||||
}
|
||||
|
||||
void writeFn(WrenVM* vm, const char* text) {
|
||||
(void)(vm);
|
||||
printf("%s", text);
|
||||
}
|
||||
|
||||
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
|
||||
(void)(vm);
|
||||
switch (errorType) {
|
||||
case WREN_ERROR_COMPILE:
|
||||
printf("[%s line %d] [Error] %s\n", module, line, msg);
|
||||
break;
|
||||
case WREN_ERROR_STACK_TRACE:
|
||||
printf("[%s line %d] in %s\n", module, line, msg);
|
||||
break;
|
||||
case WREN_ERROR_RUNTIME:
|
||||
printf("[Runtime Error] %s\n", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void load_input(WrenVM* vm) {
|
||||
char* data = read_file("input.txt");
|
||||
if(data != NULL) {
|
||||
wrenSetSlotString(vm, 0, data);
|
||||
free(data);
|
||||
} else {
|
||||
wrenSetSlotNull(vm, 0);
|
||||
}
|
||||
}
|
||||
|
||||
WrenForeignMethodFn bindForeignMethodFn(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature) {
|
||||
(void)(vm);
|
||||
if(!strcmp(module, "aoc") && !strcmp(className, "AoC") && isStatic && !strcmp(signature, "input")) {
|
||||
return &load_input;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WrenLoadModuleResult loadModuleFn(WrenVM* vm, const char* name) {
|
||||
(void)(vm);
|
||||
WrenLoadModuleResult result = {0};
|
||||
if(!strcmp(name, "aoc")) {
|
||||
result.source = aoc_mod;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
(void)(argc);
|
||||
int exit_code = 0;
|
||||
|
||||
if(argv[1] == NULL) {
|
||||
fprintf(stderr, "Syntax: %s <FILE>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* code = read_file(argv[1]);
|
||||
if(code == NULL) {
|
||||
fprintf(stderr, "Couldn't load file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
WrenConfiguration config;
|
||||
wrenInitConfiguration(&config);
|
||||
|
||||
config.writeFn = &writeFn;
|
||||
config.errorFn = &errorFn;
|
||||
config.loadModuleFn = &loadModuleFn;
|
||||
config.bindForeignMethodFn = &bindForeignMethodFn;
|
||||
|
||||
WrenVM* vm = wrenNewVM(&config);
|
||||
WrenInterpretResult result = wrenInterpret(vm, "main", code);
|
||||
free(code);
|
||||
|
||||
if(result == WREN_RESULT_COMPILE_ERROR) {
|
||||
fprintf(stderr, "Wren exited with compile error\n");
|
||||
exit_code = 1;
|
||||
} else if(result == WREN_RESULT_RUNTIME_ERROR) {
|
||||
fprintf(stderr, "Wren exited with runtime error\n");
|
||||
exit_code = 1;
|
||||
}
|
||||
|
||||
wrenFreeVM(vm);
|
||||
return exit_code;
|
||||
}
|
||||
Reference in New Issue
Block a user