Skip to content

Commit

Permalink
completed day 5 part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Lawrence Niu committed Sep 24, 2022
1 parent c38606d commit 7a12007
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 148 deletions.
83 changes: 0 additions & 83 deletions src/bingo.rs

This file was deleted.

32 changes: 32 additions & 0 deletions src/canvas.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::geometry;
use std::collections::hash_map;
use std::collections::HashMap;

pub struct Canvas {
mapping: HashMap<geometry::Point, u32>,
}

impl Canvas {
pub fn new() -> Self {
Canvas {
mapping: HashMap::new(),
}
}

fn count_point(&mut self, point: geometry::Point) {
self.mapping
.entry(point)
.and_modify(|count| {
*count += 1;
})
.or_insert(1);
}

pub fn count_line(&mut self, line: &geometry::Line) {
line.trace().into_iter().for_each(|p| self.count_point(p));
}

pub fn iter(&self) -> hash_map::Iter<'_, geometry::Point, u32> {
self.mapping.iter()
}
}
20 changes: 0 additions & 20 deletions src/draw.rs

This file was deleted.

122 changes: 122 additions & 0 deletions src/geometry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use std::cmp;
use std::error;
use std::fmt;
use std::str;

#[derive(Debug)]
pub struct ParsePointError(String);

impl fmt::Display for ParsePointError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed to parse point from string.\n {}", self.0)
}
}

impl error::Error for ParsePointError {}

#[derive(Eq, Hash, PartialEq)]
pub struct Point {
pub x: u32,
pub y: u32,
}

impl str::FromStr for Point {
type Err = ParsePointError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut tokens = s.split(',');
let x = tokens
.next()
.ok_or(ParsePointError(format!("missing x in \"x,y\"")))
.and_then(|x_str| {
x_str.trim().parse().map_err(|parse_err| {
ParsePointError(format!("failed to parse x.\n {}", parse_err))
})
})?;
let y = tokens
.next()
.ok_or(ParsePointError(format!("missing y in \"x,y\"")))
.and_then(|y_str| {
y_str.trim().parse().map_err(|parse_err| {
ParsePointError(format!("failed to parse y.\n {}", parse_err))
})
})?;
Ok(Point { x, y })
}
}

#[derive(Debug)]
pub struct ParseLineError(String);

impl fmt::Display for ParseLineError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed to parse line from string.\n {}", self.0)
}
}

impl error::Error for ParseLineError {}

pub struct Line {
pub from: Point,
pub to: Point,
}

impl str::FromStr for Line {
type Err = ParseLineError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut tokens = s.split_whitespace();
let from = tokens
.next()
.ok_or(ParseLineError(format!("could not find \"from\" point.")))
.and_then(|from_str| {
from_str.parse().map_err(|parse_err| {
ParseLineError(format!("could not parse \"from\" point.\n {}", parse_err))
})
})?;
tokens.next(); // -> symbol which is ignored
let to = tokens
.next()
.ok_or(ParseLineError(format!("could not find \"to\" point.")))
.and_then(|to_str| {
to_str.parse().map_err(|parse_err| {
ParseLineError(format!("could not parse \"to\" point.\n {}", parse_err))
})
})?;
Ok(Line { from, to })
}
}

impl Line {
pub fn is_diagonal(&self) -> bool {
self.from.x != self.to.x && self.from.y != self.to.y
}

pub fn trace(&self) -> Vec<Point> {
if self.is_diagonal() {
unimplemented!();
}
let is_vertical = self.from.x == self.to.x;
let ((a, b), pivot_value) = if is_vertical {
((self.from.y, self.to.y), self.from.x)
} else {
((self.from.x, self.to.x), self.from.y)
};

(cmp::min(a, b)..=cmp::max(a, b))
.map(|value| {
if is_vertical {
Point {
x: pivot_value,
y: value,
}
} else {
Point {
x: value,
y: pivot_value,
}
}
})
.collect()
}
}
57 changes: 12 additions & 45 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,21 @@
mod bingo;
mod draw;
mod canvas;
mod geometry;

use anyhow::Result;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::str;

fn play_bingo(draws: &[u32], mut boards: Vec<bingo::Board>) -> u64 {
for v in draws.iter().copied() {
boards.iter_mut().for_each(|b| b.mark(v));
if 1 == boards.len() {
if boards[0].has_won() {
return (boards[0].score() as u64) * (v as u64);
}
} else {
boards = boards.into_iter().filter(|b| !b.has_won()).collect();
fn process_lines(reader: impl BufRead) -> Result<u64> {
let mut board = canvas::Canvas::new();
for line_res in reader.lines() {
let line_str = line_res?;
let line: geometry::Line = line_str.parse()?;
if !line.is_diagonal() {
board.count_line(&line);
}
}
unreachable!();
}

fn process_lines(reader: impl BufRead) -> Result<(Vec<u32>, Vec<bingo::Board>)> {
let mut lines_iter = reader.lines();
let draw_str = lines_iter.next().ok_or(draw::ParseDrawError::from(
"could not find draw buffer in file.",
))??;

let draw_buffer: Vec<u32> = draw_str
.split(',')
.map(|token| token.parse::<u32>())
.collect::<Result<Vec<u32>, _>>()?;

let mut boards: Vec<bingo::Board> = Vec::new();
let mut board_buffer: Vec<u32> = Vec::new();
lines_iter.next(); // ignore first empty line
for lines_res in lines_iter {
let line = lines_res?;
if line.is_empty() {
boards.push(bingo::Board::try_from(&board_buffer[..])?);
board_buffer.clear();
} else {
for value in line.split_whitespace() {
board_buffer.push(value.parse()?);
}
}
}
//the last board line is not delimited by an empty space.
boards.push(bingo::Board::try_from(&board_buffer[..])?);

Ok((draw_buffer, boards))
Ok(board.iter().filter(|(_, counts)| 1 < **counts).count() as u64)
}
fn main() {
const INPUT_PATH: &str = "data/input.txt";
Expand All @@ -58,8 +25,8 @@ fn main() {
Err(err) => {
eprintln!("Could not process file {}:\n {}", INPUT_PATH, err);
}
Ok((draws, boards)) => {
println!("Final score: {}", play_bingo(&draws[..], boards));
Ok(count) => {
println!("# overlapping points: {}", count);
}
},
Err(err) => {
Expand Down

0 comments on commit 7a12007

Please sign in to comment.