Compare commits
7 commits
a903132905
...
471a3064ad
Author | SHA1 | Date | |
---|---|---|---|
dece | 471a3064ad | ||
dece | 4beec9475d | ||
dece | d81a9006cd | ||
dece | 1ae5233c68 | ||
dece | e5f906dae1 | ||
dece | 3e46c5be83 | ||
dece | b563dcbb18 |
36
2015/src/bin/day10.rs
Normal file
36
2015/src/bin/day10.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use aoc::input;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut v = input::read_chars();
|
||||||
|
|
||||||
|
// Part 1
|
||||||
|
for _ in 0..40 {
|
||||||
|
v = step(&v);
|
||||||
|
}
|
||||||
|
println!("Length after 40 steps: {}", v.len());
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
for _ in 0..10 {
|
||||||
|
v = step(&v);
|
||||||
|
}
|
||||||
|
println!("Length after 50 steps: {}", v.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(s: &str) -> String {
|
||||||
|
let mut count = 1;
|
||||||
|
let mut pc = ' ';
|
||||||
|
let mut result = String::new();
|
||||||
|
for c in s.chars() {
|
||||||
|
if c == pc {
|
||||||
|
count += 1;
|
||||||
|
} else if pc != ' ' {
|
||||||
|
result.push_str(&count.to_string());
|
||||||
|
result.push(pc);
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
pc = c;
|
||||||
|
}
|
||||||
|
result.push_str(&count.to_string());
|
||||||
|
result.push(pc);
|
||||||
|
result
|
||||||
|
}
|
75
2015/src/bin/day11.rs
Normal file
75
2015/src/bin/day11.rs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
use aoc::input;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut pass = input::read_chars();
|
||||||
|
|
||||||
|
// Part 1
|
||||||
|
get_next_pass(&mut pass);
|
||||||
|
println!("Next pass: {}", pass);
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
get_next_pass(&mut pass);
|
||||||
|
println!("Next pass: {}", pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_next_pass(pass: &mut String) {
|
||||||
|
loop {
|
||||||
|
unsafe { inc(pass.as_bytes_mut()) }
|
||||||
|
let pb = pass.as_bytes();
|
||||||
|
if has_seq(pb) && !has_banned_chars(pb) && has_pairs(&pass) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_seq(pass: &[u8]) -> bool {
|
||||||
|
for i in 0..(pass.len() - 2) {
|
||||||
|
if pass[i] == pass[i + 1] - 1 && pass[i + 1] == pass[i + 2] - 1 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_banned_chars(pass: &[u8]) -> bool {
|
||||||
|
for b in b"iol".iter() {
|
||||||
|
if pass.contains(b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_pairs(pass: &str) -> bool {
|
||||||
|
let mut num_pairs = 0;
|
||||||
|
let mut pc = ' ';
|
||||||
|
let mut skip_next = false;
|
||||||
|
for c in pass.chars() {
|
||||||
|
if skip_next {
|
||||||
|
skip_next = false;
|
||||||
|
pc = c;
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c == pc {
|
||||||
|
num_pairs += 1;
|
||||||
|
skip_next = true;
|
||||||
|
}
|
||||||
|
pc = c;
|
||||||
|
}
|
||||||
|
num_pairs >= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inc(pass: &mut [u8]) {
|
||||||
|
let mut i = pass.len() - 1;
|
||||||
|
loop {
|
||||||
|
let lc = pass[i];
|
||||||
|
if lc < b'z' {
|
||||||
|
let offset = if lc == b'i' || lc == b'o' || lc == b'l' { 2 } else { 1 };
|
||||||
|
pass[i] = pass[i] + offset;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pass[i] = b'a';
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
2015/src/bin/day5.rs
Normal file
59
2015/src/bin/day5.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use aoc::input;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lines = input::read_lines();
|
||||||
|
|
||||||
|
// Part 1
|
||||||
|
let mut goods = 0;
|
||||||
|
let bad_pairs = vec!("ab", "cd", "pq", "xy");
|
||||||
|
for line in &lines {
|
||||||
|
let mut has_bad_pair = false;
|
||||||
|
for p in &bad_pairs {
|
||||||
|
if line.contains(p) { has_bad_pair = true; break }
|
||||||
|
}
|
||||||
|
if has_bad_pair { continue }
|
||||||
|
let mut num_vowels = 0;
|
||||||
|
let mut cc = ' ';
|
||||||
|
let mut has_doubled = false;
|
||||||
|
for c in line.chars() {
|
||||||
|
if "aeiou".contains(c) { num_vowels += 1 }
|
||||||
|
if c == cc { has_doubled = true }
|
||||||
|
cc = c;
|
||||||
|
}
|
||||||
|
if num_vowels < 3 { continue }
|
||||||
|
if !has_doubled { continue }
|
||||||
|
goods += 1;
|
||||||
|
}
|
||||||
|
println!("Good strings: {}", goods);
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
goods = 0;
|
||||||
|
for line in &lines {
|
||||||
|
let mut cond1 = false;
|
||||||
|
let chars: Vec<char> = line.chars().collect();
|
||||||
|
for i in 0..(chars.len() - 2) {
|
||||||
|
let c1 = chars[i];
|
||||||
|
let c2 = chars[i + 1];
|
||||||
|
for j in (i + 2)..(chars.len() - 1) {
|
||||||
|
if chars[j] == c1 && chars[j + 1] == c2 {
|
||||||
|
cond1 = true;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cond1 { break }
|
||||||
|
}
|
||||||
|
if !cond1 { continue }
|
||||||
|
|
||||||
|
let mut cond2 = false;
|
||||||
|
let mut cm2 = ' ';
|
||||||
|
let mut cm1 = ' ';
|
||||||
|
for c in line.chars() {
|
||||||
|
if c == cm2 { cond2 = true }
|
||||||
|
cm2 = cm1;
|
||||||
|
cm1 = c;
|
||||||
|
}
|
||||||
|
if !cond2 { continue }
|
||||||
|
goods += 1;
|
||||||
|
}
|
||||||
|
println!("Best strings: {}", goods);
|
||||||
|
}
|
53
2015/src/bin/day6.rs
Normal file
53
2015/src/bin/day6.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
|
use aoc::input;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lines = input::read_lines();
|
||||||
|
let mut grid = vec![false; 1_000_000];
|
||||||
|
|
||||||
|
// Part 1
|
||||||
|
for line in &lines {
|
||||||
|
let mut parts = line.split_whitespace();
|
||||||
|
let state = if parts.next() == Some("turn") {
|
||||||
|
parts.next().and_then(|s| Some(s == "on"))
|
||||||
|
} else { // toggle
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let s: Vec<usize> = parts.next().unwrap().split(",")
|
||||||
|
.map(|p| p.parse::<usize>().unwrap()).collect();
|
||||||
|
let e: Vec<usize> = parts.nth(1).unwrap().split(",")
|
||||||
|
.map(|p| p.parse::<usize>().unwrap()).collect();
|
||||||
|
for i in s[0]..=e[0] {
|
||||||
|
for j in s[1]..=e[1] {
|
||||||
|
grid[i * 1000 + j] = match state {
|
||||||
|
Some(c) => c,
|
||||||
|
None => !grid[i * 1000 + j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Lights on: {}", grid.iter().map(|s| if *s { 1 } else { 0 }).sum::<u32>());
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
let mut grid = vec![0; 1_000_000];
|
||||||
|
for line in &lines {
|
||||||
|
let mut parts = line.split_whitespace();
|
||||||
|
let change: i32 = if parts.next() == Some("turn") {
|
||||||
|
if parts.next().unwrap() == "on" { 1 } else { -1 }
|
||||||
|
} else { // toggle
|
||||||
|
2
|
||||||
|
};
|
||||||
|
let s: Vec<usize> = parts.next().unwrap().split(",")
|
||||||
|
.map(|p| p.parse::<usize>().unwrap()).collect();
|
||||||
|
let e: Vec<usize> = parts.nth(1).unwrap().split(",")
|
||||||
|
.map(|p| p.parse::<usize>().unwrap()).collect();
|
||||||
|
for i in s[0]..=e[0] {
|
||||||
|
for j in s[1]..=e[1] {
|
||||||
|
let current = grid[i * 1000 + j];
|
||||||
|
grid[i * 1000 + j] = cmp::max(current + change, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Brightness: {}", grid.iter().sum::<i32>());
|
||||||
|
}
|
67
2015/src/bin/day7.rs
Normal file
67
2015/src/bin/day7.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use aoc::input;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Op {
|
||||||
|
And(String, String), // left-hand can be an int
|
||||||
|
Or(String, String),
|
||||||
|
Not(String),
|
||||||
|
Lshift(String, u16),
|
||||||
|
Rshift(String, u16),
|
||||||
|
Value(String), // either int or wire
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lines = input::read_lines();
|
||||||
|
let mut wiring: HashMap<String, Op> = HashMap::new();
|
||||||
|
for line in lines {
|
||||||
|
let mut parts = line.split(" -> ");
|
||||||
|
let op_text = parts.next().unwrap();
|
||||||
|
let target = parts.next().unwrap();
|
||||||
|
let op_parts: Vec<&str> = op_text.split_whitespace().collect();
|
||||||
|
let op = match op_parts.len() {
|
||||||
|
1 => { Op::Value(op_parts[0].to_string()) }
|
||||||
|
2 => { Op::Not(op_parts[1].to_string()) }
|
||||||
|
3 => { match op_parts[1] {
|
||||||
|
"AND" => { Op::And(op_parts[0].to_string(), op_parts[2].to_string()) }
|
||||||
|
"OR" => { Op::Or(op_parts[0].to_string(), op_parts[2].to_string()) }
|
||||||
|
"LSHIFT" => { Op::Lshift(op_parts[0].to_string(), op_parts[2].parse::<u16>().unwrap()) }
|
||||||
|
"RSHIFT" => { Op::Rshift(op_parts[0].to_string(), op_parts[2].parse::<u16>().unwrap()) }
|
||||||
|
_ => panic!()
|
||||||
|
} }
|
||||||
|
_ => panic!()
|
||||||
|
};
|
||||||
|
wiring.insert(target.to_string(), op);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Part 1
|
||||||
|
let mut cache: HashMap<String, u16> = HashMap::new();
|
||||||
|
let part1 = solve(&wiring, "a", &mut cache);
|
||||||
|
println!("Wire a: {}", part1);
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
wiring.insert("b".to_string(), Op::Value(part1.to_string()));
|
||||||
|
let mut cache: HashMap<String, u16> = HashMap::new();
|
||||||
|
println!("Wire a with b overridden: {}", solve(&wiring, "a", &mut cache));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve(wiring: &HashMap<String, Op>, name: &str, cache: &mut HashMap<String, u16>) -> u16 {
|
||||||
|
if cache.contains_key(name) {
|
||||||
|
return *cache.get(name).unwrap()
|
||||||
|
}
|
||||||
|
let value = if let Ok(value) = name.parse::<u16>() {
|
||||||
|
return value
|
||||||
|
} else {
|
||||||
|
match wiring.get(name).unwrap() {
|
||||||
|
Op::And(lh, rh) => { solve(wiring, lh, cache) & solve(wiring, rh, cache) }
|
||||||
|
Op::Or(lh, rh) => { solve(wiring, lh, cache) | solve(wiring, rh, cache) }
|
||||||
|
Op::Not(op) => { !solve(wiring, op, cache) }
|
||||||
|
Op::Lshift(lh, rh) => { solve(wiring, lh, cache) << rh }
|
||||||
|
Op::Rshift(lh, rh) => { solve(wiring, lh, cache) >> rh }
|
||||||
|
Op::Value(v) => { solve(wiring, v, cache) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cache.insert(name.to_string(), value);
|
||||||
|
value
|
||||||
|
}
|
40
2015/src/bin/day8.rs
Normal file
40
2015/src/bin/day8.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use aoc::input;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lines = input::read_lines();
|
||||||
|
|
||||||
|
// Part 1
|
||||||
|
let mut used_mem = 0;
|
||||||
|
let mut num_chars = 0;
|
||||||
|
for line in &lines {
|
||||||
|
let chars = line.chars().collect::<Vec<char>>();
|
||||||
|
let line_mem = chars.len();
|
||||||
|
let mut line_num_chars = line_mem - 2;
|
||||||
|
let mut index = 1;
|
||||||
|
while index < line_mem - 1 {
|
||||||
|
if chars[index] == '\\' {
|
||||||
|
if chars[index + 1] == '"' || chars[index + 1] == '\\' {
|
||||||
|
line_num_chars -= 1;
|
||||||
|
index += 1;
|
||||||
|
} else if chars[index + 1] == 'x' {
|
||||||
|
line_num_chars -= 3;
|
||||||
|
index += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
used_mem += line_mem;
|
||||||
|
num_chars += line_num_chars;
|
||||||
|
}
|
||||||
|
println!("{} - {} = {}", used_mem, num_chars, used_mem - num_chars);
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
let mut encoded_size = used_mem;
|
||||||
|
for line in &lines {
|
||||||
|
for c in line.chars() {
|
||||||
|
if c == '\\' || c == '"' { encoded_size += 1 }
|
||||||
|
}
|
||||||
|
encoded_size += 2; // enclosing quotes
|
||||||
|
}
|
||||||
|
println!("{} - {} = {}", encoded_size, used_mem, encoded_size - used_mem);
|
||||||
|
}
|
118
2015/src/bin/day9.rs
Normal file
118
2015/src/bin/day9.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use aoc::input;
|
||||||
|
|
||||||
|
type Dists = HashMap<String, HashMap<String, u32>>;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lines = input::read_lines();
|
||||||
|
let mut places: HashSet<String> = HashSet::new();
|
||||||
|
let mut dists: Dists = HashMap::new();
|
||||||
|
for line in lines {
|
||||||
|
let parts = line.split_whitespace().collect::<Vec<&str>>();
|
||||||
|
let from = parts[0];
|
||||||
|
let to = parts[2];
|
||||||
|
let dist = parts[4].parse::<u32>().unwrap();
|
||||||
|
if !dists.contains_key(from) {
|
||||||
|
dists.insert(from.to_string(), HashMap::new());
|
||||||
|
}
|
||||||
|
if !dists.contains_key(to) {
|
||||||
|
dists.insert(to.to_string(), HashMap::new());
|
||||||
|
}
|
||||||
|
dists.get_mut(from).unwrap().insert(to.to_string(), dist);
|
||||||
|
dists.get_mut(to).unwrap().insert(from.to_string(), dist);
|
||||||
|
places.insert(from.to_string());
|
||||||
|
places.insert(to.to_string());
|
||||||
|
}
|
||||||
|
let path_len = places.len();
|
||||||
|
|
||||||
|
// Part 1
|
||||||
|
let mut min: u32 = u32::MAX;
|
||||||
|
for place in &places {
|
||||||
|
let shortest_dist =
|
||||||
|
find_shortest_path(&dists, &places, &mut vec![place.to_owned()], 0, path_len);
|
||||||
|
if shortest_dist < min {
|
||||||
|
min = shortest_dist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Shortest distance: {}", min);
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
let mut max: u32 = 0;
|
||||||
|
for place in &places {
|
||||||
|
let longest_dist =
|
||||||
|
find_longest_path(&dists, &places, &mut vec![place.to_owned()], 0, path_len);
|
||||||
|
if longest_dist > max {
|
||||||
|
max = longest_dist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Longest distance: {}", max);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_shortest_path(
|
||||||
|
dists: &Dists,
|
||||||
|
places: &HashSet<String>,
|
||||||
|
cur_path: &mut Vec<String>,
|
||||||
|
cur_dist: u32,
|
||||||
|
max_places: usize,
|
||||||
|
) -> u32 {
|
||||||
|
if cur_path.len() == max_places {
|
||||||
|
return cur_dist;
|
||||||
|
}
|
||||||
|
// get next unexplored places
|
||||||
|
let dists_from_here = dists.get(cur_path.last().unwrap()).unwrap();
|
||||||
|
let mut min: u32 = u32::MAX;
|
||||||
|
for next_place in places {
|
||||||
|
if cur_path.contains(next_place) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cur_path.push(next_place.to_string());
|
||||||
|
let next_place_dist = dists_from_here.get(next_place).unwrap();
|
||||||
|
let shortest_dist = find_shortest_path(
|
||||||
|
dists,
|
||||||
|
places,
|
||||||
|
cur_path,
|
||||||
|
cur_dist + next_place_dist,
|
||||||
|
max_places,
|
||||||
|
);
|
||||||
|
cur_path.pop();
|
||||||
|
if shortest_dist < min {
|
||||||
|
min = shortest_dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
min
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_longest_path(
|
||||||
|
dists: &Dists,
|
||||||
|
places: &HashSet<String>,
|
||||||
|
cur_path: &mut Vec<String>,
|
||||||
|
cur_dist: u32,
|
||||||
|
max_places: usize,
|
||||||
|
) -> u32 {
|
||||||
|
if cur_path.len() == max_places {
|
||||||
|
return cur_dist;
|
||||||
|
}
|
||||||
|
// get next unexplored places
|
||||||
|
let dists_from_here = dists.get(cur_path.last().unwrap()).unwrap();
|
||||||
|
let mut max: u32 = 0;
|
||||||
|
for next_place in places {
|
||||||
|
if cur_path.contains(next_place) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cur_path.push(next_place.to_string());
|
||||||
|
let next_place_dist = dists_from_here.get(next_place).unwrap();
|
||||||
|
let longest_dist = find_longest_path(
|
||||||
|
dists,
|
||||||
|
places,
|
||||||
|
cur_path,
|
||||||
|
cur_dist + next_place_dist,
|
||||||
|
max_places,
|
||||||
|
);
|
||||||
|
cur_path.pop();
|
||||||
|
if longest_dist > max {
|
||||||
|
max = longest_dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -25,7 +26,6 @@ def main():
|
||||||
input_text = fetch(input_url)
|
input_text = fetch(input_url)
|
||||||
create_files(input_text, args.day, args.year, args.lang)
|
create_files(input_text, args.day, args.year, args.lang)
|
||||||
webbrowser.open_new_tab(day_url)
|
webbrowser.open_new_tab(day_url)
|
||||||
webbrowser.open_new_tab(input_url)
|
|
||||||
|
|
||||||
def fetch(input_url):
|
def fetch(input_url):
|
||||||
response = requests.get(input_url, cookies={"session": SESSION_ID})
|
response = requests.get(input_url, cookies={"session": SESSION_ID})
|
||||||
|
|
Loading…
Reference in a new issue