current work
This commit is contained in:
parent
036953fd2c
commit
31daef03c7
5 changed files with 254 additions and 12 deletions
52
src/game.rs
Normal file
52
src/game.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// A game is a self-contained struct that holds everything that an instance of
|
||||||
|
// Tetris needs to run, except for something to tick the time forward.
|
||||||
|
|
||||||
|
use crate::playfield::PlayField;
|
||||||
|
use crate::srs::RotationSystem;
|
||||||
|
use crate::srs::SRS;
|
||||||
|
|
||||||
|
pub struct Game<RS: RotationSystem> {
|
||||||
|
playfield: PlayField,
|
||||||
|
rotation_system: RS,
|
||||||
|
level: u8,
|
||||||
|
points: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PlayerControllable {
|
||||||
|
fn move_left(&mut self);
|
||||||
|
fn move_up(&mut self);
|
||||||
|
fn move_right(&mut self);
|
||||||
|
fn move_down(&mut self);
|
||||||
|
fn rotate_left(&mut self);
|
||||||
|
fn rotate_right(&mut self);
|
||||||
|
fn hard_drop(&mut self);
|
||||||
|
fn hold(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RS: RotationSystem> PlayerControllable for Game<RS> {
|
||||||
|
fn move_left(&mut self) {}
|
||||||
|
fn move_up(&mut self) {}
|
||||||
|
fn move_right(&mut self) {}
|
||||||
|
fn move_down(&mut self) {}
|
||||||
|
fn rotate_left(&mut self) {}
|
||||||
|
fn rotate_right(&mut self) {}
|
||||||
|
fn hard_drop(&mut self) {}
|
||||||
|
|
||||||
|
fn hold(&mut self) {
|
||||||
|
// if self.can_swap_hold {
|
||||||
|
// match self.hold_piece {
|
||||||
|
// None => {
|
||||||
|
// self.hold_piece = Some(self.active_piece);
|
||||||
|
// self.get_new_piece();
|
||||||
|
// }
|
||||||
|
// Some(piece) => {
|
||||||
|
// self.hold_piece = Some(self.active_piece);
|
||||||
|
// self.active_piece = piece;
|
||||||
|
// self.reset_position();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// self.can_swap_hold = false;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
|
mod game;
|
||||||
|
mod playfield;
|
||||||
mod random;
|
mod random;
|
||||||
|
mod srs;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Tetrino {
|
pub enum Tetromino {
|
||||||
I,
|
I,
|
||||||
O,
|
O,
|
||||||
T,
|
T,
|
||||||
|
|
76
src/playfield.rs
Normal file
76
src/playfield.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
use crate::random::RandomSystem;
|
||||||
|
use crate::Tetromino;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum MinoColor {
|
||||||
|
Cyan,
|
||||||
|
Yellow,
|
||||||
|
Purple,
|
||||||
|
Green,
|
||||||
|
Red,
|
||||||
|
Blue,
|
||||||
|
Orange,
|
||||||
|
Gray,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Movement {
|
||||||
|
Rotate,
|
||||||
|
Gravity,
|
||||||
|
Translation,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Position {
|
||||||
|
x: u8,
|
||||||
|
y: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PlayField {
|
||||||
|
can_swap_hold: bool,
|
||||||
|
hold_piece: Option<Tetromino>,
|
||||||
|
field: [[Option<MinoColor>; 10]; 40], // access via y, x
|
||||||
|
active_piece: Tetromino,
|
||||||
|
active_pos: Position,
|
||||||
|
bag: RandomSystem,
|
||||||
|
next_pieces: VecDeque<Tetromino>,
|
||||||
|
last_movement: Movement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayField {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut bag = RandomSystem::new();
|
||||||
|
let active_piece = bag.get_tetrino();
|
||||||
|
let mut next_pieces = VecDeque::with_capacity(3);
|
||||||
|
for _ in 0..next_pieces.len() {
|
||||||
|
next_pieces.push_back(bag.get_tetrino());
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayField {
|
||||||
|
can_swap_hold: true,
|
||||||
|
hold_piece: None,
|
||||||
|
field: [[None; 10]; 40],
|
||||||
|
active_piece,
|
||||||
|
active_pos: Position { x: 0, y: 0 },
|
||||||
|
bag,
|
||||||
|
next_pieces,
|
||||||
|
last_movement: Movement::Gravity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_new_piece(&mut self) {
|
||||||
|
self.active_piece = self
|
||||||
|
.next_pieces
|
||||||
|
.pop_front()
|
||||||
|
.expect("visible queue to be populated");
|
||||||
|
self.next_pieces.push_back(self.bag.get_tetrino());
|
||||||
|
self.reset_position();
|
||||||
|
self.can_swap_hold = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Place the current Tetromino at its default spawn position and
|
||||||
|
/// orientation. Used for hold-swapping or spawning in a new piece.
|
||||||
|
fn reset_position(&mut self) {
|
||||||
|
self.last_movement = Movement::Gravity;
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::Tetrino;
|
use crate::Tetromino;
|
||||||
use rand::{rngs::ThreadRng, seq::SliceRandom, thread_rng};
|
use rand::{rngs::ThreadRng, seq::SliceRandom, thread_rng};
|
||||||
|
|
||||||
pub struct RandomSystem {
|
pub struct RandomSystem {
|
||||||
rng: ThreadRng,
|
rng: ThreadRng,
|
||||||
bag: [Tetrino; 7],
|
bag: [Tetromino; 7],
|
||||||
cur_pos: usize,
|
cur_pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@ impl RandomSystem {
|
||||||
let rng = thread_rng();
|
let rng = thread_rng();
|
||||||
RandomSystem {
|
RandomSystem {
|
||||||
rng: rng,
|
rng: rng,
|
||||||
bag: [Tetrino::I; 7],
|
bag: [Tetromino::I; 7], // Default value, should get init on first get
|
||||||
cur_pos: 0,
|
cur_pos: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tetrino(&mut self) -> Tetrino {
|
pub fn get_tetrino(&mut self) -> Tetromino {
|
||||||
if self.cur_pos == 0 {
|
if self.cur_pos == 0 {
|
||||||
self.refresh_bag();
|
self.refresh_bag();
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,13 @@ impl RandomSystem {
|
||||||
|
|
||||||
fn refresh_bag(&mut self) {
|
fn refresh_bag(&mut self) {
|
||||||
self.bag = [
|
self.bag = [
|
||||||
Tetrino::I,
|
Tetromino::I,
|
||||||
Tetrino::O,
|
Tetromino::O,
|
||||||
Tetrino::T,
|
Tetromino::T,
|
||||||
Tetrino::S,
|
Tetromino::S,
|
||||||
Tetrino::Z,
|
Tetromino::Z,
|
||||||
Tetrino::J,
|
Tetromino::J,
|
||||||
Tetrino::L,
|
Tetromino::L,
|
||||||
];
|
];
|
||||||
self.bag.shuffle(&mut self.rng);
|
self.bag.shuffle(&mut self.rng);
|
||||||
self.cur_pos = 0;
|
self.cur_pos = 0;
|
||||||
|
|
111
src/srs.rs
Normal file
111
src/srs.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
use crate::playfield::{PlayField, Position};
|
||||||
|
use crate::Tetromino;
|
||||||
|
|
||||||
|
#[derive(Copy)]
|
||||||
|
pub struct Offset {
|
||||||
|
x: i8,
|
||||||
|
y: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RotationDirection {
|
||||||
|
Clockwise,
|
||||||
|
AntiClockwise,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RotationSystem {
|
||||||
|
fn get_rotation_offset(
|
||||||
|
piece: &Tetromino,
|
||||||
|
center: &Position,
|
||||||
|
direction: RotationDirection,
|
||||||
|
playfield: &PlayField,
|
||||||
|
) -> Option<Offset>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SRS {}
|
||||||
|
|
||||||
|
impl RotationSystem for SRS {
|
||||||
|
fn get_rotation_offset(
|
||||||
|
piece: &Tetromino,
|
||||||
|
center: &Position,
|
||||||
|
direction: RotationDirection,
|
||||||
|
playfield: &PlayField,
|
||||||
|
) -> Option<Offset> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
|
enum Rotation {
|
||||||
|
O, // Spawn state
|
||||||
|
R, // Right rotation: clockwise rotation from spawn state
|
||||||
|
U, // Upside-down rotation: rotation after 2 left or right rotations from spawn state
|
||||||
|
L, // Left rotation: counterclockwise rotation from spawn state
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OffsetData {
|
||||||
|
O: Vec<Offset>,
|
||||||
|
R: Vec<Offset>,
|
||||||
|
U: Vec<Offset>,
|
||||||
|
L: Vec<Offset>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OffsetData {
|
||||||
|
pub fn apply_right_rotation() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const JLSTZOffsetData: OffsetData = OffsetData {
|
||||||
|
O: vec![Offset { x: 0, y: 0 }],
|
||||||
|
R: vec![
|
||||||
|
Offset { x: 0, y: 0 },
|
||||||
|
Offset { x: 1, y: 0 },
|
||||||
|
Offset { x: 1, y: -1 },
|
||||||
|
Offset { x: 0, y: 2 },
|
||||||
|
Offset { x: 1, y: 2 },
|
||||||
|
],
|
||||||
|
U: vec![Offset { x: 0, y: 0 }],
|
||||||
|
L: vec![
|
||||||
|
Offset { x: 0, y: 0 },
|
||||||
|
Offset { x: -1, y: 0 },
|
||||||
|
Offset { x: -1, y: -1 },
|
||||||
|
Offset { x: 0, y: 2 },
|
||||||
|
Offset { x: -1, y: 2 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const IOffsetData: OffsetData = OffsetData {
|
||||||
|
O: vec![
|
||||||
|
Offset { x: 0, y: 0 },
|
||||||
|
Offset { x: -1, y: 0 },
|
||||||
|
Offset { x: 2, y: 0 },
|
||||||
|
Offset { x: -1, y: 0 },
|
||||||
|
Offset { x: 2, y: 0 },
|
||||||
|
],
|
||||||
|
R: vec![
|
||||||
|
Offset { x: -1, y: 0 },
|
||||||
|
Offset { x: 0, y: 0 },
|
||||||
|
Offset { x: 0, y: 0 },
|
||||||
|
Offset { x: 0, y: 1 },
|
||||||
|
Offset { x: 0, y: -2 },
|
||||||
|
],
|
||||||
|
U: vec![
|
||||||
|
Offset { x: -1, y: 1 },
|
||||||
|
Offset { x: 1, y: 1 },
|
||||||
|
Offset { x: -2, y: 1 },
|
||||||
|
Offset { x: 1, y: 0 },
|
||||||
|
Offset { x: -2, y: 0 },
|
||||||
|
],
|
||||||
|
L: vec![
|
||||||
|
Offset { x: 0, y: 1 },
|
||||||
|
Offset { x: 0, y: 1 },
|
||||||
|
Offset { x: 0, y: 1 },
|
||||||
|
Offset { x: 0, y: -1 },
|
||||||
|
Offset { x: 0, y: 2 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const OOffsetData: OffsetData = OffsetData {
|
||||||
|
O: vec![Offset { x: 0, y: 0 }],
|
||||||
|
R: vec![Offset { x: 0, y: -1 }],
|
||||||
|
U: vec![Offset { x: -1, y: -1 }],
|
||||||
|
L: vec![Offset { x: -1, y: 0 }],
|
||||||
|
};
|
Loading…
Reference in a new issue