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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::hexagon::{DoubledCoord, Hex, OffsetCoord, HexMath, HEX_DIRECTIONS, HEX_DIAGONALS};

pub const HEX_EVEN: i32 = 1;
pub const HEX_ODD: i32 = -1;

pub struct HexDirection;

impl HexDirection {
    pub fn direction(direction: i32) -> Hex {
        HEX_DIRECTIONS[direction as usize]
    }

    pub fn neighbor(hex: Hex, direction: i32) -> Hex {
        hex.add(Self::direction(direction))
    }

    pub fn diagonal_neighbor(hex: Hex, direction: i32) -> Hex {
        hex.add(HEX_DIAGONALS[direction as usize])
    }
}

pub struct HexOffset;

impl HexOffset {
    pub fn q_from_cube(offset: i32, hex: Hex) -> OffsetCoord {
        let col: i32 = hex.q();
        let row: i32 = hex.r() + (hex.q() + offset * (hex.q() & 1)) / 2 as i32;
        if offset != HEX_EVEN && offset != HEX_ODD {
            panic!("offset must be EVEN (+1) or ODD (-1)");
        }
        return OffsetCoord { col, row };
    }

    pub fn q_to_cube(offset: i32, coord: OffsetCoord) -> Hex {
        let q: i32 = coord.col;
        let r: i32 = coord.row - (coord.col + offset * (coord.col & 1)) / 2 as i32;

        if offset != HEX_EVEN && offset != HEX_ODD {
            panic!("offset must be EVEN (+1) or ODD (-1)");
        }

        return Hex::new(q, r);
    }

    pub fn r_from_cube(offset: i32, hex: Hex) -> OffsetCoord {
        let col: i32 = hex.q() + (hex.r() + offset * (hex.r() & 1)) / 2 as i32;
        let row: i32 = hex.r();

        if offset != HEX_EVEN && offset != HEX_ODD {
            panic!("offset must be EVEN (+1) or ODD (-1)");
        }

        return OffsetCoord { col, row };
    }

    pub fn r_to_cube(offset: i32, coord: OffsetCoord) -> Hex {
        let q: i32 = coord.col - (coord.row + offset * (coord.row & 1)) / 2 as i32;
        let r: i32 = coord.row;

        if offset != HEX_EVEN && offset != HEX_ODD {
            panic!("offset must be EVEN (+1) or ODD (-1)");
        }

        return Hex::new(q, r);
    }
}

pub struct HexDoubled;

impl HexDoubled {
    pub fn q_from_cube(h: Hex) -> DoubledCoord {
        let col: i32 = h.q();
        let row: i32 = 2 * h.r() + h.q();
        return DoubledCoord { col, row };
    }

    pub fn q_to_cube(h: DoubledCoord) -> Hex {
        let q: i32 = h.col;
        let r: i32 = (h.row - h.col) / 2 as i32;
        return Hex::new(q, r);
    }

    pub fn r_from_cube(h: Hex) -> DoubledCoord {
        let col: i32 = 2 * h.q() + h.r();
        let row: i32 = h.r();
        return DoubledCoord { col, row };
    }

    pub fn r_to_cube(h: DoubledCoord) -> Hex {
        let q: i32 = (h.col - h.row) / 2 as i32;
        let r: i32 = h.row;
        return Hex::new(q, r);
    }
}