#![warn(clippy::pedantic)]

use std::io::{stdin, Read};

use aoc::*;

#[derive(Debug, Clone, Copy)]
struct Tree {
    height: u32,
    visible: bool,
    score: usize,
}

fn make_visible<'a>(trees: impl IntoIterator<Item = &'a mut Tree>) {
    let mut seen: Vec<Tree> = Vec::new();
    let mut highest: Option<Tree> = None;

    for tree in trees {
        let update = match highest {
            None => true,
            Some(highest) => tree.height > highest.height,
        };

        if update {
            tree.visible = true;
            highest = Some(*tree);
        }

        let mut score = 0;
        for t in seen.iter().rev() {
            score += 1;
            if t.height >= tree.height {
                break;
            }
        }
        tree.score *= score;
        seen.push(*tree);
    }
}

fn main() {
    let mut data = String::new();
    stdin().read_to_string(&mut data).unwrap();

    let mut grid: Vec<Vec<Tree>> = data
        .lines()
        .map(|line| {
            line.chars()
                .map(|c| Tree {
                    height: c.to_digit(10).unwrap(),
                    visible: false,
                    score: 1,
                })
                .collect()
        })
        .collect();

    for line in &mut grid {
        make_visible(line.iter_mut());
        make_visible(line.iter_mut().rev());
    }

    let width = grid[0].len();
    for i in 0..width {
        make_visible(grid.iter_mut().map(|l| &mut l[i]));
        make_visible(grid.iter_mut().map(|l| &mut l[i]).rev());
    }

    println!("{:?}", grid.iter().flatten().filter(|&t| t.visible).count());
    println!(
        "{:?}",
        grid.iter().flatten().map(|t| t.score).max().unwrap()
    );
}
