From 98f2f530a6d2fdfc5f219f154d43c1ee1c47a445 Mon Sep 17 00:00:00 2001 From: "Matthias@Dell" Date: Sun, 10 Dec 2023 11:44:27 +0100 Subject: [PATCH] day10: rust --- 10/day10.rs | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 10/day10.rs diff --git a/10/day10.rs b/10/day10.rs new file mode 100644 index 0000000..38de88e --- /dev/null +++ b/10/day10.rs @@ -0,0 +1,158 @@ +use std::io::{self, BufRead}; + +// connection2 = connection12 ^ connection1 +const N : u8 = 0b00001000; +const S: u8 = 0b00000100; +const E: u8 = 0b00000010; +const W: u8 = 0b00000001; +const START: u8 = 0b00010000; +const NOTHING: u8 = 0b00000000; +const LOOP_TILE : u8 = 0b10000000; + +#[derive(Eq, PartialEq, Clone, Copy)] +struct Pos { + x: usize, + y: usize, +} +impl Pos { + fn n(&self) -> Option { + if self.y > 0 { return Some(Pos{x: self.x, y: self.y-1}) } + else { return None } + } + fn s(&self) -> Option { Some(Pos{x: self.x, y: self.y+1}) } + fn w(&self) -> Option { + if self.x > 0 { return Some(Pos{x: self.x-1, y: self.y}) } + else { return None } + } + fn e(&self) -> Option { Some(Pos{x: self.x+1, y: self.y}) } +} +impl std::fmt::Display for Pos { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "({}, {})", self.x, self.y) + } +} + +fn follow(tiles: &mut Vec>, start: &Pos, mut direction: u8) -> Option { + let xlen: usize = tiles[0].len(); // assume all are same size + let ylen: usize = tiles.len(); + let mut steps: usize = 0; + let mut current = *start; + // mark the start tile as loop tile and with its directions + tiles[current.y][current.x] = START | direction | LOOP_TILE; + loop { + // println!("Now at {}={} moving in direction {:08b}", current, tiles[current.y][current.x], direction); + let next: Option = match direction { + N => current.n(), + S => current.s(), + E => current.e(), + W => current.w(), + _ => panic!("Invalid direction {}", direction), + }; + if next.is_none() { println!("BOUND"); return None } // reached bounds + current = next.unwrap(); + steps += 1; + // get opposite direction + let opposite: u8; + if direction & 0b1100 != 0 { opposite = direction ^ 0b1100 } + else { opposite = direction ^0b0011 } + // check if back at start + // println!("Tile={:08b}", tiles[current.y][current.x]); + if tiles[current.y][current.x] & START != 0 { + tiles[current.y][current.x] |= opposite; + return Some(steps) + } + // check if connected to last tile + if tiles[current.y][current.x] & opposite == 0 { println!("NC"); return None } // not connected to last + direction = tiles[current.y][current.x] ^ opposite; + // if direction == 0 { return None } // dead end + // mark as part of loop + tiles[current.y][current.x] |= LOOP_TILE; + } +} + + +fn get_inner_area(tiles: &Vec>) -> usize { + let mut count: usize = 0; + for y in 0..tiles.len() { + let mut in_loop: bool = false; + let mut last_corner_tile: u8 = 0; + for x in 0..tiles[0].len() { + if tiles[y][x] & LOOP_TILE != 0 { // loop tile + if tiles[y][x] & (E | W) == 0 { // vertical tile + in_loop = !in_loop + } + else if tiles[y][x] & (N | S) != 0 { // corner + // println!("Corner tile {:08b}", tiles[y][x]); + if last_corner_tile == 0 { + last_corner_tile = tiles[y][x]; + } + // toggle if vertical direction of corner tile differs + else { + if (last_corner_tile & 0b1100) != (tiles[y][x] & 0b1100) { in_loop = !in_loop } + last_corner_tile = 0; + } + } + } + else if in_loop { + count += 1; + println!("({},{})", x, y); + } + } + } + return count; +} + +fn main() { + // let input = "example.txt"; + let input = "input.txt"; + let lines = read_lines(&input); + let mut tiles: Vec> = Vec::new(); + tiles.reserve(150); + let mut start_pos = Pos{x: 0, y: 0}; + for (y, line) in lines.map(|r| r.ok().unwrap()).enumerate() { + tiles.push(line.chars().enumerate().map(|(x, c)| { + match c { + '|' => N | S, + '-' => E | W, + 'L' => N | E, + 'J' => N | W, + '7' => S | W, + 'F' => S | E, + 'S' => { start_pos = Pos{x, y}; START }, + _ => NOTHING + } + }).collect()); + } + let mut distance: usize = 0; + let mut num_tiles: usize = 0; + for direction in [N, S, E, W] { + println!("Starting at ({},{})", start_pos.x, start_pos.y); + if let Some(steps) = follow(&mut tiles, &start_pos, direction) { + assert!(steps % 2 == 0, "steps={} not even", steps); + num_tiles = steps; + distance = steps / 2; + break; + } + else { // reset visited tiles + for y in 0..tiles.len() { + for x in 0..tiles[0].len() { + tiles[y][x] &= 0b0111_1111; + } + } + } + } + println!("Furthest tile distance: (1): {}", distance); + // unmark the start tile + tiles[start_pos.y][start_pos.x] &= !START; + let area = get_inner_area(&tiles); + println!("Area in loop: (2): {}", area); + +} + +fn read_lines

(filename: P) -> io::Lines> +where P: AsRef, { + return match std::fs::File::open(filename) { + Err(why) => panic!("Could not open file. {}", why), + Ok(file) => std::io::BufReader::new(file).lines() + }; +}