use advent2020::errors::{SeatParseError, TopLevelError}; use std::cmp::{Ord, Ordering}; use std::collections::BTreeSet; use std::env; use std::fs; use std::str::FromStr; const PLANE_ROWS: usize = 128; const PLANE_COLUMNS: usize = 8; #[derive(Debug)] struct Seat { row: usize, column: usize, id: usize, } impl PartialOrd for Seat { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialEq for Seat { fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl Eq for Seat {} impl Ord for Seat { fn cmp(&self, other: &Self) -> Ordering { self.id.cmp(&other.id) } } impl FromStr for Seat { type Err = SeatParseError; fn from_str(map: &str) -> Result { if map.len() != 10 { return Err(SeatParseError::InvalidSeatIdentifier(map.to_string())); } let (row_stuff, column_stuff) = map.split_at(7); let mut row_high = PLANE_ROWS - 1; let mut row_low = 0; for direction in row_stuff.chars() { match direction { 'F' => row_high = row_low + ((row_high - row_low) / 2), 'B' => row_low = row_low + ((row_high - row_low + 1) / 2), _ => return Err(SeatParseError::UnexpectedRowCharacter(direction)), } } if row_high != row_low { return Err(SeatParseError::DidNotResolveRow(map.to_string())); } let mut column_high = PLANE_COLUMNS - 1; let mut column_low = 0; for direction in column_stuff.chars() { match direction { 'L' => column_high = column_low + ((column_high - column_low) / 2), 'R' => column_low = column_low + ((column_high - column_low + 1) / 2), _ => return Err(SeatParseError::UnexpectedColumnCharacter(direction)), } } if column_high != column_low { return Err(SeatParseError::DidNotResolveColumn(map.to_string())); } Ok(Seat { row: row_high, column: column_high, id: (row_high * PLANE_COLUMNS) + column_high, }) } } #[test] fn example_boarding_passes() { assert_eq!( Seat::from_str("FBFBBFFRLR"), Ok(Seat { row: 44, column: 5, id: 357 }) ); assert_eq!( Seat::from_str("BFFFBBFRRR"), Ok(Seat { row: 70, column: 7, id: 567 }) ); assert_eq!( Seat::from_str("FFFBBBFRRR"), Ok(Seat { row: 14, column: 7, id: 119 }) ); assert_eq!( Seat::from_str("BBFFBBFRLL"), Ok(Seat { row: 102, column: 4, id: 820 }) ); } fn real_main() -> Result<(), TopLevelError> { let mut seats = BTreeSet::new(); let mut highest_id = 0; for argument in env::args().skip(1) { let contents = fs::read_to_string(argument)?; for line in contents.lines() { let seat = Seat::from_str(line)?; if seat.id > highest_id { highest_id = seat.id; } seats.insert(seat); } } println!("Loaded {} seats.", seats.len()); println!(" highest id is {}", highest_id); let mut last_id = 0; for seat in seats.iter() { if seat.id == last_id + 2 { println!(" my seat is {}", last_id + 1); return Ok(()); } last_id = seat.id; } Err(TopLevelError::NoSolutionFound) } fn main() { if let Err(e) = real_main() { eprintln!("ERROR: {}", e); } }