MediumStructs and enumsNot started

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
 Rust · reference solution
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.

Your program
use std::io::{self, BufRead};

enum Zone {
    Local,
    National,
    International,
}

struct Parcel {
    weight_g: u32,
    zone: Zone,
}

impl Parcel {
    fn price(&self) -> u32 {
        // base price for the zone plus 15 cents per started 100 g
        0
    }
}

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_word = parts.next().unwrap();
        // turn zone_word into a Zone, build a Parcel and price it
        let parcel = Parcel { weight_g, zone: Zone::Local };
        let price = parcel.price();
        total += price;
        println!("{}", price);
    }
    println!("Total: {}", total);
}
Run is not available for Rust in the browser yet. Write your program here, then download it and run it locally with rustc 1.94 against the examples above. The reference solution below was verified the same way.

Tests: 5 cases including the examples. Passing every test marks the exercise solved in this browser.

How this page was checked. Every program on it was run with rustc 1.94 at build time by the publishing checks, and the output shown is what it printed. Running Rust inside the browser is not available yet, so the Run button is absent rather than pretending; copy the code and run it with rustc 1.94 locally.