mirror of
https://github.com/mii443/rustris.git
synced 2025-08-22 08:15:44 +00:00
rustris_base
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
273
Cargo.lock
generated
Normal file
273
Cargo.lock
generated
Normal file
@ -0,0 +1,273 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "486d44227f71a1ef39554c0dc47e44b9f4139927c75043312690c3f476d1d788"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"ntapi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustris"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crossterm",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "rustris"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.21.0"
|
||||
rand = "0.8.4"
|
16
src/block.rs
Normal file
16
src/block.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Block {
|
||||
Air,
|
||||
Block,
|
||||
Ghost
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn show(self) -> String {
|
||||
match self {
|
||||
Block::Air => String::from("・"),
|
||||
Block::Block => String::from("■"),
|
||||
Block::Ghost => String::from("□"),
|
||||
}
|
||||
}
|
||||
}
|
93
src/game_data.rs
Normal file
93
src/game_data.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use crate::{
|
||||
mino::*,
|
||||
block::*,
|
||||
mino_rotation::*
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GameData {
|
||||
pub minos: Vec<Mino>,
|
||||
pub field: Vec<Vec<Block>>,
|
||||
pub control_mino: Option<Mino>,
|
||||
pub mino_pos: (i32, i32),
|
||||
pub next_minos: Vec<Mino>,
|
||||
pub mino_rotation: MinoRotation,
|
||||
pub field_size: (usize, usize),
|
||||
}
|
||||
|
||||
impl GameData {
|
||||
pub fn new(field_size: (usize, usize)) -> GameData {
|
||||
let minos: Vec<Mino> = vec![
|
||||
Mino {
|
||||
id: String::from("I"),
|
||||
shape: vec![
|
||||
vec![false, false, true ,false],
|
||||
vec![false, false, true ,false],
|
||||
vec![false, false, true ,false],
|
||||
vec![false, false, true ,false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("J"),
|
||||
shape: vec![
|
||||
vec![false, true, false],
|
||||
vec![false, true, false],
|
||||
vec![true, true, false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("L"),
|
||||
shape: vec![
|
||||
vec![false ,true ,false],
|
||||
vec![false ,true ,false],
|
||||
vec![false ,true ,true],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("S"),
|
||||
shape: vec![
|
||||
vec![false ,true ,true],
|
||||
vec![true ,true ,false],
|
||||
vec![false ,false ,false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("Z"),
|
||||
shape: vec![
|
||||
vec![true ,true ,false],
|
||||
vec![false ,true ,true],
|
||||
vec![false ,false ,false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("T"),
|
||||
shape: vec![
|
||||
vec![false ,true ,false],
|
||||
vec![true ,true ,true],
|
||||
vec![false ,false ,false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("O"),
|
||||
shape: vec![
|
||||
vec![true ,true],
|
||||
vec![true ,true],
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
let field: Vec<Vec<Block>> = vec![vec![Block::Air; field_size.0]; field_size.1];
|
||||
|
||||
let next_minos = minos.clone();
|
||||
|
||||
GameData {
|
||||
minos,
|
||||
field,
|
||||
control_mino: None,
|
||||
mino_pos: (0, 0) ,
|
||||
next_minos,
|
||||
mino_rotation: MinoRotation::Up,
|
||||
field_size
|
||||
}
|
||||
}
|
||||
}
|
177
src/main.rs
Normal file
177
src/main.rs
Normal file
@ -0,0 +1,177 @@
|
||||
mod game_data;
|
||||
mod mino;
|
||||
mod block;
|
||||
mod rustris;
|
||||
mod mino_rotation;
|
||||
use std::{io::stdout, sync::{Arc, Mutex}, thread, time::Duration};
|
||||
|
||||
use crossterm::{cursor, event::{Event, KeyCode, KeyEvent, KeyModifiers, read}, execute, style::{Print}, terminal::{self, Clear, ClearType, enable_raw_mode}};
|
||||
|
||||
use crate::{block::Block, rustris::Rustris};
|
||||
|
||||
fn main() {
|
||||
let stdout = Arc::new(Mutex::new(stdout()));
|
||||
enable_raw_mode().unwrap();
|
||||
|
||||
{
|
||||
let mut stdout = stdout.lock().unwrap();
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::MoveTo(0, 0),
|
||||
cursor::Hide,
|
||||
Clear(ClearType::All)
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
let console_size = terminal::size().expect("Error: Cannot get console size.");
|
||||
for _ in 0..console_size.1 {
|
||||
for _ in 0..console_size.0 {
|
||||
print!(" ");
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
let rustris = Arc::new(Mutex::new(Rustris::new((10, 21))));
|
||||
|
||||
{
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.game_data.control_mino = Some(rustris.get_next_mino());
|
||||
}
|
||||
|
||||
let rustris_rc = Arc::clone(&rustris);
|
||||
let stdout_rc = Arc::clone(&stdout);
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
{
|
||||
let mut rustris_rc = rustris_rc.lock().unwrap();
|
||||
if !rustris_rc.move_mino(1, 0) {
|
||||
rustris_rc.place_control_mino(Block::Block);
|
||||
rustris_rc.game_data.control_mino = Some(rustris_rc.get_next_mino());
|
||||
rustris_rc.game_data.mino_pos = (0, 5);
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut stdout = stdout_rc.lock().unwrap();
|
||||
let buf = rustris_rc.lock().unwrap().show();
|
||||
execute!(stdout, Print(buf)).unwrap()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loop {
|
||||
{
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
let mut stdout = stdout.lock().unwrap();
|
||||
let buf = rustris.show();
|
||||
execute!(stdout, Print(buf)).unwrap();
|
||||
}
|
||||
|
||||
match read().unwrap() {
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Right,
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.move_mino(0, 1);
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Left,
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.move_mino(0, -1);
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Down,
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.move_mino(1, 0);
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Up,
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
while rustris.move_mino(1, 0) { }
|
||||
|
||||
rustris.place_control_mino(Block::Block);
|
||||
rustris.game_data.control_mino = Some(rustris.get_next_mino());
|
||||
rustris.game_data.mino_pos = (0, 5);
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char('x'),
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.rotate_mino_to_right();
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char('z'),
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.rotate_mino_to_left();
|
||||
}
|
||||
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char('q'),
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
break;
|
||||
}
|
||||
|
||||
_ => ()
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
for x in 0..(rustris.game_data.field_size.1) {
|
||||
let mut air = false;
|
||||
for y in 0..(rustris.game_data.field_size.0) {
|
||||
if let Block::Air = rustris.game_data.field[x][y] {
|
||||
air = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !air {
|
||||
for y in 0..(rustris.game_data.field_size.0) {
|
||||
rustris.game_data.field[x][y] = Block::Air;
|
||||
}
|
||||
|
||||
for x2 in (0..(rustris.game_data.field_size.1)).rev() {
|
||||
if x2 < x && x2 < 20 {
|
||||
for y2 in 0..(rustris.game_data.field_size.0) {
|
||||
rustris.game_data.field[x2 + 1][y2] = rustris.game_data.field[x2][y2];
|
||||
rustris.game_data.field[x2][y2] = Block::Air;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut stdout = stdout.lock().unwrap();
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::MoveTo(0, 0),
|
||||
cursor::Show,
|
||||
Clear(ClearType::All)
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
}
|
5
src/mino.rs
Normal file
5
src/mino.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Mino {
|
||||
pub id: String,
|
||||
pub shape: Vec<Vec<bool>>
|
||||
}
|
69
src/mino_rotation.rs
Normal file
69
src/mino_rotation.rs
Normal file
@ -0,0 +1,69 @@
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum MinoRotation {
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
Left
|
||||
}
|
||||
|
||||
impl MinoRotation {
|
||||
pub fn to_count(&self) -> i32 {
|
||||
match self {
|
||||
MinoRotation::Up => 0,
|
||||
MinoRotation::Right => 1,
|
||||
MinoRotation::Down => 2,
|
||||
MinoRotation::Left => 3
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(rotation: i32) -> MinoRotation {
|
||||
let mut rotation = rotation;
|
||||
if rotation < 0 {
|
||||
rotation += 4;
|
||||
}
|
||||
rotation %= 4;
|
||||
|
||||
match rotation {
|
||||
0 => MinoRotation::Up,
|
||||
1 => MinoRotation::Right,
|
||||
2 => MinoRotation::Down,
|
||||
3 => MinoRotation::Left,
|
||||
_ => MinoRotation::Up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod mino_rotation_test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn convert_rotate_test() {
|
||||
assert_eq!(MinoRotation::get(-1), MinoRotation::Left);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_rotate_test1() {
|
||||
assert_eq!(MinoRotation::get(0), MinoRotation::Up);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_rotate_test2() {
|
||||
assert_eq!(MinoRotation::get(1), MinoRotation::Right);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_rotate_test3() {
|
||||
assert_eq!(MinoRotation::get(2), MinoRotation::Down);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_rotate_test4() {
|
||||
assert_eq!(MinoRotation::get(3), MinoRotation::Left);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_rotate_test5() {
|
||||
assert_eq!(MinoRotation::get(4), MinoRotation::Up);
|
||||
}
|
||||
}
|
229
src/rustris.rs
Normal file
229
src/rustris.rs
Normal file
@ -0,0 +1,229 @@
|
||||
use crossterm::terminal;
|
||||
use rand::prelude::*;
|
||||
|
||||
use crate::{block::Block, game_data::*, mino::Mino, mino_rotation::MinoRotation};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rustris {
|
||||
pub game_data: GameData
|
||||
}
|
||||
|
||||
impl Rustris {
|
||||
pub fn new(field_size: (usize, usize)) -> Rustris {
|
||||
let game_data = GameData::new(field_size);
|
||||
Rustris { game_data }
|
||||
}
|
||||
|
||||
pub fn get_next_mino(&mut self) -> Mino {
|
||||
if self.game_data.next_minos.is_empty() {
|
||||
self.game_data.next_minos = self.game_data.minos.clone();
|
||||
}
|
||||
|
||||
let next_mino_index = rand::thread_rng().gen_range(0..self.game_data.next_minos.len());
|
||||
let next_mino = self.game_data.next_minos[next_mino_index].clone();
|
||||
self.game_data.next_minos.remove(next_mino_index);
|
||||
next_mino
|
||||
}
|
||||
|
||||
pub fn check_field(&mut self) -> bool {
|
||||
match self.try_place_control_mino(Block::Block) {
|
||||
Ok(_) => true,
|
||||
Err(()) => false
|
||||
}
|
||||
}
|
||||
|
||||
fn rotate_mino(&mut self, rotation: MinoRotation) -> bool {
|
||||
let original_rotation = self.game_data.mino_rotation.clone();
|
||||
self.game_data.mino_rotation = rotation;
|
||||
|
||||
if self.check_field() {
|
||||
true
|
||||
} else {
|
||||
self.game_data.mino_rotation = original_rotation;
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotate_mino_to_right(&mut self) -> bool {
|
||||
self.rotate_mino(MinoRotation::get(self.game_data.mino_rotation.to_count() + 1))
|
||||
}
|
||||
|
||||
pub fn rotate_mino_to_left(&mut self) -> bool {
|
||||
self.rotate_mino(MinoRotation::get(self.game_data.mino_rotation.to_count() - 1))
|
||||
}
|
||||
|
||||
pub fn move_mino(&mut self, x: i32, y: i32) -> bool {
|
||||
self.game_data.mino_pos.0 += x;
|
||||
self.game_data.mino_pos.1 += y;
|
||||
|
||||
if self.check_field() {
|
||||
true
|
||||
} else {
|
||||
self.game_data.mino_pos.0 -= x;
|
||||
self.game_data.mino_pos.1 -= y;
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn rotate_to_right<T: Clone>(vec: Vec<Vec<T>>) -> Vec<Vec<T>> {
|
||||
let x_max = vec.len();
|
||||
let y_max = vec[0].len();
|
||||
|
||||
let mut buffer: Vec<Vec<T>> = vec![vec![]; y_max];
|
||||
for y in (0..y_max).rev() {
|
||||
for x in (0..x_max).rev() {
|
||||
buffer[x].push(vec[y][x].clone());
|
||||
}
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
fn try_place_control_mino(&mut self, block_type: Block) -> Result<Vec<Vec<Block>>, ()> {
|
||||
if let Some(control_mino) = &self.game_data.control_mino {
|
||||
let mut shape = control_mino.shape.clone();
|
||||
let offset = self.game_data.mino_pos;
|
||||
|
||||
let rotate_count = self.game_data.mino_rotation.to_count();
|
||||
|
||||
for _ in 0..rotate_count {
|
||||
shape = Rustris::rotate_to_right(shape);
|
||||
}
|
||||
|
||||
let mut field = self.game_data.field.clone();
|
||||
|
||||
for x in 0..shape.len() {
|
||||
for y in 0..shape[x].len() {
|
||||
|
||||
if shape[x][y] {
|
||||
if (x as i32 + offset.0) < 0 ||
|
||||
(x as i32 + offset.0) > (self.game_data.field_size.1 - 1) as i32 ||
|
||||
(y as i32 + offset.1) < 0 ||
|
||||
(y as i32 + offset.1) > (self.game_data.field_size.0 - 1) as i32 {
|
||||
return Err(());
|
||||
}
|
||||
match field[(x as i32 + offset.0) as usize][(y as i32 + offset.1) as usize] {
|
||||
Block::Block => {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
Block::Air => {
|
||||
field[(x as i32 + offset.0) as usize][(y as i32 + offset.1) as usize] = block_type;
|
||||
}
|
||||
|
||||
Block::Ghost => {
|
||||
field[(x as i32 + offset.0) as usize][(y as i32 + offset.1) as usize] = block_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(field);
|
||||
}
|
||||
|
||||
Err(())
|
||||
}
|
||||
|
||||
pub fn place_control_mino(&mut self, block_type: Block) -> bool {
|
||||
match self.try_place_control_mino(block_type) {
|
||||
Ok(field) => {
|
||||
self.game_data.field = field;
|
||||
true
|
||||
}
|
||||
Err(()) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(&mut self) -> String {
|
||||
let original_field = self.game_data.field.clone();
|
||||
let original_mino_pos = self.game_data.mino_pos;
|
||||
|
||||
while self.move_mino(1, 0) { }
|
||||
self.place_control_mino(Block::Ghost);
|
||||
self.game_data.mino_pos = original_mino_pos;
|
||||
self.place_control_mino(Block::Block);
|
||||
|
||||
let console_size = terminal::size().expect("Error: Cannot get console size.");
|
||||
|
||||
let mut print_buffer = String::default();
|
||||
|
||||
for blocks in &self.game_data.field {
|
||||
print_buffer += &" ".repeat((console_size.0 / 5).into());
|
||||
|
||||
for block in blocks {
|
||||
print_buffer += &block.show();
|
||||
}
|
||||
print_buffer += "\n";
|
||||
}
|
||||
|
||||
for _ in 0..(console_size.1 / 6) {
|
||||
for _ in 0..console_size.0 {
|
||||
print_buffer += " ";
|
||||
}
|
||||
print_buffer += "\n";
|
||||
}
|
||||
|
||||
self.game_data.field = original_field;
|
||||
|
||||
print_buffer
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod rustris_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn rotate_test() {
|
||||
let rotate_before =
|
||||
vec![
|
||||
vec![0, 0, 1],
|
||||
vec![1, 1, 0],
|
||||
vec![1, 0, 0]
|
||||
];
|
||||
let rotate_after =
|
||||
vec![
|
||||
vec![1, 1, 0],
|
||||
vec![0, 1, 0],
|
||||
vec![0, 0, 1]
|
||||
];
|
||||
assert_eq!(Rustris::rotate_to_right(rotate_before), rotate_after);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rotate_test2() {
|
||||
let rotate_before =
|
||||
vec![
|
||||
vec![1, 0, 0],
|
||||
vec![1, 1, 1],
|
||||
vec![1, 0, 0]
|
||||
];
|
||||
let rotate_after =
|
||||
vec![
|
||||
vec![1, 1, 1],
|
||||
vec![0, 1, 0],
|
||||
vec![0, 1, 0]
|
||||
];
|
||||
assert_eq!(Rustris::rotate_to_right(rotate_before), rotate_after);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rotate_test3() {
|
||||
let rotate_before =
|
||||
vec![
|
||||
vec![1, 0, 0],
|
||||
vec![1, 1, 1],
|
||||
vec![0, 1, 0]
|
||||
];
|
||||
let rotate_after =
|
||||
vec![
|
||||
vec![0, 1, 1],
|
||||
vec![1, 1, 0],
|
||||
vec![0, 1, 0]
|
||||
];
|
||||
assert_eq!(Rustris::rotate_to_right(rotate_before), rotate_after);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user