use crate::{BOARD_HEIGHT, BOARD_WIDTH, Coord, Dir, Tile, board::Board};
pub fn get_end_of_block_chain(board: &Board, start: &Coord, dir: &Dir) -> Option<(Coord, u64)> {
let mut next_tile = Tile::Block;
let mut end_coord = *start;
let mut blocks_moved = 0;
while next_tile == Tile::Block {
if let Some(next_coord) = get_next_coord(&end_coord, dir) {
next_tile = board[next_coord];
end_coord = next_coord;
match next_tile {
Tile::Block => {
blocks_moved += 1;
},
_ => {
break;
},
}
} else {
return None;
}
}
Some((end_coord, blocks_moved))
}
pub fn get_next_coord(coord: &Coord, dir: &Dir) -> Option<Coord> {
match dir {
Dir::Up if coord.row > 0 => Some(Coord {
row: coord.row - 1,
column: coord.column,
}),
Dir::Right if coord.column < BOARD_WIDTH - 1 => Some(Coord {
row: coord.row,
column: coord.column + 1,
}),
Dir::Down if coord.row < BOARD_HEIGHT - 1 => Some(Coord {
row: coord.row + 1,
column: coord.column,
}),
Dir::Left if coord.column > 0 => Some(Coord {
row: coord.row,
column: coord.column - 1,
}),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_end_of_block_chain_up_test() {
let mut board = Board::new([[Tile::Empty; BOARD_WIDTH]; BOARD_HEIGHT]);
let start = Coord { column: 0, row: 3 };
let dir = Dir::Up;
board.data[0][0] = Tile::CommonBeast;
board.data[1][0] = Tile::Block;
board.data[2][0] = Tile::Block;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 0, row: 0 }, 2)),
"Should seek to the position where the CommonBeast is"
);
board.data[3][0] = Tile::SuperBeast;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 0, row: 0 }, 2)),
"Should seek to the position where the SuperBeast is"
);
board.data[0][0] = Tile::Block;
assert_eq!(get_end_of_block_chain(&board, &start, &dir), None, "When hitting the frame return None");
}
#[test]
fn get_end_of_block_chain_right_test() {
let mut board = Board::new([[Tile::Empty; BOARD_WIDTH]; BOARD_HEIGHT]);
let start = Coord { column: 0, row: 0 };
let dir = Dir::Right;
board.data[0][1] = Tile::Block;
board.data[0][2] = Tile::Block;
board.data[0][3] = Tile::Block;
board.data[0][4] = Tile::CommonBeast;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 4, row: 0 }, 3)),
"Should seek to the position where the CommonBeast is"
);
board.data[0][4] = Tile::StaticBlock;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 4, row: 0 }, 3)),
"Should seek to the position where the StaticBlock is"
);
let start = Coord {
column: BOARD_WIDTH - 4,
row: 0,
};
board.data[0][BOARD_WIDTH - 3] = Tile::Block;
board.data[0][BOARD_WIDTH - 2] = Tile::Block;
board.data[0][BOARD_WIDTH - 1] = Tile::Block;
assert_eq!(get_end_of_block_chain(&board, &start, &dir), None, "When hitting the frame return None");
}
#[test]
fn get_end_of_block_chain_down_test() {
let mut board = Board::new([[Tile::Empty; BOARD_WIDTH]; BOARD_HEIGHT]);
let start = Coord { column: 0, row: 0 };
let dir = Dir::Down;
board.data[1][0] = Tile::Block;
board.data[2][0] = Tile::Block;
board.data[3][0] = Tile::CommonBeast;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 0, row: 3 }, 2)),
"Should seek to the position where the CommonBeast is"
);
board.data[3][0] = Tile::HatchedBeast;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 0, row: 3 }, 2)),
"Should seek to the position where the HatchedBeast is"
);
let start = Coord {
column: 0,
row: BOARD_HEIGHT - 3,
};
board.data[BOARD_HEIGHT - 2][0] = Tile::Block;
board.data[BOARD_HEIGHT - 1][0] = Tile::Block;
assert_eq!(get_end_of_block_chain(&board, &start, &dir), None, "When hitting the frame return None");
}
#[test]
fn get_end_of_block_chain_left_test() {
let mut board = Board::new([[Tile::Empty; BOARD_WIDTH]; BOARD_HEIGHT]);
let start = Coord { column: 6, row: 0 };
let dir = Dir::Left;
board.data[0][0] = Tile::CommonBeast;
board.data[0][1] = Tile::Block;
board.data[0][2] = Tile::Block;
board.data[0][3] = Tile::Block;
board.data[0][4] = Tile::Block;
board.data[0][5] = Tile::Block;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 0, row: 0 }, 5)),
"Should seek to the position where the CommonBeast is"
);
board.data[0][0] = Tile::Empty;
assert_eq!(
get_end_of_block_chain(&board, &start, &dir),
Some((Coord { column: 0, row: 0 }, 5)),
"Should seek to the position where the Empty is"
);
board.data[0][0] = Tile::Block;
assert_eq!(get_end_of_block_chain(&board, &start, &dir), None, "When hitting the frame return None");
}
#[test]
fn get_next_coord_test() {
assert_eq!(
get_next_coord(&Coord { row: 5, column: 5 }, &Dir::Up),
Some(Coord { row: 4, column: 5 }),
"The next tile is above"
);
assert_eq!(
get_next_coord(&Coord { row: 5, column: 5 }, &Dir::Right),
Some(Coord { row: 5, column: 6 }),
"The next tile is right"
);
assert_eq!(
get_next_coord(&Coord { row: 5, column: 5 }, &Dir::Down),
Some(Coord { row: 6, column: 5 }),
"The next tile is below"
);
assert_eq!(
get_next_coord(&Coord { row: 5, column: 5 }, &Dir::Left),
Some(Coord { row: 5, column: 4 }),
"The next tile is left"
);
}
#[test]
fn get_next_coord_edge_test() {
let coord = Coord { row: 0, column: 5 };
assert_eq!(get_next_coord(&coord, &Dir::Up), None, "The next tile is out of bounds");
let coord = Coord {
row: 0,
column: BOARD_WIDTH - 1,
};
assert_eq!(get_next_coord(&coord, &Dir::Right), None, "The next tile is out of bounds");
let coord = Coord {
row: BOARD_HEIGHT - 1,
column: 5,
};
assert_eq!(get_next_coord(&coord, &Dir::Down), None, "The next tile is out of bounds");
let coord = Coord { row: 5, column: 0 };
assert_eq!(get_next_coord(&coord, &Dir::Left), None, "The next tile is out of bounds");
}
}