mirror of
https://github.com/mii443/rustris.git
synced 2025-08-22 16:25:42 +00:00
add SRS
This commit is contained in:
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
// IntelliSense を使用して利用可能な属性を学べます。
|
||||
// 既存の属性の説明をホバーして表示します。
|
||||
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'rustris'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=rustris",
|
||||
"--package=rustris"
|
||||
],
|
||||
"filter": {
|
||||
"name": "rustris",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'rustris'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=rustris",
|
||||
"--package=rustris"
|
||||
],
|
||||
"filter": {
|
||||
"name": "rustris",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
pub enum Block {
|
||||
Air,
|
||||
Block,
|
||||
Ghost
|
||||
Ghost,
|
||||
Control
|
||||
}
|
||||
|
||||
impl Block {
|
||||
@ -11,6 +12,7 @@ impl Block {
|
||||
Block::Air => String::from("・"),
|
||||
Block::Block => String::from("■"),
|
||||
Block::Ghost => String::from("□"),
|
||||
Block::Control => String::from("■"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,34 +13,36 @@ pub struct GameData {
|
||||
pub next_minos: Vec<Mino>,
|
||||
pub mino_rotation: MinoRotation,
|
||||
pub field_size: (usize, usize),
|
||||
pub show_ghost: bool,
|
||||
pub hold_mino: Option<Mino>
|
||||
}
|
||||
|
||||
impl GameData {
|
||||
pub fn new(field_size: (usize, usize)) -> GameData {
|
||||
pub fn new(field_size: (usize, usize), show_ghost: bool) -> 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],
|
||||
vec![false, false, false ,false],
|
||||
vec![true, true, true ,true],
|
||||
vec![false, false, false ,false],
|
||||
vec![false, false, false ,false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("J"),
|
||||
shape: vec![
|
||||
vec![false, true, false],
|
||||
vec![false, true, false],
|
||||
vec![true, true, false],
|
||||
vec![true, false, false],
|
||||
vec![true, true, true],
|
||||
vec![false, false, false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
id: String::from("L"),
|
||||
shape: vec![
|
||||
vec![false ,true ,false],
|
||||
vec![false ,true ,false],
|
||||
vec![false ,true ,true],
|
||||
vec![false ,false ,true],
|
||||
vec![true ,true ,true],
|
||||
vec![false ,false ,false],
|
||||
]
|
||||
},
|
||||
Mino {
|
||||
@ -84,10 +86,12 @@ impl GameData {
|
||||
minos,
|
||||
field,
|
||||
control_mino: None,
|
||||
mino_pos: (0, 0) ,
|
||||
mino_pos: (0, 0),
|
||||
next_minos,
|
||||
mino_rotation: MinoRotation::Up,
|
||||
field_size
|
||||
field_size,
|
||||
show_ghost,
|
||||
hold_mino: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
5
src/game_status.rs
Normal file
5
src/game_status.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[derive(Debug)]
|
||||
pub enum GameStatus {
|
||||
Playing,
|
||||
Gameover
|
||||
}
|
211
src/main.rs
211
src/main.rs
@ -3,9 +3,14 @@ mod mino;
|
||||
mod block;
|
||||
mod rustris;
|
||||
mod mino_rotation;
|
||||
use std::{io::stdout, sync::{Arc, Mutex}, thread, time::Duration};
|
||||
mod game_status;
|
||||
mod super_rotation;
|
||||
use std::{io::stdout, process::exit, 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 crossterm::{cursor, event::{Event, KeyCode, KeyEvent, KeyModifiers, read}, execute, style::{Color, Print, ResetColor, SetBackgroundColor, SetForegroundColor}, terminal::{self, Clear, ClearType, enable_raw_mode}};
|
||||
use game_data::GameData;
|
||||
use game_status::GameStatus;
|
||||
use mino_rotation::MinoRotation;
|
||||
|
||||
use crate::{block::Block, rustris::Rustris};
|
||||
|
||||
@ -31,7 +36,98 @@ fn main() {
|
||||
println!();
|
||||
}
|
||||
|
||||
let rustris = Arc::new(Mutex::new(Rustris::new((10, 21))));
|
||||
let rustris = Arc::new(Mutex::new(
|
||||
Rustris::new(
|
||||
GameData::new((10, 21), true)
|
||||
)
|
||||
));
|
||||
|
||||
{
|
||||
let mut select = 0;
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
|
||||
loop {
|
||||
let mut stdout = stdout.lock().unwrap();
|
||||
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::MoveTo(0, 0),
|
||||
cursor::Hide,
|
||||
Clear(ClearType::All)
|
||||
).unwrap();
|
||||
|
||||
if select == 0 {
|
||||
print!("> ");
|
||||
}
|
||||
println!("Play");
|
||||
|
||||
if select == 1 {
|
||||
print!("> ");
|
||||
}
|
||||
println!("Ghost {}",
|
||||
if rustris.game_data.show_ghost {
|
||||
"ON"
|
||||
} else {
|
||||
"OFF"
|
||||
}
|
||||
);
|
||||
|
||||
if select == 2 {
|
||||
print!("> ");
|
||||
}
|
||||
println!("Quit");
|
||||
|
||||
match read().unwrap() {
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Up,
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
if select > 0 {
|
||||
select -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Down,
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
if select < 2 {
|
||||
select += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Enter,
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
match select {
|
||||
0 => {
|
||||
break;
|
||||
}
|
||||
1 => {
|
||||
rustris.game_data.show_ghost = !rustris.game_data.show_ghost;
|
||||
}
|
||||
2 => {
|
||||
std::process::exit(0);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut stdout = stdout.lock().unwrap();
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::MoveTo(0, 0),
|
||||
cursor::Hide,
|
||||
Clear(ClearType::All)
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
@ -40,15 +136,36 @@ fn main() {
|
||||
|
||||
let rustris_rc = Arc::clone(&rustris);
|
||||
let stdout_rc = Arc::clone(&stdout);
|
||||
thread::spawn(move || {
|
||||
let exit_flag = Arc::new(Mutex::new(false));
|
||||
let exit_flag_rc = Arc::clone(&exit_flag);
|
||||
let control_count = Arc::new(Mutex::new(0));
|
||||
let control_count_rc = Arc::clone(&control_count);
|
||||
let frame_thread = thread::spawn(move || {
|
||||
let mut ground_flag = false;
|
||||
let mut before_control_count = 0;
|
||||
loop {
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
if *exit_flag_rc.lock().unwrap() {
|
||||
break;
|
||||
}
|
||||
thread::sleep(Duration::from_secs_f32(0.5));
|
||||
{
|
||||
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);
|
||||
if ground_flag {
|
||||
let control_count = *control_count_rc.lock().unwrap();
|
||||
if before_control_count < control_count && control_count < 15 {
|
||||
before_control_count = control_count.clone();
|
||||
ground_flag = false;
|
||||
} else {
|
||||
rustris_rc.place_control_mino(Block::Block);
|
||||
rustris_rc.next_mino();
|
||||
ground_flag = false;
|
||||
*control_count_rc.lock().unwrap() = 0;
|
||||
before_control_count = 0;
|
||||
}
|
||||
} else {
|
||||
ground_flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -74,6 +191,7 @@ fn main() {
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.move_mino(0, 1);
|
||||
*control_count.lock().unwrap() += 1;
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
@ -82,6 +200,7 @@ fn main() {
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.move_mino(0, -1);
|
||||
*control_count.lock().unwrap() += 1;
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
@ -90,6 +209,7 @@ fn main() {
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.move_mino(1, 0);
|
||||
*control_count.lock().unwrap() += 1;
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
@ -100,16 +220,8 @@ fn main() {
|
||||
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();
|
||||
rustris.next_mino();
|
||||
*control_count.lock().unwrap() += 1;
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
@ -117,9 +229,33 @@ fn main() {
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.rotate_mino_to_left();
|
||||
if let Some(holding) = rustris.game_data.hold_mino.clone() {
|
||||
let control_tmp = rustris.game_data.control_mino.clone();
|
||||
rustris.game_data.control_mino = Some(holding);
|
||||
rustris.game_data.hold_mino = control_tmp;
|
||||
rustris.game_data.mino_pos = (0, 3);
|
||||
rustris.game_data.mino_rotation = MinoRotation::Up;
|
||||
} else {
|
||||
rustris.game_data.hold_mino = rustris.game_data.control_mino.clone();
|
||||
rustris.next_mino();
|
||||
}
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char('c'),
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.rotate_mino_to_right();
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char('x'),
|
||||
modifiers: KeyModifiers::NONE
|
||||
}) => {
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
rustris.rotate_mino_to_left();
|
||||
}
|
||||
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char('q'),
|
||||
@ -158,6 +294,39 @@ fn main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut rustris = rustris.lock().unwrap();
|
||||
if let GameStatus::Gameover = rustris.game_status {
|
||||
let mut stdout = stdout.lock().unwrap();
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::MoveTo(0, 0),
|
||||
cursor::Show,
|
||||
Clear(ClearType::All),
|
||||
SetBackgroundColor(Color::Red),
|
||||
).unwrap();
|
||||
|
||||
let console_size = terminal::size().expect("Error: Cannot get console size.");
|
||||
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::MoveTo(console_size.0 / 2, console_size.1 / 2),
|
||||
Print("Game Over")
|
||||
).unwrap();
|
||||
|
||||
thread::sleep(Duration::from_secs(3));
|
||||
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::MoveTo(0, 0),
|
||||
cursor::Show,
|
||||
Clear(ClearType::All),
|
||||
ResetColor
|
||||
).unwrap();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@ -169,6 +338,10 @@ fn main() {
|
||||
Clear(ClearType::All)
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
*exit_flag.lock().unwrap() = true;
|
||||
frame_thread.join();
|
||||
main();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum MinoRotation {
|
||||
Up,
|
||||
Right,
|
||||
|
@ -1,17 +1,17 @@
|
||||
use crossterm::terminal;
|
||||
use rand::prelude::*;
|
||||
|
||||
use crate::{block::Block, game_data::*, mino::Mino, mino_rotation::MinoRotation};
|
||||
use crate::{block::Block, game_data::*, game_status::GameStatus, mino::Mino, mino_rotation::MinoRotation, super_rotation::SuperRotation};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rustris {
|
||||
pub game_data: GameData
|
||||
pub game_data: GameData,
|
||||
pub game_status: GameStatus
|
||||
}
|
||||
|
||||
impl Rustris {
|
||||
pub fn new(field_size: (usize, usize)) -> Rustris {
|
||||
let game_data = GameData::new(field_size);
|
||||
Rustris { game_data }
|
||||
pub fn new(game_data: GameData) -> Rustris {
|
||||
Rustris { game_data, game_status: GameStatus::Playing }
|
||||
}
|
||||
|
||||
pub fn get_next_mino(&mut self) -> Mino {
|
||||
@ -33,15 +33,30 @@ impl Rustris {
|
||||
}
|
||||
|
||||
fn rotate_mino(&mut self, rotation: MinoRotation) -> bool {
|
||||
let original_rotation = self.game_data.mino_rotation.clone();
|
||||
self.game_data.mino_rotation = rotation;
|
||||
if let Some(mino) = self.game_data.control_mino.clone() {
|
||||
let mut super_rotation = SuperRotation::new(
|
||||
self.game_data.field.clone(),
|
||||
mino.clone(),
|
||||
self.game_data.mino_pos.clone(),
|
||||
self.game_data.field_size.clone(),
|
||||
self.game_data.mino_rotation.clone(),
|
||||
rotation.clone()
|
||||
);
|
||||
|
||||
if self.check_field() {
|
||||
true
|
||||
} else {
|
||||
self.game_data.mino_rotation = original_rotation;
|
||||
false
|
||||
if super_rotation.rotate() {
|
||||
self.game_data.mino_pos = super_rotation.mino_position.clone();
|
||||
self.game_data.mino_rotation = super_rotation.now_rotation.clone();
|
||||
if self.check_field() {
|
||||
return true;
|
||||
} else {
|
||||
self.game_data.mino_pos = super_rotation.origin_position;
|
||||
self.game_data.mino_rotation = super_rotation.origin_rotation;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn rotate_mino_to_right(&mut self) -> bool {
|
||||
@ -65,6 +80,18 @@ impl Rustris {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_mino(&mut self) -> bool {
|
||||
self.game_data.control_mino = Some(self.get_next_mino());
|
||||
self.game_data.mino_pos = (0, 3);
|
||||
self.game_data.mino_rotation = MinoRotation::Up;
|
||||
if self.check_field() {
|
||||
true
|
||||
} else {
|
||||
self.game_status = GameStatus::Gameover;
|
||||
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();
|
||||
@ -114,6 +141,8 @@ impl Rustris {
|
||||
Block::Ghost => {
|
||||
field[(x as i32 + offset.0) as usize][(y as i32 + offset.1) as usize] = block_type;
|
||||
}
|
||||
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,10 +170,13 @@ impl Rustris {
|
||||
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);
|
||||
if self.game_data.show_ghost {
|
||||
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);
|
||||
self.place_control_mino(Block::Control);
|
||||
|
||||
let console_size = terminal::size().expect("Error: Cannot get console size.");
|
||||
|
||||
@ -159,10 +191,23 @@ impl Rustris {
|
||||
print_buffer += "\n";
|
||||
}
|
||||
|
||||
for _ in 0..(console_size.1 / 6) {
|
||||
for _ in 0..console_size.0 {
|
||||
print_buffer += " ";
|
||||
print_buffer += " Hold\n";
|
||||
if let Some(hold) = self.game_data.hold_mino.clone() {
|
||||
for shape_row in hold.shape {
|
||||
print_buffer += " ";
|
||||
for x in shape_row {
|
||||
print_buffer += if x {
|
||||
"■"
|
||||
} else {
|
||||
" "
|
||||
}
|
||||
}
|
||||
print_buffer += "\n";
|
||||
}
|
||||
}
|
||||
print_buffer += " Z ホールド, X 左回転, C 右回転\n";
|
||||
|
||||
for _ in 0..(if (console_size.1 - print_buffer.lines().count() as u16) > 0 { console_size.1 - print_buffer.lines().count() as u16 - 1 } else { console_size.1 - print_buffer.lines().count() as u16 }) {
|
||||
print_buffer += "\n";
|
||||
}
|
||||
|
||||
|
545
src/super_rotation.rs
Normal file
545
src/super_rotation.rs
Normal file
@ -0,0 +1,545 @@
|
||||
use crate::{block::Block, mino::{self, Mino}, mino_rotation::MinoRotation};
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
enum RotateDirection {
|
||||
Right,
|
||||
Left,
|
||||
}
|
||||
|
||||
pub struct SuperRotation {
|
||||
pub field: Vec<Vec<Block>>,
|
||||
pub target: Mino,
|
||||
pub mino_position: (i32, i32),
|
||||
pub origin_position: (i32, i32),
|
||||
pub field_size: (usize, usize),
|
||||
pub now_rotation: MinoRotation,
|
||||
pub origin_rotation: MinoRotation,
|
||||
pub next_rotation: MinoRotation,
|
||||
rotate_direction: RotateDirection,
|
||||
}
|
||||
|
||||
impl SuperRotation {
|
||||
pub fn new(field: Vec<Vec<Block>>, target: Mino, mino_position: (i32, i32), field_size: (usize, usize), now_rotation: MinoRotation, next_rotation: MinoRotation) -> SuperRotation {
|
||||
SuperRotation {
|
||||
field,
|
||||
target,
|
||||
mino_position,
|
||||
origin_position: mino_position.clone(),
|
||||
field_size,
|
||||
now_rotation,
|
||||
origin_rotation: now_rotation.clone(),
|
||||
next_rotation,
|
||||
rotate_direction: SuperRotation::get_rotate_direction(now_rotation.clone(), now_rotation.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotate(&mut self) -> bool {
|
||||
if self.target.id == "I" {
|
||||
if self.step0() {
|
||||
return true;
|
||||
}
|
||||
if self.i_step1() {
|
||||
return true;
|
||||
}
|
||||
if self.i_step2() {
|
||||
return true;
|
||||
}
|
||||
if self.i_step3() {
|
||||
return true;
|
||||
}
|
||||
if self.i_step4() {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if self.step0() {
|
||||
return true;
|
||||
}
|
||||
if self.step1() {
|
||||
return true;
|
||||
}
|
||||
if self.step2() {
|
||||
return true;
|
||||
}
|
||||
if self.step3() {
|
||||
return true;
|
||||
}
|
||||
if self.step4() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn i_step1(&mut self) -> bool {
|
||||
match self.origin_rotation {
|
||||
MinoRotation::Up => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Right => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_right();
|
||||
self.move_to_right();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Down => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_right();
|
||||
self.move_to_right();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_right();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Left => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_right();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn i_step2(&mut self) -> bool {
|
||||
self.step0();
|
||||
|
||||
match self.origin_rotation {
|
||||
MinoRotation::Up => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_right();
|
||||
self.move_to_right();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_right();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Right => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_right();
|
||||
self.move_to_right();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Down => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Left => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_right();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn i_step3(&mut self) -> bool {
|
||||
self.step0();
|
||||
|
||||
match self.origin_rotation {
|
||||
MinoRotation::Up => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_right();
|
||||
self.move_to_up();
|
||||
self.move_to_up();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_down();
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Right => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_right();
|
||||
self.move_to_right();
|
||||
self.move_to_up();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_up();
|
||||
self.move_to_up();
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Down => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_up();
|
||||
self.move_to_right();
|
||||
self.move_to_right();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_right();
|
||||
self.move_to_down();
|
||||
self.move_to_down();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Left => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_down();
|
||||
self.move_to_down();
|
||||
self.move_to_right();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_down();
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn i_step4(&mut self) -> bool {
|
||||
self.step0();
|
||||
|
||||
match self.origin_rotation {
|
||||
MinoRotation::Up => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_down();
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_right();
|
||||
self.move_to_up();
|
||||
self.move_to_up();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Right => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_down();
|
||||
self.move_to_down();
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_right();
|
||||
self.move_to_right();
|
||||
self.move_to_down();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Down => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Left => {
|
||||
self.move_to_left();
|
||||
self.move_to_down();
|
||||
self.move_to_down();
|
||||
}
|
||||
MinoRotation::Right => {
|
||||
self.move_to_up();
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Left => {
|
||||
match self.now_rotation {
|
||||
MinoRotation::Up => {
|
||||
self.move_to_left();
|
||||
self.move_to_left();
|
||||
self.move_to_up();
|
||||
}
|
||||
MinoRotation::Down => {
|
||||
self.move_to_right();
|
||||
self.move_to_up();
|
||||
self.move_to_up();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn step0(&mut self) -> bool {
|
||||
self.now_rotation = self.next_rotation.clone();
|
||||
self.mino_position = self.origin_position.clone();
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn step1(&mut self) -> bool {
|
||||
let rotate_direction = self.rotate_direction;
|
||||
match self.now_rotation {
|
||||
MinoRotation::Right => {
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Left => {
|
||||
self.move_to_right();
|
||||
}
|
||||
_ => {
|
||||
if self.origin_rotation == MinoRotation::Left {
|
||||
self.move_to_left();
|
||||
} else {
|
||||
self.move_to_right();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn step2(&mut self) -> bool {
|
||||
if self.now_rotation == MinoRotation::Right || self.now_rotation == MinoRotation::Left {
|
||||
self.move_to_up();
|
||||
} else {
|
||||
self.move_to_down();
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn step3(&mut self) -> bool {
|
||||
self.now_rotation = self.next_rotation.clone();
|
||||
self.mino_position = self.origin_position.clone();
|
||||
|
||||
if self.now_rotation == MinoRotation::Right || self.now_rotation == MinoRotation::Left {
|
||||
self.move_to_down();
|
||||
self.move_to_down();
|
||||
} else {
|
||||
self.move_to_up();
|
||||
self.move_to_up();
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn step4(&mut self) -> bool {
|
||||
let rotate_direction = self.rotate_direction;
|
||||
match self.now_rotation {
|
||||
MinoRotation::Right => {
|
||||
self.move_to_left();
|
||||
}
|
||||
MinoRotation::Left => {
|
||||
self.move_to_right();
|
||||
}
|
||||
_ => {
|
||||
if rotate_direction == RotateDirection::Right {
|
||||
self.move_to_left();
|
||||
} else {
|
||||
self.move_to_right();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.check_duplicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn move_to_right(&mut self) {
|
||||
self.mino_position.1 += 1;
|
||||
}
|
||||
fn move_to_left(&mut self) {
|
||||
self.mino_position.1 -= 1;
|
||||
}
|
||||
fn move_to_up(&mut self) {
|
||||
self.mino_position.0 -= 1;
|
||||
}
|
||||
fn move_to_down(&mut self) {
|
||||
self.mino_position.0 += 1;
|
||||
}
|
||||
|
||||
fn check_duplicate(&mut self) -> bool {
|
||||
let shape = self.target.shape.clone();
|
||||
let pos = self.mino_position;
|
||||
let field = self.field.clone();
|
||||
let field_size = self.field_size;
|
||||
for x in 0..shape.len() {
|
||||
for y in 0..shape[x].len() {
|
||||
if shape[x][y] {
|
||||
if (x as i32 + pos.0) < 0 ||
|
||||
(x as i32 + pos.0) > (field_size.1 - 1) as i32 ||
|
||||
(y as i32 + pos.1) < 0 ||
|
||||
(y as i32 + pos.1) > (field_size.0 - 1) as i32 {
|
||||
return false;
|
||||
}
|
||||
match field[(x as i32 + pos.0) as usize][(y as i32 + pos.1) as usize] {
|
||||
Block::Block => {
|
||||
return false;
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn get_rotate_direction(before: MinoRotation, after: MinoRotation) -> RotateDirection {
|
||||
match before {
|
||||
MinoRotation::Up => {
|
||||
if after == MinoRotation::Right {
|
||||
RotateDirection::Right
|
||||
} else {
|
||||
RotateDirection::Left
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Right => {
|
||||
if after == MinoRotation::Down {
|
||||
RotateDirection::Right
|
||||
} else {
|
||||
RotateDirection::Left
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Down => {
|
||||
if after == MinoRotation::Left {
|
||||
RotateDirection::Right
|
||||
} else {
|
||||
RotateDirection::Left
|
||||
}
|
||||
}
|
||||
|
||||
MinoRotation::Left => {
|
||||
if after == MinoRotation::Up {
|
||||
RotateDirection::Right
|
||||
} else {
|
||||
RotateDirection::Left
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod super_rotation_test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn get_rotate_direction_test1() {
|
||||
assert_eq!(SuperRotation::get_rotate_direction(MinoRotation::Up, MinoRotation::Right), RotateDirection::Right);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_rotate_direction_test2() {
|
||||
assert_eq!(SuperRotation::get_rotate_direction(MinoRotation::Down, MinoRotation::Right), RotateDirection::Left);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_rotate_direction_test3() {
|
||||
assert_eq!(SuperRotation::get_rotate_direction(MinoRotation::Left, MinoRotation::Up), RotateDirection::Right);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_rotate_direction_test4() {
|
||||
assert_eq!(SuperRotation::get_rotate_direction(MinoRotation::Right, MinoRotation::Up), RotateDirection::Left);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user