get_node() now returns Result<Option<&T>> to indicate tiles that are out of bounds. Fixed inconsistent spelling of neighbor -> neighbour
parent
45bab170b5
commit
28f5d3ea1f
68
src/lib.rs
68
src/lib.rs
|
|
@ -1,4 +1,5 @@
|
||||||
/// A trait for graph-like structures, where you can get a node by a unique value and find its neighbors.
|
/// A trait for graph-like structures, where you can get a node by a unique value and find its
|
||||||
|
/// neighbours.
|
||||||
///
|
///
|
||||||
/// **Node** represents some settled data type. The graph should likely contain `Option<Node>`
|
/// **Node** represents some settled data type. The graph should likely contain `Option<Node>`
|
||||||
/// elements prepopulated with `None` values. For example `[[None; WIDTH]; HEIGHT]` for a 2D grid.
|
/// elements prepopulated with `None` values. For example `[[None; WIDTH]; HEIGHT]` for a 2D grid.
|
||||||
|
|
@ -15,23 +16,33 @@ pub trait GraphLike<Node, NodeId> {
|
||||||
/// Used in the default implementation of `full_generation`
|
/// Used in the default implementation of `full_generation`
|
||||||
const MAX_RETRIES: usize = 5;
|
const MAX_RETRIES: usize = 5;
|
||||||
|
|
||||||
fn get_node(&self, id: NodeId) -> Option<&Node>;
|
fn get_node(&self, id: NodeId) -> Result<Option<&Node>, ()>;
|
||||||
fn set_node(&mut self, id: NodeId, node: Option<Node>);
|
fn set_node(&mut self, id: NodeId, node: Option<Node>);
|
||||||
fn iter_ids(&self) -> impl Iterator<Item = NodeId>;
|
fn iter_ids(&self) -> impl Iterator<Item = NodeId>;
|
||||||
fn iter_neighbor_ids(&self, id: NodeId) -> impl Iterator<Item = NodeId>;
|
fn iter_neighbour_ids(&self, id: NodeId) -> impl Iterator<Item = NodeId>;
|
||||||
|
|
||||||
fn iter_nodes<'a>(&'a self) -> impl Iterator<Item = (NodeId, Option<&'a Node>)>
|
fn iter_nodes<'a>(&'a self) -> impl Iterator<Item = (NodeId, Option<&'a Node>)>
|
||||||
where
|
where
|
||||||
Node: 'a,
|
Node: 'a,
|
||||||
NodeId: Copy,
|
NodeId: Copy,
|
||||||
{
|
{
|
||||||
self.iter_ids().map(|id| (id, self.get_node(id)))
|
self.iter_ids().map(|id| {
|
||||||
|
(
|
||||||
|
id,
|
||||||
|
self.get_node(id)
|
||||||
|
.expect("GraphLike::iter_ids() should only return valid ids"),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn iter_empty(&self) -> impl Iterator<Item = NodeId>
|
fn iter_empty(&self) -> impl Iterator<Item = NodeId>
|
||||||
where
|
where
|
||||||
NodeId: Copy,
|
NodeId: Copy,
|
||||||
{
|
{
|
||||||
self.iter_ids().filter(|id| self.get_node(*id).is_none())
|
self.iter_ids().filter(|id| {
|
||||||
|
self.get_node(*id)
|
||||||
|
.expect("GraphLike::iter_ids() should only return valid ids")
|
||||||
|
.is_none()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn iter_neighbour_nodes<'a>(
|
fn iter_neighbour_nodes<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
|
|
@ -41,7 +52,13 @@ pub trait GraphLike<Node, NodeId> {
|
||||||
NodeId: Copy,
|
NodeId: Copy,
|
||||||
Node: 'a,
|
Node: 'a,
|
||||||
{
|
{
|
||||||
self.iter_neighbor_ids(id).map(|id| (id, self.get_node(id)))
|
self.iter_neighbour_ids(id).map(|id| {
|
||||||
|
(
|
||||||
|
id,
|
||||||
|
self.get_node(id)
|
||||||
|
.expect("GraphLike::iter_neighbour_ids() should only return valid ids"),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn single_step(
|
fn single_step(
|
||||||
|
|
@ -144,8 +161,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphLike<u8, (usize, usize)> for TestGraph {
|
impl GraphLike<u8, (usize, usize)> for TestGraph {
|
||||||
fn get_node(&self, id: (usize, usize)) -> Option<&u8> {
|
fn get_node(&self, id: (usize, usize)) -> Result<Option<&u8>, ()> {
|
||||||
self.tiles[id.0][id.1].as_ref()
|
if id.0 >= 3 || id.1 >= 3 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
Ok(self.tiles[id.0][id.1].as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_node(&mut self, id: (usize, usize), node: Option<u8>) {
|
fn set_node(&mut self, id: (usize, usize), node: Option<u8>) {
|
||||||
|
|
@ -156,25 +176,25 @@ mod tests {
|
||||||
(0..3).flat_map(|i| (0..3).map(move |j| (i, j)))
|
(0..3).flat_map(|i| (0..3).map(move |j| (i, j)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_neighbor_ids(&self, id: (usize, usize)) -> impl Iterator<Item = (usize, usize)> {
|
fn iter_neighbour_ids(&self, id: (usize, usize)) -> impl Iterator<Item = (usize, usize)> {
|
||||||
let mut neighbors = vec![];
|
let mut neighbours = vec![];
|
||||||
if id.0 > 0 {
|
if id.0 > 0 {
|
||||||
neighbors.push((id.0 - 1, id.1));
|
neighbours.push((id.0 - 1, id.1));
|
||||||
}
|
}
|
||||||
if id.0 < 2 {
|
if id.0 < 2 {
|
||||||
neighbors.push((id.0 + 1, id.1));
|
neighbours.push((id.0 + 1, id.1));
|
||||||
}
|
}
|
||||||
if id.1 > 0 {
|
if id.1 > 0 {
|
||||||
neighbors.push((id.0, id.1 - 1));
|
neighbours.push((id.0, id.1 - 1));
|
||||||
}
|
}
|
||||||
if id.1 < 2 {
|
if id.1 < 2 {
|
||||||
neighbors.push((id.0, id.1 + 1));
|
neighbours.push((id.0, id.1 + 1));
|
||||||
}
|
}
|
||||||
neighbors.into_iter()
|
neighbours.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Entropy is the number of empty neighbors, and choose sets the value to the same value.
|
/// Entropy is the number of empty neighbours, and choose sets the value to the same value.
|
||||||
/// Just for testing.
|
/// Just for testing.
|
||||||
struct TestRuleset;
|
struct TestRuleset;
|
||||||
|
|
||||||
|
|
@ -184,11 +204,11 @@ mod tests {
|
||||||
graph: &impl GraphLike<u8, (usize, usize)>,
|
graph: &impl GraphLike<u8, (usize, usize)>,
|
||||||
id: (usize, usize),
|
id: (usize, usize),
|
||||||
) -> Option<f32> {
|
) -> Option<f32> {
|
||||||
let neighbors = graph
|
let neighbours = graph
|
||||||
.iter_neighbour_nodes(id)
|
.iter_neighbour_nodes(id)
|
||||||
.filter(|n| n.1.is_some())
|
.filter(|n| n.1.is_some())
|
||||||
.count();
|
.count();
|
||||||
Some(4_usize.strict_sub(neighbors) as f32)
|
Some(4_usize.strict_sub(neighbours) as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn choose(
|
fn choose(
|
||||||
|
|
@ -197,11 +217,11 @@ mod tests {
|
||||||
id: (usize, usize),
|
id: (usize, usize),
|
||||||
_retry_count: Option<usize>,
|
_retry_count: Option<usize>,
|
||||||
) -> Option<u8> {
|
) -> Option<u8> {
|
||||||
let neighbors = graph
|
let neighbours = graph
|
||||||
.iter_neighbour_nodes(id)
|
.iter_neighbour_nodes(id)
|
||||||
.filter(|n| n.1.is_some())
|
.filter(|n| n.1.is_some())
|
||||||
.count();
|
.count();
|
||||||
Some(4_usize.strict_sub(neighbors) as u8)
|
Some(4_usize.strict_sub(neighbours) as u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,8 +235,8 @@ mod tests {
|
||||||
[None, None, None],
|
[None, None, None],
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
assert_eq!(graph.get_node((0, 0)), None);
|
assert_eq!(graph.get_node((0, 0)), Ok(None));
|
||||||
assert_eq!(graph.get_node((1, 2)), Some(&99));
|
assert_eq!(graph.get_node((1, 2)), Ok(Some(&99)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -290,14 +310,14 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iter_neighbor_ids_works() {
|
fn iter_neighbour_ids_works() {
|
||||||
// This really tests that the implementation itself works...
|
// This really tests that the implementation itself works...
|
||||||
let graph = TestGraph {
|
let graph = TestGraph {
|
||||||
tiles: [[None; 3]; 3],
|
tiles: [[None; 3]; 3],
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
graph
|
graph
|
||||||
.iter_neighbor_ids((1, 1))
|
.iter_neighbour_ids((1, 1))
|
||||||
.collect::<HashSet<(usize, usize)>>(),
|
.collect::<HashSet<(usize, usize)>>(),
|
||||||
vec![(0, 1), (2, 1), (1, 0), (1, 2)]
|
vec![(0, 1), (2, 1), (1, 0), (1, 2)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue