The first part of all the problems. (Thanks, airplanes!)
This commit is contained in:
19
inputs/day20_example1
Normal file
19
inputs/day20_example1
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
A
|
||||||
|
A
|
||||||
|
#######.#########
|
||||||
|
#######.........#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
##### B ###.#
|
||||||
|
BC...## C ###.#
|
||||||
|
##.## ###.#
|
||||||
|
##...DE F ###.#
|
||||||
|
##### G ###.#
|
||||||
|
#########.#####.#
|
||||||
|
DE..#######...###.#
|
||||||
|
#.#########.###.#
|
||||||
|
FG..#########.....#
|
||||||
|
###########.#####
|
||||||
|
Z
|
||||||
|
Z
|
||||||
37
inputs/day20_example2
Normal file
37
inputs/day20_example2
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
A
|
||||||
|
A
|
||||||
|
#################.#############
|
||||||
|
#.#...#...................#.#.#
|
||||||
|
#.#.#.###.###.###.#########.#.#
|
||||||
|
#.#.#.......#...#.....#.#.#...#
|
||||||
|
#.#########.###.#####.#.#.###.#
|
||||||
|
#.............#.#.....#.......#
|
||||||
|
###.###########.###.#####.#.#.#
|
||||||
|
#.....# A C #.#.#.#
|
||||||
|
####### S P #####.#
|
||||||
|
#.#...# #......VT
|
||||||
|
#.#.#.# #.#####
|
||||||
|
#...#.# YN....#.#
|
||||||
|
#.###.# #####.#
|
||||||
|
DI....#.# #.....#
|
||||||
|
#####.# #.###.#
|
||||||
|
ZZ......# QG....#..AS
|
||||||
|
###.### #######
|
||||||
|
JO..#.#.# #.....#
|
||||||
|
#.#.#.# ###.#.#
|
||||||
|
#...#..DI BU....#..LF
|
||||||
|
#####.# #.#####
|
||||||
|
YN......# VT..#....QG
|
||||||
|
#.###.# #.###.#
|
||||||
|
#.#...# #.....#
|
||||||
|
###.### J L J #.#.###
|
||||||
|
#.....# O F P #.#...#
|
||||||
|
#.###.#####.#.#####.#####.###.#
|
||||||
|
#...#.#.#...#.....#.....#.#...#
|
||||||
|
#.#####.###.###.#.#.#########.#
|
||||||
|
#...#.#.....#...#.#.#.#.....#.#
|
||||||
|
#.###.#####.###.###.#.#.#######
|
||||||
|
#.#.........#...#.............#
|
||||||
|
#########.###.###.#############
|
||||||
|
B J C
|
||||||
|
U P P
|
||||||
15
src/args.rs
15
src/args.rs
@@ -18,6 +18,7 @@ pub enum Command {
|
|||||||
Amplify(Computer),
|
Amplify(Computer),
|
||||||
Image(Image),
|
Image(Image),
|
||||||
Arcade(Arcade),
|
Arcade(Arcade),
|
||||||
|
FindSanta(Computer),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_number(s: String) -> Result<(), String> {
|
fn is_number(s: String) -> Result<(), String> {
|
||||||
@@ -120,6 +121,14 @@ impl Command {
|
|||||||
.required(true)
|
.required(true)
|
||||||
.validator(is_file))
|
.validator(is_file))
|
||||||
)
|
)
|
||||||
|
.subcommand(SubCommand::with_name("final")
|
||||||
|
.about("run the final computer")
|
||||||
|
.arg(Arg::with_name("COMPUTER")
|
||||||
|
.index(1)
|
||||||
|
.help("The computer to run.")
|
||||||
|
.required(true)
|
||||||
|
.validator(is_file))
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
if let Some(problem1) = matches.subcommand_matches("fuel") {
|
if let Some(problem1) = matches.subcommand_matches("fuel") {
|
||||||
@@ -188,6 +197,12 @@ impl Command {
|
|||||||
let arcade = Arcade::new(38, 21, true, file);
|
let arcade = Arcade::new(38, 21, true, file);
|
||||||
return Command::Arcade(arcade);
|
return Command::Arcade(arcade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(fin) = matches.subcommand_matches("final") {
|
||||||
|
let file = fin.value_of("COMPUTER").expect("No final computer file!");
|
||||||
|
let comp = Computer::load(&file);
|
||||||
|
return Command::FindSanta(comp);
|
||||||
|
}
|
||||||
|
|
||||||
panic!("Failed to run a reasonable command.");
|
panic!("Failed to run a reasonable command.");
|
||||||
}
|
}
|
||||||
|
|||||||
120
src/bugs.rs
Normal file
120
src/bugs.rs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
struct BugMap {
|
||||||
|
has_bug: Vec<bool>,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BugMap {
|
||||||
|
fn new(s: &str) -> BugMap {
|
||||||
|
let mut width = 0;
|
||||||
|
let mut height = 0;
|
||||||
|
let mut has_bug = Vec::new();
|
||||||
|
|
||||||
|
println!("s length {}", s.len());
|
||||||
|
for line in s.trim().split('\n') {
|
||||||
|
println!("line: |{}|", line);
|
||||||
|
for c in line.chars() {
|
||||||
|
match c {
|
||||||
|
'.' => has_bug.push(false),
|
||||||
|
'#' => has_bug.push(true),
|
||||||
|
_ => panic!("Unexpected character in bug map"),
|
||||||
|
}
|
||||||
|
if height == 0 {
|
||||||
|
width += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
height += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BugMap{ has_bug, width, height }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, x: usize, y: usize) -> bool {
|
||||||
|
self.has_bug[ (y * self.width) + x ]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, x: usize, y: usize, v: bool) {
|
||||||
|
self.has_bug[ (y * self.width) + x ] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&self) -> BugMap {
|
||||||
|
let mut result = self.clone();
|
||||||
|
|
||||||
|
for x in 0..self.width {
|
||||||
|
for y in 0..self.height {
|
||||||
|
let above = if y > 0 { self.get(x, y - 1) } else { false };
|
||||||
|
let below = if y < (self.height - 1) { self.get(x, y + 1) } else { false };
|
||||||
|
let left = if x > 0 { self.get(x - 1, y) } else { false };
|
||||||
|
let right = if x < (self.width - 1) { self.get(x + 1, y) } else {false };
|
||||||
|
let bugs_nearby = count(above, below, left, right);
|
||||||
|
|
||||||
|
if self.get(x, y) {
|
||||||
|
result.set(x, y, bugs_nearby == 1);
|
||||||
|
} else {
|
||||||
|
result.set(x, y, (bugs_nearby >= 1) && (bugs_nearby <= 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn biodiversity(&self) -> u128 {
|
||||||
|
let mut result = 0;
|
||||||
|
let mut two_power = 1;
|
||||||
|
|
||||||
|
for v in self.has_bug.iter() {
|
||||||
|
if *v {
|
||||||
|
result += two_power;
|
||||||
|
}
|
||||||
|
two_power <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print(&self) {
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
print!("{}", if self.get(x, y) { '#' } else { '.' });
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count(a: bool, b: bool, c: bool, d: bool) -> u8 {
|
||||||
|
(a as u8) + (b as u8) + (c as u8) + (d as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_duplicate(mut cur: BugMap) -> BugMap {
|
||||||
|
let mut steps = Vec::new();
|
||||||
|
|
||||||
|
while !steps.contains(&cur) {
|
||||||
|
steps.push(cur.clone());
|
||||||
|
cur = cur.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
cur
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example() {
|
||||||
|
let map = BugMap::new("....#\n#..#.\n#..##\n..#..\n#....");
|
||||||
|
let endpoint = find_duplicate(map);
|
||||||
|
assert_eq!(2129920, endpoint.biodiversity());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn day24() {
|
||||||
|
let contents = fs::read("inputs/day24").expect("Couldn't read day 24 file");
|
||||||
|
let bugstr = str::from_utf8(&contents).expect("Couldn't read a string from day 24");
|
||||||
|
let bugmap = BugMap::new(&bugstr);
|
||||||
|
let endpoint = find_duplicate(bugmap);
|
||||||
|
assert_eq!(32776479, endpoint.biodiversity());
|
||||||
|
}
|
||||||
175
src/cards.rs
Normal file
175
src/cards.rs
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
use std::fs::read;
|
||||||
|
use std::str::{FromStr, from_utf8};
|
||||||
|
|
||||||
|
enum Shuffle {
|
||||||
|
DealNew,
|
||||||
|
Deal(usize),
|
||||||
|
Cut(usize),
|
||||||
|
CutBottom(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shuffle {
|
||||||
|
fn new(s: &str) -> Shuffle {
|
||||||
|
if s.starts_with("deal with increment ") {
|
||||||
|
let amt = usize::from_str(&s[19..].trim()).expect("Couldn't parse deal with number");
|
||||||
|
return Shuffle::Deal(amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.starts_with("cut -") {
|
||||||
|
let amt = usize::from_str(&s[5..].trim()).expect("Couldn't parse cut with negative number");
|
||||||
|
return Shuffle::CutBottom(amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.starts_with("cut ") {
|
||||||
|
let amt = usize::from_str(&s[4..].trim()).expect("Couldn't parse cut with number");
|
||||||
|
return Shuffle::Cut(amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.starts_with("deal into new stack") {
|
||||||
|
return Shuffle::DealNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Couldn't parse shuffle mechanism")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, mut deck: Vec<u32>) -> Vec<u32> {
|
||||||
|
match self {
|
||||||
|
Shuffle::DealNew => {
|
||||||
|
deck.reverse();
|
||||||
|
deck
|
||||||
|
}
|
||||||
|
Shuffle::Deal(amt) => {
|
||||||
|
let mut res = deck.clone();
|
||||||
|
let len = deck.len();
|
||||||
|
let mut out = 0;
|
||||||
|
|
||||||
|
for i in 0..len {
|
||||||
|
res[out] = deck[i];
|
||||||
|
out = (out + amt) % len;
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
Shuffle::Cut(place) => {
|
||||||
|
let len = deck.len();
|
||||||
|
let mut result = Vec::with_capacity(len);
|
||||||
|
let mut i = *place;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
result.push(deck[i]);
|
||||||
|
i = (i + 1) % len;
|
||||||
|
if i == *place {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Shuffle::CutBottom(place) => {
|
||||||
|
let len = deck.len();
|
||||||
|
let mut result = Vec::with_capacity(len);
|
||||||
|
let mut i = len - *place;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
result.push(deck[i]);
|
||||||
|
i = (i + 1) % len;
|
||||||
|
if i == (len - *place) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ShuffleOrder {
|
||||||
|
order: Vec<Shuffle>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShuffleOrder {
|
||||||
|
fn from_file(s: &str) -> ShuffleOrder {
|
||||||
|
let raw = read(s).expect("Couldn't read file.");
|
||||||
|
let strs = from_utf8(&raw).expect("Couldn't get string data");
|
||||||
|
ShuffleOrder::new(&strs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(strs: &str) -> ShuffleOrder {
|
||||||
|
let mut order = Vec::new();
|
||||||
|
|
||||||
|
for line in strs.trim().split('\n') {
|
||||||
|
order.push( Shuffle::new(line) );
|
||||||
|
}
|
||||||
|
|
||||||
|
ShuffleOrder{ order }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shuffle(&self, initial: &[u32]) -> Vec<u32> {
|
||||||
|
let mut cur = Vec::from(initial);
|
||||||
|
|
||||||
|
for shuffle in self.order.iter() {
|
||||||
|
cur = shuffle.apply(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn base() {
|
||||||
|
let deck1 = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
assert_eq!(vec![9, 8, 7, 6, 5, 4, 3, 2, 1, 0], Shuffle::DealNew.apply(deck1));
|
||||||
|
|
||||||
|
let deck2 = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
assert_eq!(vec![3, 4, 5, 6, 7, 8, 9, 0, 1, 2], Shuffle::Cut(3).apply(deck2));
|
||||||
|
|
||||||
|
let deck3 = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
assert_eq!(vec![6, 7, 8, 9, 0, 1, 2, 3, 4, 5], Shuffle::CutBottom(4).apply(deck3));
|
||||||
|
|
||||||
|
let deck4 = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
assert_eq!(vec![0, 7, 4, 1, 8, 5, 2, 9, 6, 3], Shuffle::Deal(3).apply(deck4));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example1() {
|
||||||
|
let shuffles = ShuffleOrder::new("deal with increment 7\ndeal into new stack\ndeal into new stack");
|
||||||
|
let done = shuffles.shuffle(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
assert_eq!(vec![0, 3, 6, 9, 2, 5, 8, 1, 4, 7], done);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example2() {
|
||||||
|
let shuffles = ShuffleOrder::new("cut 6\ndeal with increment 7\ndeal into new stack");
|
||||||
|
let done = shuffles.shuffle(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
assert_eq!(vec![3, 0, 7, 4, 1, 8, 5, 2, 9, 6], done);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example3() {
|
||||||
|
let shuffles = ShuffleOrder::new("deal with increment 7\ndeal with increment 9\ncut -2");
|
||||||
|
let done = shuffles.shuffle(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
assert_eq!(vec![6, 3, 0, 7, 4, 1, 8, 5, 2, 9], done);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example4() {
|
||||||
|
let shuffles = ShuffleOrder::new("deal into new stack\ncut -2\ndeal with increment 7\ncut 8\ncut -4\ndeal with increment 7\ncut 3\ndeal with increment 9\ndeal with increment 3\ncut -1");
|
||||||
|
let done = shuffles.shuffle(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
assert_eq!(vec![9, 2, 5, 8, 1, 4, 7, 0, 3, 6], done);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_card(deck: &[u32], v: u32) -> usize {
|
||||||
|
for (idx, value) in deck.iter().enumerate() {
|
||||||
|
if *value == v {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Couldn't find card {}", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn day22a() {
|
||||||
|
let shuffles = ShuffleOrder::from_file("inputs/day22");
|
||||||
|
let deck: Vec<u32> = (0..10007).collect();
|
||||||
|
let result = shuffles.shuffle(&deck);
|
||||||
|
assert_eq!(2939, find_card(&result, 2019));
|
||||||
|
}
|
||||||
274
src/donut.rs
Normal file
274
src/donut.rs
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::fs;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
struct Maze<TileType> {
|
||||||
|
data: Vec<TileType>,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
enum InputTile {
|
||||||
|
Wall,
|
||||||
|
Empty,
|
||||||
|
Blank,
|
||||||
|
Letter(char),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
enum Tile {
|
||||||
|
Wall,
|
||||||
|
Empty,
|
||||||
|
Jump(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a InputTile> for Tile {
|
||||||
|
fn from(x: &InputTile) -> Tile {
|
||||||
|
match x {
|
||||||
|
InputTile::Wall => Tile::Wall,
|
||||||
|
InputTile::Empty => Tile::Empty,
|
||||||
|
InputTile::Blank => Tile::Wall,
|
||||||
|
InputTile::Letter(_) => Tile::Wall,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Maze<T> {
|
||||||
|
fn get(&self, x: usize, y:usize) -> T {
|
||||||
|
assert!(x < self.width);
|
||||||
|
assert!(y < self.height);
|
||||||
|
self.data[ (self.width * y) + x ].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, x: usize, y: usize, v: T) {
|
||||||
|
self.data[ (self.width * y) + x ] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Maze<InputTile> {
|
||||||
|
fn new(f: &str) -> Maze<InputTile> {
|
||||||
|
let contents = fs::read(f).expect("Couldn't open input donut maze");
|
||||||
|
let strmap = str::from_utf8(&contents).expect("Couldn't turn donut maze into string");
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let mut width = 0;
|
||||||
|
let mut height = 0;
|
||||||
|
|
||||||
|
for line in strmap.trim_right().split('\n') {
|
||||||
|
for c in line.chars() {
|
||||||
|
match c {
|
||||||
|
' ' => data.push(InputTile::Blank),
|
||||||
|
'.' => data.push(InputTile::Empty),
|
||||||
|
'#' => data.push(InputTile::Wall),
|
||||||
|
x if x.is_ascii_alphabetic() => data.push(InputTile::Letter(x)),
|
||||||
|
_ => panic!("Unknown character {}", c),
|
||||||
|
}
|
||||||
|
if height == 0 {
|
||||||
|
width += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
height += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while data.len() < (width * height) { data.push(InputTile::Blank); }
|
||||||
|
|
||||||
|
Maze{ data, width, height }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print(&self) {
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
match self.get(x, y) {
|
||||||
|
InputTile::Blank => print!(" "),
|
||||||
|
InputTile::Empty => print!("."),
|
||||||
|
InputTile::Wall => print!("#"),
|
||||||
|
InputTile::Letter(c) => print!("{}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Maze<Tile> {
|
||||||
|
fn new(f: &str) -> Maze<Tile> {
|
||||||
|
let inputmap: Maze<InputTile> = Maze::<InputTile>::new(f);
|
||||||
|
let mut top = 0;
|
||||||
|
let mut left = 0;
|
||||||
|
let mut bottom = 0;
|
||||||
|
let mut right = 0;
|
||||||
|
|
||||||
|
// find the top left corner
|
||||||
|
for y in 0..inputmap.height {
|
||||||
|
for x in 0..inputmap.width {
|
||||||
|
if top == 0 && inputmap.get(x, y) == InputTile::Wall {
|
||||||
|
top = y;
|
||||||
|
left = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the bottom right corner
|
||||||
|
for y in (0..inputmap.height).rev() {
|
||||||
|
for x in (0..inputmap.width).rev() {
|
||||||
|
if bottom == 0 && inputmap.get(x, y) == InputTile::Wall {
|
||||||
|
bottom = y;
|
||||||
|
right = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let width = (right - left) + 1;
|
||||||
|
let height = (bottom - top) + 1;
|
||||||
|
let mut data = Vec::with_capacity(width * height);
|
||||||
|
// Just copy the core bits over.
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
data.push( Tile::from(&inputmap.get(x + left, y + top)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we go back through and add the jump points.
|
||||||
|
let mut res = Maze{ data, width, height };
|
||||||
|
for y in 0..inputmap.height-1 {
|
||||||
|
for x in 0..inputmap.width-1 {
|
||||||
|
if let InputTile::Letter(c1) = inputmap.get(x, y) {
|
||||||
|
let mut s = String::new();
|
||||||
|
|
||||||
|
s.push(c1);
|
||||||
|
if let InputTile::Letter(c2) = inputmap.get(x + 1, y) {
|
||||||
|
s.push(c2);
|
||||||
|
if x + 2 < inputmap.width && inputmap.get(x + 2, y) == InputTile::Empty {
|
||||||
|
res.set( (x + 2) - left, y - top, Tile::Jump(s));
|
||||||
|
} else if x > 0 && inputmap.get(x - 1, y) == InputTile::Empty {
|
||||||
|
res.set( (x - 1) - left, y - top, Tile::Jump(s));
|
||||||
|
}
|
||||||
|
} else if let InputTile::Letter(c2) = inputmap.get(x, y + 1) {
|
||||||
|
s.push(c2);
|
||||||
|
if y + 2 < inputmap.height && inputmap.get(x, y + 2) == InputTile::Empty {
|
||||||
|
res.set( x - left, (y + 2) - top, Tile::Jump(s));
|
||||||
|
} else if y > 0 && inputmap.get(x, y - 1) == InputTile::Empty {
|
||||||
|
res.set( x - left, y - 1 - top, Tile::Jump(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn origin(&self) -> (usize, usize) {
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
if self.get(x, y) == Tile::Jump("AA".to_string()) {
|
||||||
|
return (x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Couldn't find origin!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jump_from(&self, sx: usize, sy: usize) -> Option<(usize, usize)> {
|
||||||
|
if let Tile::Jump(label) = self.get(sx, sy) {
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
if (sx != x) || (sy != y) {
|
||||||
|
if let Tile::Jump(label2) = self.get(x, y) {
|
||||||
|
if label == label2 {
|
||||||
|
return Some((x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_moves(&self, x: usize, y: usize) -> Vec<(usize, usize)> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
if x > 0 { res.push((x - 1, y)); }
|
||||||
|
if y > 0 { res.push((x, y - 1)); }
|
||||||
|
if x < (self.width - 1) { res.push((x + 1, y)); }
|
||||||
|
if y < (self.height - 1) { res.push((x, y + 1)); }
|
||||||
|
if let Some(target) = self.jump_from(x, y) { res.push(target); }
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_path(&self) -> Vec<(usize, usize)> {
|
||||||
|
let initial_path = vec![self.origin()];
|
||||||
|
let mut queue = VecDeque::new();
|
||||||
|
|
||||||
|
queue.push_back(initial_path);
|
||||||
|
while let Some(mut cur) = queue.pop_front() {
|
||||||
|
assert_ne!(cur.len(), 0);
|
||||||
|
let (x, y) = cur[cur.len() - 1];
|
||||||
|
let mut nexts = self.next_moves(x, y);
|
||||||
|
for next in nexts.drain(0..) {
|
||||||
|
let (nx, ny) = next;
|
||||||
|
|
||||||
|
if let Tile::Jump(lbl) = self.get(nx, ny) {
|
||||||
|
if lbl == "ZZ".to_string() {
|
||||||
|
cur.push((nx, ny));
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cur.contains(&next) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.get(nx, ny) == Tile::Wall {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut newcopy = cur.clone();
|
||||||
|
newcopy.push((nx, ny));
|
||||||
|
queue.push_back(newcopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("No path found!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print(&self) {
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
match self.get(x, y) {
|
||||||
|
Tile::Empty => print!("."),
|
||||||
|
Tile::Wall => print!("#"),
|
||||||
|
Tile::Jump(s) => print!("{}", s.chars().next().unwrap()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example1() {
|
||||||
|
let maze = Maze::<Tile>::new("inputs/day20_example1");
|
||||||
|
assert_eq!(None, maze.jump_from(7, 0));
|
||||||
|
assert_eq!(Some((0, 6)), maze.jump_from(7, 4));
|
||||||
|
assert_eq!(Some((7, 4)), maze.jump_from(0, 6));
|
||||||
|
assert_eq!(23, maze.find_path().len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example2() {
|
||||||
|
let maze = Maze::<Tile>::new("inputs/day20_example2");
|
||||||
|
let path = maze.find_path();
|
||||||
|
assert_eq!(58, path.len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn day20() {
|
||||||
|
let maze = Maze::<Tile>::new("inputs/day20");
|
||||||
|
let path = maze.find_path();
|
||||||
|
assert_eq!(606, path.len() - 1);
|
||||||
|
}
|
||||||
16
src/main.rs
16
src/main.rs
@@ -1,13 +1,21 @@
|
|||||||
mod arcade;
|
mod arcade;
|
||||||
mod args;
|
mod args;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
mod bugs;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod cards;
|
||||||
|
#[cfg(test)]
|
||||||
mod chemistry;
|
mod chemistry;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
mod donut;
|
||||||
|
#[cfg(test)]
|
||||||
mod fft;
|
mod fft;
|
||||||
mod fuel;
|
mod fuel;
|
||||||
mod image;
|
mod image;
|
||||||
mod machine;
|
mod machine;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
mod maze;
|
||||||
|
#[cfg(test)]
|
||||||
mod nbody;
|
mod nbody;
|
||||||
mod orbits;
|
mod orbits;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -16,6 +24,7 @@ mod repair;
|
|||||||
mod robot;
|
mod robot;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod router;
|
mod router;
|
||||||
|
mod santafind;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod scaffold;
|
mod scaffold;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -29,6 +38,7 @@ mod wiremap;
|
|||||||
use crate::args::Command;
|
use crate::args::Command;
|
||||||
use crate::fuel::calculate_fuel;
|
use crate::fuel::calculate_fuel;
|
||||||
use crate::orbits::Object;
|
use crate::orbits::Object;
|
||||||
|
use crate::santafind::find_santa;
|
||||||
use crate::wiremap::WireMap;
|
use crate::wiremap::WireMap;
|
||||||
use std::cmp::{max,min};
|
use std::cmp::{max,min};
|
||||||
use terminal_graphics::Display;
|
use terminal_graphics::Display;
|
||||||
@@ -184,5 +194,9 @@ fn main() {
|
|||||||
});
|
});
|
||||||
println!("Final score: {}", result.score);
|
println!("Final score: {}", result.score);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Command::FindSanta(comp) => {
|
||||||
|
find_santa(comp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
240
src/maze.rs
Normal file
240
src/maze.rs
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
use std::fs;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
struct Maze {
|
||||||
|
data: Vec<Tile>,
|
||||||
|
keyset: HashSet<char>,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
enum Tile {
|
||||||
|
Wall,
|
||||||
|
Empty,
|
||||||
|
Door(char),
|
||||||
|
Key(char),
|
||||||
|
Entrance,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tile {
|
||||||
|
fn is_key(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Tile::Key(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Maze {
|
||||||
|
fn new(s: &str) -> Maze {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let mut keyset = HashSet::new();
|
||||||
|
let mut width = 0;
|
||||||
|
let mut height = 0;
|
||||||
|
|
||||||
|
for line in s.trim().split('\n') {
|
||||||
|
for c in line.chars() {
|
||||||
|
match c {
|
||||||
|
'#' => data.push(Tile::Wall),
|
||||||
|
'.' => data.push(Tile::Empty),
|
||||||
|
'@' => data.push(Tile::Entrance),
|
||||||
|
kd if kd.is_ascii_lowercase() => {
|
||||||
|
data.push(Tile::Key(kd));
|
||||||
|
keyset.insert(kd);
|
||||||
|
}
|
||||||
|
kd if kd.is_ascii_uppercase() => data.push(Tile::Door(kd.to_ascii_lowercase())),
|
||||||
|
kd => panic!("Unrecognized character: {}", kd),
|
||||||
|
}
|
||||||
|
if height == 0 { width += 1 }
|
||||||
|
}
|
||||||
|
height += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Maze{ data, keyset, width, height }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, x: usize, y: usize) -> Tile {
|
||||||
|
self.data[ (y * self.width) + x ]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn origin(&self) -> (usize, usize) {
|
||||||
|
for x in 0..self.width {
|
||||||
|
for y in 0..self.height {
|
||||||
|
if self.get(x, y) == Tile::Entrance {
|
||||||
|
return (x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("No origin found?!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_steps(&self, x: usize, y: usize) -> Vec<(usize, usize)> {
|
||||||
|
let mut initial_res = Vec::new();
|
||||||
|
|
||||||
|
if x > 0 { initial_res.push((x - 1, y)); }
|
||||||
|
if y > 0 { initial_res.push((x, y - 1)); }
|
||||||
|
if x < (self.width - 1) { initial_res.push((x + 1, y)); }
|
||||||
|
if y < (self.height - 1) { initial_res.push((x, y + 1)); }
|
||||||
|
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
for (x, y) in initial_res {
|
||||||
|
if self.get(x, y) != Tile::Wall {
|
||||||
|
res.push((x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct SearchState {
|
||||||
|
collected_keys: HashSet<char>,
|
||||||
|
path: Vec<(usize, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SearchState {
|
||||||
|
fn new(maze: &Maze) -> SearchState {
|
||||||
|
SearchState {
|
||||||
|
collected_keys: HashSet::new(),
|
||||||
|
path: vec![maze.origin()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_prune(&self, best_cases: &mut HashMap<(usize,usize),Vec<HashSet<char>>>) -> bool {
|
||||||
|
// let mut history = vec![];
|
||||||
|
//
|
||||||
|
// for (x, y) in self.path.iter().rev() {
|
||||||
|
// if maze.get(*x, *y).is_key() {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if history.contains(&(x, y)) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// history.push((x, y));
|
||||||
|
// }
|
||||||
|
|
||||||
|
assert_ne!(self.path.len(), 0);
|
||||||
|
let lastpos = self.path[self.path.len() - 1];
|
||||||
|
|
||||||
|
match best_cases.get_mut(&lastpos) {
|
||||||
|
None => {
|
||||||
|
let _ = best_cases.insert(lastpos, vec![self.collected_keys.clone()]);
|
||||||
|
}
|
||||||
|
Some(seen) => {
|
||||||
|
for previous in seen.iter_mut() {
|
||||||
|
if self.collected_keys.is_subset(previous) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if previous.is_subset(&self.collected_keys) {
|
||||||
|
*previous = self.collected_keys.clone();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seen.push(self.collected_keys.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_keys(maze: &Maze) -> Vec<(usize, usize)> {
|
||||||
|
let initial_state = SearchState::new(maze);
|
||||||
|
let mut queue = VecDeque::new();
|
||||||
|
let mut best_states = HashMap::new();
|
||||||
|
|
||||||
|
queue.push_back(initial_state);
|
||||||
|
while let Some(state) = queue.pop_front() {
|
||||||
|
// println!("path length {} [queue length {}, have {:?}, want {:?}]", state.path.len(), queue.len(), state.collected_keys, maze.keyset);
|
||||||
|
assert_ne!(state.path.len(), 0);
|
||||||
|
let (x, y) = state.path[state.path.len() - 1];
|
||||||
|
let mut new_items = Vec::new();
|
||||||
|
|
||||||
|
for (newx, newy) in maze.next_steps(x, y).drain(0..) {
|
||||||
|
match maze.get(newx, newy) {
|
||||||
|
Tile::Wall => continue,
|
||||||
|
Tile::Empty => {
|
||||||
|
let mut newstate = state.clone();
|
||||||
|
newstate.path.push((newx, newy));
|
||||||
|
new_items.push(newstate);
|
||||||
|
}
|
||||||
|
Tile::Door(k) => {
|
||||||
|
if state.collected_keys.contains(&k) {
|
||||||
|
let mut newstate = state.clone();
|
||||||
|
newstate.path.push((newx, newy));
|
||||||
|
new_items.push(newstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tile::Key(k) => {
|
||||||
|
let mut newstate = state.clone();
|
||||||
|
newstate.path.push((newx, newy));
|
||||||
|
newstate.collected_keys.insert(k);
|
||||||
|
if newstate.collected_keys == maze.keyset {
|
||||||
|
return newstate.path;
|
||||||
|
}
|
||||||
|
new_items.push(newstate);
|
||||||
|
}
|
||||||
|
Tile::Entrance => {
|
||||||
|
let mut newstate = state.clone();
|
||||||
|
newstate.path.push((newx, newy));
|
||||||
|
new_items.push(newstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for newstate in new_items.drain(0..) {
|
||||||
|
if !newstate.should_prune(&mut best_states) {
|
||||||
|
queue.push_back(newstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Gave up finding all the keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example1() {
|
||||||
|
let example1 = Maze::new("#########\n#b.A.@.a#\n#########\n");
|
||||||
|
assert_eq!((5, 1), example1.origin());
|
||||||
|
let target1 = vec![(5, 1), (6, 1), (7, 1), (6, 1), (5, 1), (4, 1), (3, 1), (2, 1), (1, 1)];
|
||||||
|
assert_eq!(target1, find_keys(&example1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example2() {
|
||||||
|
let example2 = Maze::new("########################\n#f.D.E.e.C.b.A.@.a.B.c.#\n######################.#\n#d.....................#\n########################");
|
||||||
|
assert_eq!(86, find_keys(&example2).len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example3() {
|
||||||
|
let example3 = Maze::new("########################\n#...............b.C.D.f#\n#.######################\n#.....@.a.B.c.d.A.e.F.g#\n########################");
|
||||||
|
assert_eq!(132, find_keys(&example3).len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example4() {
|
||||||
|
let example4 = Maze::new("#################\n#i.G..c...e..H.p#\n########.########\n#j.A..b...f..D.o#\n########@########\n#k.E..a...g..B.n#\n########.########\n#l.F..d...h..C.m#\n#################");
|
||||||
|
assert_eq!(136, find_keys(&example4).len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example5() {
|
||||||
|
let example5 = Maze::new("########################\n#@..............ac.GI.b#\n###d#e#f################\n###A#B#C################\n###g#h#i################\n########################");
|
||||||
|
assert_eq!(81, find_keys(&example5).len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn day18a() {
|
||||||
|
let day18_contents = fs::read("inputs/day18").expect("Couldn't open day18 problem");
|
||||||
|
let day18_str = str::from_utf8(&day18_contents).expect("Couldn't decode day18 problem");
|
||||||
|
let maze = Maze::new(&day18_str);
|
||||||
|
assert_eq!(6098, find_keys(&maze).len() - 1);
|
||||||
|
}
|
||||||
126
src/santafind.rs
Normal file
126
src/santafind.rs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
use crate::machine::{Computer, RunResult};
|
||||||
|
|
||||||
|
const GATHER_STEPS: [&'static str; 34] = [
|
||||||
|
"south",
|
||||||
|
"take monolith",
|
||||||
|
"east",
|
||||||
|
"take asterisk",
|
||||||
|
"west",
|
||||||
|
"north",
|
||||||
|
"west",
|
||||||
|
"take coin",
|
||||||
|
"north",
|
||||||
|
"east",
|
||||||
|
"take astronaut ice cream",
|
||||||
|
"west",
|
||||||
|
"south",
|
||||||
|
"east",
|
||||||
|
"north",
|
||||||
|
"north",
|
||||||
|
"take mutex",
|
||||||
|
"west",
|
||||||
|
"take astrolabe",
|
||||||
|
"west",
|
||||||
|
"take dehydrated water",
|
||||||
|
"west",
|
||||||
|
"take wreath",
|
||||||
|
"east",
|
||||||
|
"south",
|
||||||
|
"east",
|
||||||
|
"north",
|
||||||
|
"drop astronaut ice cream",
|
||||||
|
"drop wreath",
|
||||||
|
"drop coin",
|
||||||
|
"drop dehydrated water",
|
||||||
|
"drop asterisk",
|
||||||
|
"drop astrolabe",
|
||||||
|
"drop mutex",
|
||||||
|
];
|
||||||
|
|
||||||
|
const THINGS: [&'static str; 8] = [
|
||||||
|
"astronaut ice cream",
|
||||||
|
"wreath",
|
||||||
|
"coin",
|
||||||
|
"dehydrated water",
|
||||||
|
"asterisk",
|
||||||
|
"astrolabe",
|
||||||
|
"mutex",
|
||||||
|
"monolith",
|
||||||
|
];
|
||||||
|
|
||||||
|
fn combine_commands(cmds: &[&str]) -> String {
|
||||||
|
let mut res = String::new();
|
||||||
|
|
||||||
|
for cmd in cmds.iter() {
|
||||||
|
res.push_str(cmd);
|
||||||
|
res.push_str("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_things(c: u16) -> String {
|
||||||
|
let mut res = String::new();
|
||||||
|
|
||||||
|
for bit in 0..8 {
|
||||||
|
if (c >> bit) & 0x1 == 1 {
|
||||||
|
res.push_str("take ");
|
||||||
|
res.push_str(THINGS[bit]);
|
||||||
|
res.push_str("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_computer(mut comp: Computer, buffer: &mut String) -> (Box<dyn FnOnce(i64) -> Computer>, String) {
|
||||||
|
let mut outbuf = String::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match comp.run() {
|
||||||
|
RunResult::Continue(comp2) => comp = comp2,
|
||||||
|
RunResult::Halted(_) => panic!("Machine halted in run_computer: {}", outbuf),
|
||||||
|
RunResult::Output(c, comp2) => {
|
||||||
|
outbuf.push(c as u8 as char);
|
||||||
|
comp = comp2;
|
||||||
|
}
|
||||||
|
RunResult::Input(f) => {
|
||||||
|
if buffer.len() == 0 {
|
||||||
|
return (f, outbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = buffer.remove(0);
|
||||||
|
comp = f(c as u8 as i64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_everything(comp: Computer) -> Computer {
|
||||||
|
let mut gather_buffer = combine_commands(&GATHER_STEPS);
|
||||||
|
let (res, outb) = run_computer(comp, &mut gather_buffer);
|
||||||
|
println!("{}", outb);
|
||||||
|
res('\n' as u8 as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combination_works(comp: Computer, code: u16) -> bool {
|
||||||
|
let mut get_buffer = select_things(code);
|
||||||
|
let (next, _) = run_computer(comp, &mut get_buffer);
|
||||||
|
let mut north = "nv\nnorth\n".to_string();
|
||||||
|
let (_after, outbuf) = run_computer(next('i' as u8 as i64), &mut north);
|
||||||
|
println!("outbuf: {}", outbuf);
|
||||||
|
!outbuf.contains("heavier") && !outbuf.contains("lighter")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_santa(base_computer: Computer) {
|
||||||
|
let at_checkpoint = gather_everything(base_computer);
|
||||||
|
|
||||||
|
for code in 1..256 {
|
||||||
|
println!("------------------------------------------");
|
||||||
|
println!("Trying code: {}", code);
|
||||||
|
if combination_works(at_checkpoint.clone(), code) {
|
||||||
|
println!("Combination {} worked.", code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user