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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::cmp::Ordering;
use std::collections::BinaryHeap;

/// Represents the states used in the A* algorithm.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct State {
    pub cost: usize,
    pub position: (usize, usize),
}

impl Ord for State {
    /// Defines the ordering for `State`, ensuring that states with lower costs have higher priority.
    ///
    /// # Parameters
    /// - `other`: The other `State` to compare against.
    ///
    /// # Returns
    /// `Ordering` result of the comparison.
    fn cmp(&self, other: &Self) -> Ordering {
        // Higher priority for states with lower cost (min-heap behavior)
        other.cost.cmp(&self.cost)
    }
}

impl PartialOrd for State {
    /// Provides partial ordering for `State`.
    ///
    /// # Parameters
    /// - `other`: The other `State` to compare against.
    ///
    /// # Returns
    /// `Ordering` result of the comparison.
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        // Use the full ordering implementation from `Ord`
        Some(self.cmp(other))
    }
}

/// Priority queue used in the A* algorithm.
#[derive(Debug)]
pub struct PriorityQueue {
    heap: BinaryHeap<State>,
}

impl PriorityQueue {
    /// Creates a new, empty `PriorityQueue`.
    ///
    /// # Returns
    /// A new `PriorityQueue` instance.
    ///
    /// # Examples
    ///
    /// ```
    /// use crate::PriorityQueue;
    ///
    /// // Create a new empty priority queue
    /// let mut open_set = PriorityQueue::new();
    ///
    /// // Check if the queue is empty
    /// assert!(open_set.is_empty());
    /// ```
    pub fn new() -> Self {
        PriorityQueue {
            heap: BinaryHeap::new(),
        }
    }

    /// Adds a new `State` to the queue.
    ///
    /// # Parameters
    /// - `state`: The state to be added to the queue.
    ///
    /// # Examples
    ///
    /// ```
    /// use crate::{PriorityQueue, State};
    /// use std::collections::HashMap;
    ///
    /// // Create a new priority queue
    /// let mut open_set = PriorityQueue::new();
    ///
    /// // Create a state representing a node in the A* algorithm
    /// let state = State {
    ///     cost: 10, // f-score value calculated in AStar
    ///     position: (1, 2), // position of the node in the grid
    /// };
    ///
    /// // Add the state to the priority queue
    /// open_set.push(state);
    ///
    /// // The queue should no longer be empty
    /// assert!(!open_set.is_empty());
    /// ```
    pub fn push(&mut self, state: State) {
        // Add the state to the heap
        self.heap.push(state);
    }

    /// Removes and returns the `State` with the highest priority from the queue.
    ///
    /// # Returns
    /// The `State` with the highest priority (if available) or `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use crate::{PriorityQueue, State};
    /// use std::collections::HashMap;
    ///
    /// // Create a new priority queue and add some states
    /// let mut open_set = PriorityQueue::new();
    /// open_set.push(State { cost: 10, position: (1, 2) });
    /// open_set.push(State { cost: 5, position: (2, 3) }); // Lower cost, higher priority
    ///
    /// // Remove and get the state with the highest priority
    /// if let Some(state) = open_set.pop() {
    ///     assert_eq!(state.cost, 5); // Lower cost should be popped first
    ///     assert_eq!(state.position, (2, 3));
    /// } else {
    ///     panic!("Expected a state, but got None");
    /// }
    /// ```
    pub fn pop(&mut self) -> Option<State> {
        // Remove and return the state with the highest priority
        self.heap.pop()
    }

    /// Checks if the queue is empty.
    ///
    /// # Returns
    /// A boolean indicating whether the queue is empty.
    ///
    /// # Examples
    ///
    /// ```
    /// use crate::{PriorityQueue, State};
    ///
    /// // Create a new priority queue
    /// let mut open_set = PriorityQueue::new();
    ///
    /// // Initially, the queue should be empty
    /// assert!(open_set.is_empty());
    ///
    /// // Add a state to the queue
    /// open_set.push(State { cost: 10, position: (1, 2) });
    ///
    /// // Now the queue should not be empty
    /// assert!(!open_set.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        // Check if the heap is empty
        self.heap.is_empty()
    }
}