refactor patterns

This commit is contained in:
Theis Pieter Hollebeek 2025-03-03 19:57:32 +01:00
parent 099317ffc9
commit 33748e4956
5 changed files with 98 additions and 65 deletions

View File

@ -37,42 +37,35 @@ impl Board {
y,
}: &CurrentTetromino,
) -> i8 {
let pattern = tetromino.direction_pattern(direction);
let pattern = tetromino.pattern(direction);
let mut y = *y;
loop {
if self.pattern_and_position_colliding(pattern, *x, y) {
if self.pattern_and_position_colliding(&pattern, *x, y) {
break y - 1;
}
y += 1;
}
}
fn pattern_and_position_colliding(&self, pattern: [[bool; 4]; 4], x: i8, y: i8) -> bool {
for (y_offset, row) in pattern.iter().enumerate() {
for x_offset in row
.iter()
.enumerate()
.filter(|(_, exists)| **exists)
.map(|(x, _)| x)
{
let x = x_offset as i8 + x;
let y = y_offset as i8 + y;
fn pattern_and_position_colliding(&self, pattern: &Vec<(usize, usize)>, x: i8, y: i8) -> bool {
for (x_offset, y_offset) in pattern {
let x = *x_offset as i8 + x;
let y = *y_offset as i8 + y;
if y < 0 {
continue;
}
if y < 0 {
continue;
}
if y >= Board::HEIGHT as i8 {
return true;
}
if y >= Board::HEIGHT as i8 {
return true;
}
if x < 0 || x >= Board::WIDTH as i8 {
return true;
}
if x < 0 || x >= Board::WIDTH as i8 {
return true;
}
if self.0[y as usize][x as usize].is_some() {
return true;
}
if self.0[y as usize][x as usize].is_some() {
return true;
}
}
@ -88,8 +81,7 @@ impl Board {
y,
}: &CurrentTetromino,
) -> bool {
let pattern = tetromino.direction_pattern(direction);
self.pattern_and_position_colliding(pattern, *x, *y)
self.pattern_and_position_colliding(&tetromino.pattern(direction), *x, *y)
}
pub fn lines_cleared(&mut self) -> usize {

View File

@ -250,27 +250,20 @@ impl Game {
fn place_current_tetromino(&mut self) {
let next = CurrentTetromino::new(self.take_next_in_bag(Tetromino::random()));
let current = std::mem::replace(&mut self.current_tetromino, next);
let pattern = current.tetromino.direction_pattern(&current.direction);
let pattern = current.tetromino.pattern(&current.direction);
if current.y <= 0 {
self.game_over = true;
}
for (y, row) in pattern.iter().enumerate() {
for x in row
.iter()
.enumerate()
.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());
for (x, y) in pattern {
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());
}
self.has_swapped_held = false;

View File

@ -194,6 +194,7 @@ pub fn start_game() -> Result<(), String> {
}
ctx.draw_board(&game.board, &game.current_tetromino)?;
ctx.draw_bag(&game.held_tetromino, &game.next_tetrominos)?;
if paused {
ctx.draw_important_text(

View File

@ -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> {
fn window_size(&self) -> Result<(i32, i32), Err>;
@ -34,25 +38,18 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
x: i8,
y: i8,
color: Rgb,
pattern: [[bool; 4]; 4],
pattern: &Vec<(usize, usize)>,
filled: bool,
) -> Result<(), Err> {
for (y_offset, row) in pattern.iter().enumerate() {
for x_offset in row
.iter()
.enumerate()
.filter(|(_, exists)| **exists)
.map(|(x, _)| x)
{
let x = x_offset as i8 + x;
let y = y_offset as i8 + y;
for (x_offset, y_offset) in pattern {
let x = *x_offset as i8 + x;
let y = *y_offset as i8 + y;
if y < 0 {
continue;
}
self.draw_board_tile(x as i32, y as i32, &color, filled)?
if y < 0 {
continue;
}
self.draw_board_tile(x as i32, y as i32, &color, filled)?
}
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 y = center(tile_size * Board::HEIGHT as i32, win_height) + y * tile_size;
if filled {
self.fill_rect(x, y, 24, 24, color)?;
self.fill_rect(x, y, tile_size, tile_size, color)?;
} else {
self.outline_rect(x, y, 24, 24, color)?;
self.outline_rect(x, y, tile_size, tile_size, color)?;
}
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> {
let (win_width, win_height) = self.window_size()?;
self.outline_rect(
@ -90,13 +111,13 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
}
}
let pattern = current.tetromino.direction_pattern(&current.direction);
let pattern = current.tetromino.pattern(&current.direction);
self.draw_tetromino_from_parts(
current.x,
board.lowest_y(&current),
Rgb(255, 255, 255),
pattern,
&pattern,
false,
)?;
@ -104,7 +125,7 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
current.x,
current.y,
Rgb::from_tetromino(&current.tetromino),
pattern,
&pattern,
true,
)?;
@ -124,9 +145,23 @@ pub trait GameUiCtx<Err>: UiCtx<Err> {
let x = center(width, win_width);
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)?;
Ok(())

View File

@ -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 {
Self::I => match direction {
Direction::Up => [