2
\$\begingroup\$

In a grid of hexagons, we often want to find the neighbors of a cell with distance n. In the image below we have a rhombus-shaped grid of hexagons with an axial coordinate system showing the cell (row, col) = (3,3) (dark gray), its 1-distance neighbors (medium gray) and its 2-distance neighbors (light gray).

In the code below (which has the correct output), we create 5 arrays. Array #1 contains, for each row and column, indecies of neighbors with a distance of 1 or less. Array #2, #3, and #4 contain indecies of neighbors with distance 2, 3, 4 or less respectively. The last array contains, for each distance 1,2,3, and 4, for each cell, the number of neighbors of the cell with the given distance or less. This is necessary as cells close to the grid boundary have fewer neighbors than cells close to the center.

#[macro_use]
extern crate ndarray;

use ndarray::prelude::*;
use std::ops::AddAssign;


fn hex_distance(r1: i8, c1: i8, r2: i8, c2: i8) -> i8 {
    // Distance from cell (r1, c1) to cell (r2, c2) in a hexagonal grid
    ((r1 - r2).abs() + (r1 + c1 - r2 - c2).abs() + (c1 - c2).abs()) / 2
}

fn generate_neighs() -> (Array<usize, Ix4>, Array<usize, Ix4>,Array<usize, Ix4>,
                        Array<usize, Ix4>, Array<usize, Ix3>) {
    // Return 4 arrays with indecies of neighbors (including self) with distance of (1..5) or less;
    // and a (4 X rows x cols) array with the number of neighbors for each row and column since
    // the number of n-distance neighbors can vary for each cell.
    let rows = 7;
    let cols = 7;
    // Indecies of neighbors with distance of 1 or less
    let mut neighs1 = Array::zeros((rows, cols, 7, 2));
    let mut neighs2 = Array::zeros((rows, cols, 19, 2));
    let mut neighs3 = Array::zeros((rows, cols, 37, 2));
    let mut neighs4 = Array::zeros((rows, cols, 43, 2));
    // For distance 1..5 or less, for each row and col: the number of neighbors.
    let mut n_neighs = Array::zeros((4, rows, cols));
    neighs1.slice_mut(s![0, 0, 0, ..]).assign(&Array::ones(2));
    for r1 in 0..rows {
        for c1 in 0..cols {
            // Want to store index of self first, so that it can be easily excluded
            neighs1.slice_mut(s![r1, c1, 0, ..]).assign(&array![r1, c1]);
            n_neighs.slice_mut(s![.., r1, c1]).add_assign(1);
            for r2 in 0..rows {
                for c2 in 0..cols {
                    let dist = hex_distance(r1 as i8, c1 as i8, r2 as i8, c2 as i8);
                    if (r1, c1) != (r2, c2) && dist <= 4 {
                        let n = n_neighs[[3, r1, c1]];
                        neighs4 .slice_mut(s![r1, c1, n, ..])
                                .assign(&array![r2, c2]);
                        n_neighs[[3, r1, c1]] += 1;
                        if dist <= 3 {
                            let n = n_neighs[[2, r1, c1]];
                            neighs3 .slice_mut(s![r1, c1, n, ..])
                                    .assign(&array![r2, c2]);
                            n_neighs[[2, r1, c1]] += 1;
                            if dist <= 2 {
                                let n = n_neighs[[1, r1, c1]];
                                neighs2 .slice_mut(s![r1, c1, n, ..])
                                        .assign(&array![r2, c2]);
                                n_neighs[[1, r1, c1]] += 1;
                                if dist == 1 {
                                    let n = n_neighs[[0, r1, c1]];
                                    neighs1 .slice_mut(s![r1, c1, n, ..])
                                            .assign(&array![r2, c2]);
                                    n_neighs[[0, r1, c1]] += 1;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return (neighs1, neighs2, neighs3, neighs4, n_neighs)
}

fn main() {
    let neighs = generate_neighs();
    println!("{}", neighs.4);
}

Besides the code review I have a question, namely, how can I make these 5 arrays easily available throughout my program (without ever calling the function twice)? Is there any way of making them immutable (they won't change), making them global (for use in same file), and exporting them (for use in other files)?

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.