Added testing to day 5 and rewrote to use nom
This commit is contained in:
@@ -8,3 +8,4 @@ repository.workspace = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nom.workspace = true
|
||||
|
||||
229
day5/src/main.rs
229
day5/src/main.rs
@@ -1,40 +1,77 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{prelude::*, BufReader};
|
||||
use std::fs;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Crate {
|
||||
label: String,
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::character::complete::{self, newline};
|
||||
use nom::error::Error;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::sequence::{delimited, preceded, separated_pair};
|
||||
use nom::Parser;
|
||||
|
||||
#[derive(Clone, Debug, Default, Copy)]
|
||||
struct Crate<'a> {
|
||||
label: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GameBoard {
|
||||
impl<'a> Parser<&'a str, Self, Error<&'a str>> for Crate<'a> {
|
||||
fn parse(&mut self, input: &'a str) -> nom::IResult<&'a str, Self, Error<&'a str>> {
|
||||
let (input, label) = delimited::<&str, _, &str, _, Error<&'a str>, _, _, _>(
|
||||
tag("["),
|
||||
complete::alpha1,
|
||||
tag("]"),
|
||||
)(input)?;
|
||||
self.label = label;
|
||||
Ok((input, *self))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Copy)]
|
||||
struct GameMove {
|
||||
quantity: usize,
|
||||
from: usize,
|
||||
to: usize,
|
||||
}
|
||||
impl<'a> Parser<&'a str, Self, Error<&'a str>> for GameMove {
|
||||
fn parse(&mut self, input: &'a str) -> nom::IResult<&'a str, Self, Error<&'a str>> {
|
||||
let (input, quantity) = preceded(tag("move "), complete::u8.map(|x| x as usize))(input)?;
|
||||
let (input, from) = preceded(tag(" from "), complete::u8.map(|x| x as usize))(input)?;
|
||||
let (input, to) = preceded(tag(" to "), complete::u8.map(|x| x as usize))(input)?;
|
||||
self.quantity = quantity;
|
||||
self.from = from;
|
||||
self.to = to;
|
||||
Ok((input, *self))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct GameBoard<'a> {
|
||||
_labels: Vec<String>,
|
||||
board: Vec<Vec<Crate>>,
|
||||
board: Vec<Vec<Crate<'a>>>,
|
||||
}
|
||||
|
||||
impl GameBoard {
|
||||
fn _game1_move(&mut self, count: usize, from: usize, to: usize) {
|
||||
impl<'a> GameBoard<'a> {
|
||||
pub fn game1_move(&mut self, m: &GameMove) {
|
||||
let v = &mut Vec::new();
|
||||
let work = self.board.get_mut(from - 1).unwrap();
|
||||
for _ in 0..count {
|
||||
let work = self.board.get_mut(m.from - 1).unwrap();
|
||||
for _ in 0..m.quantity {
|
||||
v.push(work.pop().unwrap());
|
||||
}
|
||||
let work = self.board.get_mut(to - 1).unwrap();
|
||||
for _ in 0..count {
|
||||
let work = self.board.get_mut(m.to - 1).unwrap();
|
||||
for _ in 0..m.quantity {
|
||||
work.append(v);
|
||||
}
|
||||
}
|
||||
fn game2_move(&mut self, count: usize, from: usize, to: usize) {
|
||||
pub fn game2_move(&mut self, m: &GameMove) {
|
||||
let v = &mut Vec::new();
|
||||
let work = self.board.get_mut(from - 1).unwrap();
|
||||
for _ in 0..count {
|
||||
let work = self.board.get_mut(m.from - 1).unwrap();
|
||||
for _ in 0..m.quantity {
|
||||
v.push(work.pop().unwrap());
|
||||
}
|
||||
v.reverse();
|
||||
let work = self.board.get_mut(to - 1).unwrap();
|
||||
for _ in 0..count {
|
||||
let work = self.board.get_mut(m.to - 1).unwrap();
|
||||
for _ in 0..m.quantity {
|
||||
work.append(v);
|
||||
}
|
||||
}
|
||||
@@ -42,81 +79,99 @@ impl GameBoard {
|
||||
self.board
|
||||
.iter()
|
||||
.map(|x| x.last().unwrap().label.clone())
|
||||
.fold(String::new(), |acc, x| acc + &x)
|
||||
}
|
||||
}
|
||||
impl From<Vec<String>> for GameBoard {
|
||||
fn from(v: Vec<String>) -> Self {
|
||||
let mut board_vec = v.clone();
|
||||
let label_vec = board_vec.pop().unwrap();
|
||||
// get labels
|
||||
let labels = label_vec
|
||||
.split_whitespace()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect::<Vec<String>>();
|
||||
//TODO sscanf for crates
|
||||
board_vec.reverse();
|
||||
let mut board = vec![Vec::new(); labels.len()];
|
||||
for line in &board_vec {
|
||||
board.iter_mut().enumerate().for_each(|(i, col)| {
|
||||
let (begin, end) = (i * 4, std::cmp::min(i * 4 + 4, line.len()));
|
||||
let crate_str = line[begin..end]
|
||||
.to_string()
|
||||
.matches(char::is_alphabetic)
|
||||
.collect::<String>();
|
||||
if !crate_str.is_empty() {
|
||||
col.push(Crate { label: crate_str });
|
||||
}
|
||||
});
|
||||
}
|
||||
GameBoard {
|
||||
_labels: labels,
|
||||
board,
|
||||
}
|
||||
.fold(String::new(), |acc, x| acc + x)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
impl<'a> Parser<&'a str, Self, Error<&'a str>> for GameBoard<'a> {
|
||||
fn parse(&mut self, input: &'a str) -> nom::IResult<&'a str, Self, Error<&'a str>> {
|
||||
let (input, crates) = separated_list1(
|
||||
newline,
|
||||
separated_list1(
|
||||
tag(" "),
|
||||
alt((tag(" ").map(|_| None), Crate::default().map(Some))),
|
||||
),
|
||||
)(input)?;
|
||||
let (input, _) = newline(input)?;
|
||||
let (input, labels) = separated_list1(
|
||||
tag(" "),
|
||||
delimited(tag(" "), complete::u8.map(|x| x.to_string()), tag(" ")),
|
||||
)(input)?;
|
||||
let (input, _) = newline(input)?;
|
||||
//self._labels = labels;
|
||||
let mut board = vec![Vec::new(); crates[0].len()];
|
||||
for cols in crates {
|
||||
for (col, c) in cols.iter().enumerate() {
|
||||
if c.is_none() {
|
||||
continue;
|
||||
}
|
||||
board[col].push(c.unwrap());
|
||||
}
|
||||
}
|
||||
board.iter_mut().for_each(|col| col.reverse());
|
||||
self.board = board;
|
||||
let b = GameBoard {
|
||||
_labels: labels,
|
||||
board: self.board.clone(),
|
||||
};
|
||||
Ok((input, b))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> nom::IResult<&str, (GameBoard, Vec<GameMove>)> {
|
||||
separated_pair(
|
||||
GameBoard::default(),
|
||||
newline,
|
||||
separated_list1(newline, GameMove::default()),
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> String {
|
||||
let (_, (mut board, moves)) = parse_input(input).unwrap();
|
||||
for m in moves {
|
||||
board.game1_move(&m);
|
||||
}
|
||||
board.get_tops()
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> String {
|
||||
let (_, (mut board, moves)) = parse_input(input).unwrap();
|
||||
for m in moves {
|
||||
board.game2_move(&m);
|
||||
}
|
||||
board.get_tops()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
//Read in file
|
||||
let file = File::open("input")?;
|
||||
let reader = BufReader::new(file);
|
||||
let file = fs::read_to_string("input").unwrap();
|
||||
|
||||
//read in the parts of the file
|
||||
let (board_lines, movement_lines, _) = reader.lines().fold(
|
||||
(Vec::new(), Vec::new(), false),
|
||||
|mut acc: (Vec<String>, Vec<String>, bool), line| {
|
||||
let line = line.unwrap();
|
||||
if line.is_empty() {
|
||||
acc.2 = true;
|
||||
} else if acc.2 {
|
||||
acc.1.push(line);
|
||||
} else {
|
||||
acc.0.push(line);
|
||||
}
|
||||
acc
|
||||
},
|
||||
);
|
||||
println!("{board_lines:?}");
|
||||
let mut board = GameBoard::from(board_lines);
|
||||
|
||||
for line in &movement_lines {
|
||||
match line
|
||||
.split_whitespace()
|
||||
.filter_map(|x| x.parse::<usize>().ok())
|
||||
.collect::<Vec<usize>>()[..]
|
||||
{
|
||||
[count, from, to] => board.game2_move(count, from, to),
|
||||
_ => panic!(
|
||||
"{:#?} {:?}",
|
||||
board,
|
||||
line.matches(char::is_numeric)
|
||||
.map(|x| x.parse::<usize>().unwrap())
|
||||
.collect::<Vec<usize>>()
|
||||
),
|
||||
};
|
||||
println!("Part 1: {}", part1(&file));
|
||||
println!("Part 2: {}", part2(&file));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
const INPUT: &str = " [D]
|
||||
[N] [C]
|
||||
[Z] [M] [P]
|
||||
1 2 3
|
||||
|
||||
move 1 from 2 to 1
|
||||
move 3 from 1 to 3
|
||||
move 2 from 2 to 1
|
||||
move 1 from 1 to 2";
|
||||
|
||||
#[test]
|
||||
fn part1_works() {
|
||||
assert_eq!(part1(INPUT), "CMZ");
|
||||
}
|
||||
|
||||
println!("{}", board.get_tops());
|
||||
|
||||
Ok(())
|
||||
#[test]
|
||||
fn part2_works() {
|
||||
assert_eq!(part2(INPUT), "MCD");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user