mirror of
https://github.com/kristoferssolo/customs-rs.git
synced 2025-10-21 19:20:33 +00:00
feat: pass all tests
This commit is contained in:
parent
a8311c5e0f
commit
941d905af8
@ -2,12 +2,22 @@ use std::str::FromStr;
|
||||
|
||||
use crate::{error::InputError, utils::Time};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd)]
|
||||
pub enum CitizenshipType {
|
||||
Citizen,
|
||||
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 {
|
||||
type Err = InputError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
@ -21,13 +31,16 @@ impl FromStr for CitizenshipType {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Citizenship {
|
||||
pub id: Time,
|
||||
pub arrival_time: Time,
|
||||
pub type_: CitizenshipType,
|
||||
}
|
||||
|
||||
impl Citizenship {
|
||||
pub fn new(id: Time, type_: CitizenshipType) -> Self {
|
||||
Self { id, type_ }
|
||||
pub fn new(arrival_time: Time, type_: CitizenshipType) -> Self {
|
||||
Self {
|
||||
arrival_time,
|
||||
type_,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +53,10 @@ impl FromStr for Citizenship {
|
||||
(Some(citizenship), Some(id)) => {
|
||||
let id = id.parse::<Time>().map_err(|_| InputError::InvalidFormat)?;
|
||||
let type_ = CitizenshipType::from_str(citizenship)?;
|
||||
Ok(Self { id, type_ })
|
||||
Ok(Self {
|
||||
arrival_time: id,
|
||||
type_,
|
||||
})
|
||||
}
|
||||
_ => Err(InputError::InvalidFormat),
|
||||
}
|
||||
|
||||
@ -4,5 +4,6 @@ pub mod customs_info;
|
||||
pub mod error;
|
||||
pub mod officer;
|
||||
pub mod output;
|
||||
pub mod output_time;
|
||||
pub mod process;
|
||||
pub mod utils;
|
||||
|
||||
@ -6,10 +6,11 @@ use crate::{
|
||||
utils::{CustomsCount, Time},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Officer {
|
||||
pub id: CustomsCount,
|
||||
pub time: Time,
|
||||
pub processing_time: Time,
|
||||
pub departure_time: Time,
|
||||
pub citizenship: CitizenshipType,
|
||||
}
|
||||
|
||||
@ -17,10 +18,19 @@ impl Officer {
|
||||
pub fn new(id: CustomsCount, time: Time, citizenship: CitizenshipType) -> Self {
|
||||
Self {
|
||||
id,
|
||||
time,
|
||||
processing_time: time,
|
||||
departure_time: 0,
|
||||
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 {
|
||||
@ -52,7 +62,8 @@ impl FromStr for Officer {
|
||||
Ok(Self {
|
||||
id,
|
||||
citizenship,
|
||||
time,
|
||||
departure_time: 0,
|
||||
processing_time: time,
|
||||
})
|
||||
}
|
||||
_ => Err(InputError::InvalidFormat),
|
||||
|
||||
@ -1,52 +1,44 @@
|
||||
use std::{cmp, fmt::Display};
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::{
|
||||
citizenship::{Citizenship, CitizenshipType},
|
||||
customs::Customs,
|
||||
officer::Officer,
|
||||
utils::Time,
|
||||
output_time::OutputTime,
|
||||
utils::{Data, Time},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Output(Vec<OutputTime>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OutputTime {
|
||||
input: Time,
|
||||
output: Time,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
pub fn new(mut customs: Customs, all_citizens: Vec<Citizenship>) -> Self {
|
||||
customs.sort();
|
||||
dbg!(&customs);
|
||||
let citizens = Self::from((&customs.citizens, &all_citizens, CitizenshipType::Citizen));
|
||||
let noncitizens = Self::from((
|
||||
&customs.noncitizens,
|
||||
&all_citizens,
|
||||
CitizenshipType::NonCitizen,
|
||||
));
|
||||
let mut output = Vec::new();
|
||||
output.extend(citizens.0);
|
||||
output.extend(noncitizens.0);
|
||||
Self(output)
|
||||
pub fn sort(&mut self) {
|
||||
// first by departure time, then by CitizenshipType (citizens first), then by Officer id
|
||||
self.0.sort_by(|a, b| {
|
||||
let departure_time_cmp = a.departure_time.cmp(&b.departure_time);
|
||||
if departure_time_cmp.is_ne() {
|
||||
return departure_time_cmp;
|
||||
}
|
||||
let citizenship_cmp = a.citizenship.cmp(&b.citizenship);
|
||||
if citizenship_cmp.is_ne() {
|
||||
return citizenship_cmp;
|
||||
}
|
||||
a.officer_id.cmp(&b.officer_id)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&Vec<Officer>, &Vec<Citizenship>, CitizenshipType)> for Output {
|
||||
fn from(value: (&Vec<Officer>, &Vec<Citizenship>, CitizenshipType)) -> Self {
|
||||
let (customs, citizens, type_) = value;
|
||||
impl From<Data> for Output {
|
||||
fn from(value: Data) -> Self {
|
||||
let mut outputs = Vec::new();
|
||||
for officer in customs {
|
||||
let mut prev = 0;
|
||||
for citizen in citizens {
|
||||
if citizen.type_ == officer.citizenship && citizen.type_ == type_ {
|
||||
let output_ = officer.time + cmp::max(citizen.id, prev);
|
||||
let output = OutputTime::new(citizen.id, output_);
|
||||
outputs.push(output);
|
||||
prev = output_;
|
||||
}
|
||||
}
|
||||
let mut citizens = value.customs.citizens;
|
||||
let mut noncitizens = value.customs.noncitizens;
|
||||
|
||||
for citizen in &value.citizens {
|
||||
let time = match citizen.type_ {
|
||||
CitizenshipType::Citizen => foo(&citizen, &mut citizens),
|
||||
CitizenshipType::NonCitizen => foo(&citizen, &mut noncitizens),
|
||||
};
|
||||
outputs.push(time);
|
||||
}
|
||||
Self(outputs)
|
||||
}
|
||||
@ -69,14 +61,37 @@ impl Into<String> for Output {
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputTime {
|
||||
pub fn new(input: Time, output: Time) -> Self {
|
||||
Self { input, output }
|
||||
fn calculate_departure_time(officer: &mut Officer, arrival_time: Time) -> Time {
|
||||
if arrival_time > officer.departure_time {
|
||||
arrival_time + officer.processing_time
|
||||
} else {
|
||||
officer.potential_departure_time()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for OutputTime {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} {}", self.input, self.output)
|
||||
}
|
||||
fn foo(citizen: &Citizenship, customs: &mut Vec<Officer>) -> OutputTime {
|
||||
let arrival_time = citizen.arrival_time;
|
||||
|
||||
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
48
src/output_time.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -7,15 +7,16 @@ use crate::{
|
||||
error::ParseError,
|
||||
officer::Officer,
|
||||
output::Output,
|
||||
utils::Data,
|
||||
};
|
||||
|
||||
pub fn process(input: &str) -> String {
|
||||
match parse_input(input) {
|
||||
Ok(data) => data.into(),
|
||||
Err(e) => {
|
||||
println!("Error: {e}");
|
||||
"nothing\n".into()
|
||||
Ok(mut data) => {
|
||||
data.sort();
|
||||
data.into()
|
||||
}
|
||||
Err(_) => "nothing\n".into(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +50,6 @@ pub fn parse_input(input: &str) -> Result<Output, ParseError> {
|
||||
return Err(ParseError::NoCitizens);
|
||||
}
|
||||
|
||||
let mut citizen_customs_new = Vec::new();
|
||||
for customs_id in 1..=first.citizen.count {
|
||||
if customs
|
||||
.citizens
|
||||
@ -59,10 +59,9 @@ pub fn parse_input(input: &str) -> Result<Output, ParseError> {
|
||||
continue;
|
||||
}
|
||||
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 {
|
||||
if customs
|
||||
.noncitizens
|
||||
@ -76,11 +75,9 @@ pub fn parse_input(input: &str) -> Result<Output, ParseError> {
|
||||
first.noncitizen.time,
|
||||
CitizenshipType::NonCitizen,
|
||||
);
|
||||
noncitizen_customs_new.push(new);
|
||||
customs.noncitizens.push(new);
|
||||
}
|
||||
|
||||
customs.citizens.extend(citizen_customs_new);
|
||||
customs.noncitizens.extend(noncitizen_customs_new);
|
||||
|
||||
Ok(Output::new(customs, citizens))
|
||||
let data = Data::new(customs, citizens);
|
||||
Ok(Output::from(data))
|
||||
}
|
||||
|
||||
14
src/utils.rs
14
src/utils.rs
@ -1,2 +1,16 @@
|
||||
use crate::{citizenship::Citizenship, customs::Customs};
|
||||
|
||||
pub type Time = u32;
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user