Skip to content

Commit 5bbbc0c

Browse files
committed
Giving tiles its own two-axis iterator implementation based on the Grid struct in the maze example
1 parent 99c03a9 commit 5bbbc0c

File tree

3 files changed

+239
-12
lines changed

3 files changed

+239
-12
lines changed

examples/reversi/board.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ use std::ops::Deref;
22

33
use turtle::Color;
44

5-
/// (Row, Column)
6-
pub type Position = (usize, usize);
7-
8-
type Tiles = [[Option<Piece>; 8]; 8];
5+
use tiles::{Tiles, Position};
96

107
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118
pub enum Piece {
@@ -36,11 +33,11 @@ impl Piece {
3633
}
3734
}
3835

39-
fn valid_moves_for(tiles: Tiles, piece: Piece) -> Vec<Position> {
36+
fn valid_moves_for(tiles: &Tiles, piece: Piece) -> Vec<Position> {
4037
Default::default() //TODO
4138
}
4239

43-
#[derive(Debug, Clone, PartialEq, Eq)]
40+
#[derive(Debug)]
4441
pub struct Board {
4542
current: Piece,
4643
/// None - empty tile
@@ -68,7 +65,7 @@ impl Board {
6865
tiles[4][3] = Some(Piece::B);
6966
tiles[4][4] = Some(Piece::A);
7067
let current = Piece::A;
71-
let valid_moves = valid_moves_for(tiles, current);
68+
let valid_moves = valid_moves_for(&tiles, current);
7269

7370
Self {
7471
current,

examples/reversi/main.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
extern crate turtle;
66

77
mod board;
8+
mod tiles;
89

910
use std::f64::consts::PI;
1011

@@ -33,8 +34,8 @@ fn main() {
3334
let width = 580.0;
3435
let height = 580.0;
3536
let board = Board::new();
36-
let rows = board.len();
37-
let cols = board[0].len();
37+
let rows = board.col_size();
38+
let cols = board.row_size();
3839

3940
// These values are used quite often, so it makes sense to compute them in advance so that
4041
// we don't need to keep repeating ourselves
@@ -47,6 +48,7 @@ fn main() {
4748
tile_height: height / rows as f64,
4849
};
4950

51+
turtle.set_speed("instant"); //TODO: Remove this line
5052
turtle.pen_up();
5153
turtle.forward(height / 2.0);
5254
turtle.right(90.0);
@@ -87,8 +89,8 @@ fn draw_board(turtle: &mut Turtle, dim: &Dimensions) {
8789

8890
fn draw_board_pieces(turtle: &mut Turtle, board: &Board, dim: &Dimensions) {
8991
// Draw starting pieces
90-
for (row, row_pieces) in board.iter().enumerate() {
91-
for (col, piece) in row_pieces.iter().enumerate() {
92+
for (row, row_pieces) in board.rows().enumerate() {
93+
for (col, piece) in row_pieces.enumerate() {
9294
if let &Some(piece) = piece {
9395
move_to_tile(turtle, (row, col), &dim);
9496
draw_piece(turtle, piece, &dim);
@@ -117,7 +119,6 @@ fn play_game(turtle: &mut Turtle, mut board: Board, dim: &Dimensions) {
117119
let row = ((1.0 - (mouse[1] + dim.height/2.0) / dim.height) * dim.rows as f64).floor() as isize;
118120
let col = ((mouse[0] + dim.width/2.0) / dim.width * dim.cols as f64).floor() as isize;
119121

120-
println!("Play {:?}", (row, col));
121122
if row >= 0 && row < dim.rows as isize
122123
&& col >= 0 && col < dim.cols as isize
123124
&& board.is_valid_move(&(row as usize, col as usize)) {

examples/reversi/tiles.rs

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
use std::ops::{Index, IndexMut};
2+
3+
use board::Piece;
4+
5+
const SIZE: usize = 8;
6+
7+
/// (Row, Column)
8+
pub type Position = (usize, usize);
9+
10+
/// A row or column of pieces
11+
pub type Pieces = [Option<Piece>; SIZE];
12+
13+
/// Used to determine whether to iterate over rows or columns
14+
#[derive(Clone, Copy)]
15+
enum TilesIterTarget {
16+
Rows,
17+
Columns,
18+
DiagonalsTLBR,
19+
DiagonalsTRBL,
20+
}
21+
22+
pub struct TilesIter<'a> {
23+
grid: &'a [Pieces; SIZE],
24+
target: TilesIterTarget,
25+
current: usize,
26+
end: usize,
27+
}
28+
29+
impl<'a> TilesIter<'a> {
30+
fn new(grid: &'a [Pieces; SIZE], target: TilesIterTarget) -> Self {
31+
Self {
32+
grid,
33+
target,
34+
current: 0,
35+
end: match target {
36+
TilesIterTarget::Rows => grid.len(),
37+
TilesIterTarget::Columns => grid[0].len(),
38+
TilesIterTarget::DiagonalsTLBR => unimplemented!(),
39+
TilesIterTarget::DiagonalsTRBL => unimplemented!(),
40+
},
41+
}
42+
}
43+
}
44+
45+
impl<'a> Iterator for TilesIter<'a> {
46+
type Item = TilesPieceIter<'a>;
47+
48+
fn next(&mut self) -> Option<Self::Item> {
49+
if self.current >= self.end {
50+
return None;
51+
}
52+
53+
let iter = TilesPieceIter::new(
54+
self.grid,
55+
self.target,
56+
self.current
57+
);
58+
59+
self.current += 1;
60+
Some(iter)
61+
}
62+
}
63+
64+
impl<'a> DoubleEndedIterator for TilesIter<'a> {
65+
fn next_back(&mut self) -> Option<Self::Item> {
66+
if self.current >= self.end {
67+
return None;
68+
}
69+
70+
let iter = TilesPieceIter::new(
71+
self.grid,
72+
self.target,
73+
self.end - 1
74+
);
75+
76+
self.end -= 1;
77+
Some(iter)
78+
}
79+
}
80+
81+
pub struct TilesPieceIter<'a> {
82+
grid: &'a [Pieces; SIZE],
83+
target: TilesIterTarget,
84+
/// The row or column being iterated over
85+
index: usize,
86+
/// The current position in the row or column being iterated over
87+
current: usize,
88+
// Index of the item just after the last item in the row or column being iterated over
89+
end: usize,
90+
}
91+
92+
impl<'a> TilesPieceIter<'a> {
93+
fn new(grid: &'a [Pieces; SIZE], target: TilesIterTarget, index: usize) -> Self {
94+
Self {
95+
grid,
96+
target,
97+
index,
98+
current: 0,
99+
end: match target {
100+
TilesIterTarget::Rows => grid[0].len(),
101+
TilesIterTarget::Columns => grid.len(),
102+
TilesIterTarget::DiagonalsTLBR => unimplemented!(),
103+
TilesIterTarget::DiagonalsTRBL => unimplemented!(),
104+
},
105+
}
106+
}
107+
108+
fn get(&self, current: usize) -> &'a Option<Piece> {
109+
match self.target {
110+
TilesIterTarget::Rows => {
111+
&self.grid[self.index][current]
112+
},
113+
TilesIterTarget::Columns => {
114+
&self.grid[current][self.index]
115+
},
116+
TilesIterTarget::DiagonalsTLBR => unimplemented!(),
117+
TilesIterTarget::DiagonalsTRBL => unimplemented!(),
118+
}
119+
}
120+
}
121+
122+
impl<'a> Iterator for TilesPieceIter<'a> {
123+
type Item = &'a Option<Piece>;
124+
125+
fn next(&mut self) -> Option<Self::Item> {
126+
if self.current >= self.end {
127+
return None;
128+
}
129+
130+
let cell = self.get(self.current);
131+
132+
self.current += 1;
133+
Some(cell)
134+
}
135+
}
136+
137+
impl<'a> DoubleEndedIterator for TilesPieceIter<'a> {
138+
fn next_back(&mut self) -> Option<Self::Item> {
139+
if self.current >= self.end {
140+
return None;
141+
}
142+
143+
let cell = self.get(self.end - 1);
144+
145+
self.end -= 1;
146+
Some(cell)
147+
}
148+
}
149+
150+
#[derive(Debug, Default)]
151+
pub struct Tiles([Pieces; SIZE]);
152+
153+
impl Index<usize> for Tiles {
154+
type Output = Pieces;
155+
156+
fn index(&self, index: usize) -> &Self::Output {
157+
self.0.index(index)
158+
}
159+
}
160+
161+
impl IndexMut<usize> for Tiles {
162+
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
163+
self.0.index_mut(index)
164+
}
165+
}
166+
167+
impl Tiles {
168+
/// Returns the positions of adjacent pieces
169+
pub fn adjacent_pieces(&self, (row, col): Position) -> Vec<Position> {
170+
let row = row as isize;
171+
let col = col as isize;
172+
let test: [(isize, isize); 8] = [
173+
(row-1, col-1),
174+
(row-1, col),
175+
(row-1, col+1),
176+
(row, col-1),
177+
(row, col+1),
178+
(row+1, col-1),
179+
(row+1, col),
180+
(row+1, col+1),
181+
];
182+
183+
test.into_iter().filter_map(|&pos| {
184+
self.get(pos).map(|_| (pos.0 as usize, pos.1 as usize))
185+
}).collect()
186+
}
187+
188+
/// Gets the piece at the given position, if there is any
189+
pub fn get(&self, (row, col): (isize, isize)) -> Option<Piece> {
190+
if row > 0 && col > 0 {
191+
*self.0.get(row as usize)
192+
.map(|r| r.get(col as usize).unwrap_or(&None))
193+
.unwrap_or(&None)
194+
}
195+
else {
196+
None
197+
}
198+
}
199+
200+
/// Returns the size of each row
201+
pub fn row_size(&self) -> usize {
202+
self.0[0].len()
203+
}
204+
205+
/// Returns the size of each column
206+
pub fn col_size(&self) -> usize {
207+
self.0.len()
208+
}
209+
210+
/// Returns an iterator over each row
211+
pub fn rows(&self) -> TilesIter {
212+
TilesIter::new(&self.0, TilesIterTarget::Rows)
213+
}
214+
215+
/// Returns an iterator over each row
216+
pub fn cols(&self) -> TilesIter {
217+
TilesIter::new(&self.0, TilesIterTarget::Columns)
218+
}
219+
220+
/// Returns an iterator over each top-left to bottom-right diagonal
221+
pub fn diagonals_tlbr(&self) -> TilesIter {
222+
TilesIter::new(&self.0, TilesIterTarget::DiagonalsTLBR)
223+
}
224+
225+
/// Returns an iterator over each top-right to bottom-left diagonal
226+
pub fn diagonals_trbl(&self) -> TilesIter {
227+
TilesIter::new(&self.0, TilesIterTarget::DiagonalsTRBL)
228+
}
229+
}

0 commit comments

Comments
 (0)