Parcel shipping cost
A courier prices a parcel from its delivery zone and its weight. Each zone has a base price in cents: local 300, national 550, international 1200. On top of the base price every started 100 g costs 15 cents, so 250 g counts as three units and 100 g as one. Complete the program: turn the zone word into a Zone value, build a Parcel, and implement price so that it returns the cost in cents. Print each parcel's price on its own line, in input order, then Total: <sum>.
Input
The first line is the number of parcels N. Each of the next N lines has a weight in grams and a zone word (local, national or international) separated by a space.
Output
N lines with one price each, then a final line Total: <sum of the prices>.
Example 1
Input
3 250 local 1000 national 5000 international
Output
345 700 1950 Total: 2995
250 g local: 300 + 3 * 15 = 345. 1000 g national: 550 + 10 * 15 = 700. 5000 g international: 1200 + 50 * 15 = 1950. The total is 2995.
Example 2
Input
1 1 local
Output
315 Total: 315
1 g is one started unit of 100 g: 300 + 15 = 315.
Constraints
- 1 <= N <= 1000
- 1 <= weight <= 30000
- The zone word is always one of the three listed
Hints
Hint 1 of 3
A match on the zone word ("local" => Zone::Local, and so on) turns text into the enum; a second match on self.zone gives the base price.
Hint 2 of 3
The number of started 100 g units is (weight_g + 99) / 100.
Hint 3 of 3
Put the base-price match in an impl Zone block and call it from Parcel::price, so each part of the rule lives next to the data it describes.
Solution
Show a reference solution and explanation
use std::io::{self, BufRead};
enum Zone {
Local,
National,
International,
}
impl Zone {
fn from_word(word: &str) -> Zone {
match word {
"local" => Zone::Local,
"national" => Zone::National,
_ => Zone::International,
}
}
fn base_price(&self) -> u32 {
match self {
Zone::Local => 300,
Zone::National => 550,
Zone::International => 1200,
}
}
}
struct Parcel {
weight_g: u32,
zone: Zone,
}
impl Parcel {
fn price(&self) -> u32 {
let started_hundreds = (self.weight_g + 99) / 100;
self.zone.base_price() + 15 * started_hundreds
}
}
fn main() {
let stdin = io::stdin();
let mut lines = stdin.lock().lines();
let n: usize = lines.next().unwrap().unwrap().trim().parse().unwrap();
let mut total = 0;
for _ in 0..n {
let line = lines.next().unwrap().unwrap();
let mut parts = line.split_whitespace();
let weight_g: u32 = parts.next().unwrap().parse().unwrap();
let zone = Zone::from_word(parts.next().unwrap());
let parcel = Parcel { weight_g, zone };
let price = parcel.price();
total += price;
println!("{}", price);
}
println!("Total: {}", total);
}
Why it works
An enum is the right type for a value with exactly three possibilities: the compiler then checks that every match on it handles all three, and adding a fourth zone later produces an error at each place that forgot it. The struct groups the two facts about a parcel, and the impl blocks attach behaviour to the data, so parcel.price() reads naturally at the call site. Parsing text into the enum at the input boundary means the rest of the program never compares strings again. Rounding the weight up to started units uses the same add-then-divide trick as ceiling division elsewhere on this site.