retris/
block.rs

1use cursive::{
2    Vec2,
3    theme::{BaseColor, Color, ColorStyle},
4};
5use rand::thread_rng;
6use rand::seq::SliceRandom;
7
8type Pos = (i32, i32);
9
10
11#[derive(Clone, Debug)]
12pub struct BlockWithPos {
13    pub block: Block,
14    pub pos: Vec2,
15}
16
17impl BlockWithPos {
18    pub fn new(block: Block, pos: Vec2) -> Self {
19        Self {
20            block,
21            pos,
22        }
23    }
24
25    pub fn cells(&self) -> Vec<Vec2> {
26        self.block.cells().into_iter().map(|cell| {
27            let x = self.pos.x as i32 + cell.0;
28            let y = self.pos.y as i32 + cell.1;
29            Vec2::new(x as usize, y as usize)
30        }).collect::<Vec<Vec2>>()
31    }
32
33    pub fn color(&self) -> ColorStyle {
34        self.block.color()
35    }
36}
37
38#[derive(Clone, Debug)]
39pub struct Block {
40    shape: Shape,
41    rotation: Rotation,
42}
43
44impl Default for Block {
45    fn default() -> Self {
46        Self {
47            shape: Shape::random(),
48            rotation: Rotation::R0,
49        }
50    }
51}
52
53impl Block {
54    pub fn new(shape: Shape) -> Self {
55        Self {
56            shape,
57            rotation: Rotation::R0,
58        }
59    }
60
61    pub fn cells(&self) -> Vec<Pos> {
62        match self.rotation {
63            Rotation::R0 => self.shape.cells(),
64            Rotation::R90 => self.shape.cells().into_iter().map(|(x,y)| (-y,x)).collect(),
65            Rotation::R180 => self.shape.cells().into_iter().map(|(x,y)| (-x,-y)).collect(),
66            Rotation::R270 => self.shape.cells().into_iter().map(|(x,y)| (y,-x)).collect(),
67        }
68    }
69
70    pub fn rotate(&self, clockwise: bool) -> Block {
71        if clockwise {
72            self.rotate_clockwise()
73        } else {
74            self.rotate_counter_clockwise()
75        }
76    }
77
78    fn rotate_clockwise(&self) -> Block {
79        match (&self.shape, &self.rotation) {
80            (Shape::O, _) => self.clone(),
81            (_,Rotation::R0) => Block { shape: self.shape.clone(), rotation: Rotation::R90 },
82            (_,Rotation::R90) => Block { shape: self.shape.clone(), rotation: Rotation::R180 },
83            (_,Rotation::R180) => Block { shape: self.shape.clone(), rotation: Rotation::R270 },
84            (_,Rotation::R270) => Block { shape: self.shape.clone(), rotation: Rotation::R0 },
85        }
86    }
87
88    fn rotate_counter_clockwise(&self) -> Block {
89        match (&self.shape, &self.rotation) {
90            (Shape::O, _) => self.clone(),
91            (_,Rotation::R0) => Block { shape: self.shape.clone(), rotation: Rotation::R270 },
92            (_,Rotation::R90) => Block { shape: self.shape.clone(), rotation: Rotation::R0 },
93            (_,Rotation::R180) => Block { shape: self.shape.clone(), rotation: Rotation::R90 },
94            (_,Rotation::R270) => Block { shape: self.shape.clone(), rotation: Rotation::R180 },
95        }
96    }
97
98    pub fn flip_turn(&self) -> Block {
99        match (&self.shape, &self.rotation) {
100            (Shape::O, _) => self.clone(),
101            (_,Rotation::R0) => Block { shape: self.shape.clone(), rotation: Rotation::R180 },
102            (_,Rotation::R90) => Block { shape: self.shape.clone(), rotation: Rotation::R270 },
103            (_,Rotation::R180) => Block { shape: self.shape.clone(), rotation: Rotation::R0 },
104            (_,Rotation::R270) => Block { shape: self.shape.clone(), rotation: Rotation::R90 },
105        }
106    }
107
108    pub fn color(&self) -> ColorStyle {
109        match self.shape {
110            Shape::I => ColorStyle::new(Color::Dark(BaseColor::Blue), Color::Dark(BaseColor::Blue)),
111            Shape::O => ColorStyle::new(Color::Dark(BaseColor::Yellow), Color::Dark(BaseColor::Yellow)),
112            Shape::T => ColorStyle::new(Color::Dark(BaseColor::Magenta), Color::Dark(BaseColor::Magenta)),
113            Shape::S => ColorStyle::new(Color::Dark(BaseColor::Green), Color::Dark(BaseColor::Green)),
114            Shape::Z => ColorStyle::new(Color::Dark(BaseColor::Red), Color::Dark(BaseColor::Red)),
115            Shape::J => ColorStyle::new(Color::Dark(BaseColor::Cyan), Color::Dark(BaseColor::Cyan)),
116            Shape::L => ColorStyle::new(Color::Dark(BaseColor::White), Color::Dark(BaseColor::White)),
117        }
118    }
119}
120
121//       I         O         T           S           Z          J        L
122//                    
123//   _ _ _ _      _ _        _          _ _       _ _        _             _  
124//  |_|_|_|_|    |_|_|     _|_|_      _|_|_|     |_|_|_     |_|_ _     _ _|_|  
125//               |_|_|    |_|_|_|    |_|_|         |_|_|    |_|_|_|   |_|_|_| 
126#[derive(Clone, Debug)]
127pub enum Shape {
128    I,
129    O,
130    T,
131    S,
132    Z,
133    J,
134    L,
135}  
136
137impl Shape {
138    fn random() -> Self {
139        Self::all().pop().unwrap()
140    }
141
142    pub fn all() -> Vec<Shape> {
143        let mut shapes = vec![Shape::I, Shape::O, Shape::T, Shape::S, Shape::Z, Shape::J, Shape::L];
144        shapes.shuffle(&mut thread_rng());
145        shapes
146    }
147
148    fn cells(&self) -> Vec<Pos> {
149        match self {
150            Shape::I => vec![(0,0),(-2,0),(-1,0),(1,0)],
151            Shape::O => vec![(0,0),(-1,-1),(0,-1),(-1,0)],
152            Shape::T => vec![(0,0),(-1,0),(0,-1),(1,0)],
153            Shape::S => vec![(0,0),(-1,0),(0,-1),(1,-1)],
154            Shape::Z => vec![(0,0),(1,0),(0,-1),(-1,-1)],
155            Shape::J => vec![(0,0),(-1,-1),(-1,0),(1,0)],
156            Shape::L => vec![(0,0),(-1,0),(1,0),(1,-1)],
157        }
158    }
159}
160
161#[derive(Clone, Debug)]
162enum Rotation {
163    R0,
164    R90,
165    R180,
166    R270,
167}