place_current_tetromino + try_rotate fn

This commit is contained in:
Theis Pieter Hollebeek 2025-03-02 21:00:37 +01:00
parent 3837963cfa
commit 4b5124f1c3

View File

@ -19,13 +19,28 @@ enum Direction {
Left, Left,
} }
impl Direction {
fn rotate(&self, diff: &DirectionDiff) -> Self {
match (self, diff) {
(Direction::Up, DirectionDiff::CW) => Self::Right,
(Direction::Up, DirectionDiff::CCW) => Self::Left,
(Direction::Right, DirectionDiff::CW) => Self::Down,
(Direction::Right, DirectionDiff::CCW) => Self::Up,
(Direction::Down, DirectionDiff::CW) => Self::Left,
(Direction::Down, DirectionDiff::CCW) => Self::Right,
(Direction::Left, DirectionDiff::CW) => Self::Up,
(Direction::Left, DirectionDiff::CCW) => Self::Down,
}
}
}
enum DirectionDiff { enum DirectionDiff {
CW, CW,
CCW, CCW,
} }
impl Tetromino { impl Tetromino {
fn new_random() -> Self { fn random() -> Self {
let v: u8 = rand::random(); let v: u8 = rand::random();
match v % 7 { match v % 7 {
0 => Self::I, 0 => Self::I,
@ -51,7 +66,7 @@ impl Tetromino {
} }
} }
fn direction_pattern(&self, direction: Direction) -> [[bool; 4]; 4] { fn direction_pattern(&self, direction: &Direction) -> [[bool; 4]; 4] {
let idx = match direction { let idx = match direction {
Direction::Up => 0, Direction::Up => 0,
Direction::Right => 1, Direction::Right => 1,
@ -62,140 +77,32 @@ impl Tetromino {
self.directions()[idx] self.directions()[idx]
} }
fn rotation_pattern_from_string(pattern: &'static str) -> [[bool; 4]; 4] { fn directions(&self) -> [[[bool; 4]; 4]; 4] {
pattern let dir = match self {
.split_whitespace()
.map(|row| {
let row: [char; 4] = row.chars().collect::<Vec<_>>().try_into().unwrap();
row.map(|c| {
if c == '#' {
true
} else if c == '-' {
false
} else {
panic!("invalid rotation pattern");
}
})
})
.collect::<Vec<_>>()
.try_into()
.unwrap()
}
const fn directions(&self) -> [[[bool; 4]; 4]; 4] {
match self {
Self::I => [ Self::I => [
Self::rotation_pattern_from_string( [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
r" [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]],
---- [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]],
#### [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
----
----
",
),
Self::rotation_pattern_from_string(
r"
--#-
--#-
--#-
--#-
",
),
Self::rotation_pattern_from_string(
r"
----
----
####
----
",
),
Self::rotation_pattern_from_string(
r"
-#--
-#--
-#--
-#--
",
),
], ],
Self::J => [ Self::J => [
Self::rotation_pattern_from_string( [[0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
r" [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
---- [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 0], [0, 0, 1, 0]],
#--- [[0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0]],
###-
----
",
),
Self::rotation_pattern_from_string(
r"
----
-##-
-#--
-#--
",
),
Self::rotation_pattern_from_string(
r"
----
----
###-
--#-
",
),
Self::rotation_pattern_from_string(
r"
----
-#--
-#--
##--
",
),
], ],
Self::L => [ Self::L => [
Self::rotation_pattern_from_string( [[0, 0, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
r" [[0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0]],
---- [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 0], [1, 0, 0, 0]],
--#- [[0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
###- ],
---- Self::O => [
", [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
), [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
Self::rotation_pattern_from_string( [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
r" [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
----
-#--
-#--
-##-
",
),
Self::rotation_pattern_from_string(
r"
----
----
###-
#---
",
),
Self::rotation_pattern_from_string(
r"
----
##--
-#--
-#--
",
),
], ],
Self::O => {
[Self::rotation_pattern_from_string(
r"
----
-##-
-##-
----
",
); 4]
}
Self::S => [ Self::S => [
[[0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0]], [[0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0]],
@ -214,10 +121,12 @@ impl Tetromino {
[[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0]],
[[0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [1, 0, 0, 0]], [[0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [1, 0, 0, 0]],
], ],
} };
dir.map(|dir| dir.map(|row| row.map(|v| v != 0)))
} }
const fn wallkicks(&self, direction: Direction, diff: DirectionDiff) -> [(i8, i8); 5] { const fn wall_kicks(&self, direction: &Direction, diff: &DirectionDiff) -> [(i8, i8); 5] {
match self { match self {
Self::J | Self::L | Self::S | Self::T | Self::Z => match (direction, diff) { Self::J | Self::L | Self::S | Self::T | Self::Z => match (direction, diff) {
(Direction::Up, DirectionDiff::CW) => [(0, 0), (-1, 0), (-1, 1), (0, -2), (-1, -2)], (Direction::Up, DirectionDiff::CW) => [(0, 0), (-1, 0), (-1, 1), (0, -2), (-1, -2)],
@ -276,7 +185,7 @@ impl CurrentTetromino {
} }
} }
struct Board([[Rgb; Self::WIDTH]; Self::HEIGHT]); struct Board(pub [[Option<Rgb>; Self::WIDTH]; Self::HEIGHT]);
impl Board { impl Board {
const WIDTH: usize = 10; const WIDTH: usize = 10;
@ -285,7 +194,7 @@ impl Board {
impl Board { impl Board {
pub fn new() -> Self { pub fn new() -> Self {
Board([[Rgb(0, 0, 0); Self::WIDTH]; Self::HEIGHT]) Board([[None; Self::WIDTH]; Self::HEIGHT])
} }
pub fn colliding( pub fn colliding(
@ -295,13 +204,13 @@ impl Board {
direction, direction,
x: cur_x, x: cur_x,
y: cur_y, y: cur_y,
}: CurrentTetromino, }: &CurrentTetromino,
) -> bool { ) -> bool {
let pattern = tetromino.direction_pattern(direction); let pattern = tetromino.direction_pattern(direction);
for y in 0..pattern.len() { for y in 0..pattern.len() {
for x in 0..pattern[y].len() { for x in 0..pattern[y].len() {
if pattern[y][x] == 0 { if !pattern[y][x] {
continue; continue;
} }
@ -320,7 +229,7 @@ impl Board {
return true; return true;
} }
if self.0[y as usize][x as usize] != Rgb(0, 0, 0) { if self.0[y as usize][x as usize].is_some() {
return true; return true;
} }
} }
@ -365,6 +274,49 @@ impl Game {
last last
} }
fn try_rotate(&mut self, diff: DirectionDiff) {
let rotated = self.current_tetromino.direction.rotate(&diff);
let old_direction = std::mem::replace(&mut self.current_tetromino.direction, rotated);
if !self.board.colliding(&self.current_tetromino) {
return;
}
let wall_kicks = self
.current_tetromino
.tetromino
.wall_kicks(&old_direction, &diff);
for (x, y) in wall_kicks {
self.current_tetromino.x += x;
self.current_tetromino.y += y;
if !(self.board.colliding(&self.current_tetromino)) {
return;
}
self.current_tetromino.x -= x;
self.current_tetromino.y -= y;
}
self.current_tetromino.direction = old_direction;
}
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);
for (y, row) in pattern.iter().enumerate() {
for x in row
.iter()
.enumerate()
.filter(|(_, exists)| **exists)
.map(|(idx, _)| idx)
{
let y = (current.y + y as i8) as usize;
let x = (current.x + x as i8) as usize;
self.board.0[y][x] = Some(current.tetromino.color());
}
}
}
fn try_swap_tetromino(&mut self) { fn try_swap_tetromino(&mut self) {
if self.has_swapped_held { if self.has_swapped_held {
return; return;
@ -373,7 +325,7 @@ impl Game {
let held_or_first_in_bag_tetromino = self let held_or_first_in_bag_tetromino = self
.held_tetromino .held_tetromino
.take() .take()
.unwrap_or_else(|| self.take_next_in_bag(Tetromino::new_random())); .unwrap_or_else(|| self.take_next_in_bag(Tetromino::random()));
let current_tetromino = CurrentTetromino::new(held_or_first_in_bag_tetromino); let current_tetromino = CurrentTetromino::new(held_or_first_in_bag_tetromino);
let old_tetromino = std::mem::replace(&mut self.current_tetromino, current_tetromino); let old_tetromino = std::mem::replace(&mut self.current_tetromino, current_tetromino);
self.held_tetromino.replace(old_tetromino.tetromino); self.held_tetromino.replace(old_tetromino.tetromino);