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#[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}