place_current_tetromino + try_rotate fn
This commit is contained in:
parent
3837963cfa
commit
4b5124f1c3
228
src/main.rs
228
src/main.rs
@ -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(¤t.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);
|
||||||
|
Loading…
Reference in New Issue
Block a user