Skip to content

Instantly share code, notes, and snippets.

@AnthonyMikh
Created October 21, 2018 15:14
Show Gist options
  • Save AnthonyMikh/8328a5e13120e5680930d718736e4cb6 to your computer and use it in GitHub Desktop.
Save AnthonyMikh/8328a5e13120e5680930d718736e4cb6 to your computer and use it in GitHub Desktop.
Решение задачи №133 от UniLecs (Pac-Man)
/// Верхняя (включающая) граница на размеры поля
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
}
@AnthonyMikh
Copy link
Author

@AnthonyMikh
Copy link
Author

AnthonyMikh commented Oct 21, 2018

Пусть нам надо найти количество точек, съеденных 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment