#![warn(clippy::pedantic)]

use std::{cmp::max, io::stdin, str::FromStr};

use enum_map::{enum_map, Enum, EnumMap};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)]
enum Colour {
    Red,
    Green,
    Blue,
}

impl FromStr for Colour {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "red" => Ok(Self::Red),
            "green" => Ok(Self::Green),
            "blue" => Ok(Self::Blue),
            _ => Err(()),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Draw {
    cubes: EnumMap<Colour, usize>,
}

impl Draw {
    pub fn is_valid(&self) -> bool {
        let max_values = enum_map! {
            Colour::Red => 12,
            Colour::Green => 13,
            Colour::Blue => 14,
        };

        self.cubes.iter().all(|(c, n)| *n <= max_values[c])
    }
}

impl FromStr for Draw {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let cubes = s
            .split(", ")
            .map(|c| {
                let (n, colour) = c.split_once(' ').unwrap();
                let n = n.parse().unwrap();
                let colour = colour.parse().unwrap();
                (colour, n)
            })
            .collect();
        Ok(Draw { cubes })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Game {
    draws: Vec<Draw>,
}

impl Game {
    pub fn is_valid(&self) -> bool {
        self.draws.iter().all(Draw::is_valid)
    }

    pub fn minimum_cubes_power(&self) -> usize {
        self.draws
            .iter()
            .map(|draw| draw.cubes)
            .fold(EnumMap::default(), |mut acc, cubes| {
                for (c, n) in cubes {
                    acc[c] = max(acc[c], n);
                }
                acc
            })
            .values()
            .product()
    }
}

impl FromStr for Game {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let (_, draws) = s.split_once(": ").unwrap();
        let draws = draws
            .split("; ")
            .map(|draw| draw.parse().unwrap())
            .collect();
        Ok(Game { draws })
    }
}

fn main() {
    let games: Vec<Game> = stdin()
        .lines()
        .map(|l| l.unwrap().parse().unwrap())
        .collect();

    let valid_game_ids = games
        .iter()
        .enumerate()
        .filter_map(|(i, g)| g.is_valid().then_some(i + 1));

    println!("{}", valid_game_ids.sum::<usize>());

    let powers = games.iter().map(Game::minimum_cubes_power);

    println!("{}", powers.sum::<usize>());
}
