2022 Day 22 Part 1 but there's a bug somewhere...
This commit is contained in:
parent
5546820772
commit
dcbfeb2844
1 changed files with 308 additions and 0 deletions
308
2022/src/bin/day22.rs
Normal file
308
2022/src/bin/day22.rs
Normal file
|
|
@ -0,0 +1,308 @@
|
||||||
|
use std::{iter::Peekable, str::Chars};
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../../input/day22.txt");
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (board, moves) = parse(INPUT);
|
||||||
|
|
||||||
|
println!("{}", part1(board, moves));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &str) -> (Board, Vec<Move>) {
|
||||||
|
let mut blocks = aoc::blocks(input);
|
||||||
|
|
||||||
|
let board = Board::parse(blocks.next().unwrap());
|
||||||
|
let moves = Move::parse_all(blocks.next().unwrap().trim());
|
||||||
|
|
||||||
|
assert!(blocks.next().is_none());
|
||||||
|
|
||||||
|
(board, moves)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Board {
|
||||||
|
rows: Vec<Range>,
|
||||||
|
cols: Vec<Range>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
enum Tile {
|
||||||
|
Open,
|
||||||
|
Wall,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Range {
|
||||||
|
start: usize,
|
||||||
|
tiles: Vec<Tile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Range {
|
||||||
|
fn start(&self) -> usize {
|
||||||
|
self.start
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&self) -> usize {
|
||||||
|
self.start + self.tiles.len() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn at(&self, c: usize) -> Option<Tile> {
|
||||||
|
if self.start() <= c && c <= self.end() {
|
||||||
|
return Some(self.tiles[c - self.start]);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Board {
|
||||||
|
fn parse(text: &str) -> Self {
|
||||||
|
let rows = Self::parse_rows(text);
|
||||||
|
let cols = Self::parse_cols(&rows);
|
||||||
|
|
||||||
|
let row_max = rows.len() - 1;
|
||||||
|
let col_max = cols.len() - 1;
|
||||||
|
|
||||||
|
let board = Self { rows, cols };
|
||||||
|
board.check(row_max, col_max);
|
||||||
|
board
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_rows(text: &str) -> Vec<Range> {
|
||||||
|
let lines: Vec<&str> = text.lines().collect();
|
||||||
|
|
||||||
|
let mut rows = vec![];
|
||||||
|
|
||||||
|
let mut col_max = 0;
|
||||||
|
|
||||||
|
for line in lines.iter() {
|
||||||
|
let mut start = 0usize;
|
||||||
|
let mut tiles = vec![];
|
||||||
|
for fill in line.chars() {
|
||||||
|
match fill {
|
||||||
|
' ' => start += 1,
|
||||||
|
'.' => tiles.push(Tile::Open),
|
||||||
|
'#' => tiles.push(Tile::Wall),
|
||||||
|
other => panic!("{:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
col_max = col_max.max(start + tiles.len());
|
||||||
|
|
||||||
|
rows.push(Range { start, tiles });
|
||||||
|
}
|
||||||
|
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_cols(rows: &[Range]) -> Vec<Range> {
|
||||||
|
let col_max = rows.iter().map(|r| r.end()).max().unwrap();
|
||||||
|
|
||||||
|
let mut cols = vec![];
|
||||||
|
|
||||||
|
for c in 0..=col_max {
|
||||||
|
let mut start = 0;
|
||||||
|
for (r, row) in rows.iter().enumerate() {
|
||||||
|
if row.at(c).is_some() {
|
||||||
|
start = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tiles = vec![];
|
||||||
|
for row in &rows[start..] {
|
||||||
|
let Some(tile) = row.at(c) else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
tiles.push(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
cols.push(Range { start, tiles })
|
||||||
|
}
|
||||||
|
|
||||||
|
cols
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check(&self, row_max: usize, col_max: usize) {
|
||||||
|
for r in 0..=row_max {
|
||||||
|
for c in 0..=col_max {
|
||||||
|
assert_eq!(self.rows[r].at(c), self.cols[c].at(r), "{} {}", r, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum Move {
|
||||||
|
Forward(u64),
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Move {
|
||||||
|
fn parse_all(line: &str) -> Vec<Self> {
|
||||||
|
let mut chars = line.chars().peekable();
|
||||||
|
let mut moves = vec![];
|
||||||
|
|
||||||
|
let mut mv = chars.peek().unwrap().is_ascii_digit();
|
||||||
|
while chars.peek().is_some() {
|
||||||
|
if mv {
|
||||||
|
moves.push(Self::parse_walk(&mut chars));
|
||||||
|
} else {
|
||||||
|
moves.push(Self::parse_turn(&mut chars));
|
||||||
|
}
|
||||||
|
mv = !mv;
|
||||||
|
}
|
||||||
|
moves
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_walk(chars: &mut Peekable<Chars>) -> Self {
|
||||||
|
let mut n = 0;
|
||||||
|
loop {
|
||||||
|
let Some(c) = chars.peek() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if !c.is_ascii_digit() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = chars.next().unwrap();
|
||||||
|
|
||||||
|
n *= 10;
|
||||||
|
n += (c as u64) - ('0' as u64);
|
||||||
|
}
|
||||||
|
Move::Forward(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_turn(chars: &mut Peekable<Chars>) -> Self {
|
||||||
|
match chars.next().unwrap() {
|
||||||
|
'L' => Move::Left,
|
||||||
|
'R' => Move::Right,
|
||||||
|
other => panic!("{:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
enum Heading {
|
||||||
|
North,
|
||||||
|
East,
|
||||||
|
South,
|
||||||
|
West,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Heading {
|
||||||
|
fn turn_left(&self) -> Self {
|
||||||
|
use Heading::*;
|
||||||
|
match self {
|
||||||
|
North => West,
|
||||||
|
East => North,
|
||||||
|
South => East,
|
||||||
|
West => South,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn turn_right(&self) -> Self {
|
||||||
|
use Heading::*;
|
||||||
|
match self {
|
||||||
|
North => East,
|
||||||
|
East => South,
|
||||||
|
South => West,
|
||||||
|
West => North,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(board: Board, moves: Vec<Move>) -> u64 {
|
||||||
|
let mut r = 0;
|
||||||
|
let mut c = board.rows[r].start;
|
||||||
|
let mut h = Heading::East;
|
||||||
|
|
||||||
|
for mv in moves {
|
||||||
|
match mv {
|
||||||
|
Move::Left => h = h.turn_left(),
|
||||||
|
Move::Right => h = h.turn_right(),
|
||||||
|
Move::Forward(steps) => (r, c) = board.walk(r, c, h, steps),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
score(r, c, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn score(r: usize, c: usize, h: Heading) -> u64 {
|
||||||
|
// 1 indexing
|
||||||
|
let r: u64 = (r + 1).try_into().unwrap();
|
||||||
|
let c: u64 = (c + 1).try_into().unwrap();
|
||||||
|
|
||||||
|
let h = match h {
|
||||||
|
Heading::North => 3,
|
||||||
|
Heading::East => 0,
|
||||||
|
Heading::South => 1,
|
||||||
|
Heading::West => 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
1000 * r + 4 * c + h
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Board {
|
||||||
|
fn walk(&self, r: usize, c: usize, h: Heading, distance: u64) -> (usize, usize) {
|
||||||
|
let d: i64 = distance.try_into().unwrap();
|
||||||
|
match h {
|
||||||
|
Heading::North => self.walk_vertical(r, c, -d),
|
||||||
|
Heading::South => self.walk_vertical(r, c, d),
|
||||||
|
|
||||||
|
Heading::East => self.walk_horizontal(r, c, d),
|
||||||
|
Heading::West => self.walk_horizontal(r, c, -d),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_horizontal(&self, r: usize, c: usize, dc: i64) -> (usize, usize) {
|
||||||
|
let c = self.rows[r].walk(c, dc);
|
||||||
|
(r, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_vertical(&self, r: usize, c: usize, dr: i64) -> (usize, usize) {
|
||||||
|
let r = self.cols[c].walk(r, dr);
|
||||||
|
(r, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Range {
|
||||||
|
fn walk(&self, offset: usize, delta: i64) -> usize {
|
||||||
|
let mut walkway: Vec<(usize, Tile)> = self
|
||||||
|
.tiles
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, t)| (i + self.start, t))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Walkway starts at current position.
|
||||||
|
walkway.rotate_left(offset - self.start);
|
||||||
|
assert_eq!(walkway[0], (offset, Tile::Open));
|
||||||
|
|
||||||
|
if delta < 0 {
|
||||||
|
walkway.reverse();
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_walk: usize = delta.abs().try_into().unwrap();
|
||||||
|
|
||||||
|
println!("{} {} {}", offset, delta, to_walk);
|
||||||
|
|
||||||
|
let dest = walkway
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.cycle()
|
||||||
|
.take(to_walk + 1) // Consume the start tile
|
||||||
|
.inspect(|(i, t)| {
|
||||||
|
println!("{} {:?}", i, t);
|
||||||
|
})
|
||||||
|
.take_while(|&(_i, t)| t == Tile::Open)
|
||||||
|
.last();
|
||||||
|
|
||||||
|
match dest {
|
||||||
|
Some((i, _tile)) => i,
|
||||||
|
None => offset, // Didn't move
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue