stepping
This commit is contained in:
parent
4b5124f1c3
commit
8e588a8a70
25
src/actions.rs
Normal file
25
src/actions.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum Controls {
|
||||
Left,
|
||||
Right,
|
||||
SoftDrop,
|
||||
HardDrop,
|
||||
}
|
||||
|
||||
pub struct ControlsHeld(HashMap<Controls, usize>);
|
||||
|
||||
impl std::ops::Deref for ControlsHeld {
|
||||
type Target = HashMap<Controls, usize>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for ControlsHeld {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
71
src/board.rs
Normal file
71
src/board.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::{CurrentTetromino, Tetromino};
|
||||
|
||||
pub struct Board([[Option<Tetromino>; Self::WIDTH]; Self::HEIGHT]);
|
||||
|
||||
impl Deref for Board {
|
||||
type Target = [[Option<Tetromino>; Self::WIDTH]; Self::HEIGHT];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Board {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Board {
|
||||
pub const WIDTH: usize = 10;
|
||||
pub const HEIGHT: usize = 20;
|
||||
|
||||
pub fn new() -> Self {
|
||||
let board = std::array::from_fn(|_| std::array::from_fn(|_| None));
|
||||
Board(board)
|
||||
}
|
||||
|
||||
pub fn colliding(
|
||||
&self,
|
||||
CurrentTetromino {
|
||||
tetromino,
|
||||
direction,
|
||||
x: cur_x,
|
||||
y: cur_y,
|
||||
}: &CurrentTetromino,
|
||||
) -> bool {
|
||||
let pattern = tetromino.direction_pattern(direction);
|
||||
|
||||
for (y, row) in pattern.iter().enumerate() {
|
||||
for x in row
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, exists)| **exists)
|
||||
.map(|(x, _)| x)
|
||||
{
|
||||
let x = x as i8 + cur_x;
|
||||
let y = y as i8 + cur_y;
|
||||
|
||||
if y < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if y >= Board::HEIGHT 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
306
src/main.rs
306
src/main.rs
@ -1,171 +1,15 @@
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Tetromino {
|
||||
I,
|
||||
J,
|
||||
L,
|
||||
O,
|
||||
S,
|
||||
T,
|
||||
Z,
|
||||
}
|
||||
#![allow(dead_code)]
|
||||
|
||||
use actions::{Controls, ControlsHeld};
|
||||
use board::Board;
|
||||
use tetromino::{Direction, DirectionDiff, Tetromino};
|
||||
|
||||
mod actions;
|
||||
mod board;
|
||||
mod tetromino;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Rgb(u8, u8, u8);
|
||||
|
||||
enum Direction {
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
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 {
|
||||
CW,
|
||||
CCW,
|
||||
}
|
||||
|
||||
impl Tetromino {
|
||||
fn random() -> Self {
|
||||
let v: u8 = rand::random();
|
||||
match v % 7 {
|
||||
0 => Self::I,
|
||||
1 => Self::J,
|
||||
2 => Self::L,
|
||||
3 => Self::O,
|
||||
4 => Self::S,
|
||||
5 => Self::T,
|
||||
6 => Self::Z,
|
||||
_ => unreachable!("v%7 is always in range 0..=6"),
|
||||
}
|
||||
}
|
||||
|
||||
const fn color(&self) -> Rgb {
|
||||
match self {
|
||||
Self::I => Rgb(0, 255, 255),
|
||||
Self::J => Rgb(0, 0, 255),
|
||||
Self::L => Rgb(255, 128, 0),
|
||||
Self::O => Rgb(255, 255, 0),
|
||||
Self::S => Rgb(0, 255, 0),
|
||||
Self::T => Rgb(255, 0, 255),
|
||||
Self::Z => Rgb(255, 0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
fn direction_pattern(&self, direction: &Direction) -> [[bool; 4]; 4] {
|
||||
let idx = match direction {
|
||||
Direction::Up => 0,
|
||||
Direction::Right => 1,
|
||||
Direction::Down => 2,
|
||||
Direction::Left => 3,
|
||||
};
|
||||
|
||||
self.directions()[idx]
|
||||
}
|
||||
|
||||
fn directions(&self) -> [[[bool; 4]; 4]; 4] {
|
||||
let dir = match self {
|
||||
Self::I => [
|
||||
[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
|
||||
[[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::J => [
|
||||
[[0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[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::L => [
|
||||
[[0, 0, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[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]],
|
||||
[[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::S => [
|
||||
[[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, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0]],
|
||||
[[0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0]],
|
||||
],
|
||||
Self::T => [
|
||||
[[0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0]],
|
||||
],
|
||||
Self::Z => [
|
||||
[[0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 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]],
|
||||
],
|
||||
};
|
||||
|
||||
dir.map(|dir| dir.map(|row| row.map(|v| v != 0)))
|
||||
}
|
||||
|
||||
const fn wall_kicks(&self, direction: &Direction, diff: &DirectionDiff) -> [(i8, i8); 5] {
|
||||
match self {
|
||||
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::CCW) => [(0, 0), (1, 0), (1, 1), (0, -2), (1, -2)],
|
||||
|
||||
(Direction::Right, DirectionDiff::CW) => [(0, 0), (1, 0), (1, -1), (0, 2), (1, 2)],
|
||||
(Direction::Right, DirectionDiff::CCW) => [(0, 0), (1, 0), (1, -1), (0, 2), (1, 2)],
|
||||
|
||||
(Direction::Down, DirectionDiff::CW) => [(0, 0), (1, 0), (1, 1), (0, -2), (1, -2)],
|
||||
(Direction::Down, DirectionDiff::CCW) => {
|
||||
[(0, 0), (-1, 0), (-1, 1), (0, -2), (-1, -2)]
|
||||
}
|
||||
|
||||
(Direction::Left, DirectionDiff::CW) => {
|
||||
[(0, 0), (-1, 0), (-1, -1), (0, 2), (-1, 2)]
|
||||
}
|
||||
(Direction::Left, DirectionDiff::CCW) => [(0, 0), (1, 0), (1, 1), (0, -2), (1, -2)],
|
||||
},
|
||||
Self::I => match (direction, diff) {
|
||||
(Direction::Up, DirectionDiff::CW) => [(0, 0), (-2, 0), (1, 0), (-2, -1), (1, 2)],
|
||||
(Direction::Up, DirectionDiff::CCW) => [(0, 0), (-1, 0), (2, 0), (-1, 2), (2, -1)],
|
||||
(Direction::Right, DirectionDiff::CW) => [(0, 0), (-1, 0), (2, 0), (1, 2), (2, -1)],
|
||||
(Direction::Right, DirectionDiff::CCW) => {
|
||||
[(0, 0), (2, 0), (-1, 0), (2, 1), (-1, -2)]
|
||||
}
|
||||
(Direction::Down, DirectionDiff::CW) => [(0, 0), (2, 0), (-1, 0), (2, 1), (-1, -2)],
|
||||
(Direction::Down, DirectionDiff::CCW) => {
|
||||
[(0, 0), (1, 0), (-2, 0), (1, -2), (-2, 1)]
|
||||
}
|
||||
(Direction::Left, DirectionDiff::CW) => [(0, 0), (1, 0), (-2, 0), (1, -2), (-2, 1)],
|
||||
(Direction::Left, DirectionDiff::CCW) => {
|
||||
[(0, 0), (-2, 0), (1, 0), (-2, -1), (1, 2)]
|
||||
}
|
||||
},
|
||||
Self::O => [(0, 0); 5],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CurrentTetromino {
|
||||
tetromino: Tetromino,
|
||||
direction: Direction,
|
||||
@ -185,60 +29,6 @@ impl CurrentTetromino {
|
||||
}
|
||||
}
|
||||
|
||||
struct Board(pub [[Option<Rgb>; Self::WIDTH]; Self::HEIGHT]);
|
||||
|
||||
impl Board {
|
||||
const WIDTH: usize = 10;
|
||||
const HEIGHT: usize = 20;
|
||||
}
|
||||
|
||||
impl Board {
|
||||
pub fn new() -> Self {
|
||||
Board([[None; Self::WIDTH]; Self::HEIGHT])
|
||||
}
|
||||
|
||||
pub fn colliding(
|
||||
&self,
|
||||
CurrentTetromino {
|
||||
tetromino,
|
||||
direction,
|
||||
x: cur_x,
|
||||
y: cur_y,
|
||||
}: &CurrentTetromino,
|
||||
) -> bool {
|
||||
let pattern = tetromino.direction_pattern(direction);
|
||||
|
||||
for y in 0..pattern.len() {
|
||||
for x in 0..pattern[y].len() {
|
||||
if !pattern[y][x] {
|
||||
continue;
|
||||
}
|
||||
|
||||
let x = x as i8 + cur_x;
|
||||
let y = y as i8 + cur_y;
|
||||
|
||||
if y < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if y >= Board::HEIGHT 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct Game {
|
||||
board: Board,
|
||||
next_tetrominos: [Tetromino; 3],
|
||||
@ -246,11 +36,12 @@ struct Game {
|
||||
held_tetromino: Option<Tetromino>,
|
||||
has_swapped_held: bool,
|
||||
score: Score,
|
||||
ticks: usize,
|
||||
}
|
||||
|
||||
struct Score {
|
||||
level: usize,
|
||||
score: usize,
|
||||
points: usize,
|
||||
lines: usize,
|
||||
combo: usize,
|
||||
}
|
||||
@ -259,7 +50,7 @@ impl Score {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
level: 0,
|
||||
score: 0,
|
||||
points: 0,
|
||||
lines: 0,
|
||||
combo: 0,
|
||||
}
|
||||
@ -274,11 +65,72 @@ impl Game {
|
||||
last
|
||||
}
|
||||
|
||||
fn try_rotate(&mut self, diff: DirectionDiff) {
|
||||
fn hard_drop(&mut self, controls: &ControlsHeld) {
|
||||
if controls.contains_key(&Controls::HardDrop) {
|
||||
loop {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn soft_drop(&mut self, controls: &ControlsHeld) {
|
||||
let mut delay = 32 - self.score.level * 2;
|
||||
if controls.contains_key(&Controls::SoftDrop) {
|
||||
delay /= 10;
|
||||
}
|
||||
|
||||
if self.ticks % delay != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.current_tetromino.y += 1;
|
||||
if self.board.colliding(&self.current_tetromino) {
|
||||
self.current_tetromino.y -= 1;
|
||||
self.place_current_tetromino();
|
||||
self.check_line_clears();
|
||||
self.has_swapped_held = false;
|
||||
} else if controls.contains_key(&Controls::SoftDrop) {
|
||||
self.score.points += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn move_horizontally(&mut self, controls: &ControlsHeld) {
|
||||
for key in [Controls::Left, Controls::Right] {
|
||||
let Some(held_since) = controls.get(&key) else {
|
||||
continue;
|
||||
};
|
||||
let held_for = self.ticks - held_since;
|
||||
if held_for < 15 {
|
||||
continue;
|
||||
}
|
||||
let offset = match key {
|
||||
Controls::Left => -1,
|
||||
Controls::Right => 1,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.current_tetromino.x += offset;
|
||||
if self.board.colliding(&self.current_tetromino) {
|
||||
self.current_tetromino.x -= offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_line_clears(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn step(&mut self, controls: &ControlsHeld) {
|
||||
// TODO: ensure game is running at 60fps (`if !check_update_time(context, 60) { return; }`)
|
||||
self.ticks += 1;
|
||||
self.soft_drop(controls);
|
||||
self.move_horizontally(controls);
|
||||
}
|
||||
|
||||
fn try_rotate(&mut self, diff: DirectionDiff) -> bool {
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
let wall_kicks = self
|
||||
.current_tetromino
|
||||
@ -289,13 +141,14 @@ impl Game {
|
||||
self.current_tetromino.x += x;
|
||||
self.current_tetromino.y += y;
|
||||
if !(self.board.colliding(&self.current_tetromino)) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
self.current_tetromino.x -= x;
|
||||
self.current_tetromino.y -= y;
|
||||
}
|
||||
|
||||
self.current_tetromino.direction = old_direction;
|
||||
false
|
||||
}
|
||||
|
||||
fn place_current_tetromino(&mut self) {
|
||||
@ -308,11 +161,11 @@ impl Game {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, exists)| **exists)
|
||||
.map(|(idx, _)| idx)
|
||||
.map(|(x, _)| x)
|
||||
{
|
||||
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());
|
||||
self.board[y][x] = Some(current.tetromino.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -347,6 +200,7 @@ mod test {
|
||||
current_tetromino: CurrentTetromino::new(Tetromino::J),
|
||||
held_tetromino: None,
|
||||
has_swapped_held: false,
|
||||
ticks: 0,
|
||||
};
|
||||
assert_eq!(game.take_next_in_bag(Tetromino::S), Tetromino::I);
|
||||
assert_eq!(
|
||||
|
166
src/tetromino.rs
Normal file
166
src/tetromino.rs
Normal file
@ -0,0 +1,166 @@
|
||||
use crate::Rgb;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Tetromino {
|
||||
I,
|
||||
J,
|
||||
L,
|
||||
O,
|
||||
S,
|
||||
T,
|
||||
Z,
|
||||
}
|
||||
|
||||
pub enum Direction {
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
Left,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
pub 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DirectionDiff {
|
||||
Cw,
|
||||
Ccw,
|
||||
}
|
||||
|
||||
impl Tetromino {
|
||||
pub fn random() -> Self {
|
||||
let v: u8 = rand::random();
|
||||
match v % 7 {
|
||||
0 => Self::I,
|
||||
1 => Self::J,
|
||||
2 => Self::L,
|
||||
3 => Self::O,
|
||||
4 => Self::S,
|
||||
5 => Self::T,
|
||||
6 => Self::Z,
|
||||
_ => unreachable!("v%7 is always in range 0..=6"),
|
||||
}
|
||||
}
|
||||
|
||||
const fn color(&self) -> Rgb {
|
||||
match self {
|
||||
Self::I => Rgb(0, 255, 255),
|
||||
Self::J => Rgb(0, 0, 255),
|
||||
Self::L => Rgb(255, 128, 0),
|
||||
Self::O => Rgb(255, 255, 0),
|
||||
Self::S => Rgb(0, 255, 0),
|
||||
Self::T => Rgb(255, 0, 255),
|
||||
Self::Z => Rgb(255, 0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn direction_pattern(&self, direction: &Direction) -> [[bool; 4]; 4] {
|
||||
let idx = match direction {
|
||||
Direction::Up => 0,
|
||||
Direction::Right => 1,
|
||||
Direction::Down => 2,
|
||||
Direction::Left => 3,
|
||||
};
|
||||
|
||||
self.directions()[idx]
|
||||
}
|
||||
|
||||
fn directions(&self) -> [[[bool; 4]; 4]; 4] {
|
||||
let dir = match self {
|
||||
Self::I => [
|
||||
[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
|
||||
[[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::J => [
|
||||
[[0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[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::L => [
|
||||
[[0, 0, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[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]],
|
||||
[[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::S => [
|
||||
[[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, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0]],
|
||||
[[0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0]],
|
||||
],
|
||||
Self::T => [
|
||||
[[0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0]],
|
||||
],
|
||||
Self::Z => [
|
||||
[[0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
|
||||
[[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 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]],
|
||||
],
|
||||
};
|
||||
|
||||
dir.map(|dir| dir.map(|row| row.map(|v| v != 0)))
|
||||
}
|
||||
|
||||
pub const fn wall_kicks(&self, direction: &Direction, diff: &DirectionDiff) -> [(i8, i8); 5] {
|
||||
match self {
|
||||
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::Ccw) => [(0, 0), (1, 0), (1, 1), (0, -2), (1, -2)],
|
||||
|
||||
(Direction::Right, DirectionDiff::Cw) => [(0, 0), (1, 0), (1, -1), (0, 2), (1, 2)],
|
||||
(Direction::Right, DirectionDiff::Ccw) => [(0, 0), (1, 0), (1, -1), (0, 2), (1, 2)],
|
||||
|
||||
(Direction::Down, DirectionDiff::Cw) => [(0, 0), (1, 0), (1, 1), (0, -2), (1, -2)],
|
||||
(Direction::Down, DirectionDiff::Ccw) => {
|
||||
[(0, 0), (-1, 0), (-1, 1), (0, -2), (-1, -2)]
|
||||
}
|
||||
|
||||
(Direction::Left, DirectionDiff::Cw) => {
|
||||
[(0, 0), (-1, 0), (-1, -1), (0, 2), (-1, 2)]
|
||||
}
|
||||
(Direction::Left, DirectionDiff::Ccw) => [(0, 0), (1, 0), (1, 1), (0, -2), (1, -2)],
|
||||
},
|
||||
Self::I => match (direction, diff) {
|
||||
(Direction::Up, DirectionDiff::Cw) => [(0, 0), (-2, 0), (1, 0), (-2, -1), (1, 2)],
|
||||
(Direction::Up, DirectionDiff::Ccw) => [(0, 0), (-1, 0), (2, 0), (-1, 2), (2, -1)],
|
||||
(Direction::Right, DirectionDiff::Cw) => [(0, 0), (-1, 0), (2, 0), (1, 2), (2, -1)],
|
||||
(Direction::Right, DirectionDiff::Ccw) => {
|
||||
[(0, 0), (2, 0), (-1, 0), (2, 1), (-1, -2)]
|
||||
}
|
||||
(Direction::Down, DirectionDiff::Cw) => [(0, 0), (2, 0), (-1, 0), (2, 1), (-1, -2)],
|
||||
(Direction::Down, DirectionDiff::Ccw) => {
|
||||
[(0, 0), (1, 0), (-2, 0), (1, -2), (-2, 1)]
|
||||
}
|
||||
(Direction::Left, DirectionDiff::Cw) => [(0, 0), (1, 0), (-2, 0), (1, -2), (-2, 1)],
|
||||
(Direction::Left, DirectionDiff::Ccw) => {
|
||||
[(0, 0), (-2, 0), (1, 0), (-2, -1), (1, 2)]
|
||||
}
|
||||
},
|
||||
Self::O => [(0, 0); 5],
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user