feat: pass all tests

This commit is contained in:
Kristofers Solo 2024-03-17 21:14:08 +02:00
parent a8311c5e0f
commit 941d905af8
7 changed files with 165 additions and 63 deletions

View File

@ -2,12 +2,22 @@ use std::str::FromStr;
use crate::{error::InputError, utils::Time}; use crate::{error::InputError, utils::Time};
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd)]
pub enum CitizenshipType { pub enum CitizenshipType {
Citizen, Citizen,
NonCitizen, NonCitizen,
} }
impl Ord for CitizenshipType {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(CitizenshipType::Citizen, CitizenshipType::NonCitizen) => std::cmp::Ordering::Less,
(CitizenshipType::NonCitizen, CitizenshipType::Citizen) => std::cmp::Ordering::Greater,
_ => std::cmp::Ordering::Equal,
}
}
}
impl FromStr for CitizenshipType { impl FromStr for CitizenshipType {
type Err = InputError; type Err = InputError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -21,13 +31,16 @@ impl FromStr for CitizenshipType {
#[derive(Debug)] #[derive(Debug)]
pub struct Citizenship { pub struct Citizenship {
pub id: Time, pub arrival_time: Time,
pub type_: CitizenshipType, pub type_: CitizenshipType,
} }
impl Citizenship { impl Citizenship {
pub fn new(id: Time, type_: CitizenshipType) -> Self { pub fn new(arrival_time: Time, type_: CitizenshipType) -> Self {
Self { id, type_ } Self {
arrival_time,
type_,
}
} }
} }
@ -40,7 +53,10 @@ impl FromStr for Citizenship {
(Some(citizenship), Some(id)) => { (Some(citizenship), Some(id)) => {
let id = id.parse::<Time>().map_err(|_| InputError::InvalidFormat)?; let id = id.parse::<Time>().map_err(|_| InputError::InvalidFormat)?;
let type_ = CitizenshipType::from_str(citizenship)?; let type_ = CitizenshipType::from_str(citizenship)?;
Ok(Self { id, type_ }) Ok(Self {
arrival_time: id,
type_,
})
} }
_ => Err(InputError::InvalidFormat), _ => Err(InputError::InvalidFormat),
} }

View File

@ -4,5 +4,6 @@ pub mod customs_info;
pub mod error; pub mod error;
pub mod officer; pub mod officer;
pub mod output; pub mod output;
pub mod output_time;
pub mod process; pub mod process;
pub mod utils; pub mod utils;

View File

@ -6,10 +6,11 @@ use crate::{
utils::{CustomsCount, Time}, utils::{CustomsCount, Time},
}; };
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct Officer { pub struct Officer {
pub id: CustomsCount, pub id: CustomsCount,
pub time: Time, pub processing_time: Time,
pub departure_time: Time,
pub citizenship: CitizenshipType, pub citizenship: CitizenshipType,
} }
@ -17,10 +18,19 @@ impl Officer {
pub fn new(id: CustomsCount, time: Time, citizenship: CitizenshipType) -> Self { pub fn new(id: CustomsCount, time: Time, citizenship: CitizenshipType) -> Self {
Self { Self {
id, id,
time, processing_time: time,
departure_time: 0,
citizenship, citizenship,
} }
} }
pub fn potential_departure_time(&self) -> Time {
self.processing_time + self.departure_time
}
pub fn filter_departure_time(&self, num: Time) -> bool {
self.departure_time == 0 || self.departure_time == num
}
} }
impl PartialOrd for Officer { impl PartialOrd for Officer {
@ -52,7 +62,8 @@ impl FromStr for Officer {
Ok(Self { Ok(Self {
id, id,
citizenship, citizenship,
time, departure_time: 0,
processing_time: time,
}) })
} }
_ => Err(InputError::InvalidFormat), _ => Err(InputError::InvalidFormat),

View File

@ -1,52 +1,44 @@
use std::{cmp, fmt::Display}; use std::fmt::Display;
use crate::{ use crate::{
citizenship::{Citizenship, CitizenshipType}, citizenship::{Citizenship, CitizenshipType},
customs::Customs,
officer::Officer, officer::Officer,
utils::Time, output_time::OutputTime,
utils::{Data, Time},
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct Output(Vec<OutputTime>); pub struct Output(Vec<OutputTime>);
#[derive(Debug)]
pub struct OutputTime {
input: Time,
output: Time,
}
impl Output { impl Output {
pub fn new(mut customs: Customs, all_citizens: Vec<Citizenship>) -> Self { pub fn sort(&mut self) {
customs.sort(); // first by departure time, then by CitizenshipType (citizens first), then by Officer id
dbg!(&customs); self.0.sort_by(|a, b| {
let citizens = Self::from((&customs.citizens, &all_citizens, CitizenshipType::Citizen)); let departure_time_cmp = a.departure_time.cmp(&b.departure_time);
let noncitizens = Self::from(( if departure_time_cmp.is_ne() {
&customs.noncitizens, return departure_time_cmp;
&all_citizens, }
CitizenshipType::NonCitizen, let citizenship_cmp = a.citizenship.cmp(&b.citizenship);
)); if citizenship_cmp.is_ne() {
let mut output = Vec::new(); return citizenship_cmp;
output.extend(citizens.0); }
output.extend(noncitizens.0); a.officer_id.cmp(&b.officer_id)
Self(output) });
} }
} }
impl From<(&Vec<Officer>, &Vec<Citizenship>, CitizenshipType)> for Output { impl From<Data> for Output {
fn from(value: (&Vec<Officer>, &Vec<Citizenship>, CitizenshipType)) -> Self { fn from(value: Data) -> Self {
let (customs, citizens, type_) = value;
let mut outputs = Vec::new(); let mut outputs = Vec::new();
for officer in customs { let mut citizens = value.customs.citizens;
let mut prev = 0; let mut noncitizens = value.customs.noncitizens;
for citizen in citizens {
if citizen.type_ == officer.citizenship && citizen.type_ == type_ { for citizen in &value.citizens {
let output_ = officer.time + cmp::max(citizen.id, prev); let time = match citizen.type_ {
let output = OutputTime::new(citizen.id, output_); CitizenshipType::Citizen => foo(&citizen, &mut citizens),
outputs.push(output); CitizenshipType::NonCitizen => foo(&citizen, &mut noncitizens),
prev = output_; };
} outputs.push(time);
}
} }
Self(outputs) Self(outputs)
} }
@ -69,14 +61,37 @@ impl Into<String> for Output {
} }
} }
impl OutputTime { fn calculate_departure_time(officer: &mut Officer, arrival_time: Time) -> Time {
pub fn new(input: Time, output: Time) -> Self { if arrival_time > officer.departure_time {
Self { input, output } arrival_time + officer.processing_time
} else {
officer.potential_departure_time()
} }
} }
impl Display for OutputTime { fn foo(citizen: &Citizenship, customs: &mut Vec<Officer>) -> OutputTime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let arrival_time = citizen.arrival_time;
write!(f, "{} {}", self.input, self.output)
} let officer = customs
.iter_mut()
.filter(|officer| officer.departure_time == 0 || arrival_time >= officer.departure_time)
.min_by_key(|officer| officer.id);
let officer = match officer {
Some(x) => x,
None => customs
.iter_mut()
.min_by_key(|officer| (officer.departure_time, officer.id))
.unwrap(),
};
let departure_time = calculate_departure_time(officer, arrival_time);
officer.departure_time = departure_time;
OutputTime::new(
arrival_time,
departure_time,
officer.citizenship,
officer.id,
)
} }

48
src/output_time.rs Normal file
View File

@ -0,0 +1,48 @@
use std::fmt::Display;
use crate::{
citizenship::CitizenshipType,
utils::{CustomsCount, Time},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutputTime {
pub arrival_time: Time,
pub departure_time: Time,
pub citizenship: CitizenshipType,
pub officer_id: CustomsCount,
}
impl OutputTime {
pub fn new(
input: Time,
output: Time,
citizenship: CitizenshipType,
officer_id: CustomsCount,
) -> Self {
Self {
arrival_time: input,
departure_time: output,
citizenship,
officer_id,
}
}
}
impl PartialOrd for OutputTime {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.departure_time.partial_cmp(&other.departure_time)
}
}
impl Ord for OutputTime {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.departure_time.cmp(&other.departure_time)
}
}
impl Display for OutputTime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.arrival_time, self.departure_time)
}
}

View File

@ -7,15 +7,16 @@ use crate::{
error::ParseError, error::ParseError,
officer::Officer, officer::Officer,
output::Output, output::Output,
utils::Data,
}; };
pub fn process(input: &str) -> String { pub fn process(input: &str) -> String {
match parse_input(input) { match parse_input(input) {
Ok(data) => data.into(), Ok(mut data) => {
Err(e) => { data.sort();
println!("Error: {e}"); data.into()
"nothing\n".into()
} }
Err(_) => "nothing\n".into(),
} }
} }
@ -49,7 +50,6 @@ pub fn parse_input(input: &str) -> Result<Output, ParseError> {
return Err(ParseError::NoCitizens); return Err(ParseError::NoCitizens);
} }
let mut citizen_customs_new = Vec::new();
for customs_id in 1..=first.citizen.count { for customs_id in 1..=first.citizen.count {
if customs if customs
.citizens .citizens
@ -59,10 +59,9 @@ pub fn parse_input(input: &str) -> Result<Output, ParseError> {
continue; continue;
} }
let new = Officer::new(customs_id, first.citizen.time, CitizenshipType::Citizen); let new = Officer::new(customs_id, first.citizen.time, CitizenshipType::Citizen);
citizen_customs_new.push(new); customs.citizens.push(new);
} }
let mut noncitizen_customs_new = Vec::new();
for customs_id in 1..=first.noncitizen.count { for customs_id in 1..=first.noncitizen.count {
if customs if customs
.noncitizens .noncitizens
@ -76,11 +75,9 @@ pub fn parse_input(input: &str) -> Result<Output, ParseError> {
first.noncitizen.time, first.noncitizen.time,
CitizenshipType::NonCitizen, CitizenshipType::NonCitizen,
); );
noncitizen_customs_new.push(new); customs.noncitizens.push(new);
} }
customs.citizens.extend(citizen_customs_new); let data = Data::new(customs, citizens);
customs.noncitizens.extend(noncitizen_customs_new); Ok(Output::from(data))
Ok(Output::new(customs, citizens))
} }

View File

@ -1,2 +1,16 @@
use crate::{citizenship::Citizenship, customs::Customs};
pub type Time = u32; pub type Time = u32;
pub type CustomsCount = u8; pub type CustomsCount = u8;
#[derive(Debug)]
pub struct Data {
pub customs: Customs,
pub citizens: Vec<Citizenship>,
}
impl Data {
pub fn new(customs: Customs, citizens: Vec<Citizenship>) -> Self {
Self { customs, citizens }
}
}