diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..038a39d --- /dev/null +++ b/.vscode/launch.json @@ -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}" + } + ] +} \ No newline at end of file diff --git a/src/block.rs b/src/block.rs index 296ef90..ce9c281 100644 --- a/src/block.rs +++ b/src/block.rs @@ -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("■"), } } } diff --git a/src/game_data.rs b/src/game_data.rs index 2491edd..05173a3 100644 --- a/src/game_data.rs +++ b/src/game_data.rs @@ -13,34 +13,36 @@ pub struct GameData { pub next_minos: Vec, pub mino_rotation: MinoRotation, pub field_size: (usize, usize), + pub show_ghost: bool, + pub hold_mino: Option } impl GameData { - pub fn new(field_size: (usize, usize)) -> GameData { + pub fn new(field_size: (usize, usize), show_ghost: bool) -> GameData { let minos: Vec = 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 } } } diff --git a/src/game_status.rs b/src/game_status.rs new file mode 100644 index 0000000..888c07a --- /dev/null +++ b/src/game_status.rs @@ -0,0 +1,5 @@ +#[derive(Debug)] +pub enum GameStatus { + Playing, + Gameover +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e90db2d..5bc60c0 100644 --- a/src/main.rs +++ b/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)] diff --git a/src/mino_rotation.rs b/src/mino_rotation.rs index 98faf83..195bf9a 100644 --- a/src/mino_rotation.rs +++ b/src/mino_rotation.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum MinoRotation { Up, Right, diff --git a/src/rustris.rs b/src/rustris.rs index 126e633..c0fc0f2 100644 --- a/src/rustris.rs +++ b/src/rustris.rs @@ -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(vec: Vec>) -> Vec> { 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"; } diff --git a/src/super_rotation.rs b/src/super_rotation.rs new file mode 100644 index 0000000..bc2c6f7 --- /dev/null +++ b/src/super_rotation.rs @@ -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>, + 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>, 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); + } +} \ No newline at end of file