1use rand::seq::SliceRandom;
7
8use crate::pieces::{xy, Piece, PieceColor, PIECES};
9
10#[derive(Clone)]
14pub struct Board {
15 pub width: u16,
16 pub height: u16,
17 pub cells: Vec<Vec<PieceColor>>,
18}
19
20#[derive(Clone)]
25pub struct Bag {
26 pieces: Vec<Piece>,
27}
28
29impl Bag {
30 pub fn new() -> Bag {
31 let mut pieces = PIECES.to_vec();
32 let mut rng = rand::thread_rng();
33 pieces.shuffle(&mut rng);
34 Bag { pieces }
35 }
36
37 pub fn next(&mut self) -> Piece {
38 if self.pieces.len() == 0 {
39 self.pieces = PIECES.to_vec();
40 let mut rng = rand::thread_rng();
41 self.pieces.shuffle(&mut rng);
42 }
43 self.pieces.pop().unwrap()
45 }
46}
47
48#[derive(Clone, Debug)]
53pub struct CurrentPiece {
54 pub piece: Piece,
55 pub x: i32,
56 pub y: i32,
57}
58
59pub fn clear_lines(board: &mut Board) -> i32 {
63 let mut y = board.height as usize - 2;
64 let mut lines = 0;
65 while y > 0 {
66 if (0..board.width).all(|x| board.cells[x as usize][y] != PieceColor::Empty) {
67 lines += 1;
68 for y2 in (1..=y).rev() {
69 for x in 0..board.width {
70 board.cells[x as usize][y2] = board.cells[x as usize][y2 - 1];
71 }
72 }
73 } else {
74 y -= 1;
75 }
76 }
77 lines
78}
79
80pub fn draw_piece(piece: &Piece, board: &mut Board, x: i32, y: i32, color: PieceColor) {
84 for square in piece.view() {
85 let x = xy(&square).0 as i32 + x as i32;
86 let y = xy(&square).1 as i32 + y as i32;
87 board.cells[x as usize][y as usize] = color;
88 }
89}
90
91pub fn remove_piece(piece: &Piece, board: &mut Board, x: i32, y: i32) {
95 for square in piece.view() {
96 let x = xy(&square).0 as i32 + x as i32;
97 let y = xy(&square).1 as i32 + y as i32;
98 board.cells[x as usize][y as usize] = PieceColor::Empty;
99 }
100}
101
102pub fn remove_tracer(board: &mut Board) {
106 for y in 0..board.height {
108 for x in 0..board.width {
109 if board.cells[x as usize][y as usize] == PieceColor::Tracer {
110 board.cells[x as usize][y as usize] = PieceColor::Empty;
111 }
112 }
113 }
114}
115
116pub fn draw_tracer(piece: &Piece, board: &mut Board, x: i32, y: i32) {
120 remove_tracer(board);
122 for square in piece.view() {
123 let x = xy(&square).0 as i32 + x as i32;
124 let y = xy(&square).1 as i32 + y as i32;
125 board.cells[x as usize][y as usize] = PieceColor::Tracer;
126 }
127}
128
129impl CurrentPiece {
130 pub fn collides(&self, board: &Board, x: i32, y: i32) -> bool {
137 for square in self.piece.view() {
138 let dx = xy(&square).0 as i32;
139 let dy = xy(&square).1 as i32;
140 let x = dx as i32 + x as i32;
141 let y = dy as i32 + y as i32;
142
143 if x < 0 || x >= board.width as i32 || y >= board.height as i32 {
144 return true;
145 }
146 if y >= 0
147 && board.cells[x as usize][y as usize] != PieceColor::Empty
148 && board.cells[x as usize][y as usize] != PieceColor::Tracer
149 {
150 return true;
151 }
152 }
153 false
154 }
155
156 pub fn rotate_right(&mut self, board: &Board) -> bool {
161 self.piece.rotate_right();
162 if self.collides(board, self.x, self.y) {
163 self.piece.rotate_left();
164 return false;
165 }
166 true
167 }
168
169 pub fn move_left(&mut self, board: &Board) -> bool {
174 let x = self.x - 1;
175 if !self.collides(board, x, self.y) {
176 self.x = x;
177 return true;
178 }
179 false
180 }
181
182 pub fn move_right(&mut self, board: &Board) -> bool {
187 let x = self.x + 1;
188 if !self.collides(board, x, self.y) {
189 self.x = x;
190 return true;
191 }
192 false
193 }
194
195 pub fn move_down(&mut self, board: &Board) -> bool {
200 let y = self.y + 1;
201 if !self.collides(board, self.x, y) {
202 self.y = y;
203 return true;
204 }
205 false
206 }
207}