Compare commits

..

1 commit

Author SHA1 Message Date
df219182e8 day12 2020-05-14 23:35:15 +02:00
16 changed files with 78 additions and 1768 deletions

32
Cargo.lock generated
View file

@ -3,35 +3,3 @@
[[package]]
name = "aoc2019"
version = "0.1.0"
dependencies = [
"ncurses",
]
[[package]]
name = "cc"
version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
[[package]]
name = "libc"
version = "0.2.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
[[package]]
name = "ncurses"
version = "5.99.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15699bee2f37e9f8828c7b35b2bc70d13846db453f2d507713b758fabe536b82"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "pkg-config"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"

View file

@ -4,8 +4,7 @@ version = "0.1.0"
authors = ["Stefan Schwarz <stefan@f2o.io>"]
edition = "2018"
[dependencies]
ncurses = "5.99.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "day1"
@ -39,22 +38,6 @@ path = "src/day9/main.rs"
name = "day10"
path = "src/day10/main.rs"
[[bin]]
name = "day11"
path = "src/day11/main.rs"
[[bin]]
name = "day12"
path = "src/day12/main.rs"
[[bin]]
name = "day13"
path = "src/day13/main.rs"
[[bin]]
name = "day14"
path = "src/day14/main.rs"
[[bin]]
name = "day15"
path = "src/day15/main.rs"

View file

@ -1 +0,0 @@
# Advent of Code 2019

View file

@ -1 +0,0 @@
3,8,1005,8,320,1106,0,11,0,0,0,104,1,104,0,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,1,10,4,10,102,1,8,29,2,1005,1,10,1006,0,11,3,8,1002,8,-1,10,101,1,10,10,4,10,108,0,8,10,4,10,102,1,8,57,1,8,15,10,1006,0,79,1,6,3,10,3,8,102,-1,8,10,101,1,10,10,4,10,108,0,8,10,4,10,101,0,8,90,2,103,18,10,1006,0,3,2,105,14,10,3,8,102,-1,8,10,1001,10,1,10,4,10,108,0,8,10,4,10,101,0,8,123,2,9,2,10,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,1001,8,0,150,1,2,2,10,2,1009,6,10,1,1006,12,10,1006,0,81,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,102,1,8,187,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,0,10,4,10,101,0,8,209,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,231,1,1008,11,10,1,1001,4,10,2,1104,18,10,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,1001,8,0,264,1,8,14,10,1006,0,36,3,8,1002,8,-1,10,1001,10,1,10,4,10,108,0,8,10,4,10,101,0,8,293,1006,0,80,1006,0,68,101,1,9,9,1007,9,960,10,1005,10,15,99,109,642,104,0,104,1,21102,1,846914232732,1,21102,1,337,0,1105,1,441,21102,1,387512115980,1,21101,348,0,0,1106,0,441,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,21102,209533824219,1,1,21102,1,395,0,1106,0,441,21101,0,21477985303,1,21102,406,1,0,1106,0,441,3,10,104,0,104,0,3,10,104,0,104,0,21101,868494234468,0,1,21101,429,0,0,1106,0,441,21102,838429471080,1,1,21102,1,440,0,1106,0,441,99,109,2,21201,-1,0,1,21101,0,40,2,21102,472,1,3,21101,0,462,0,1106,0,505,109,-2,2106,0,0,0,1,0,0,1,109,2,3,10,204,-1,1001,467,468,483,4,0,1001,467,1,467,108,4,467,10,1006,10,499,1102,1,0,467,109,-2,2106,0,0,0,109,4,2101,0,-1,504,1207,-3,0,10,1006,10,522,21101,0,0,-3,21202,-3,1,1,22101,0,-2,2,21102,1,1,3,21102,541,1,0,1106,0,546,109,-4,2105,1,0,109,5,1207,-3,1,10,1006,10,569,2207,-4,-2,10,1006,10,569,22102,1,-4,-4,1105,1,637,22102,1,-4,1,21201,-3,-1,2,21202,-2,2,3,21102,588,1,0,1105,1,546,22101,0,1,-4,21102,1,1,-1,2207,-4,-2,10,1006,10,607,21101,0,0,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,629,21201,-1,0,1,21102,629,1,0,105,1,504,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2105,1,0

File diff suppressed because one or more lines are too long

56
input14
View file

@ -1,56 +0,0 @@
18 FHWM => 1 XGQNZ
4 FVPWN, 9 CQGW => 7 QGHT
22 KZMS, 1 DMCJL => 8 TWGCK
1 LMGQN, 1 DSWDM, 1 GKGZ => 1 TGPH
22 WCSW => 1 LVTG
13 JSWR => 4 GKGZ
162 ORE => 3 FVPWN
59 CQGW, 15 MSNG, 6 XGKRF, 10 LJRQ, 1 HRKGV, 15 RKVC => 1 FUEL
5 DMCJL => 1 QBLH
2 XDRJ, 2 RKVC => 8 CTCNL
1 QXHX => 5 GFPSK
22 QGHT, 6 GFPSK, 5 DHTPL => 3 CSDR
4 QGHT, 2 HFXD => 4 XDRJ
10 WQCGV, 1 JSWR, 21 RHTLN => 7 VTPC
11 CQGW, 1 FVPWN => 3 HFXD
5 VTPC => 2 NCXW
8 LDZVS => 6 DQLH
117 ORE => 2 KWZNB
3 TGPH, 1 JPFQ, 2 WHWLK, 5 RKVC, 16 DQLH => 9 LJRQ
14 KWZNB, 2 CQGW => 8 MLPK
6 LDZVS => 2 JSWR
1 RKVC, 8 HCGT, 9 DHTPL => 6 FHWM
3 DHTPL, 1 HWSR, 36 LDZVS => 6 DSWDM
5 WHWLK, 1 LJHWT, 8 HSTHS => 7 VMPX
22 ZJCDZ, 3 WQCGV => 5 DHTPL
10 LJHWT, 32 GFPSK, 2 RHTLN => 4 HFRMP
2 FKVD, 3 TWGCK, 1 HWSR => 1 RNLZW
2 CSDR, 3 DQLH, 2 HSTHS => 9 JPFQ
1 JSWR, 1 PCWS, 1 HFRMP => 3 XGKRF
2 QGHT, 9 LVTG, 3 QBLH => 7 RHTLN
10 LJHWT, 4 CTCNL => 8 QXHX
16 MLPK, 1 HFXD => 9 ZJCDZ
6 QGHT => 9 WCSW
4 HWSR, 4 MLPK, 1 KZMS => 3 BGZHQ
12 MLPK => 8 RKVC
1 HWSR, 1 VNWFS => 7 BGFJ
7 FHWM, 11 CTDF, 1 LDZVS => 2 VNWFS
4 CTDF => 4 HSTHS
2 ZJCDZ => 6 LJHWT
1 VMPX, 1 NCXW, 1 HSTHS, 41 XGKRF, 30 HLNG, 1 GKGZ => 7 HRKGV
1 XGQNZ, 10 PCWS, 3 BGFJ => 8 FKVD
1 GFPSK, 1 DMCJL, 1 LVTG => 5 XDTZB
3 WCSW => 5 KZMS
6 TWGCK, 1 QXHX, 4 BGFJ => 2 LMGQN
1 WCSW => 7 LDZVS
1 XDTZB, 9 VNWFS => 3 WHWLK
3 HFXD, 4 WCSW, 1 MLPK => 5 WQCGV
2 BGFJ, 1 HSTHS, 22 MDCB, 10 HWSR, 6 RNLZW, 8 GKGZ => 5 MSNG
4 QGHT, 1 FKVD => 7 MDCB
9 MLPK, 3 LJHWT => 7 DMCJL
121 ORE => 2 CQGW
9 DHTPL, 2 BGZHQ => 8 CTDF
2 JSWR, 30 RHTLN => 7 HLNG
2 QBLH => 7 PCWS
14 LVTG => 8 HWSR
7 DMCJL => 1 HCGT

View file

@ -1 +0,0 @@
3,1033,1008,1033,1,1032,1005,1032,31,1008,1033,2,1032,1005,1032,58,1008,1033,3,1032,1005,1032,81,1008,1033,4,1032,1005,1032,104,99,1002,1034,1,1039,102,1,1036,1041,1001,1035,-1,1040,1008,1038,0,1043,102,-1,1043,1032,1,1037,1032,1042,1106,0,124,1002,1034,1,1039,1001,1036,0,1041,1001,1035,1,1040,1008,1038,0,1043,1,1037,1038,1042,1105,1,124,1001,1034,-1,1039,1008,1036,0,1041,1001,1035,0,1040,1002,1038,1,1043,101,0,1037,1042,1105,1,124,1001,1034,1,1039,1008,1036,0,1041,102,1,1035,1040,1001,1038,0,1043,101,0,1037,1042,1006,1039,217,1006,1040,217,1008,1039,40,1032,1005,1032,217,1008,1040,40,1032,1005,1032,217,1008,1039,1,1032,1006,1032,165,1008,1040,9,1032,1006,1032,165,1102,1,2,1044,1105,1,224,2,1041,1043,1032,1006,1032,179,1102,1,1,1044,1106,0,224,1,1041,1043,1032,1006,1032,217,1,1042,1043,1032,1001,1032,-1,1032,1002,1032,39,1032,1,1032,1039,1032,101,-1,1032,1032,101,252,1032,211,1007,0,35,1044,1106,0,224,1101,0,0,1044,1105,1,224,1006,1044,247,102,1,1039,1034,1002,1040,1,1035,1002,1041,1,1036,102,1,1043,1038,101,0,1042,1037,4,1044,1105,1,0,1,5,41,19,22,1,39,81,29,20,15,82,33,18,45,30,32,55,28,26,70,13,56,32,28,18,3,59,90,11,95,15,85,8,61,25,59,24,34,1,85,5,25,54,57,18,20,54,80,91,28,65,36,12,44,36,13,92,24,56,13,39,69,29,79,10,41,27,23,25,72,20,3,61,15,51,11,12,12,48,10,45,13,29,49,90,30,17,9,41,21,18,7,30,48,17,83,71,4,10,31,10,96,81,77,9,50,39,21,36,33,72,12,3,23,79,18,4,75,17,58,64,8,7,97,60,72,72,1,94,55,42,2,94,2,21,88,19,82,57,96,19,25,27,41,62,15,40,23,61,86,27,73,61,13,46,52,81,12,34,23,73,23,59,1,30,47,9,99,10,37,17,28,98,5,92,73,8,63,4,86,76,79,7,30,68,28,91,12,12,98,74,4,22,44,10,23,45,37,16,90,76,23,74,75,12,21,38,14,15,76,28,49,71,7,6,6,71,53,33,12,87,15,92,66,21,38,13,53,92,34,49,25,6,67,21,27,89,24,61,25,30,41,30,99,28,19,41,90,51,74,14,33,54,48,10,14,42,2,67,76,10,21,2,67,43,27,69,11,16,78,7,36,9,24,48,63,81,53,29,94,34,25,99,66,47,17,97,33,52,11,62,22,52,30,23,89,95,15,13,50,48,26,10,6,69,78,13,6,94,1,28,67,10,70,16,50,19,24,15,79,50,27,3,19,62,4,31,83,20,17,83,67,5,80,26,36,62,87,3,10,80,22,65,60,10,78,4,20,60,30,11,7,83,10,13,72,81,37,22,14,55,63,51,27,32,77,52,20,50,16,48,2,55,10,53,26,84,6,87,43,37,26,3,85,62,25,78,50,16,10,37,22,54,5,80,24,7,32,49,18,27,12,41,70,82,20,34,91,15,98,77,22,6,79,3,8,54,17,32,4,44,2,97,14,15,65,30,97,14,79,75,11,77,5,61,37,20,91,20,45,74,19,40,2,41,89,12,34,44,18,62,57,17,68,22,96,7,59,63,2,60,70,2,26,75,26,3,53,19,80,16,97,7,34,58,52,66,24,75,25,30,75,42,13,12,89,13,3,84,92,1,75,30,54,43,2,56,15,1,15,84,99,6,98,42,17,29,1,18,26,70,71,29,91,23,21,87,66,18,38,32,18,81,65,2,58,99,12,4,84,24,32,88,30,67,49,29,59,64,18,70,10,24,56,5,27,97,50,4,28,85,65,16,67,83,15,16,61,18,86,8,36,25,36,29,97,45,19,81,41,29,45,30,69,26,57,93,27,72,34,30,99,61,2,48,16,12,76,98,28,14,32,32,90,48,10,30,57,23,39,2,8,39,33,13,88,34,31,74,15,60,8,47,60,31,5,79,1,98,86,33,3,99,33,62,11,96,25,22,38,98,84,3,56,70,49,3,8,56,87,4,29,59,65,26,34,77,7,14,78,26,25,70,49,3,31,45,92,24,95,17,4,9,4,96,64,92,27,67,4,99,6,44,7,16,86,2,75,1,6,68,81,4,1,44,49,7,92,8,40,36,25,81,13,56,99,10,2,30,72,6,43,30,12,43,93,19,20,23,95,10,19,66,63,28,96,40,50,8,15,56,38,13,93,42,71,12,18,87,8,4,21,85,9,2,66,77,10,80,26,61,9,43,20,88,10,39,67,55,31,49,17,58,26,80,20,84,54,49,5,73,11,52,15,63,7,62,24,57,92,61,25,87,56,37,31,38,14,99,0,0,21,21,1,10,1,0,0,0,0,0,0

View file

@ -1,3 +1,4 @@
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{BufRead, BufReader};
@ -45,6 +46,18 @@ impl Sub for &XY {
}
}
impl PartialOrd for XY {
fn partial_cmp(&self, other: &XY) -> Option<Ordering> {
self.angle().partial_cmp(&other.angle())
}
}
impl Ord for XY {
fn cmp(&self, other: &XY) -> Ordering {
self.angle().partial_cmp(&other.angle()).unwrap()
}
}
impl XY {
fn direction(&self) -> Self {
let d = gcd(self.y, self.x).abs();
@ -75,17 +88,20 @@ impl XY {
}
struct MonitoringStation {
map: Vec<XY>,
map: HashMap<XY, Position>,
}
impl MonitoringStation {
fn laser(&self, root: &XY, skip: usize, n: usize) -> Vec<XY> {
let mut map: HashMap<XY, Vec<&XY>> = HashMap::new();
let mut map: HashMap<XY, Vec<XY>> = HashMap::new();
// collect vec for each direction
map = self
.map
.iter()
.filter_map(|xy| {
.filter_map(|(xy, pos)| {
if *pos == Position::Empty {
return None;
}
if xy == root {
return None;
}
@ -93,7 +109,7 @@ impl MonitoringStation {
Some((xy, rel.direction()))
})
.fold(map, |mut acc, (xy, dir)| {
acc.entry(dir).or_insert(vec![]).push(xy);
acc.entry(dir).or_insert(vec![]).push(xy.clone());
acc
});
@ -106,9 +122,8 @@ impl MonitoringStation {
// lets iterate over sorted angles
let mut angles = map.keys().cloned().collect::<Vec<XY>>();
angles.sort_by(|a, b| a.angle().partial_cmp(&b.angle()).unwrap());
angles.sort();
// cycle around and return first element of each vec
angles
.iter()
.cycle()
@ -125,21 +140,23 @@ impl MonitoringStation {
.flatten()
.skip(skip)
.take(n)
.cloned()
.collect::<Vec<XY>>()
}
fn find(&self) -> (usize, XY) {
let best = (0, &XY::from((0, 0)));
let best = self
.map
let best = (0, XY::from((0, 0)));
self.map
.iter()
.map(|root| {
.filter(|(_, pos)| **pos == Position::Astroid)
.map(|(root, _)| {
let insight = self
.map
.iter()
// get direction to any of the astroids
.filter_map(|xy| {
.filter_map(|(xy, pos)| {
if *pos == Position::Empty {
return None;
}
let rel = xy - root;
Some(rel.direction())
})
@ -152,17 +169,12 @@ impl MonitoringStation {
- 1;
(insight, root)
})
.fold(
best,
|acc, astroid| {
if astroid.0 > acc.0 {
astroid
} else {
acc
}
},
);
(best.0, best.1.clone())
.fold(best, |acc, astroid| {
if astroid.0 > acc.0 {
return (astroid.0, astroid.1.clone());
}
acc
})
}
}
@ -171,22 +183,25 @@ where
T: BufRead,
{
fn from(reader: T) -> Self {
let map: HashMap<XY, Position> = HashMap::new();
let map = reader
.split(b'\n')
.enumerate()
.flat_map(|(y, line)| {
line.unwrap()
.into_iter()
.iter()
.enumerate()
.filter_map(move |(x, c)| {
.map(|(x, c)| {
let xy = XY::from((x, y));
match Position::from(&c) {
Position::Astroid => Some(xy),
Position::Empty => None,
}
let p = Position::from(c);
(xy, p)
})
.collect::<Vec<(XY, Position)>>()
})
.collect::<Vec<XY>>();
.fold(map, |mut map, (xy, p)| {
map.insert(xy.clone(), p.clone());
map
});
MonitoringStation { map }
}
}

View file

@ -1,186 +0,0 @@
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use aoc2019::intcode;
#[derive(Hash, Default, PartialEq, Eq, Clone)]
struct Panel {
x: isize,
y: isize,
}
enum Color {
Black,
White,
}
impl From<isize> for Color {
fn from(color: isize) -> Self {
match color {
0 => Color::Black,
1 => Color::White,
_ => panic!("invalid color"),
}
}
}
impl Into<isize> for &Color {
fn into(self) -> isize {
match self {
Color::Black => 0,
Color::White => 1,
}
}
}
impl Color {
fn char(&self) -> char {
match self {
Color::Black => ' ',
Color::White => '\u{2588}',
}
}
}
enum Direction {
Up,
Down,
Left,
Right,
}
enum Turn {
Left,
Right,
}
impl From<isize> for Turn {
fn from(turn: isize) -> Self {
match turn {
0 => Turn::Left,
1 => Turn::Right,
_ => panic!("invalid turn direction"),
}
}
}
struct Robot {
panel: Panel,
direction: Direction,
}
impl Robot {
fn turn(&mut self, direction: Turn) {
self.direction = match self.direction {
Direction::Up => match direction {
Turn::Left => Direction::Left,
Turn::Right => Direction::Right,
},
Direction::Right => match direction {
Turn::Left => Direction::Up,
Turn::Right => Direction::Down,
},
Direction::Down => match direction {
Turn::Left => Direction::Right,
Turn::Right => Direction::Left,
},
Direction::Left => match direction {
Turn::Left => Direction::Down,
Turn::Right => Direction::Up,
},
}
}
fn step(&mut self) {
self.panel = match self.direction {
Direction::Up => Panel {
x: self.panel.x,
y: self.panel.y + 1,
},
Direction::Left => Panel {
x: self.panel.x + 1,
y: self.panel.y,
},
Direction::Down => Panel {
x: self.panel.x,
y: self.panel.y - 1,
},
Direction::Right => Panel {
x: self.panel.x - 1,
y: self.panel.y,
},
}
}
}
fn main() -> io::Result<()> {
let filename = env::args().nth(1).expect("provide file as first param");
let mut computer = intcode::Computer::from(File::open(filename)?);
let mut canvas: HashMap<Panel, Color> = HashMap::new();
canvas.insert(Panel { x: 0, y: 0 }, Color::White);
let mut robot = Robot {
panel: Panel::default(),
direction: Direction::Up,
};
let mut input: isize = canvas
.get(&robot.panel)
.or_else(|| Some(&Color::Black))
.unwrap()
.into();
while let Some(output) = computer.run_io(input) {
canvas.insert(robot.panel.clone(), Color::from(output));
let output = computer.run_must_output();
robot.turn(Turn::from(output));
robot.step();
input = canvas
.get(&robot.panel)
.or_else(|| Some(&Color::Black))
.unwrap()
.into();
}
let mut xmin: isize = 0;
let mut xmax: isize = 0;
let mut ymin: isize = 0;
let mut ymax: isize = 0;
let painted = canvas
.iter()
.map(|(k, _)| {
if k.x < xmin {
xmin = k.x;
}
if k.x > xmax {
xmax = k.x;
}
if k.y < ymin {
ymin = k.y;
}
if k.y > ymax {
ymax = k.y;
}
})
.count();
println!("painted: {}", painted);
println!("canvas: x:{}-{} y:{}-{}", xmin, xmax, ymin, ymax);
for y in (ymin..=ymax).rev() {
for x in (xmin..=xmax).rev() {
print!(
"{}",
canvas
.get(&Panel { x, y })
.unwrap_or_else(|| &Color::Black)
.char()
)
}
println!()
}
Ok(())
}

View file

@ -1,10 +1,7 @@
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
#[derive(PartialEq, Debug, Default, Clone, Hash)]
#[derive(PartialEq, Debug, Default)]
struct Object {
x: isize,
y: isize,
@ -48,33 +45,19 @@ impl Object {
}
struct Space {
iteration: u128,
moons: Vec<Object>,
velocy: Vec<Object>,
}
impl From<Vec<Object>> for Space {
fn from(moons: Vec<Object>) -> Self {
let iteration = 0;
let velocy = Vec::from_iter((0..moons.len()).map(|_| Object::default()));
Space {
iteration,
moons,
velocy,
}
}
}
impl Hash for Space {
fn hash<H: Hasher>(&self, state: &mut H) {
self.moons.iter().for_each(|m| m.hash(state));
self.velocy.iter().for_each(|v| v.hash(state));
Space { moons, velocy }
}
}
impl Space {
fn step(&mut self) {
self.iteration += 1;
fn step(&mut self) -> impl Iterator<Item = (&'_ Object, &'_ Object, usize)> {
let moons: &mut Vec<Object> = self.moons.as_mut();
let velocy: &mut Vec<Object> = self.velocy.as_mut();
@ -90,148 +73,26 @@ impl Space {
.iter_mut()
.enumerate()
.for_each(|(idx, m)| m.apply(velocy.get(idx).unwrap()));
}
fn status(&self) -> impl Iterator<Item = (&'_ Object, &'_ Object)> {
self.moons
.iter()
.zip(self.velocy.iter())
.map(|(a, b)| (a, b))
}
fn iteration(&self) -> u128 {
return self.iteration;
}
fn hashed(&self) -> u64 {
let mut hash = DefaultHasher::new();
self.hash(&mut hash);
hash.finish()
}
fn reapeats(mut self) -> u128 {
let mut known: HashMap<u64, u128> = HashMap::new();
loop {
println!("a lot");
known.insert(self.hashed(), self.iteration());
// 4686774924
for _ in 0..10000000 {
self.step();
if let Some(iteration) = known.get(&self.hashed()) {
let ago = self.iteration() - iteration;
return ago;
}
}
}
}
}
#[derive(Eq, PartialEq, Clone)]
struct Axis {
p: isize,
}
impl From<isize> for Axis {
fn from(p: isize) -> Self {
Axis { p }
}
}
impl Axis {
fn attract(&self, other: &Axis, v: &mut Axis) {
v.p += Axis::cmp(self.p, other.p);
}
fn apply(&mut self, v: &Axis) {
self.p += v.p;
}
fn cmp(a: isize, b: isize) -> isize {
match b.cmp(&a) {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
}
}
fn energy(&self) -> usize {
return self.p.abs() as usize;
}
}
struct AxisSpace {
iteration: usize,
moons: Vec<Axis>,
velocy: Vec<Axis>,
}
impl From<Vec<isize>> for AxisSpace {
fn from(moons: Vec<isize>) -> Self {
let iteration = 0;
let moons = Vec::from_iter(moons.iter().map(|i| Axis::from(*i)));
let velocy = Vec::from_iter((0..moons.len()).map(|_| Axis::from(0)));
AxisSpace {
iteration,
moons,
velocy,
}
}
}
impl AxisSpace {
fn step(&mut self) {
self.iteration += 1;
let moons: &mut Vec<Axis> = self.moons.as_mut();
let velocy: &mut Vec<Axis> = self.velocy.as_mut();
moons.iter().enumerate().for_each(|(idx, a)| {
moons.iter().for_each(|b| {
if a == b {
return;
}
a.attract(&b, &mut velocy[idx])
})
});
moons
.iter_mut()
.enumerate()
.for_each(|(idx, m)| m.apply(velocy.get(idx).unwrap()));
.iter()
.zip(velocy.iter())
.map(|(a, b)| (a, b, a.energy() * b.energy()))
}
fn iteration(&self) -> usize {
return self.iteration;
}
fn reapeats(mut self) -> usize {
let want = self.moons.clone();
self.step();
while self.moons != want {
self.step();
}
return self.iteration() + 1;
}
}
fn gcd(x: usize, y: usize) -> usize {
let mut x = x;
let mut y = y;
while y != 0 {
let t = y;
y = x % y;
x = t;
}
x
}
fn lcm(a: usize, b: usize) -> usize {
a * b / gcd(a, b)
}
fn lcm3(a: usize, b: usize, c: usize) -> usize {
lcm(a, lcm(b, c))
}
fn main() {
// part1
let moons = vec![
Object::from((-1, 0, 2)),
Object::from((2, -10, -7)),
Object::from((4, -8, 8)),
Object::from((3, 5, -1)),
];
let moons = vec![
Object::from((-8, -10, 0)),
Object::from((5, 5, 10)),
Object::from((2, -7, 3)),
Object::from((9, -8, -3)),
];
let moons = vec![
Object::from((17, 5, 1)),
Object::from((-2, -8, 8)),
@ -239,94 +100,23 @@ fn main() {
Object::from((1, -10, 4)),
];
let mut space = Space::from(moons);
let mut step_energy = 0;
let mut total_energy = 0;
(1..=100).for_each(|_i| {
(1..=10).for_each(|_| {
space.step();
(1..=9).for_each(|_| {
space.step().count();
});
step_energy = space
.status()
.map(|(o, v)| o.energy() * v.energy())
.fold(0, |mut acc, c| {
acc += c;
acc
});
});
println!("energy: {}", step_energy);
// part2
let xspace = AxisSpace::from(vec![-1, 2, 4, 3]);
let yspace = AxisSpace::from(vec![0, -10, -8, 5]);
let zspace = AxisSpace::from(vec![2, -7, 8, -1]);
let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats());
println!("matching space found {} iterations ago", total);
let xspace = AxisSpace::from(vec![-8, 5, 2, 9]);
let yspace = AxisSpace::from(vec![-10, 5, -7, -8]);
let zspace = AxisSpace::from(vec![0, 10, 3, -3]);
let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats());
println!("matching space found {} iterations ago", total);
let xspace = AxisSpace::from(vec![17, -2, 7, 1]);
let yspace = AxisSpace::from(vec![5, -8, -6, -10]);
let zspace = AxisSpace::from(vec![1, 8, 14, 4]);
let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats());
println!("matching space found {} iterations ago", total);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn day12example1() {
let space = Space::from(vec![
Object::from((-1, 0, 2)),
Object::from((2, -10, -7)),
Object::from((4, -8, 8)),
Object::from((3, 5, -1)),
]);
assert!(space.status().eq(vec![
(&Object::from((-1, 0, 2)), &Object::default()),
(&Object::from((2, -10, -7)), &Object::from((0, 0, 0))),
(&Object::from((4, -8, 8)), &Object::from((0, 0, 0))),
(&Object::from((3, 5, -1)), &Object::from((0, 0, 0))),
]));
}
#[test]
fn day12part1() {
let mut space = Space::from(vec![
Object::from((17, 5, 1)),
Object::from((-2, -8, 8)),
Object::from((7, -6, 14)),
Object::from((1, -10, 4)),
]);
(1..=1000).for_each(|_| {
space.step();
});
let energy = space
.status()
.map(|(o, v)| {
let step_energy = space
.step()
.map(|(o, v, e)| {
println!("{:?} {:?}", o, v);
o.energy() * v.energy()
e
})
.fold(0, |mut acc, c| {
acc += c;
acc
});
assert_eq!(energy, 9876)
}
#[test]
fn day12example2() {
let space = Space::from(vec![
Object::from((-1, 0, 2)),
Object::from((2, -10, -7)),
Object::from((4, -8, 8)),
Object::from((3, 5, -1)),
]);
assert_eq!(space.reapeats(), 2772)
}
total_energy += step_energy;
println!("total:{}, stepe:{}", total_energy, step_energy)
})
}

View file

@ -1,135 +0,0 @@
use aoc2019::intcode;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use ncurses;
fn main() -> Result<(), Box<dyn Error>> {
let f = File::open("input13")?;
let mut computer = intcode::Computer::from(f);
let mut grid: Grid = HashMap::new();
while let Some(output) = computer.run_until_n_output(3) {
let mut output = output.into_iter();
let xy = XY {
x: output.next().unwrap(),
y: output.next().unwrap(),
};
let tile = Tile::from(output.next().unwrap());
grid.insert(xy, tile);
}
// part 1
let blocks = grid.iter().filter(|(_, v)| **v == Tile::Block).count();
println!("blocks: {}", blocks);
// part2
ncurses::initscr();
ncurses::noecho();
let mut computer = computer.clone_with_modified_program(vec![(0, 2)]);
let mut paddlex = 0;
let mut score = 0;
while !computer.halted {
if let Some(output) = &computer.run_until_input() {
output.chunks(3).for_each(|c| {
if let &[x, y, value] = c {
if x == -1 && y == 0 {
score = value;
} else {
let tile = Tile::from(value);
if Tile::from(value) == Tile::HorizontalPaddle {
paddlex = x;
}
ncurses::mvprintw((y + 1) as i32, x as i32, tile.char());
}
}
});
}
let np = next_pos(&mut computer.clone());
ncurses::mvprintw(
0,
0,
&format!(
"willx: {:0>2} paddlex: {:0>2} score: {:0>7}",
np, paddlex, score
),
);
let joystick = match np.cmp(&paddlex) {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
};
computer.push_input_and_step(joystick);
ncurses::refresh();
}
ncurses::endwin();
println!("score: {}", score);
Ok(())
}
fn next_pos(computer: &mut intcode::Computer) -> isize {
while !computer.halted {
if let Some(output) = computer.run_until_input() {
for c in output.chunks(3) {
if let &[x, y, value] = c {
if x == -1 && y == 0 {
// skip score
} else if Tile::from(value) == Tile::Ball && y == 23 {
return x;
}
}
}
}
computer.push_input_and_step(0);
}
0
}
#[derive(Eq, PartialEq)]
enum Tile {
Empty,
Wall,
Block,
HorizontalPaddle,
Ball,
}
impl From<isize> for Tile {
fn from(i: isize) -> Self {
match i {
0 => Tile::Empty,
1 => Tile::Wall,
2 => Tile::Block,
3 => Tile::HorizontalPaddle,
4 => Tile::Ball,
_ => unreachable!("there are only 5 tiles..."),
}
}
}
impl Tile {
fn char(&self) -> &str {
match self {
Tile::Empty => " ",
Tile::Wall => "X",
Tile::Block => "O",
Tile::HorizontalPaddle => "-",
Tile::Ball => "*",
}
}
}
#[derive(Eq, PartialEq, Hash)]
struct XY {
x: isize,
y: isize,
}
impl From<(isize, isize)> for XY {
fn from(xy: (isize, isize)) -> Self {
XY { x: xy.0, y: xy.1 }
}
}
type Grid = HashMap<XY, Tile>;

View file

@ -1,385 +0,0 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use std::convert::*;
use std::fs::File;
use std::io::{BufRead, BufReader};
type Resource = String;
type Pipeline = HashMap<Resource, ResourceBuilder>;
#[derive(Debug)]
struct ResourceBuilder {
requirements: Vec<Resource>,
out_count: usize,
}
impl From<(Vec<Resource>, usize)> for ResourceBuilder {
fn from(build: (Vec<Resource>, usize)) -> Self {
ResourceBuilder {
requirements: build.0,
out_count: build.1,
}
}
}
#[derive(Default, Debug)]
struct NanoFactory {
pipeline: Pipeline,
ordered: Vec<Resource>,
}
#[derive(Debug)]
enum NanoFactoryBuildState {
InputCount,
InputResource,
OutputArrow,
OutputCount,
OutputResource,
}
impl NanoFactory {
/// sort resources
fn resolve_order(&mut self) {
self.ordered = vec![Resource::from("ORE")];
let mut sortable: HashMap<Resource, Vec<Resource>> = self
.pipeline
.iter()
.map(|(k, v)| (k.clone(), v.requirements.clone()))
.collect();
while sortable.len() > 0 {
sortable = sortable
.into_iter()
.filter_map(|(k, v)| {
if v.iter().all(|i| self.ordered.contains(i)) {
self.ordered.push(k);
None
} else {
Some((k, v))
}
})
.collect();
}
self.ordered.reverse();
self.ordered.retain(|res| res != "ORE");
}
/// calculate how much ores are required for required_fuel
fn resource_usage(&self, required_fuel: u128) -> usize {
// create storage to track leftover resources
let mut storage: HashMap<Resource, u128> = HashMap::new();
storage.insert(Resource::from("FUEL"), required_fuel);
// calculate resource costs
self.ordered.iter().for_each(|res| {
let rb = self.pipeline.get(res).unwrap();
let count = (storage.get(res).unwrap().clone() + (rb.out_count as u128) - 1)
/ (rb.out_count as u128);
rb.requirements.iter().for_each(|req| {
storage
.entry(req.clone())
.and_modify(|v| *v += count)
.or_insert(count);
storage.insert(res.clone(), 0);
})
});
// return cost for ore
println!("{:?}", storage);
*storage.get("ORE").unwrap() as usize
}
/// generate a single fuel
fn generate_fuel(&self) -> usize {
let mut storage: HashMap<Resource, usize> = HashMap::new();
self.lookup_resource(&mut storage, "FUEL")
}
/// recursively calculate the cost of a resource in ores
fn lookup_resource(&self, storage: &mut HashMap<Resource, usize>, resource: &str) -> usize {
if resource == "ORE" {
return 1;
}
// use from storage
if let Some(count) = storage.get_mut(resource) {
if *count > 0 {
*count -= 1;
return 0;
}
}
// initialize storage with zero
if storage.get(resource).is_none() {
storage.insert(resource.into(), 0);
}
// build resource and and to storage
let required = self
.pipeline
.get(resource)
.expect("unable to find resource");
let cost = required.requirements.iter().fold(0, |mut acc, c| {
acc += self.lookup_resource(storage, c);
acc
});
// update storage
let stored = storage.get_mut(resource).unwrap();
*stored += required.out_count - 1;
cost
}
}
impl<T> From<T> for NanoFactory
where
T: BufRead,
{
fn from(bufreader: T) -> Self {
let mut f = NanoFactory::default();
let mut state = NanoFactoryBuildState::InputCount;
bufreader.split(b'\n').enumerate().for_each(|(nr, line)| {
let line = line.unwrap();
let mut line = line.into_iter().peekable();
let mut count_var = 0;
let mut cur_requirements = Vec::new();
loop {
match state {
// numeric input
NanoFactoryBuildState::InputCount | NanoFactoryBuildState::OutputCount => {
while let Some(c) = next_if_in_range(&mut line, 48..=57) {
count_var = count_var * 10 + (c as usize) - 48;
}
assert_eq!(line.next().unwrap(), b' ');
state = match state {
NanoFactoryBuildState::InputCount => {
NanoFactoryBuildState::InputResource
}
NanoFactoryBuildState::OutputCount => {
NanoFactoryBuildState::OutputResource
}
_ => unreachable!(),
}
}
// input resouce name
NanoFactoryBuildState::InputResource => {
let mut r = Resource::new();
while let Some(c) = next_if_in_range(&mut line, 65..=90) {
r.push(c.into());
}
for _ in 0..count_var {
cur_requirements.push(r.clone());
}
r.truncate(0);
count_var = 0;
let next = line.next();
match next {
Some(b',') => {
assert_eq!(line.next().unwrap(), b' ');
state = NanoFactoryBuildState::InputCount;
}
Some(b' ') => state = NanoFactoryBuildState::OutputArrow,
_ => panic!(
"invalid format in line {}, expected ' ' or ',', got '{:?}'",
nr, next
),
}
}
// output resource name
NanoFactoryBuildState::OutputResource => {
let mut r = Resource::new();
while let Some(c) = next_if_in_range(&mut line, 65..=90) {
r.push(c.into());
}
f.pipeline
.insert(r, ResourceBuilder::from((cur_requirements, count_var)));
state = NanoFactoryBuildState::InputCount;
return;
}
// arrow between input and output ' => '
NanoFactoryBuildState::OutputArrow => {
assert_eq!(line.next().unwrap(), b'=');
assert_eq!(line.next().unwrap(), b'>');
assert_eq!(line.next().unwrap(), b' ');
state = NanoFactoryBuildState::OutputCount
}
};
}
});
f
}
}
fn next_if_in_range<I, T>(
peekable: &mut std::iter::Peekable<I>,
range: std::ops::RangeInclusive<T>,
) -> Option<T>
where
I: std::iter::Iterator<Item = T>,
T: Copy + std::cmp::PartialOrd,
{
if let Some(peeked) = peekable.peek() {
if range.contains(peeked) {
peekable.next()
} else {
None
}
} else {
None
}
}
fn main() {
let f = File::open("input14").unwrap();
let bufreader = BufReader::new(f);
let mut factory = NanoFactory::from(bufreader);
// part1
println!("ores: {}", factory.generate_fuel());
// part2 as binary search
factory.resolve_order();
let mut min = 1;
let mut max = 1_000_000_000_000;
let mut fuel;
loop {
fuel = (min + max) / 2;
let ore = factory.resource_usage(fuel);
match 1_000_000_000_000.cmp(&ore) {
Ordering::Less => max = fuel - 1,
Ordering::Greater => {
min = fuel + 1;
if min > max {
break;
}
}
Ordering::Equal => {
break;
}
};
}
println!("ammount: {}", fuel);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn example1() {
let bufreader = BufReader::new(
"10 ORE => 10 A
1 ORE => 1 B
7 A, 1 B => 1 C
7 A, 1 C => 1 D
7 A, 1 D => 1 E
7 A, 1 E => 1 FUEL
"
.trim()
.as_bytes(),
);
let mut factory = NanoFactory::from(bufreader);
factory.resolve_order();
assert_eq!(factory.generate_fuel(), 31);
assert_eq!(factory.resource_usage(1), 31);
}
#[test]
fn example2() {
let bufreader = BufReader::new(
"
9 ORE => 2 A
8 ORE => 3 B
7 ORE => 5 C
3 A, 4 B => 1 AB
5 B, 7 C => 1 BC
4 C, 1 A => 1 CA
2 AB, 3 BC, 4 CA => 1 FUEL
"
.trim()
.as_bytes(),
);
let mut factory = NanoFactory::from(bufreader);
factory.resolve_order();
assert_eq!(factory.generate_fuel(), 165);
assert_eq!(factory.resource_usage(1), 165);
}
#[test]
fn example3() {
let bufreader = BufReader::new(
"
157 ORE => 5 NZVS
165 ORE => 6 DCFZ
44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
179 ORE => 7 PSHF
177 ORE => 5 HKGWZ
7 DCFZ, 7 PSHF => 2 XJWVT
165 ORE => 2 GPVTF
3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT
"
.trim()
.as_bytes(),
);
let factory = NanoFactory::from(bufreader);
assert_eq!(factory.generate_fuel(), 13312);
}
#[test]
fn example4() {
let bufreader = BufReader::new(
"
2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
17 NVRVD, 3 JNWZP => 8 VPVL
53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
22 VJHF, 37 MNCFX => 5 FWMGM
139 ORE => 4 NVRVD
144 ORE => 7 JNWZP
5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC
5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV
145 ORE => 6 MNCFX
1 NVRVD => 8 CXFTF
1 VJHF, 6 MNCFX => 4 RFSQX
176 ORE => 6 VJHF
"
.trim()
.as_bytes(),
);
let mut factory = NanoFactory::from(bufreader);
factory.resolve_order();
assert_eq!(factory.generate_fuel(), 180697);
assert_eq!(factory.resource_usage(1), 180697);
}
#[test]
fn example5() {
let bufreader = BufReader::new(
"
171 ORE => 8 CNZTR
7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
114 ORE => 4 BHXH
14 VRPVC => 6 BMBT
6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL
6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT
15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW
13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW
5 BMBT => 4 WPTQ
189 ORE => 9 KTJDG
1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP
12 VRPVC, 27 CNZTR => 2 XDBXC
15 KTJDG, 12 BHXH => 5 XCVML
3 BHXH, 2 VRPVC => 7 MZWV
121 ORE => 7 VRPVC
7 XCVML => 6 RJRHP
5 BHXH, 4 VRPVC => 5 LTCX
"
.trim()
.as_bytes(),
);
let mut factory = NanoFactory::from(bufreader);
factory.resolve_order();
assert_eq!(factory.generate_fuel(), 2210736);
assert_eq!(factory.resource_usage(1), 2210736);
}
}

View file

@ -1,205 +0,0 @@
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use aoc2019::intcode;
fn main() -> Result<(), Box<dyn Error>> {
let f = File::open("input15")?;
let computer = intcode::Computer::from(f);
let mut map = Map::new();
let steps = map.walk(&XY { x: 0, y: 0 }, &computer, 0).unwrap();
for y in map.ymin..=map.ymax {
for x in map.xmin..=map.xmax {
if x == 0 && y == 0 {
print!("0");
continue;
}
let status = map.m.get(&XY { x, y }).unwrap_or(&Status::Empty);
let c = match status {
Status::HitWall => "#",
Status::MoveComplete => ".",
Status::Finished => "X",
Status::Empty => " ",
Status::Oxigenated => "o",
};
print!("{}", c);
}
println!("");
}
println!("i walked {} steps", steps);
let steps = map.fill();
println!("filled with oxygen after {} minutes", steps);
Ok(())
}
#[derive(Default, Debug)]
struct Map {
m: HashMap<XY, Status>,
xmin: isize,
xmax: isize,
ymin: isize,
ymax: isize,
}
impl Map {
fn new() -> Self {
Map::default()
}
fn walk(&mut self, start: &XY, computer: &intcode::Computer, steps: usize) -> Option<usize> {
let steps = steps + 1;
let mut result = None;
for dir in 1..=4 {
let direction = Direction::from(dir);
let xy = start.add((&direction).into());
if self.m.contains_key(&xy) {
continue;
}
self.update_limits(&xy);
let mut computer = computer.clone();
if let Some(status) = computer.run_io(dir) {
let status = Status::from(status);
self.m.insert(xy.clone(), status.clone());
match status {
Status::HitWall => (),
Status::MoveComplete => match self.walk(&xy, &computer, steps) {
Some(i) => result = Some(i + 1),
None => (),
},
Status::Finished => result = Some(1),
_ => unreachable!("unknown status"),
}
} else {
unreachable!("computer unexpectedly halted");
}
}
result
}
fn fill(&mut self) -> usize {
let mut src: Vec<XY> = self
.m
.iter()
.filter_map(|(xy, status)| match status {
Status::Finished => Some(xy),
_ => None,
})
.cloned()
.collect();
let mut steps = 0;
while src.len() > 0 {
steps += 1;
src.iter()
.for_each(|xy| *self.m.get_mut(xy).unwrap() = Status::Oxigenated);
src = src
.into_iter()
.map(|xy| {
(1..=4)
.map(Direction::from)
.map(move |d| xy.add((&d).into()))
})
.flatten()
.filter(|xy| match self.m.get(xy) {
Some(Status::MoveComplete) => true,
_ => false,
})
.collect();
}
assert_eq!(
self.m
.values()
.filter(|status| match status {
Status::MoveComplete => true,
_ => false,
})
.count(),
0
);
steps - 1
}
fn update_limits(&mut self, xy: &XY) {
if self.xmin > xy.x {
self.xmin = xy.x
}
if self.xmax < xy.x {
self.xmax = xy.x
}
if self.ymin > xy.y {
self.ymin = xy.y
}
if self.ymax < xy.y {
self.ymax = xy.y
}
}
}
#[derive(Debug)]
enum Direction {
North = 1,
South = 2,
West = 3,
East = 4,
}
impl From<isize> for Direction {
fn from(i: isize) -> Self {
match i {
1 => Direction::North,
2 => Direction::South,
3 => Direction::West,
4 => Direction::East,
_ => unreachable!("no status for computer output"),
}
}
}
impl Into<(isize, isize)> for &Direction {
fn into(self) -> (isize, isize) {
match self {
Direction::North => (0, 1),
Direction::South => (0, -1),
Direction::West => (-1, 0),
Direction::East => (1, 0),
}
}
}
#[derive(Clone, Debug)]
enum Status {
HitWall = 0,
MoveComplete = 1,
Finished = 2,
Empty = 3,
Oxigenated = 4,
}
impl From<isize> for Status {
fn from(i: isize) -> Self {
match i {
0 => Status::HitWall,
1 => Status::MoveComplete,
2 => Status::Finished,
_ => unreachable!("no status for computer output"),
}
}
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct XY {
x: isize,
y: isize,
}
impl XY {
fn add(&self, delta: (isize, isize)) -> XY {
XY {
x: self.x + delta.0,
y: self.y + delta.1,
}
}
}

View file

@ -1,477 +0,0 @@
use std::collections::VecDeque;
use std::fs::File;
use std::io::{BufRead, BufReader};
#[derive(Copy, Clone)]
enum Var {
A = 1,
B,
C,
}
#[derive(Copy, Clone, Debug)]
enum Mode {
Position,
Immediate,
Relative,
}
impl Default for Mode {
fn default() -> Self {
Mode::Position
}
}
impl From<isize> for Mode {
fn from(b: isize) -> Self {
match b {
0 => Mode::Position,
1 => Mode::Immediate,
2 => Mode::Relative,
_ => panic!("invalid mode {}", b),
}
}
}
#[derive(Copy, Clone, Default, Debug)]
struct Modes {
a: Mode,
b: Mode,
c: Mode,
}
impl Modes {
fn mode_for(&self, v: &Var) -> Mode {
match v {
Var::A => self.a,
Var::B => self.b,
Var::C => self.c,
}
}
}
impl From<(Mode, Mode, Mode)> for Modes {
fn from(modes: (Mode, Mode, Mode)) -> Self {
Modes {
a: modes.0,
b: modes.1,
c: modes.2,
}
}
}
impl From<&ModedOpcode> for Modes {
fn from(mo: &ModedOpcode) -> Self {
mo.modes
}
}
#[derive(Copy, Clone)]
enum Opcode {
Add,
Multiply,
Input,
Output,
JumpIfTrue,
JumpIfFalse,
LessThan,
Equals,
RelativeAdj,
Halt,
}
impl From<&ModedOpcode> for Opcode {
fn from(mo: &ModedOpcode) -> Self {
mo.op
}
}
impl From<isize> for Opcode {
fn from(i: isize) -> Self {
match i {
1 => Opcode::Add,
2 => Opcode::Multiply,
3 => Opcode::Input,
4 => Opcode::Output,
5 => Opcode::JumpIfTrue,
6 => Opcode::JumpIfFalse,
7 => Opcode::LessThan,
8 => Opcode::Equals,
9 => Opcode::RelativeAdj,
99 => Opcode::Halt,
_ => panic!("invalid opcode {}", i),
}
}
}
struct ModedOpcode {
modes: Modes,
op: Opcode,
}
impl From<isize> for ModedOpcode {
fn from(i: isize) -> Self {
let code = i % 100;
let modes = i / 100;
let a = (modes % 10) / 1;
let b = (modes % 100) / 10;
let c = (modes % 1000) / 100;
let modes = (Mode::from(a), Mode::from(b), Mode::from(c));
ModedOpcode {
modes: Modes::from(modes),
op: Opcode::from(code),
}
}
}
pub struct Computer {
pos: usize,
rel: isize,
program: Vec<isize>,
modes: Modes,
inputs: VecDeque<isize>,
outputs: VecDeque<isize>,
pub halted: bool,
}
impl Clone for Computer {
fn clone(&self) -> Self {
Computer::from(self.program.clone())
}
}
impl From<File> for Computer {
fn from(f: File) -> Self {
let f = BufReader::new(f);
let program: Vec<isize> = f
.split(b',')
.map(|o| {
let o = o.unwrap();
let mut o = o.iter().peekable();
let sign = if o.peek() == Some(&&b'-') { -1 } else { 1 };
o.filter(|i| **i >= b'0' && **i <= b'9')
.fold(0, |s, i| ((i - b'0') as isize + 10 * s))
* sign
})
.collect();
Computer::from(program)
}
}
impl From<Vec<isize>> for Computer {
fn from(program: Vec<isize>) -> Self {
Computer {
pos: 0,
rel: 0,
program,
modes: Default::default(),
inputs: VecDeque::new(),
outputs: VecDeque::new(),
halted: false,
}
}
}
impl Computer {
pub fn get_outputs(&self) -> &VecDeque<isize> {
&self.outputs
}
pub fn pop_output(&mut self) -> Option<isize> {
self.outputs.pop_front()
}
pub fn push_input_and_step(&mut self, input: isize) {
self.inputs.push_back(input);
self.step()
}
pub fn clone_with_modified_program(&self, u: Vec<(usize, isize)>) -> Computer {
let mut computer = self.clone();
for (pos, val) in u {
computer.program[pos] = val;
}
computer
}
pub fn clone_with_input(&self, input: Vec<isize>) -> Computer {
let mut computer = self.clone();
computer.inputs = VecDeque::from(input);
computer
}
pub fn run(&mut self) {
while !self.halted {
self.step();
}
}
pub fn run_until_input(&mut self) -> Option<Vec<isize>> {
self.step_until_input();
if self.outputs.len() > 0 {
return Some(self.outputs.split_off(0).into_iter().collect());
}
return None;
}
pub fn run_until_n_output(&mut self, n: usize) -> Option<Vec<isize>> {
loop {
self.step();
if self.outputs.len() >= n {
return Some(self.outputs.split_off(0).into_iter().collect());
}
if self.halted {
return None;
}
}
}
pub fn run_until_output(&mut self) -> Option<isize> {
loop {
self.step();
if self.outputs.len() > 0 {
return self.outputs.pop_front();
}
if self.halted {
return None;
}
}
}
pub fn run_must_output(&mut self) -> isize {
self.run_until_output()
.expect("computer halted without output")
}
pub fn run_io(&mut self, input: isize) -> Option<isize> {
self.inputs.push_back(input);
self.run_until_output()
}
fn step_until_input(&mut self) {
while !self.halted {
let instruction = self.program[self.pos];
let instruction = ModedOpcode::from(instruction);
self.modes = Modes::from(&instruction);
let advance = match Opcode::from(&instruction) {
Opcode::Add => self.add(),
Opcode::Multiply => self.multiply(),
Opcode::Input => return,
Opcode::Output => self.output(),
Opcode::JumpIfTrue => self.jump_if_true(),
Opcode::JumpIfFalse => self.jump_if_false(),
Opcode::LessThan => self.less_than(),
Opcode::Equals => self.equals(),
Opcode::RelativeAdj => self.relative_adj(),
Opcode::Halt => self.halt(),
};
self.pos += advance;
}
}
pub fn step(&mut self) {
let instruction = self.program[self.pos];
let instruction = ModedOpcode::from(instruction);
self.modes = Modes::from(&instruction);
let advance = match Opcode::from(&instruction) {
Opcode::Add => self.add(),
Opcode::Multiply => self.multiply(),
Opcode::Input => self.input(),
Opcode::Output => self.output(),
Opcode::JumpIfTrue => self.jump_if_true(),
Opcode::JumpIfFalse => self.jump_if_false(),
Opcode::LessThan => self.less_than(),
Opcode::Equals => self.equals(),
Opcode::RelativeAdj => self.relative_adj(),
Opcode::Halt => self.halt(),
};
self.pos += advance;
}
fn get_pos(&self, pos: usize) -> isize {
*self.program.get(pos).unwrap_or(&0)
}
fn get(&self, v: &Var) -> isize {
let want = self.pos + *v as usize;
let want = match self.modes.mode_for(v) {
Mode::Position => self.get_pos(want as usize) as usize,
Mode::Immediate => want,
Mode::Relative => (self.rel + self.get_pos(want)) as usize,
};
self.get_pos(want)
}
fn get_a(&self) -> isize {
self.get(&Var::A)
}
fn get_b(&self) -> isize {
self.get(&Var::B)
}
fn set(&mut self, v: &Var, value: isize) {
let length = self.program.len();
let want = self.pos + *v as usize;
let want = match self.modes.mode_for(v) {
Mode::Position => self.get_pos(want) as usize,
Mode::Immediate => want,
Mode::Relative => (self.rel + self.get_pos(want)) as usize,
};
if length <= want {
self.program.resize(want + 1, 0);
}
self.program[want] = value;
}
fn set_a(&mut self, value: isize) {
self.set(&Var::A, value)
}
fn set_c(&mut self, value: isize) {
self.set(&Var::C, value)
}
fn add(&mut self) -> usize {
self.set_c(self.get_a() + self.get_b());
4
}
fn multiply(&mut self) -> usize {
self.set_c(self.get_a() * self.get_b());
4
}
fn input(&mut self) -> usize {
let value = self.inputs.pop_front().expect("no input provided");
self.set_a(value);
2
}
fn output(&mut self) -> usize {
self.outputs.push_back(self.get_a());
2
}
fn jump_if_true(&mut self) -> usize {
if self.get_a() > 0 {
self.pos = self.get_b() as usize;
return 0;
}
3
}
fn jump_if_false(&mut self) -> usize {
if self.get_a() == 0 {
self.pos = self.get_b() as usize;
return 0;
}
3
}
fn less_than(&mut self) -> usize {
if self.get_a() < self.get_b() {
self.set_c(1)
} else {
self.set_c(0)
}
4
}
fn equals(&mut self) -> usize {
if self.get_a() == self.get_b() {
self.set_c(1)
} else {
self.set_c(0)
}
4
}
fn relative_adj(&mut self) -> usize {
self.rel = self.rel + self.get_a();
2
}
fn halt(&mut self) -> usize {
self.halted = true;
0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn example1() {
let program = vec![
109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99,
];
let mut computer = Computer::from(program.clone());
computer.run();
assert_eq!(computer.get_outputs().iter().eq(program.iter()), true)
}
#[test]
fn example2() {
assert_eq!(
Computer::from(vec![1102, 34915192, 34915192, 7, 4, 7, 99, 0]).run_must_output(),
1219070632396864
)
}
#[test]
fn example3() {
assert_eq!(
Computer::from(vec![104, 1125899906842624, 99]).run_must_output(),
1125899906842624
)
}
#[test]
fn day5exampe1() {
let computer = Computer::from(vec![3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8]);
assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
}
#[test]
fn day5exampe2() {
let computer = Computer::from(vec![3, 3, 1108, -1, 8, 3, 4, 3, 99]);
assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
}
#[test]
fn day5exampe3() {
let computer = Computer::from(vec![
3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9,
]);
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
let computer = Computer::from(vec![3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1]);
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
}
#[test]
fn day5exampe4() {
let computer = Computer::from(vec![
3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36, 98, 0,
0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000, 1, 20, 4,
20, 1105, 1, 46, 98, 99,
]);
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 999);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1000);
assert_eq!(computer.clone_with_input(vec![9]).run_must_output(), 1001);
}
#[test]
fn day9part1() {
let computer = Computer::from(File::open("input9").unwrap());
assert_eq!(
computer.clone_with_input(vec![1]).run_must_output(),
3063082071
);
}
}

View file

@ -1 +0,0 @@
pub mod intcode;

3
src/main.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}