mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Rewrite old code into 2018 style.
Nice test for my 2018 repo set up. Which turns out needs some tweaking.
This commit is contained in:
5
2016/.gitignore
vendored
5
2016/.gitignore
vendored
@@ -1,3 +1,2 @@
|
|||||||
*/solution
|
Cargo.lock
|
||||||
*/target
|
target
|
||||||
*/Cargo.lock
|
|
||||||
|
|||||||
7
2016/Cargo.toml
Normal file
7
2016/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "aoc-2016"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Bert Peters <bert@bertptrs.nl>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "2.32"
|
||||||
@@ -1 +0,0 @@
|
|||||||
R8, R4, R4, R8
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::env;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
fn dist(pos: (i32, i32)) -> i32
|
|
||||||
{
|
|
||||||
let (x, y) = pos;
|
|
||||||
|
|
||||||
return x.abs() + y.abs()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk(pos: (i32, i32), dir: i32) -> (i32, i32)
|
|
||||||
{
|
|
||||||
let backwards = if dir & 2 == 2 { -1 } else { 1 };
|
|
||||||
let (x, y) = pos;
|
|
||||||
|
|
||||||
(x + backwards * (1 - (dir & 1)), y + backwards * (dir & 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
let path = Path::new(&args[1]);
|
|
||||||
let display = path.display();
|
|
||||||
|
|
||||||
// Open the path in read-only mode, returns `io::Result<File>`
|
|
||||||
let mut file = match File::open(&path) {
|
|
||||||
// The `description` method of `io::Error` returns a string that
|
|
||||||
// describes the error
|
|
||||||
Err(why) => panic!("couldn't open {}: {}", display,
|
|
||||||
why.description()),
|
|
||||||
Ok(file) => file,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut content = String::new();
|
|
||||||
match file.read_to_string(&mut content) {
|
|
||||||
Err(why) => panic!("couldn't open {}: {}", display,
|
|
||||||
why.description()),
|
|
||||||
Ok(_) => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut pos = (0, 0);
|
|
||||||
let mut dir = 0;
|
|
||||||
let mut found = false;
|
|
||||||
|
|
||||||
let mut positions = HashSet::new();
|
|
||||||
positions.insert(pos);
|
|
||||||
|
|
||||||
for instruction in content.split(", ") {
|
|
||||||
let turn = &instruction[..1];
|
|
||||||
let steps_opt: Option<i32> = instruction[1..].trim().parse().ok();
|
|
||||||
let steps = match steps_opt {
|
|
||||||
Some(num) => num,
|
|
||||||
None => panic!("Could note parse number of steps"),
|
|
||||||
};
|
|
||||||
if turn == "R" {
|
|
||||||
dir += 1;
|
|
||||||
} else {
|
|
||||||
dir += 3;
|
|
||||||
}
|
|
||||||
dir %= 4;
|
|
||||||
|
|
||||||
for _ in 0..steps {
|
|
||||||
pos = walk(pos, dir);
|
|
||||||
if !found && positions.contains(&pos) {
|
|
||||||
println!("Visited twice at dist {}", dist(pos)) ;
|
|
||||||
found = true;
|
|
||||||
} else {
|
|
||||||
positions.insert(pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Total distance is {}", dist(pos));
|
|
||||||
}
|
|
||||||
63
2016/src/common.rs
Normal file
63
2016/src/common.rs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
/// Apply Erathostenes's sieve to the supplied array
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `dest` - the destination slice to fill with the sieve. This is
|
||||||
|
/// assumed to be filled with "true" before being handed to this
|
||||||
|
/// method.
|
||||||
|
pub fn prime_sieve(dest: &mut[bool]) {
|
||||||
|
if dest.len() >= 1 {
|
||||||
|
dest[0] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if dest.len() >= 2 {
|
||||||
|
dest[1] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let limit = (dest.len() as f64).sqrt() as usize;
|
||||||
|
|
||||||
|
for i in 1..(limit + 1) {
|
||||||
|
if !dest[i] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in ((i * i)..(dest.len())).step_by(i) {
|
||||||
|
dest[j] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solution trait
|
||||||
|
///
|
||||||
|
/// Every day's solution should implement this function so that it can
|
||||||
|
/// be easily run from the main program.
|
||||||
|
pub trait Solution {
|
||||||
|
/// Solve the first part of the day
|
||||||
|
fn part1(&mut self, input: &mut io::Read) -> String;
|
||||||
|
|
||||||
|
/// Solve the second part of the day
|
||||||
|
fn part2(&mut self, input: &mut io::Read) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_prime_sieve() {
|
||||||
|
let mut input = [true; 10];
|
||||||
|
prime_sieve(&mut input);
|
||||||
|
|
||||||
|
let output = [
|
||||||
|
false, false,
|
||||||
|
true, true,
|
||||||
|
false, true,
|
||||||
|
false, true,
|
||||||
|
false, false
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(output, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
112
2016/src/day1.rs
Normal file
112
2016/src/day1.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
use std::io;
|
||||||
|
use common;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
|
||||||
|
fn dist(pos: (i32, i32)) -> i32 {
|
||||||
|
let (x, y) = pos;
|
||||||
|
|
||||||
|
return x.abs() + y.abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Day1 {
|
||||||
|
pos: (i32, i32),
|
||||||
|
dir: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Day1 {
|
||||||
|
pub fn new() -> Day1 {
|
||||||
|
Day1{
|
||||||
|
pos: (0, 0),
|
||||||
|
dir: (0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk(&mut self) -> (i32, i32) {
|
||||||
|
let backwards = if self.dir & 2 == 2 { -1 } else { 1 };
|
||||||
|
let (x, y) = self.pos;
|
||||||
|
|
||||||
|
self.pos = (x + backwards * (1 - (self.dir & 1)), y + backwards * (self.dir & 1));
|
||||||
|
self.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
fn turn(&mut self, action: &str) {
|
||||||
|
if action == "R" {
|
||||||
|
self.dir += 1;
|
||||||
|
} else {
|
||||||
|
self.dir += 3;
|
||||||
|
}
|
||||||
|
self.dir %= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl common::Solution for Day1 {
|
||||||
|
fn part1(&mut self, input: &mut io::Read) -> String {
|
||||||
|
let mut content = String::new();
|
||||||
|
match input.read_to_string(&mut content) {
|
||||||
|
Err(why) => panic!("couldn't open input: {}", why.description()),
|
||||||
|
Ok(_) => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
for instruction in content.split(", ") {
|
||||||
|
let turn = &instruction[..1];
|
||||||
|
let steps: i32 = instruction[1..].trim().parse().expect("Invalid number of steps");
|
||||||
|
self.turn(turn);
|
||||||
|
|
||||||
|
for _ in 0..steps {
|
||||||
|
self.walk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format!("{}", dist(self.pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(&mut self, input: &mut io::Read) -> String {
|
||||||
|
let mut content = String::new();
|
||||||
|
match input.read_to_string(&mut content) {
|
||||||
|
Err(why) => panic!("couldn't open input: {}", why.description()),
|
||||||
|
Ok(_) => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut positions = HashSet::new();
|
||||||
|
positions.insert(self.pos);
|
||||||
|
|
||||||
|
for instruction in content.split(", ") {
|
||||||
|
let turn = &instruction[..1];
|
||||||
|
let steps: i32 = instruction[1..].trim().parse().expect("Invalid number of steps");
|
||||||
|
self.turn(turn);
|
||||||
|
|
||||||
|
for _ in 0..steps {
|
||||||
|
let pos = self.walk();
|
||||||
|
if positions.contains(&pos) {
|
||||||
|
return format!("{}", dist(pos))
|
||||||
|
} else {
|
||||||
|
positions.insert(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Never visited anything twice!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Day1;
|
||||||
|
use common::Solution;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part1() {
|
||||||
|
let mut instance = Day1::new();
|
||||||
|
|
||||||
|
assert_eq!("8", instance.part1(&mut "R8, R4, R4, R8".as_bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part2() {
|
||||||
|
let mut instance = Day1::new();
|
||||||
|
|
||||||
|
assert_eq!("4", instance.part2(&mut "R8, R4, R4, R8".as_bytes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
65
2016/src/main.rs
Normal file
65
2016/src/main.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
extern crate clap;
|
||||||
|
use clap::{Arg, App};
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub mod common;
|
||||||
|
pub mod day1;
|
||||||
|
|
||||||
|
fn get_impl(day: i32) -> Box<common::Solution> {
|
||||||
|
match day {
|
||||||
|
1 => { Box::new(day1::Day1::new()) }
|
||||||
|
_ => {
|
||||||
|
panic!("Unimplemented day {}", day)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let matches = App::new("Advent of Code")
|
||||||
|
.version("2016")
|
||||||
|
.author("Bert Peters <bert@bertptrs.nl>")
|
||||||
|
.arg(Arg::with_name("day")
|
||||||
|
.value_name("DAY")
|
||||||
|
.help("Number of the day to execute")
|
||||||
|
.required(true)
|
||||||
|
.takes_value(true))
|
||||||
|
.arg(Arg::with_name("part2")
|
||||||
|
.short("2")
|
||||||
|
.help("Whether to run part 2")
|
||||||
|
.long("part2"))
|
||||||
|
.arg(Arg::with_name("input")
|
||||||
|
.short("i")
|
||||||
|
.long("input")
|
||||||
|
.help("Optional input file, stdin otherwise")
|
||||||
|
.takes_value(true))
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
let day: i32 = (&matches.value_of("day").unwrap()).parse()
|
||||||
|
.expect("Invalid int");
|
||||||
|
let mut implementation = get_impl(day);
|
||||||
|
let mut data: Box<io::Read> = match matches.value_of("input") {
|
||||||
|
Some(filename) => { Box::new(fs::File::open(filename).unwrap()) }
|
||||||
|
None => { Box::new(io::stdin()) }
|
||||||
|
};
|
||||||
|
|
||||||
|
if matches.is_present("part2") {
|
||||||
|
println!("{}", implementation.part2(&mut data));
|
||||||
|
} else {
|
||||||
|
println!("{}", implementation.part1(&mut data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_impl() {
|
||||||
|
// Verify that we can load all days
|
||||||
|
let last_implemented = 1;
|
||||||
|
for d in 1..(last_implemented + 1) {
|
||||||
|
get_impl(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user