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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::collections::HashMap;
use crate::coord::Coord;
use crate::grid::Grid;
use crate::search::Search;
pub use crate::search::SearchOpts;

pub fn find_path(grid: &Grid, start: Coord, end: Coord, opts: Option<SearchOpts>) -> Option<Vec<Coord>> {
  let end_on_unstoppable = match &opts {
    None => false,
    Some(opts) => match opts.end_on_unstoppable {
      None => false,
      Some(end_on_unstoppable) => end_on_unstoppable,
    }
  };

  if Coord::equals(Some(start), Some(end)) {
    Some(vec![])
  } else if !grid.is_coord_stoppable(&end.x, &end.y) & !end_on_unstoppable {
    None
  } else {
    let mut search = Search::new(start, Some(end), opts);
    let start_node = search.coordinate_to_node(None, &start.x, &start.y, &0);
    search.push(start_node);

    calculate(&mut search, &grid);

    match search.pop() {
      None => None,
      Some(node) => Some(node.format_path(&search)),
    }
  }
}

pub fn find_walkable(grid: &Grid, source: Vec<Coord>, opts: Option<SearchOpts>) -> Vec<Coord> {
  let mut search = Search::new(*source.first().unwrap(), None, opts);

  for coord in source {
    let node = search.coordinate_to_node(None, &coord.x, &coord.y, &0);
    search.push(node);
  }

  calculate(&mut search, &grid);

  let coords = &mut vec![];
  for node in search.traversed_nodes() {
    if grid.is_coord_walkable(&node.x, &node.y) {
      coords.push(Coord::new(node.x, node.y));
    }
  }
  coords.sort();
  coords.to_owned()
}

pub fn to_coord_map(coords: Vec<Coord>) -> HashMap<i32, HashMap<i32, bool>> {
  let hash = &mut HashMap::new();
  for Coord{x, y} in coords {
    match hash.get_mut(&y) {
      None => {
        let mut inner_hash = HashMap::new();
        inner_hash.insert(x, true);
        hash.insert(y, inner_hash);
      },
      Some(inner_hash) => {
        inner_hash.insert(x, true);
      },
    };
  }
  hash.to_owned()
}

fn calculate(search: &mut Search, grid: &Grid) {
  match search.size() {
    0 => (),
    _ => {
      if search.reached_destination() {
        ()
      } else {
        let mut node = search.pop().unwrap();
        node.visited = true;
        search.cache(node);

        // cardinal
        if grid.in_grid(node.x, node.y - 1) {
          search.check_adjacent_node(grid, &node, 0, -1)
        }
        // hex & intercardinal
        if !grid.is_cardinal() & grid.in_grid(node.x + 1, node.y - 1) {
          search.check_adjacent_node(grid, &node, 1, -1)
        }
        // cardinal
        if grid.in_grid(node.x + 1, node.y) {
          search.check_adjacent_node(grid, &node, 1, 0)
        }
        // intercardinal
        if grid.is_intercardinal() & grid.in_grid(node.x + 1, node.y + 1) {
          search.check_adjacent_node(grid, &node, 1, 1)
        }
        // cardinal
        if grid.in_grid(node.x, node.y + 1) {
          search.check_adjacent_node(grid, &node, 0, 1)
        }
        // hex & intercardinal
        if !grid.is_cardinal() & grid.in_grid(node.x - 1, node.y + 1) {
          search.check_adjacent_node(grid, &node, -1, 1)
        }
        // cardinal
        if grid.in_grid(node.x - 1, node.y) {
          search.check_adjacent_node(grid, &node, -1, 0)
        }
        // intercardinal
        if grid.is_intercardinal() & grid.in_grid(node.x - 1, node.y - 1) {
          search.check_adjacent_node(grid, &node, -1, -1)
        }

        calculate(search, grid)
      }
    },
  }
}