-
-
Save AnthonyMikh/8328a5e13120e5680930d718736e4cb6 to your computer and use it in GitHub Desktop.
/// Верхняя (включающая) граница на размеры поля | |
const BOUND: u32 = 1_000_000; | |
use std::ops::RangeInclusive as RangeEq; | |
/// Возвращает Some(val), если val лежит в range, | |
/// и None в противном случае. | |
fn in_range(val: u32, range: RangeEq<u32>) -> Option<u32> { | |
if *range.start() <= val && val <= *range.end() { | |
Some(val) | |
} else { | |
None | |
} | |
} | |
#[derive(Debug, Clone)] | |
struct PacmanField { | |
height: u32, | |
width: u32, | |
} | |
impl PacmanField { | |
/// Возвращает поле с указанной высотой и шириной | |
/// или None, если какой-либо из указанных размеров | |
/// нулевой или больше BOUND. | |
fn try_new(height: u32, width: u32) -> Option<Self> { | |
in_range(height, 1..=BOUND)?; | |
in_range(width, 1..=BOUND)?; | |
Some(Self { height, width }) | |
} | |
/// Возвращает количество точек, съеденных Пакманом | |
/// при прохождении до точки на пересечении row-ой строки | |
/// и col-ой колонки или None, если указанная точка лежит за пределами поля. | |
/// Строки и столбцы нумеруются от единицы. | |
fn eaten_dots(&self, row: u32, col: u32) -> Option<u32> { | |
let Self { height, width } = self.clone(); | |
in_range(row, 1..=height)?; | |
in_range(col, 1..=width)?; | |
Some(width * (row - 1) + if row % 2 == 0 { width - col + 1 } else { col }) | |
} | |
} | |
/// Возвращает количество точек, съеденных Пакманом при прохождении поля | |
/// с высотой height и шириной width до точки на пересечении row-ой строки | |
/// или None, если: | |
/// 1) одно из указанных размеров некорректно (нулевое или больше BOUND); | |
/// 2) указанная точка лежит за пределами поля. | |
/// Строки и столбцы нумеруются от единицы. | |
fn eaten_dots_on_field(height: u32, width: u32, row: u32, col: u32) -> Option<u32> { | |
PacmanField::try_new(height, width).and_then(|field| field.eaten_dots(row, col)) | |
} | |
fn main() { | |
let field = PacmanField::try_new(3, 4).unwrap(); | |
println!("{:?}", field.eaten_dots(1, 1)); // Some(1) | |
println!("{:?}", field.eaten_dots(3, 3)); // Some(11) | |
println!("{:?}", field.eaten_dots(0, 2)); // None | |
println!("{:?}", field.eaten_dots(9, 2)); // None | |
println!(); | |
println!("{:?}", eaten_dots_on_field(3, 3, 2, 1)); // Some(6) | |
println!("{:?}", eaten_dots_on_field(3, 8, 3, 2)); // Some(18) | |
println!("{:?}", eaten_dots_on_field(1, 1, 9, 9)); // None | |
} |
Пусть нам надо найти количество точек, съеденных Pac-Man-ом при прохождении до точки на пересечении row
-ой строки и col
-ой колонки. Очевидно, при этом предыдущие row - 1
строк уже пройдены тем или иным способом, поэтому съедено как минимум rect = width * (row - 1)
точек. Количество же точек, съеденных на row
-ой строке, зависит от того, в каком направлении Pac-Man движется.
Если row
— нечётное число, то Pac-Man прошёл чётное количество row - 1
строк и начинает проходить row
-ую строку от начала. Тогда количество точек, съеденных в последней строке, очевидно, равно lastline = col
. Если же row
— чётное число, то Pac-Man прошёл нечётное количество row - 1
строк и потому проходит последнюю строку от конца. При этом он проходит через width - col
клеток и останавливается на последней клетке, съедая точку в ней, поэтому всего Pac-Man съедает на последней строке lastline = width - col + 1
точек.
Окончательно получаем
rect = width * (row - 1)
lastline = width - col + 1, если row — чётное
= col, если row — нечётное
total = rect + lastline
Playground: https://play.rust-lang.org/?gist=48f322aad4d479c0bc0a0741f73197d5
Условия: https://t.me/unilecs/501