use std::{io::{stdin, Read}, collections::HashSet};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
struct Pt(i32, i32);
fn main() {
let mut stdin = stdin();
let mut buf = String::new();
stdin.read_to_string(&mut buf).unwrap();
let mut tiles: HashSet<Pt> = HashSet::new();
let mut lowest: i32 = 0;
for line in buf.split("\n") {
let pts: Vec<Pt> = line.split(" -> ").map(|l| {
let pts: Vec<&str> = l.split(",").collect();
Pt(pts[0].parse().unwrap(), pts[1].parse().unwrap())
}).collect();
let mut pos = pts[0];
tiles.insert(pos);
if pos.1 > lowest { lowest = pos.1; }
for i in 1..pts.len() {
let diff = if pts[i].1 == pos.1 {
if pts[i].0 < pos.0 { Pt(-1, 0) } else { Pt(1, 0) }
} else {
if pts[i].1 < pos.1 { Pt(0, -1) } else { Pt(0, 1) }
};
while pos != pts[i] {
pos.0 += diff.0;
pos.1 += diff.1;
tiles.insert(pos);
if pos.1 > lowest { lowest = pos.1; }
}
}
}
let sand_point = Pt(500, 0);
let mut sands: u32 = 0;
'a: loop {
let mut p = sand_point;
loop {
if is_free(&tiles, lowest, Pt(p.0, p.1 + 1)) {
p.1 += 1;
} else if is_free(&tiles, lowest, Pt(p.0 - 1, p.1 + 1)) {
p.0 -= 1;
p.1 += 1;
} else if is_free(&tiles, lowest, Pt(p.0 + 1, p.1 + 1)) {
p.0 += 1;
p.1 += 1;
} else {
tiles.insert(p);
sands += 1;
if p == sand_point { break 'a; } // part 2
break;
}
// if p.1 > lowest { break 'a; } // part 1
}
}
println!("{}", sands);
}
fn is_free(tiles: &HashSet<Pt>, lowest: i32, pt: Pt) -> bool {
// !tiles.contains(&pt) // part 1
if pt.1 > lowest + 1 { false } // part 2
else { !tiles.contains(&pt) }
}