Skip to content

Commit 97392c8

Browse files
committed
feat: fair bandwidth allocation question
1 parent dae5bd6 commit 97392c8

2 files changed

Lines changed: 154 additions & 0 deletions

File tree

src/challenge/challenge_03.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//! Challenge 03: Fair Bandwidth Allocation
2+
use anyhow::Result;
3+
use colored::Colorize;
4+
5+
use crate::utils::{VecPreview, split_whitespace_and_parse};
6+
7+
pub fn run(input: &str, output: Option<&str>) -> Result<String> {
8+
let parts: Vec<f64> = split_whitespace_and_parse(input)?;
9+
anyhow::ensure!(parts.len() == 2, "Input must contain exactly two numbers");
10+
11+
let users = parts[0] as u32;
12+
let total = parts[1];
13+
let result = fair_bandwidth_allocation(users, total);
14+
15+
if let Some(output) = output {
16+
if output == "[]" {
17+
anyhow::ensure!(
18+
users == 0 && result.is_empty(),
19+
"Output does not match expected for 0 users"
20+
);
21+
}
22+
23+
let expected_output: Vec<f64> = split_whitespace_and_parse(output)?;
24+
anyhow::ensure!(
25+
result.len() == expected_output.len()
26+
&& result
27+
.iter()
28+
.zip(expected_output.iter())
29+
.all(|(a, b)| (a - b).abs() < 1e-6),
30+
"Output vector does not match expected: got '{:?}' expected '{:?}'",
31+
result,
32+
expected_output
33+
);
34+
35+
return Ok(format!(
36+
"Result matches the specified output: {}",
37+
result.preview(15)
38+
));
39+
}
40+
41+
let result_str = if result.is_empty() {
42+
"[]"
43+
} else {
44+
&result
45+
.iter()
46+
.map(|&b| format!("{b:.6}"))
47+
.collect::<Vec<String>>()
48+
.join(" ")
49+
};
50+
51+
Ok(format!(
52+
"Calculated allocations: {result_str}, but {} output!",
53+
"missing".red().bold()
54+
))
55+
}
56+
57+
pub fn fair_bandwidth_allocation(users: u32, total: f64) -> Vec<f64> {
58+
if users == 0 {
59+
return vec![];
60+
}
61+
62+
let min = 0.1;
63+
let required = users as f64 * min;
64+
65+
if total >= required {
66+
let remaining = total - required;
67+
let share = remaining / users as f64;
68+
return vec![min + share; users as usize];
69+
}
70+
71+
// Constraint: When the available bandwidth is not enough for
72+
// all the users. You serve just the ones you can.
73+
let served = (total / min).floor() as usize;
74+
vec![min; served]
75+
}
76+
77+
#[cfg(test)]
78+
mod tests {
79+
use super::*;
80+
81+
#[test]
82+
fn test_sufficient_bandwidth() {
83+
let users = 10;
84+
let total_bandwidth = 5.0;
85+
let result = fair_bandwidth_allocation(users, total_bandwidth);
86+
assert_eq!(result.len(), users as usize);
87+
88+
for &allocation in &result {
89+
assert!((allocation - 0.5).abs() < 1e-9);
90+
}
91+
}
92+
93+
#[test]
94+
fn test_insufficient_bandwidth() {
95+
let users = 10;
96+
let total_bandwidth = 0.5;
97+
let result = fair_bandwidth_allocation(users, total_bandwidth);
98+
99+
let expected_len = (total_bandwidth / 0.1).floor() as usize;
100+
assert_eq!(result.len(), expected_len);
101+
102+
for &allocation in &result {
103+
assert!((allocation - 0.1).abs() < 1e-9);
104+
}
105+
}
106+
107+
#[test]
108+
fn test_exact_bandwidth() {
109+
let users = 5;
110+
let total_bandwidth = 0.5;
111+
let result = fair_bandwidth_allocation(users, total_bandwidth);
112+
113+
let expected_len = users as usize;
114+
assert_eq!(result.len(), expected_len);
115+
116+
for &allocation in &result {
117+
assert!((allocation - 0.1).abs() < 1e-9);
118+
}
119+
}
120+
121+
#[test]
122+
fn test_zero_users() {
123+
let users = 0;
124+
let total_bandwidth = 100.0;
125+
let result = fair_bandwidth_allocation(users, total_bandwidth);
126+
127+
assert!(result.is_empty());
128+
}
129+
130+
#[test]
131+
fn test_zero_bandwidth() {
132+
let users = 10;
133+
let total_bandwidth = 0.0;
134+
let result = fair_bandwidth_allocation(users, total_bandwidth);
135+
136+
assert!(result.is_empty());
137+
}
138+
139+
#[test]
140+
fn test_large_numbers() {
141+
let users = 1_000_000;
142+
let total_bandwidth = 230_000_000.0;
143+
let result = fair_bandwidth_allocation(users, total_bandwidth);
144+
assert_eq!(result.len(), users as usize);
145+
146+
let expected_allocation = total_bandwidth / users as f64;
147+
for &allocation in &result {
148+
assert!((allocation - expected_allocation).abs() < 1e-9);
149+
}
150+
}
151+
}

src/challenge/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
mod challenge_01;
22
mod challenge_02;
3+
mod challenge_03;
34

45
pub fn name(challenge: &str) -> Option<&'static str> {
56
match challenge {
67
"01" => Some("Research Lab Recorder"),
78
"02" => Some("Fruit Basket Reorganization"),
9+
"03" => Some("Fair Bandwidth Allocation"),
810
_ => None,
911
}
1012
}
@@ -13,6 +15,7 @@ pub fn run(challenge: &str, input: &str, output: Option<&str>) -> anyhow::Result
1315
match challenge {
1416
"01" => challenge_01::run(input, output),
1517
"02" => challenge_02::run(input, output),
18+
"03" => challenge_03::run(input, output),
1619
_ => anyhow::bail!("Error: Unknown challenge '{challenge}'"),
1720
}
1821
}

0 commit comments

Comments
 (0)