#![warn(clippy::pedantic)]
use std::collections::HashSet;
use std::io::{stdin, Read};

use nom::bytes::complete::tag;
use nom::character::complete::{anychar, newline, u32};
use nom::combinator::{map, map_opt};
use nom::multi::many1;
use nom::sequence::{preceded, separated_pair, terminated};

type Input<'a> = &'a str;
type IResult<'a, T> = nom::IResult<Input<'a>, T>;

type Point = (usize, usize);

fn point(i: Input) -> IResult<Point> {
    separated_pair(map(u32, |i| i as usize), tag(","), map(u32, |i| i as usize))(i)
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Fold {
    X(usize),
    Y(usize),
}

fn fold(i: Input) -> IResult<Fold> {
    map_opt(
        preceded(
            tag("fold along "),
            separated_pair(anychar, tag("="), map(u32, |i| i as usize)),
        ),
        |(dimension, position)| match dimension {
            'x' => Some(Fold::X(position)),
            'y' => Some(Fold::Y(position)),
            _ => None,
        },
    )(i)
}

fn input(i: Input) -> IResult<(Vec<Point>, Vec<Fold>)> {
    separated_pair(
        many1(terminated(point, newline)),
        newline,
        many1(terminated(fold, newline)),
    )(i)
}

fn do_fold(points: impl Iterator<Item = Point>, fold: Fold) -> HashSet<Point> {
    let transform = |x, n| if x < n { x } else { n - (x - n) };
    points
        .map(|(x, y)| match fold {
            Fold::X(n) => (transform(x, n), y),
            Fold::Y(n) => (x, transform(y, n)),
        })
        .collect()
}

fn main() {
    let mut data = String::new();
    stdin().lock().read_to_string(&mut data).unwrap();
    let (points, folds) = input(&data).unwrap().1;

    let mut points: HashSet<_> = points.into_iter().collect();
    let mut folds = folds.into_iter();

    points = do_fold(points.into_iter(), folds.next().unwrap());
    println!("{}", points.len());

    for fold in folds {
        points = do_fold(points.into_iter(), fold);
    }

    for row in 0..=points.iter().map(|&(_, y)| y).max().unwrap() {
        for col in 0..=points.iter().map(|&(x, _)| x).max().unwrap() {
            if points.contains(&(col, row)) {
                print!("#");
            } else {
                print!(".");
            }
        }
        println!();
    }
}
