From 4b5124f1c3c7ec3c166e70f20e552953fd0bbfc1 Mon Sep 17 00:00:00 2001 From: Theis Pieter Hollebeek Date: Sun, 2 Mar 2025 21:00:37 +0100 Subject: [PATCH] place_current_tetromino + try_rotate fn --- src/main.rs | 228 +++++++++++++++++++++------------------------------- 1 file changed, 90 insertions(+), 138 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9c13dbd..d00300a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,13 +19,28 @@ enum Direction { 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 new_random() -> Self { + fn random() -> Self { let v: u8 = rand::random(); match v % 7 { 0 => Self::I, @@ -51,7 +66,7 @@ impl Tetromino { } } - fn direction_pattern(&self, direction: Direction) -> [[bool; 4]; 4] { + fn direction_pattern(&self, direction: &Direction) -> [[bool; 4]; 4] { let idx = match direction { Direction::Up => 0, Direction::Right => 1, @@ -62,140 +77,32 @@ impl Tetromino { self.directions()[idx] } - fn rotation_pattern_from_string(pattern: &'static str) -> [[bool; 4]; 4] { - pattern - .split_whitespace() - .map(|row| { - let row: [char; 4] = row.chars().collect::>().try_into().unwrap(); - row.map(|c| { - if c == '#' { - true - } else if c == '-' { - false - } else { - panic!("invalid rotation pattern"); - } - }) - }) - .collect::>() - .try_into() - .unwrap() - } - - const fn directions(&self) -> [[[bool; 4]; 4]; 4] { - match self { + fn directions(&self) -> [[[bool; 4]; 4]; 4] { + let dir = match self { Self::I => [ - Self::rotation_pattern_from_string( - r" - ---- - #### - ---- - ---- - ", - ), - Self::rotation_pattern_from_string( - r" - --#- - --#- - --#- - --#- - ", - ), - Self::rotation_pattern_from_string( - r" - ---- - ---- - #### - ---- - ", - ), - Self::rotation_pattern_from_string( - r" - -#-- - -#-- - -#-- - -#-- - ", - ), + [[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 => [ - Self::rotation_pattern_from_string( - r" - ---- - #--- - ###- - ---- - ", - ), - Self::rotation_pattern_from_string( - r" - ---- - -##- - -#-- - -#-- - ", - ), - Self::rotation_pattern_from_string( - r" - ---- - ---- - ###- - --#- - ", - ), - Self::rotation_pattern_from_string( - r" - ---- - -#-- - -#-- - ##-- - ", - ), + [[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 => [ - Self::rotation_pattern_from_string( - r" - ---- - --#- - ###- - ---- - ", - ), - Self::rotation_pattern_from_string( - r" - ---- - -#-- - -#-- - -##- - ", - ), - Self::rotation_pattern_from_string( - r" - ---- - ---- - ###- - #--- - ", - ), - Self::rotation_pattern_from_string( - r" - ---- - ##-- - -#-- - -#-- - ", - ), + [[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::O => { - [Self::rotation_pattern_from_string( - r" - ---- - -##- - -##- - ---- - ", - ); 4] - } 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]], @@ -214,10 +121,12 @@ impl Tetromino { [[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 wallkicks(&self, direction: Direction, diff: DirectionDiff) -> [(i8, i8); 5] { + 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)], @@ -276,7 +185,7 @@ impl CurrentTetromino { } } -struct Board([[Rgb; Self::WIDTH]; Self::HEIGHT]); +struct Board(pub [[Option; Self::WIDTH]; Self::HEIGHT]); impl Board { const WIDTH: usize = 10; @@ -285,7 +194,7 @@ impl Board { impl Board { pub fn new() -> Self { - Board([[Rgb(0, 0, 0); Self::WIDTH]; Self::HEIGHT]) + Board([[None; Self::WIDTH]; Self::HEIGHT]) } pub fn colliding( @@ -295,13 +204,13 @@ impl Board { direction, x: cur_x, y: cur_y, - }: CurrentTetromino, + }: &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] == 0 { + if !pattern[y][x] { continue; } @@ -320,7 +229,7 @@ impl Board { return true; } - if self.0[y as usize][x as usize] != Rgb(0, 0, 0) { + if self.0[y as usize][x as usize].is_some() { return true; } } @@ -365,6 +274,49 @@ impl Game { last } + fn try_rotate(&mut self, diff: DirectionDiff) { + 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; + } + let wall_kicks = self + .current_tetromino + .tetromino + .wall_kicks(&old_direction, &diff); + + for (x, y) in wall_kicks { + self.current_tetromino.x += x; + self.current_tetromino.y += y; + if !(self.board.colliding(&self.current_tetromino)) { + return; + } + self.current_tetromino.x -= x; + self.current_tetromino.y -= y; + } + + self.current_tetromino.direction = old_direction; + } + + fn place_current_tetromino(&mut self) { + let next = CurrentTetromino::new(self.take_next_in_bag(Tetromino::random())); + let current = std::mem::replace(&mut self.current_tetromino, next); + let pattern = current.tetromino.direction_pattern(¤t.direction); + + for (y, row) in pattern.iter().enumerate() { + for x in row + .iter() + .enumerate() + .filter(|(_, exists)| **exists) + .map(|(idx, _)| idx) + { + 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()); + } + } + } + fn try_swap_tetromino(&mut self) { if self.has_swapped_held { return; @@ -373,7 +325,7 @@ impl Game { let held_or_first_in_bag_tetromino = self .held_tetromino .take() - .unwrap_or_else(|| self.take_next_in_bag(Tetromino::new_random())); + .unwrap_or_else(|| self.take_next_in_bag(Tetromino::random())); let current_tetromino = CurrentTetromino::new(held_or_first_in_bag_tetromino); let old_tetromino = std::mem::replace(&mut self.current_tetromino, current_tetromino); self.held_tetromino.replace(old_tetromino.tetromino);