From 0d4c2a7b4e6b319887aaec6d9a5e8323b02572a3 Mon Sep 17 00:00:00 2001 From: Max Nuding Date: Wed, 14 Dec 2022 16:14:21 +0000 Subject: [PATCH] Add visualization --- Cargo.toml | 1 + src/day14/mod.rs | 79 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 26e3dcf..32e3f52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ day17 = [] day18 = [] day19 = [] day20 = [] +visualize = [] diff --git a/src/day14/mod.rs b/src/day14/mod.rs index 2045220..722548a 100644 --- a/src/day14/mod.rs +++ b/src/day14/mod.rs @@ -1,9 +1,10 @@ use crate::read; use itertools::Itertools; -use std::collections::*; -use std::hash::{Hash, Hasher}; -use std::io::Write; +use std::{ + collections::*, + hash::{Hash, Hasher}, +}; #[derive(Debug, Clone, Eq)] pub struct Coord { pub x: i32, @@ -89,23 +90,42 @@ pub fn run() { }) .collect(); + // Hide cursor + print!("\x1B[?25l"); #[cfg(feature = "part1")] { - println!("Day 14, Part 01: {:?}", p1(&mut rocks.clone())); + #[cfg(feature = "visualize")] + print!("\x1B[2J\x1B[1;1H"); + + let _count = p1(&mut rocks.clone()); + + #[cfg(not(feature = "visualize"))] + println!("Day 14, Part 01: {:?}", _count); } #[cfg(feature = "part2")] { let floor = rocks.iter().map(|r| r.y).max().unwrap() + 2; - for x in -1000..=1000 { - rocks.insert(Coord { + (-1000..=1000) + .map(|x| Coord { x, y: floor, is_rock: true, + }) + .for_each(|coord| { + rocks.insert(coord); }); - } - println!("Day 14, Part 02: {:?}", p2(&mut rocks.clone())); + // Clear screen + #[cfg(feature = "visualize")] + print!("\x1B[2J\x1B[1;1H"); + + let _count = p2(&mut rocks); + + #[cfg(not(feature = "visualize"))] + println!("Day 14, Part 02: {:?}", _count); } + // Restore cursor + print!("\x1B[?25h"); } fn p1(rocks: &mut HashSet) -> usize { @@ -121,8 +141,9 @@ fn p1(rocks: &mut HashSet) -> usize { let mut sand = sand_start.clone(); loop { - //print(rocks, &sand); if sand.y > bottom { + #[cfg(feature = "visualize")] + print(rocks, &sand, 1, count_p1); return count_p1; } let d = sand.down(); @@ -134,6 +155,8 @@ fn p1(rocks: &mut HashSet) -> usize { if rocks.contains(&dr) { count_p1 += 1; rocks.insert(sand.clone()); + #[cfg(feature = "visualize")] + print(rocks, &sand, 1, count_p1); break; } sand = dr; @@ -158,6 +181,8 @@ fn p2(rocks: &mut HashSet) -> usize { loop { let mut sand = sand_start.clone(); if rocks.contains(&sand) { + #[cfg(feature = "visualize")] + print(rocks, &sand, 2, count_p2); return count_p2; } @@ -171,6 +196,8 @@ fn p2(rocks: &mut HashSet) -> usize { if rocks.contains(&dr) { count_p2 += 1; rocks.insert(sand.clone()); + #[cfg(feature = "visualize")] + print(rocks, &sand, 2, count_p2); break; } sand = dr; @@ -184,14 +211,17 @@ fn p2(rocks: &mut HashSet) -> usize { } } -fn print(rocks: &HashSet, sand: &Coord) { - let min_y = 10; - let min_x = 452; - let max_y = 180; - let max_x = 514; +#[cfg(feature = "visualize")] +fn print(rocks: &HashSet, sand: &Coord, part: i32, count: usize) { + let (min_y, min_x, max_y, max_x) = (10, 442, 182, 514); - let bounds = " ".repeat((max_y as usize) - (min_y as usize)); - let mut out = format!("\n{}\n", bounds); + if sand.x < min_x || sand.x > max_x || sand.y < min_y || sand.y > max_y { + return; // Don't render if not displayed + } + + let status = format!("Part: {}, Count: {}", part, count); + let bounds = " ".repeat((max_y as usize) - (min_y as usize) - status.len()); + let mut out = format!("{}{}\n", status, bounds); for x in (min_x..=max_x).rev() { for y in min_y..=max_y { @@ -201,17 +231,18 @@ fn print(rocks: &HashSet, sand: &Coord) { is_rock: false, }; let c = match (sand == testing, rocks.get(testing)) { - (true, _) => 'o', - (_, None) => ' ', - (_, Some(coord)) if coord.is_rock => '#', - _ => 'o', + (true, _) => "\x1B[31mo\x1B[0m", + (_, None) => " ", + (_, Some(coord)) if coord.is_rock => "#", + _ => "\x1B[33mo\x1B[0m", }; - out += &format!("{}", c); + out += c; } out += "\n"; } out += &bounds; - print!("{}", out); - std::io::stdout().flush().unwrap(); - std::thread::sleep(std::time::Duration::from_millis(60)); + // Clear terminal, position cursor at (1,1) + print!("\x1B[1;1H{}", out); + let ms = if part == 1 { 34 } else { 8 }; // Go faster in part 2, takes too long otherwise + std::thread::sleep(std::time::Duration::from_millis(ms)); }