1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#![feature(test)]
extern  crate test;

#[cfg(test)]
mod tests {
    use super::snail_rect;
    use test::Bencher;
    
    #[bench]
    fn bench_7kx7k(b: &mut Bencher) {
        b.iter( || snail_rect(7000, 7000) );
    }

    #[bench]
    fn bench_20kx20k(b: &mut Bencher) {
        b.iter( || snail_rect(20000, 20000) );
    }

    #[test]
    fn width_0_with_height_0() {
        let actual = snail_rect(0, 0);
        let excepted = vec![];

        assert_eq!(actual, excepted);
    }

    #[test]
    fn width_3_with_height_4() {
        let actual = snail_rect(3, 4);
        let excepted = vec![(0,0), (0,1), (0,2), (1,2), (2,2), (3,2), (3,1), (3,0), (2,0), (1,0), (1,1), (2,1)];

        assert_eq!(actual, excepted);
    }
}

pub fn snail_rect(width: usize, height: usize) -> Vec<(u32, u32)> {
    fn is_odd(num: usize) -> usize {
        2 - (num & 1)
    }

    let mut re = Vec::with_capacity(width * height);

    for ((width, height), off) in
    (is_odd(width)..=width).rev().step_by(2)
        .zip((is_odd(height)..=height).rev().step_by(2))
        .zip(0u32..)
    {
        if width == 1 {
            re.extend((0..height).map(|i| (off + i as u32  , off) ) );
            break;
        }

        if height == 1 {
            re.extend((0..width).map(|i| (off, off + i as u32) ));
            break;
        }

        re.extend((0..width - 1).map(|i| (off, i as u32 + off) ));
        re.extend((0..height - 1).map(|i| (off + i as u32, off + width as u32 - 1) ));
        re.extend((1..width).rev().map(|i| (off + height as u32 - 1, off + i as u32) ));
        re.extend((1..height).rev().map(|i| (i as u32 + off, off ) ));
    }

    re
}