1use std::collections::HashMap;
5use std::hash::Hash;
6use serde::{Deserialize, Serialize};
7use crate::wave_function::collapsable_wave_function::collapsable_wave_function::CollapsableWaveFunction;
8use crate::wave_function::collapsable_wave_function::sequential_collapsable_wave_function::SequentialCollapsableWaveFunction;
9use crate::wave_function::{Node, NodeStateCollection, NodeStateProbability, WaveFunction};
10
11pub struct Distance {
12 center: f32,
14 width: f32,
16}
17
18impl Distance {
19 pub fn new(center: f32, width: f32) -> Self {
20 Self {
21 center,
22 width,
23 }
24 }
25}
26
27pub enum Proximity {
28 ExclusiveExistence,
30 SomeDistanceAway {
32 distance: Distance,
34 },
35 InAnotherDimensionEntirely,
37}
38
39#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize)]
40enum NodeState<TValue>
41where
42 TValue: HasProximity,
43{
44 Primary {
46 state: TValue,
47 },
48 Secondary {
50 state: TValue,
51 node_index: usize,
52 },
53}
54
55impl<'de, TValue> Deserialize<'de> for NodeState<TValue>
56where
57 TValue: HasProximity, {
59 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60 where
61 D: serde::Deserializer<'de>,
62 {
63 struct NodeStateVisitor<TValue>(std::marker::PhantomData<TValue>);
65
66 impl<'de, TValue> serde::de::Visitor<'de> for NodeStateVisitor<TValue>
68 where
69 TValue: HasProximity,
70 {
71 type Value = NodeState<TValue>;
72
73 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
74 formatter.write_str("a valid NodeState variant")
75 }
76
77 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
78 where
79 V: serde::de::MapAccess<'de>,
80 {
81 let mut state: Option<TValue> = None;
82 let mut node_index: Option<usize> = None;
83
84 while let Some(key) = map.next_key::<String>()? {
86 match key.as_str() {
87 "state" => {
88 if state.is_some() {
89 return Err(serde::de::Error::duplicate_field("state"));
90 }
91 state = Some(map.next_value()?);
92 }
93 "node_index" => {
94 if node_index.is_some() {
95 return Err(serde::de::Error::duplicate_field("node_index"));
96 }
97 node_index = Some(map.next_value()?);
98 }
99 _ => {
100 return Err(serde::de::Error::unknown_field(&key, &["state", "node_index"]));
101 }
102 }
103 }
104
105 match (state, node_index) {
107 (Some(state), None) => Ok(NodeState::Primary { state }),
108 (Some(state), Some(node_index)) => Ok(NodeState::Secondary { state, node_index }),
109 _ => Err(serde::de::Error::missing_field("state")),
110 }
111 }
112 }
113
114 deserializer.deserialize_struct(
116 "NodeState",
117 &["state", "node_index"],
118 NodeStateVisitor(std::marker::PhantomData),
119 )
120 }
121}
122
123pub trait HasProximity: Eq + Hash + Clone + std::fmt::Debug + Ord + Serialize + for<'de> Deserialize<'de> {
124 fn get_proximity(&self, other: &Self) -> Proximity where Self: Sized;
125}
126
127#[derive(std::fmt::Debug, Clone)]
128pub struct ProximityGraphNode<T: Clone> {
129 proximity_graph_node_id: String,
130 distance_per_proximity_graph_node_id: HashMap<String, f32>,
131 tag: T,
132}
133
134impl<T: Clone> ProximityGraphNode<T> {
135 pub fn new(proximity_graph_node_id: String, distance_per_proximity_graph_node_id: HashMap<String, f32>, tag: T) -> Self {
136 Self {
137 proximity_graph_node_id,
138 distance_per_proximity_graph_node_id,
139 tag,
140 }
141 }
142 pub fn get_id(&self) -> &String {
143 &self.proximity_graph_node_id
144 }
145 pub fn get_tag(&self) -> &T {
146 &self.tag
147 }
148}
149
150#[derive(std::fmt::Debug, Clone)]
151pub enum ProximityGraphError {
152 FailedToMapValuesToNodesAtAnyDistance,
153 TestError,
154}
155
156pub struct ProximityGraph<T: Clone> {
157 nodes: Vec<ProximityGraphNode<T>>,
158}
159
160impl<T: Clone> ProximityGraph<T> {
161 pub fn new(nodes: Vec<ProximityGraphNode<T>>) -> Self {
162 Self {
163 nodes,
164 }
165 }
166 pub fn get_value_per_proximity_graph_node_id<TValue: HasProximity>(&self, values: Vec<TValue>, maximum_acceptable_distance_variance_factor: f32, acceptable_distance_variance_factor_difference: f32) -> Result<HashMap<String, TValue>, ProximityGraphError> {
167
168 let mut distance_variance_factor = 0.0;
174 let mut distance_variance_factor_minimum = 0.0;
175 let mut distance_variance_factor_maximum = 0.0;
176 let mut best_collapsed_wave_function = None;
177 let mut is_distance_variance_factor_acceptable = false;
178 let mut iterations = 0;
179 while best_collapsed_wave_function.is_none() || !is_distance_variance_factor_acceptable {
180 let primary_node_state_ratio_per_node_state_id = {
190 let node_state_ids = values.iter()
191 .map(|value| {
192 NodeState::Primary {
193 state: value.clone(),
194 }
195 })
196 .collect::<Vec<NodeState<TValue>>>();
197 NodeStateProbability::get_equal_probability(&node_state_ids)
198 };
199
200 let (nodes, node_state_collections) = {
201 let mut nodes = Vec::new();
202 let mut node_state_collections = Vec::new();
203
204 for proximity_graph_node in self.nodes.iter() {
206 let mut node_state_collection_ids_per_neighbor_node_id: HashMap<String, Vec<String>> = HashMap::new();
208 for (neighbor_proximity_graph_node_id, neighbor_distance) in proximity_graph_node.distance_per_proximity_graph_node_id.iter() {
209 let neighbor_distance = *neighbor_distance;
210
211 let mut node_state_collection_ids: Vec<String> = Vec::new();
212 if &proximity_graph_node.proximity_graph_node_id != neighbor_proximity_graph_node_id {
213 for (current_value_index, current_value) in values.iter().enumerate() {
215 let current_node_state = NodeState::Primary {
216 state: current_value.clone(),
217 };
218 let mut other_node_states = Vec::new();
219 for other_value in values.iter() {
220 match current_value.get_proximity(other_value) {
221 Proximity::ExclusiveExistence => {
222 },
224 Proximity::SomeDistanceAway { distance } => {
225 let distance_variance = distance.center * distance_variance_factor;
226 let from_distance = distance.center - distance_variance - distance.width;
227 let to_distance = distance.center + distance_variance + distance.width;
228
229 if from_distance <= neighbor_distance && neighbor_distance <= to_distance {
231 let other_node_state = NodeState::Primary {
233 state: other_value.clone(),
234 };
235 other_node_states.push(other_node_state);
236 }
237 },
238 Proximity::InAnotherDimensionEntirely => {
239 let other_node_state = NodeState::Primary {
241 state: other_value.clone(),
242 };
243 other_node_states.push(other_node_state);
244 },
245 }
246 }
247
248 let node_state_collection_id: String = format!("primary_{}_{}_{}", proximity_graph_node.proximity_graph_node_id, neighbor_proximity_graph_node_id, current_value_index);
250
251 let node_state_collection = NodeStateCollection::new(
252 node_state_collection_id.clone(),
253 current_node_state,
254 other_node_states,
255 );
256 node_state_collections.push(node_state_collection);
257
258 node_state_collection_ids.push(node_state_collection_id);
259 }
260 }
261
262 let neighbor_node_id = format!("primary_{}", neighbor_proximity_graph_node_id);
263 node_state_collection_ids_per_neighbor_node_id.insert(neighbor_node_id, node_state_collection_ids);
264 }
265
266 let node = Node::new(
267 format!("primary_{}", proximity_graph_node.proximity_graph_node_id),
268 primary_node_state_ratio_per_node_state_id.clone(),
269 node_state_collection_ids_per_neighbor_node_id,
270 );
271 nodes.push(node);
272 }
273
274 for (value_index, value) in values.iter().enumerate() {
276 if let Proximity::ExclusiveExistence = value.get_proximity(&value) {
277 let secondary_node_state_ratio_per_node_state_id = {
279 let mut node_states = Vec::new();
280 for (node_index, _) in self.nodes.iter().enumerate() {
281 node_states.push(
282 NodeState::Secondary {
283 node_index,
284 state: value.clone(),
285 }
286 );
287 };
288 NodeStateProbability::get_equal_probability(&node_states)
289 };
290 let node_state_collection_ids_per_neighbor_node_id = {
291 let mut node_state_collection_ids_per_neighbor_node_id = HashMap::new();
292
293 for (proximity_graph_node_index, proximity_graph_node) in self.nodes.iter().enumerate() {
296 let node_state_collection_id = format!("secondary_{}_{}", value_index, proximity_graph_node.proximity_graph_node_id);
297 let node_state_collection = NodeStateCollection::new(
298 node_state_collection_id.clone(),
299 NodeState::Secondary {
300 node_index: proximity_graph_node_index,
301 state: value.clone(),
302 },
303 vec![NodeState::Primary {
304 state: value.clone(),
305 }],
306 );
307 node_state_collections.push(node_state_collection);
308 let neighbor_node_id = format!("primary_{}", proximity_graph_node.proximity_graph_node_id);
309 node_state_collection_ids_per_neighbor_node_id.insert(neighbor_node_id, vec![node_state_collection_id]);
310 }
311
312 node_state_collection_ids_per_neighbor_node_id
313
314 };
316 let node = Node::new(
317 format!("secondary_{}", value_index),
318 secondary_node_state_ratio_per_node_state_id,
319 node_state_collection_ids_per_neighbor_node_id,
320 );
321 nodes.push(node);
322 }
323 }
324
325 (nodes, node_state_collections)
327 };
328
329 let wave_function = WaveFunction::new(nodes, node_state_collections);
333 let mut collapsable_wave_function = wave_function.get_collapsable_wave_function::<SequentialCollapsableWaveFunction<NodeState<TValue>>>(None);
334 match collapsable_wave_function.collapse() {
335 Ok(collapsed_wave_function) => {
336 best_collapsed_wave_function = Some(collapsed_wave_function);
338
339 distance_variance_factor_maximum = distance_variance_factor;
341 distance_variance_factor = (distance_variance_factor_maximum + distance_variance_factor_minimum) * 0.5;
342
343 if distance_variance_factor_maximum - distance_variance_factor_minimum <= acceptable_distance_variance_factor_difference {
344 is_distance_variance_factor_acceptable = true;
345 }
347 else {
348 }
350 },
351 Err(_) => {
352 if distance_variance_factor_maximum == 0.0 {
355 distance_variance_factor_maximum = maximum_acceptable_distance_variance_factor;
357 distance_variance_factor = maximum_acceptable_distance_variance_factor;
358 }
359 else if distance_variance_factor_maximum == maximum_acceptable_distance_variance_factor {
360 return Err(ProximityGraphError::FailedToMapValuesToNodesAtAnyDistance);
362 }
363 else {
364 distance_variance_factor_minimum = distance_variance_factor;
365 distance_variance_factor = (distance_variance_factor_maximum + distance_variance_factor_minimum) * 0.5;
366 }
367
368 if distance_variance_factor_maximum - distance_variance_factor_minimum <= acceptable_distance_variance_factor_difference {
369 is_distance_variance_factor_acceptable = true;
370 }
372 else {
373 }
375 },
376 }
377
378 iterations += 1;
381 if iterations > 10 {
382 break;
383 }
384 }
385
386 let best_collapsed_wave_function = best_collapsed_wave_function.expect("We should have already failed when both extremes were tested earlier in the logic.");
387 let mut value_per_proximity_graph_node_id = HashMap::new();
388 for (node_id, node_state) in best_collapsed_wave_function.node_state_per_node_id {
389 match node_state {
390 NodeState::Primary { state } => {
391 if let Some(proximity_graph_node_id) = node_id.strip_prefix("primary_") {
392 value_per_proximity_graph_node_id.insert(String::from(proximity_graph_node_id), state);
393 }
394 else {
395 panic!("Unexpected non-primary node ID when node state is in a primary state.");
396 }
397 },
398 NodeState::Secondary { state: _, node_index: _ } => {
399 if let Some(_) = node_id.strip_prefix("primary_") {
400 panic!("Unexpected secondary node state tied to a primary node.");
401 }
402 },
403 }
404 }
405 Ok(value_per_proximity_graph_node_id)
406 }
407}
408
409#[cfg(test)]
410mod proximity_graph_tests {
411 use std::collections::HashMap;
414
415 use serde::{Deserialize, Serialize};
416
417 use super::{Distance, HasProximity, Proximity, ProximityGraph, ProximityGraphNode};
418
419 fn get_x_by_y_grid_proximity_graph(x: usize, y: usize) -> ProximityGraph<(usize, usize)> {
420 let mut proximity_graph_nodes = Vec::new();
421 for i in 0..x {
422 for j in 0..y {
423 let mut distance_per_proximity_graph_node_id = HashMap::new();
424 for i_other in 0..x {
425 for j_other in 0..y {
426 if i != i_other || j != j_other {
427 let other_proximity_graph_node_id = format!("node_{}_{}", i_other, j_other);
428 let distance = (
429 if i < i_other {
430 i_other - i
431 }
432 else {
433 i - i_other
434 } + if j < j_other {
435 j_other - j
436 }
437 else {
438 j - j_other
439 }
440 ) as f32;
441 distance_per_proximity_graph_node_id.insert(other_proximity_graph_node_id, distance);
442 }
443 }
444 }
445 let proximity_graph_node = ProximityGraphNode {
446 proximity_graph_node_id: format!("node_{}_{}", i, j),
447 distance_per_proximity_graph_node_id,
448 tag: (i, j),
449 };
450 proximity_graph_nodes.push(proximity_graph_node);
451 }
452 }
453 ProximityGraph::new(proximity_graph_nodes)
454 }
455
456 fn get_values(total_values: usize) -> Vec<IceCreamShop> {
457 let mut values = Vec::with_capacity(total_values);
458 for index in 0..total_values {
459 match index {
460 0 => values.push(IceCreamShop::AppleCream),
461 1 => values.push(IceCreamShop::BananaBoost),
462 2 => values.push(IceCreamShop::CaramelJuice),
463 3 => values.push(IceCreamShop::DarkDestiny),
464 4 => values.push(IceCreamShop::EternalJoy),
465 _ => values.push(IceCreamShop::None),
466 }
467 }
468 values
469 }
470
471 fn println_value_per_proximity_graph_node_id(x: usize, y: usize, value_per_proximity_graph_node_id: &HashMap<String, IceCreamShop>) {
472 let mut character_per_y_per_x = HashMap::new();
473 for i in 0..x {
474 let mut character_per_y = HashMap::new();
475 for j in 0..y {
476 character_per_y.insert(j, None);
477 }
478 character_per_y_per_x.insert(i, character_per_y);
479 }
480 for (proximity_graph_node_id, ice_cream_shop) in value_per_proximity_graph_node_id.iter() {
481 let x_and_y: Vec<&str> = proximity_graph_node_id.strip_prefix("node_")
482 .unwrap()
483 .split('_')
484 .collect();
485 let x: usize = x_and_y[0].parse().unwrap();
486 let y: usize = x_and_y[1].parse().unwrap();
487 let character = match ice_cream_shop {
488 IceCreamShop::AppleCream => "A",
489 IceCreamShop::BananaBoost => "B",
490 IceCreamShop::CaramelJuice => "C",
491 IceCreamShop::DarkDestiny => "D",
492 IceCreamShop::EternalJoy => "E",
493 IceCreamShop::None => "_",
494 };
495 *character_per_y_per_x.get_mut(&x)
496 .unwrap()
497 .get_mut(&y)
498 .unwrap() = Some(character);
499 }
500
501 for j in 0..y {
502 let mut line = String::new();
503 for i in 0..x {
504 let character = character_per_y_per_x.get(&i)
505 .unwrap()
506 .get(&j)
507 .unwrap()
508 .unwrap();
509 line.push_str(character);
510 }
511 println!("{}", line);
512 }
513 }
514
515 #[derive(Clone, std::fmt::Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
516 enum IceCreamShop {
517 AppleCream,
518 BananaBoost,
519 CaramelJuice,
520 DarkDestiny,
521 EternalJoy,
522 None,
523 }
524
525 impl HasProximity for IceCreamShop {
526 fn get_proximity(&self, other: &Self) -> Proximity where Self: Sized {
527 match self {
528 Self::AppleCream => {
529 match other {
530 Self::AppleCream => Proximity::ExclusiveExistence,
531 Self::BananaBoost => Proximity::SomeDistanceAway {
532 distance: Distance {
533 center: 4.0,
534 width: 0.0,
535 }
536 },
537 Self::CaramelJuice => Proximity::SomeDistanceAway {
538 distance: Distance {
539 center: 8.0,
540 width: 0.0,
541 },
542 },
543 Self::DarkDestiny => Proximity::SomeDistanceAway {
544 distance: Distance {
545 center: 1.0,
546 width: 0.0,
547 },
548 },
549 Self::EternalJoy => Proximity::SomeDistanceAway {
550 distance: Distance {
551 center: 4.0,
552 width: 0.0,
553 },
554 },
555 Self::None => Proximity::InAnotherDimensionEntirely,
556 }
557 },
558 Self::BananaBoost => {
559 match other {
560 Self::AppleCream => Proximity::SomeDistanceAway {
561 distance: Distance {
562 center: 4.0,
563 width: 0.0,
564 },
565 },
566 Self::BananaBoost => Proximity::ExclusiveExistence,
567 Self::CaramelJuice => Proximity::SomeDistanceAway {
568 distance: Distance {
569 center: 4.0,
570 width: 0.0,
571 },
572 },
573 Self::DarkDestiny => Proximity::SomeDistanceAway {
574 distance: Distance {
575 center: 5.0,
576 width: 0.0,
577 },
578 },
579 Self::EternalJoy => Proximity::SomeDistanceAway {
580 distance: Distance {
581 center: 8.0,
582 width: 0.0,
583 },
584 },
585 Self::None => Proximity::InAnotherDimensionEntirely,
586 }
587 },
588 Self::CaramelJuice => {
589 match other {
590 Self::AppleCream => Proximity::SomeDistanceAway {
591 distance: Distance {
592 center: 8.0,
593 width: 0.0,
594 },
595 },
596 Self::BananaBoost => Proximity::SomeDistanceAway {
597 distance: Distance {
598 center: 4.0,
599 width: 0.0,
600 },
601 },
602 Self::CaramelJuice => Proximity::ExclusiveExistence,
603 Self::DarkDestiny => Proximity::SomeDistanceAway {
604 distance: Distance {
605 center: 7.0,
606 width: 0.0,
607 },
608 },
609 Self::EternalJoy => Proximity::SomeDistanceAway {
610 distance: Distance {
611 center: 4.0,
612 width: 0.0,
613 },
614 },
615 Self::None => Proximity::InAnotherDimensionEntirely,
616 }
617 },
618 Self::DarkDestiny => {
619 match other {
620 Self::AppleCream => Proximity::SomeDistanceAway {
621 distance: Distance {
622 center: 1.0,
623 width: 0.0,
624 },
625 },
626 Self::BananaBoost => Proximity::SomeDistanceAway {
627 distance: Distance {
628 center: 5.0,
629 width: 0.0,
630 },
631 },
632 Self::CaramelJuice => Proximity::SomeDistanceAway {
633 distance: Distance {
634 center: 7.0,
635 width: 0.0,
636 },
637 },
638 Self::DarkDestiny => Proximity::ExclusiveExistence,
639 Self::EternalJoy => Proximity::SomeDistanceAway {
640 distance: Distance {
641 center: 3.0,
642 width: 0.0,
643 },
644 },
645 Self::None => Proximity::InAnotherDimensionEntirely,
646 }
647 },
648 Self::EternalJoy => {
649 match other {
650 Self::AppleCream => Proximity::SomeDistanceAway {
651 distance: Distance {
652 center: 4.0,
653 width: 0.0,
654 },
655 },
656 Self::BananaBoost => Proximity::SomeDistanceAway {
657 distance: Distance {
658 center: 8.0,
659 width: 0.0,
660 },
661 },
662 Self::CaramelJuice => Proximity::SomeDistanceAway {
663 distance: Distance {
664 center: 4.0,
665 width: 0.0,
666 },
667 },
668 Self::DarkDestiny => Proximity::SomeDistanceAway {
669 distance: Distance {
670 center: 3.0,
671 width: 0.0,
672 },
673 },
674 Self::EternalJoy => Proximity::ExclusiveExistence,
675 Self::None => Proximity::InAnotherDimensionEntirely,
676 }
677 },
678 Self::None => {
679 match other {
680 Self::AppleCream => Proximity::InAnotherDimensionEntirely,
681 Self::BananaBoost => Proximity::InAnotherDimensionEntirely,
682 Self::CaramelJuice => Proximity::InAnotherDimensionEntirely,
683 Self::DarkDestiny => Proximity::InAnotherDimensionEntirely,
684 Self::EternalJoy => Proximity::InAnotherDimensionEntirely,
685 Self::None => Proximity::InAnotherDimensionEntirely,
686 }
687 },
688 }
689 }
690 }
691
692 #[test]
693 fn test_w7b0_get_x_by_y_grid_proximity_graph() {
694 let proximity_graph = get_x_by_y_grid_proximity_graph(2, 2);
695 assert_eq!(4, proximity_graph.nodes.len());
696 for index in 0..4 {
697 assert_eq!(3, proximity_graph.nodes[index].distance_per_proximity_graph_node_id.keys().len());
698 }
699 println!("{:?}", proximity_graph.nodes);
700 }
701
702 #[test_case::test_case(5, 5, 0.0, 0.0)]
703 #[test_case::test_case(4, 4, 1.0, 0.1)]
704 #[test_case::test_case(3, 3, 2.0, 0.1)]
705 fn test_h2s7_icecream_shops_in_grid(x: usize, y: usize, maximum_acceptable_distance_variance_factor: f32, acceptable_distance_variance_factor_difference: f32) {
706 let proximity_graph = get_x_by_y_grid_proximity_graph(x, y);
707 let values = get_values(x * y);
708 let value_per_proximity_graph_node_id = proximity_graph.get_value_per_proximity_graph_node_id(values, maximum_acceptable_distance_variance_factor, acceptable_distance_variance_factor_difference).expect("Failed to get value per proximity graph node ID.");
709 println_value_per_proximity_graph_node_id(x, y, &value_per_proximity_graph_node_id);
710 println!("{:?}", value_per_proximity_graph_node_id);
711 assert_eq!(IceCreamShop::AppleCream, *value_per_proximity_graph_node_id.get("node_0_0").unwrap());
712 assert_eq!(IceCreamShop::BananaBoost, *value_per_proximity_graph_node_id.get(format!("node_{}_0", x - 1).as_str()).unwrap());
713 assert_eq!(IceCreamShop::CaramelJuice, *value_per_proximity_graph_node_id.get(format!("node_{}_{}", x - 1, y - 1).as_str()).unwrap());
714 assert_eq!(IceCreamShop::DarkDestiny, *value_per_proximity_graph_node_id.get("node_0_1").unwrap());
715 assert_eq!(IceCreamShop::EternalJoy, *value_per_proximity_graph_node_id.get(format!("node_0_{}", y - 1).as_str()).unwrap());
716 }
717
718 #[test_case::test_case(6, 6, 0.0, 0.0)]
719 fn test_y7c4_icecream_shops_in_grid(x: usize, y: usize, maximum_acceptable_distance_variance_factor: f32, acceptable_distance_variance_factor_difference: f32) {
720 let proximity_graph = get_x_by_y_grid_proximity_graph(x, y);
721 let values = get_values(x * y);
722 let value_per_proximity_graph_node_id = proximity_graph.get_value_per_proximity_graph_node_id(values, maximum_acceptable_distance_variance_factor, acceptable_distance_variance_factor_difference).expect("Failed to get value per proximity graph node ID.");
723 println_value_per_proximity_graph_node_id(x, y, &value_per_proximity_graph_node_id);
724 println!("{:?}", value_per_proximity_graph_node_id);
725 assert_eq!(IceCreamShop::AppleCream, *value_per_proximity_graph_node_id.get("node_0_0").unwrap());
726 assert_eq!(IceCreamShop::BananaBoost, *value_per_proximity_graph_node_id.get("node_4_0").unwrap());
727 assert_eq!(IceCreamShop::CaramelJuice, *value_per_proximity_graph_node_id.get("node_4_4").unwrap());
728 assert_eq!(IceCreamShop::DarkDestiny, *value_per_proximity_graph_node_id.get("node_0_1").unwrap());
729 assert_eq!(IceCreamShop::EternalJoy, *value_per_proximity_graph_node_id.get("node_0_4").unwrap());
730 }
731
732 #[test_case::test_case(4, 4, 0.5, 0.1)]
733 #[test_case::test_case(3, 3, 1.0, 0.1)]
734 fn test_o1n6_icecream_shops_in_grid(x: usize, y: usize, maximum_acceptable_distance_variance_factor: f32, acceptable_distance_variance_factor_difference: f32) {
735 let proximity_graph = get_x_by_y_grid_proximity_graph(x, y);
736 let values = get_values(x * y);
737 let error = proximity_graph.get_value_per_proximity_graph_node_id(values, maximum_acceptable_distance_variance_factor, acceptable_distance_variance_factor_difference);
738 assert!(error.is_err());
739 }
740}