refactor patterns
This commit is contained in:
parent
099317ffc9
commit
33748e4956
44
src/board.rs
44
src/board.rs
@ -37,42 +37,35 @@ impl Board {
|
|||||||
y,
|
y,
|
||||||
}: &CurrentTetromino,
|
}: &CurrentTetromino,
|
||||||
) -> i8 {
|
) -> i8 {
|
||||||
let pattern = tetromino.direction_pattern(direction);
|
let pattern = tetromino.pattern(direction);
|
||||||
let mut y = *y;
|
let mut y = *y;
|
||||||
loop {
|
loop {
|
||||||
if self.pattern_and_position_colliding(pattern, *x, y) {
|
if self.pattern_and_position_colliding(&pattern, *x, y) {
|
||||||
break y - 1;
|
break y - 1;
|
||||||
}
|
}
|
||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pattern_and_position_colliding(&self, pattern: [[bool; 4]; 4], x: i8, y: i8) -> bool {
|
fn pattern_and_position_colliding(&self, pattern: &Vec<(usize, usize)>, x: i8, y: i8) -> bool {
|
||||||
for (y_offset, row) in pattern.iter().enumerate() {
|
for (x_offset, y_offset) in pattern {
|
||||||
for x_offset in row
|
let x = *x_offset as i8 + x;
|
||||||
.iter()
|
let y = *y_offset as i8 + y;
|
||||||
.enumerate()
|
|
||||||
.filter(|(_, exists)| **exists)
|
|
||||||
.map(|(x, _)| x)
|
|
||||||
{
|
|
||||||
let x = x_offset as i8 + x;
|
|
||||||
let y = y_offset as i8 + y;
|
|
||||||
|
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if y >= Board::HEIGHT as i8 {
|
if y >= Board::HEIGHT as i8 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if x < 0 || x >= Board::WIDTH as i8 {
|
if x < 0 || x >= Board::WIDTH as i8 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.0[y as usize][x as usize].is_some() {
|
if self.0[y as usize][x as usize].is_some() {
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +81,7 @@ impl Board {
|
|||||||
y,
|
y,
|
||||||
}: &CurrentTetromino,
|
}: &CurrentTetromino,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let pattern = tetromino.direction_pattern(direction);
|
self.pattern_and_position_colliding(&tetromino.pattern(direction), *x, *y)
|
||||||
self.pattern_and_position_colliding(pattern, *x, *y)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lines_cleared(&mut self) -> usize {
|
pub fn lines_cleared(&mut self) -> usize {
|
||||||
|
23
src/game.rs
23
src/game.rs
@ -250,27 +250,20 @@ impl Game {
|
|||||||
fn place_current_tetromino(&mut self) {
|
fn place_current_tetromino(&mut self) {
|
||||||
let next = CurrentTetromino::new(self.take_next_in_bag(Tetromino::random()));
|
let next = CurrentTetromino::new(self.take_next_in_bag(Tetromino::random()));
|
||||||
let current = std::mem::replace(&mut self.current_tetromino, next);
|
let current = std::mem::replace(&mut self.current_tetromino, next);
|
||||||
let pattern = current.tetromino.direction_pattern(¤t.direction);
|
let pattern = current.tetromino.pattern(¤t.direction);
|
||||||
|
|
||||||
if current.y <= 0 {
|
if current.y <= 0 {
|
||||||
self.game_over = true;
|
self.game_over = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y, row) in pattern.iter().enumerate() {
|
for (x, y) in pattern {
|
||||||
for x in row
|
let y = current.y + y as i8;
|
||||||
.iter()
|
if y < 0 {
|
||||||
.enumerate()
|
continue;
|
||||||
.filter(|(_, exists)| **exists)
|
|
||||||
.map(|(x, _)| x)
|
|
||||||
{
|
|
||||||
let y = current.y + y as i8;
|
|
||||||
if y < 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let y = y as usize;
|
|
||||||
let x = (current.x + x as i8) as usize;
|
|
||||||
self.board[y][x] = Some(current.tetromino.clone());
|
|
||||||
}
|
}
|
||||||
|
let y = y as usize;
|
||||||
|
let x = (current.x + x as i8) as usize;
|
||||||
|
self.board[y][x] = Some(current.tetromino.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.has_swapped_held = false;
|
self.has_swapped_held = false;
|
||||||
|
@ -194,6 +194,7 @@ pub fn start_game() -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.draw_board(&game.board, &game.current_tetromino)?;
|
ctx.draw_board(&game.board, &game.current_tetromino)?;
|
||||||
|
ctx.draw_bag(&game.held_tetromino, &game.next_tetrominos)?;
|
||||||
|
|
||||||
if paused {
|
if paused {
|
||||||
ctx.draw_important_text(
|
ctx.draw_important_text(
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
use crate::{board::Board, game::CurrentTetromino, tetromino::Tetromino};
|
use crate::{
|
||||||
|
board::Board,
|
||||||
|
game::CurrentTetromino,
|
||||||
|
tetromino::{Direction, Tetromino},
|
||||||
|
};
|
||||||
|
|
||||||
pub trait UiCtx<Err> {
|
pub trait UiCtx<Err> {
|
||||||
fn window_size(&self) -> Result<(i32, i32), Err>;
|
fn window_size(&self) -> Result<(i32, i32), Err>;
|
||||||
@ -34,25 +38,18 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
|
|||||||
x: i8,
|
x: i8,
|
||||||
y: i8,
|
y: i8,
|
||||||
color: Rgb,
|
color: Rgb,
|
||||||
pattern: [[bool; 4]; 4],
|
pattern: &Vec<(usize, usize)>,
|
||||||
filled: bool,
|
filled: bool,
|
||||||
) -> Result<(), Err> {
|
) -> Result<(), Err> {
|
||||||
for (y_offset, row) in pattern.iter().enumerate() {
|
for (x_offset, y_offset) in pattern {
|
||||||
for x_offset in row
|
let x = *x_offset as i8 + x;
|
||||||
.iter()
|
let y = *y_offset as i8 + y;
|
||||||
.enumerate()
|
|
||||||
.filter(|(_, exists)| **exists)
|
|
||||||
.map(|(x, _)| x)
|
|
||||||
{
|
|
||||||
let x = x_offset as i8 + x;
|
|
||||||
let y = y_offset as i8 + y;
|
|
||||||
|
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
self.draw_board_tile(x as i32, y as i32, &color, filled)?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.draw_board_tile(x as i32, y as i32, &color, filled)?
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -63,13 +60,37 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
|
|||||||
let x = center(tile_size * Board::WIDTH as i32, win_width) + x * tile_size;
|
let x = center(tile_size * Board::WIDTH as i32, win_width) + x * tile_size;
|
||||||
let y = center(tile_size * Board::HEIGHT as i32, win_height) + y * tile_size;
|
let y = center(tile_size * Board::HEIGHT as i32, win_height) + y * tile_size;
|
||||||
if filled {
|
if filled {
|
||||||
self.fill_rect(x, y, 24, 24, color)?;
|
self.fill_rect(x, y, tile_size, tile_size, color)?;
|
||||||
} else {
|
} else {
|
||||||
self.outline_rect(x, y, 24, 24, color)?;
|
self.outline_rect(x, y, tile_size, tile_size, color)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_bag(&mut self, held: &Option<Tetromino>, next_up: &[Tetromino; 3]) -> Result<(), Err> {
|
||||||
|
let (win_width, win_height) = self.window_size()?;
|
||||||
|
let x = center(24 * Board::WIDTH as i32, win_width);
|
||||||
|
let y = center(24 * Board::HEIGHT as i32, win_height);
|
||||||
|
|
||||||
|
let size = 24 * 5;
|
||||||
|
let x = x - size - 16;
|
||||||
|
|
||||||
|
self.fill_rect(x, y, size, size, &Rgb(0, 0, 0))?;
|
||||||
|
self.outline_rect(x - 1, y - 1, size + 2, size + 2, &Rgb(255, 255, 255))?;
|
||||||
|
|
||||||
|
if let Some(tetromino) = held {
|
||||||
|
let color = Rgb::from_tetromino(&tetromino);
|
||||||
|
let pattern = tetromino.pattern(&Direction::Up);
|
||||||
|
for (x_offset, y_offset) in pattern {
|
||||||
|
let x = x + (x_offset * 24) as i32;
|
||||||
|
let y = y + (y_offset * 24) as i32;
|
||||||
|
self.fill_rect(x, y, 24, 24, &color)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_board(&mut self, board: &Board, current: &CurrentTetromino) -> Result<(), Err> {
|
fn draw_board(&mut self, board: &Board, current: &CurrentTetromino) -> Result<(), Err> {
|
||||||
let (win_width, win_height) = self.window_size()?;
|
let (win_width, win_height) = self.window_size()?;
|
||||||
self.outline_rect(
|
self.outline_rect(
|
||||||
@ -90,13 +111,13 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pattern = current.tetromino.direction_pattern(¤t.direction);
|
let pattern = current.tetromino.pattern(¤t.direction);
|
||||||
|
|
||||||
self.draw_tetromino_from_parts(
|
self.draw_tetromino_from_parts(
|
||||||
current.x,
|
current.x,
|
||||||
board.lowest_y(¤t),
|
board.lowest_y(¤t),
|
||||||
Rgb(255, 255, 255),
|
Rgb(255, 255, 255),
|
||||||
pattern,
|
&pattern,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -104,7 +125,7 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
|
|||||||
current.x,
|
current.x,
|
||||||
current.y,
|
current.y,
|
||||||
Rgb::from_tetromino(¤t.tetromino),
|
Rgb::from_tetromino(¤t.tetromino),
|
||||||
pattern,
|
&pattern,
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -124,9 +145,23 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
|
|||||||
let x = center(width, win_width);
|
let x = center(width, win_width);
|
||||||
let y = center(height, win_height);
|
let y = center(height, win_height);
|
||||||
|
|
||||||
self.outline_rect(x - 9, y - 9, width + 18, height + 18, &Rgb(255, 255, 255))?;
|
let padding = 8;
|
||||||
|
|
||||||
self.fill_rect(x - 8, y - 8, width + 16, height + 16, &Rgb(16, 16, 16))?;
|
self.outline_rect(
|
||||||
|
x - padding - 1,
|
||||||
|
y - padding - 1,
|
||||||
|
width + padding * 2 + 2,
|
||||||
|
height + padding * 2 + 2,
|
||||||
|
&Rgb(255, 255, 255),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.fill_rect(
|
||||||
|
x - padding,
|
||||||
|
y - padding,
|
||||||
|
width + padding * 2,
|
||||||
|
height + padding * 2,
|
||||||
|
&Rgb(16, 16, 16),
|
||||||
|
)?;
|
||||||
self.fill_text(font, text, x, y, width, height)?;
|
self.fill_text(font, text, x, y, width, height)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -51,7 +51,19 @@ impl Tetromino {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn direction_pattern(&self, direction: &Direction) -> [[bool; 4]; 4] {
|
pub fn pattern(&self, direction: &Direction) -> Vec<(usize, usize)> {
|
||||||
|
self.raw_pattern(direction)
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(y, row)| {
|
||||||
|
row.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(move |(x, available)| if available { Some((x, y)) } else { None })
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raw_pattern(&self, direction: &Direction) -> [[bool; 4]; 4] {
|
||||||
let dir = match self {
|
let dir = match self {
|
||||||
Self::I => match direction {
|
Self::I => match direction {
|
||||||
Direction::Up => [
|
Direction::Up => [
|
||||||
|
Loading…
Reference in New Issue
Block a user