@@ -17,10 +17,11 @@ use thiserror::Error;
17
17
#[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
18
18
pub struct Grid < T > {
19
19
// Invariants:
20
- // - `data` is nonempty.
21
- // - Every row in `data` is nonempty.
22
- // - Every row in `data` has the same length.
23
- data : Vec < Vec < T > > ,
20
+ // - `data.len() == bounds.height * bounds.width`
21
+ // - `bounds.height` is nonzero.
22
+ // - `bounds.width` is nonzero.
23
+ data : Vec < T > ,
24
+ bounds : GridBounds ,
24
25
}
25
26
26
27
impl < T > Grid < T > {
@@ -32,12 +33,10 @@ impl<T> Grid<T> {
32
33
// TODO: Panic if `bounds` is empty
33
34
Grid {
34
35
data : ( 0 ..bounds. height )
35
- . map ( |y| {
36
- ( 0 ..bounds. width )
37
- . map ( |x| f ( C :: from ( Coords :: new ( y, x) ) ) )
38
- . collect :: < Vec < _ > > ( )
39
- } )
36
+ . flat_map ( |y| ( 0 ..bounds. width ) . map ( move |x| ( y, x) ) )
37
+ . map ( |( y, x) | f ( C :: from ( Coords :: new ( y, x) ) ) )
40
38
. collect ( ) ,
39
+ bounds,
41
40
}
42
41
}
43
42
@@ -46,25 +45,36 @@ impl<T> Grid<T> {
46
45
T : Clone ,
47
46
{
48
47
Grid {
49
- data : vec ! [ vec![ value; bounds. width] ; bounds. height] ,
48
+ data : vec ! [ value; bounds. width * bounds. height] ,
49
+ bounds,
50
50
}
51
51
}
52
52
53
53
pub fn height ( & self ) -> usize {
54
- self . data . len ( )
54
+ self . bounds . height
55
55
}
56
56
57
57
pub fn width ( & self ) -> usize {
58
- self . data [ 0 ] . len ( )
58
+ self . bounds . width
59
59
}
60
60
61
61
pub fn bounds ( & self ) -> GridBounds {
62
- GridBounds :: new ( self . height ( ) , self . width ( ) )
62
+ self . bounds
63
+ }
64
+
65
+ fn get_index ( & self , x : usize , y : usize ) -> Option < usize > {
66
+ if x < self . bounds . width && y < self . bounds . height {
67
+ y. checked_mul ( self . bounds . width )
68
+ . and_then ( |yw| yw. checked_add ( x) )
69
+ } else {
70
+ None
71
+ }
63
72
}
64
73
65
74
pub fn get < C : Into < ( usize , usize ) > > ( & self , coords : C ) -> Option < & T > {
66
75
let ( y, x) = coords. into ( ) ;
67
- self . data . get ( y) . and_then ( |row| row. get ( x) )
76
+ let i = self . get_index ( x, y) ?;
77
+ self . data . get ( i)
68
78
}
69
79
70
80
pub fn get_wrap ( & self , ( y, x) : ( isize , isize ) ) -> & T {
@@ -81,23 +91,40 @@ impl<T> Grid<T> {
81
91
82
92
pub fn get_mut < C : Into < ( usize , usize ) > > ( & mut self , coords : C ) -> Option < & mut T > {
83
93
let ( y, x) = coords. into ( ) ;
84
- self . data . get_mut ( y) . and_then ( |row| row. get_mut ( x) )
94
+ let i = self . get_index ( x, y) ?;
95
+ self . data . get_mut ( i)
85
96
}
86
97
87
- // Panics on out-of-bounds
98
+ // Does nothing on out-of-bounds
88
99
pub fn set < C : Into < ( usize , usize ) > > ( & mut self , coords : C , value : T ) {
89
100
let ( y, x) = coords. into ( ) ;
90
- self . data [ y] [ x] = value;
101
+ if let Some ( i) = self . get_index ( x, y) {
102
+ self . data [ i] = value;
103
+ }
91
104
}
92
105
93
106
// Panics on out-of-bounds
94
107
pub fn row_slice < R : RangeBounds < usize > > ( & self , range : R ) -> Grid < T >
95
108
where
96
109
T : Clone ,
97
110
{
98
- let bounds = ( range. start_bound ( ) . cloned ( ) , range. end_bound ( ) . cloned ( ) ) ;
111
+ let start_bound = match range. start_bound ( ) . cloned ( ) {
112
+ std:: ops:: Bound :: Included ( y) => y,
113
+ std:: ops:: Bound :: Excluded ( y) => y + 1 ,
114
+ std:: ops:: Bound :: Unbounded => 0 ,
115
+ } ;
116
+ let end_bound = match range. end_bound ( ) . cloned ( ) {
117
+ std:: ops:: Bound :: Included ( y) => y + 1 ,
118
+ std:: ops:: Bound :: Excluded ( y) => y,
119
+ std:: ops:: Bound :: Unbounded => self . bounds . height ,
120
+ } ;
99
121
Grid {
100
- data : self . data [ bounds] . to_vec ( ) ,
122
+ data : self . data [ ( start_bound * self . bounds . width ) ..( end_bound * self . bounds . width ) ]
123
+ . to_vec ( ) ,
124
+ bounds : GridBounds {
125
+ width : self . bounds . width ,
126
+ height : end_bound - start_bound,
127
+ } ,
101
128
}
102
129
}
103
130
@@ -106,9 +133,26 @@ impl<T> Grid<T> {
106
133
where
107
134
T : Clone ,
108
135
{
109
- let bounds = ( range. start_bound ( ) . cloned ( ) , range. end_bound ( ) . cloned ( ) ) ;
136
+ let start_bound = match range. start_bound ( ) . cloned ( ) {
137
+ std:: ops:: Bound :: Included ( x) => x,
138
+ std:: ops:: Bound :: Excluded ( x) => x + 1 ,
139
+ std:: ops:: Bound :: Unbounded => 0 ,
140
+ } ;
141
+ let end_bound = match range. end_bound ( ) . cloned ( ) {
142
+ std:: ops:: Bound :: Included ( x) => x + 1 ,
143
+ std:: ops:: Bound :: Excluded ( x) => x,
144
+ std:: ops:: Bound :: Unbounded => self . bounds . width ,
145
+ } ;
146
+
110
147
Grid {
111
- data : self . data . iter ( ) . map ( |row| row[ bounds] . to_vec ( ) ) . collect ( ) ,
148
+ data : ( 0 ..self . bounds . height )
149
+ . map ( |y| y * self . bounds . width )
150
+ . flat_map ( |yw| self . data [ ( yw + start_bound) ..( yw + end_bound) ] . to_vec ( ) )
151
+ . collect ( ) ,
152
+ bounds : GridBounds {
153
+ width : end_bound - start_bound,
154
+ height : self . bounds . height ,
155
+ } ,
112
156
}
113
157
}
114
158
@@ -117,11 +161,8 @@ impl<T> Grid<T> {
117
161
F : FnMut ( T ) -> U ,
118
162
{
119
163
Grid {
120
- data : self
121
- . data
122
- . into_iter ( )
123
- . map ( |row| row. into_iter ( ) . map ( & mut f) . collect ( ) )
124
- . collect ( ) ,
164
+ data : self . data . into_iter ( ) . map ( & mut f) . collect ( ) ,
165
+ bounds : self . bounds ,
125
166
}
126
167
}
127
168
@@ -130,30 +171,30 @@ impl<T> Grid<T> {
130
171
F : FnMut ( T ) -> Result < U , E > ,
131
172
{
132
173
let mut data = Vec :: with_capacity ( self . data . len ( ) ) ;
133
- for row in self . data {
134
- let mut new_row = Vec :: with_capacity ( row. len ( ) ) ;
135
- for value in row {
136
- new_row. push ( f ( value) ?) ;
137
- }
138
- data. push ( new_row) ;
174
+ for value in self . data {
175
+ data. push ( f ( value) ?) ;
139
176
}
140
- Ok ( Grid { data } )
177
+ Ok ( Grid {
178
+ data,
179
+ bounds : self . bounds ,
180
+ } )
141
181
}
142
182
143
183
pub fn map_cells < U , F > ( & self , mut f : F ) -> Grid < U >
144
184
where
145
185
F : FnMut ( Cell < ' _ , T > ) -> U ,
146
186
{
147
- let mut data = Vec :: with_capacity ( self . height ( ) ) ;
187
+ let mut data = Vec :: with_capacity ( self . data . len ( ) ) ;
148
188
for y in 0 ..self . height ( ) {
149
- let mut new_row = Vec :: with_capacity ( self . width ( ) ) ;
150
189
for x in 0 ..self . width ( ) {
151
190
let cell = Cell :: new ( self , y, x) ;
152
- new_row . push ( f ( cell) ) ;
191
+ data . push ( f ( cell) ) ;
153
192
}
154
- data. push ( new_row) ;
155
193
}
156
- Grid { data }
194
+ Grid {
195
+ data,
196
+ bounds : self . bounds ,
197
+ }
157
198
}
158
199
159
200
pub fn enumerate ( & self ) -> Enumerate < ' _ , T > {
@@ -176,15 +217,16 @@ impl<T> Grid<T> {
176
217
where
177
218
P : FnMut ( & Vec < T > ) -> bool ,
178
219
{
179
- Grid :: try_from ( self . data . into_iter ( ) . filter ( predicate) . collect :: < Vec < _ > > ( ) ) . ok ( )
220
+ Grid :: try_from ( self . into_rows ( ) . filter ( predicate) . collect :: < Vec < _ > > ( ) ) . ok ( )
180
221
}
181
222
182
- pub fn into_rows ( self ) -> impl Iterator < Item = Vec < T > > {
183
- self . data . into_iter ( )
223
+ pub fn into_rows ( mut self ) -> impl Iterator < Item = Vec < T > > {
224
+ std:: iter:: repeat_n ( self . bounds . width , self . bounds . height )
225
+ . map ( move |w| self . data . drain ( ..w) . collect ( ) )
184
226
}
185
227
186
228
pub fn into_values ( self ) -> impl Iterator < Item = T > {
187
- self . data . into_iter ( ) . flatten ( )
229
+ self . data . into_iter ( )
188
230
}
189
231
190
232
pub fn iter_coords ( & self ) -> IterCoords {
@@ -308,14 +350,14 @@ impl<T: FromStr> Grid<T> {
308
350
309
351
impl < T : fmt:: Display > fmt:: Display for Grid < T > {
310
352
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
311
- let mut first = true ;
312
- for row in & self . data {
313
- if !std:: mem:: replace ( & mut first, false ) {
353
+ let mut col = 0 ;
354
+ for value in & self . data {
355
+ if col >= self . bounds . width {
356
+ col = 0 ;
314
357
writeln ! ( f) ?;
315
358
}
316
- for cell in row {
317
- write ! ( f, "{cell}" ) ?;
318
- }
359
+ write ! ( f, "{value}" ) ?;
360
+ col += 1 ;
319
361
}
320
362
Ok ( ( ) )
321
363
}
@@ -325,6 +367,7 @@ impl<T> TryFrom<Vec<Vec<T>>> for Grid<T> {
325
367
type Error = GridFromError ;
326
368
327
369
fn try_from ( data : Vec < Vec < T > > ) -> Result < Grid < T > , GridFromError > {
370
+ let height = data. len ( ) ;
328
371
let width = match data. first ( ) {
329
372
Some ( row) => row. len ( ) ,
330
373
None => return Err ( GridFromError :: Empty ) ,
@@ -337,7 +380,10 @@ impl<T> TryFrom<Vec<Vec<T>>> for Grid<T> {
337
380
if width == 0 {
338
381
return Err ( GridFromError :: Empty ) ;
339
382
}
340
- Ok ( Grid { data } )
383
+ Ok ( Grid {
384
+ data : data. into_iter ( ) . flatten ( ) . collect ( ) ,
385
+ bounds : GridBounds { width, height } ,
386
+ } )
341
387
}
342
388
}
343
389
@@ -376,14 +422,14 @@ pub struct Draw<'a>(&'a Grid<bool>);
376
422
377
423
impl fmt:: Display for Draw < ' _ > {
378
424
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
379
- let mut first = true ;
380
- for row in & self . 0 . data {
381
- if !std:: mem:: replace ( & mut first, false ) {
425
+ let mut col = 0 ;
426
+ for & cell in & self . 0 . data {
427
+ if col >= self . 0 . bounds . width {
428
+ col = 0 ;
382
429
writeln ! ( f) ?;
383
430
}
384
- for & cell in row {
385
- write ! ( f, "{}" , if cell { '#' } else { '.' } ) ?;
386
- }
431
+ write ! ( f, "{}" , if cell { '#' } else { '.' } ) ?;
432
+ col += 1 ;
387
433
}
388
434
Ok ( ( ) )
389
435
}
@@ -565,11 +611,11 @@ mod tests {
565
611
assert_eq ! (
566
612
gr,
567
613
Grid {
568
- data: vec![
569
- vec! [ 'a' , 'b' , 'c' ] ,
570
- vec! [ 'd' , 'e' , 'f' ] ,
571
- vec! [ 'g' , 'h' , 'i' ]
572
- ]
614
+ data: vec![ 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' ] ,
615
+ bounds : GridBounds {
616
+ width : 3 ,
617
+ height : 3
618
+ } ,
573
619
}
574
620
) ;
575
621
}
@@ -580,7 +626,11 @@ mod tests {
580
626
assert_eq ! (
581
627
gr,
582
628
Grid {
583
- data: vec![ vec![ 1 , 2 , 3 ] , vec![ 4 , 5 , 6 ] , vec![ 7 , 8 , 9 ] ]
629
+ data: vec![ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] ,
630
+ bounds: GridBounds {
631
+ width: 3 ,
632
+ height: 3
633
+ } ,
584
634
}
585
635
) ;
586
636
}
@@ -599,12 +649,13 @@ mod tests {
599
649
gr,
600
650
Grid {
601
651
data: vec![
602
- vec![ 22 , 13 , 17 , 11 , 0 ] ,
603
- vec![ 8 , 2 , 23 , 4 , 24 ] ,
604
- vec![ 21 , 9 , 14 , 16 , 7 ] ,
605
- vec![ 6 , 10 , 3 , 18 , 5 ] ,
606
- vec![ 1 , 12 , 20 , 15 , 19 ] ,
607
- ]
652
+ 22 , 13 , 17 , 11 , 0 , 8 , 2 , 23 , 4 , 24 , 21 , 9 , 14 , 16 , 7 , 6 , 10 , 3 , 18 , 5 , 1 , 12 ,
653
+ 20 , 15 , 19 ,
654
+ ] ,
655
+ bounds: GridBounds {
656
+ width: 5 ,
657
+ height: 5
658
+ } ,
608
659
}
609
660
) ;
610
661
}
@@ -622,11 +673,11 @@ mod tests {
622
673
assert_eq ! (
623
674
gr. row_slice( 2 ..) ,
624
675
Grid {
625
- data: vec![
626
- vec! [ 21 , 9 , 14 , 16 , 7 ] ,
627
- vec! [ 6 , 10 , 3 , 18 , 5 ] ,
628
- vec! [ 1 , 12 , 20 , 15 , 19 ] ,
629
- ]
676
+ data: vec![ 21 , 9 , 14 , 16 , 7 , 6 , 10 , 3 , 18 , 5 , 1 , 12 , 20 , 15 , 19 ] ,
677
+ bounds : GridBounds {
678
+ width : 5 ,
679
+ height : 3
680
+ } ,
630
681
}
631
682
) ;
632
683
}
@@ -644,13 +695,11 @@ mod tests {
644
695
assert_eq ! (
645
696
gr. column_slice( ..3 ) ,
646
697
Grid {
647
- data: vec![
648
- vec![ 22 , 13 , 17 ] ,
649
- vec![ 8 , 2 , 23 ] ,
650
- vec![ 21 , 9 , 14 ] ,
651
- vec![ 6 , 10 , 3 ] ,
652
- vec![ 1 , 12 , 20 ] ,
653
- ]
698
+ data: vec![ 22 , 13 , 17 , 8 , 2 , 23 , 21 , 9 , 14 , 6 , 10 , 3 , 1 , 12 , 20 , ] ,
699
+ bounds: GridBounds {
700
+ width: 3 ,
701
+ height: 5
702
+ } ,
654
703
}
655
704
) ;
656
705
}
0 commit comments