Fix greedy_best_first
diff --git a/graphs/greedy_best_first.py b/graphs/greedy_best_first.py
index 35f7ca9feeef..bb3160047e34 100644
--- a/graphs/greedy_best_first.py
+++ b/graphs/greedy_best_first.py
@@ -6,14 +6,32 @@
 
 Path = list[tuple[int, int]]
 
-grid = [
-    [0, 0, 0, 0, 0, 0, 0],
-    [0, 1, 0, 0, 0, 0, 0],  # 0 are free path whereas 1's are obstacles
-    [0, 0, 0, 0, 0, 0, 0],
-    [0, 0, 1, 0, 0, 0, 0],
-    [1, 0, 1, 0, 0, 0, 0],
-    [0, 0, 0, 0, 0, 0, 0],
-    [0, 0, 0, 0, 1, 0, 0],
+# 0's are free path whereas 1's are obstacles
+TEST_GRIDS = [
+    [
+        [0, 0, 0, 0, 0, 0, 0],
+        [0, 1, 0, 0, 0, 0, 0],
+        [0, 0, 0, 0, 0, 0, 0],
+        [0, 0, 1, 0, 0, 0, 0],
+        [1, 0, 1, 0, 0, 0, 0],
+        [0, 0, 0, 0, 0, 0, 0],
+        [0, 0, 0, 0, 1, 0, 0],
+    ],
+    [
+        [0, 0, 0, 1, 1, 0, 0],
+        [0, 0, 0, 0, 1, 0, 1],
+        [0, 0, 0, 1, 1, 0, 0],
+        [0, 1, 0, 0, 1, 0, 0],
+        [1, 0, 0, 1, 1, 0, 1],
+        [0, 0, 0, 0, 0, 0, 0],
+    ],
+    [
+        [0, 0, 1, 0, 0],
+        [0, 1, 0, 0, 0],
+        [0, 0, 1, 0, 1],
+        [1, 0, 0, 1, 1],
+        [0, 0, 0, 0, 0],
+    ],
 ]
 
 delta = ([-1, 0], [0, -1], [1, 0], [0, 1])  # up, left, down, right
@@ -65,10 +83,14 @@ def calculate_heuristic(self) -> float:
     def __lt__(self, other) -> bool:
         return self.f_cost < other.f_cost
 
+    def __eq__(self, other) -> bool:
+        return self.pos == other.pos
+
 
 class GreedyBestFirst:
     """
-    >>> gbf = GreedyBestFirst((0, 0), (len(grid) - 1, len(grid[0]) - 1))
+    >>> grid = TEST_GRIDS[2]
+    >>> gbf = GreedyBestFirst(grid, (0, 0), (len(grid) - 1, len(grid[0]) - 1))
     >>> [x.pos for x in gbf.get_successors(gbf.start)]
     [(1, 0), (0, 1)]
     >>> (gbf.start.pos_y + delta[3][0], gbf.start.pos_x + delta[3][1])
@@ -78,11 +100,14 @@ class GreedyBestFirst:
     >>> gbf.retrace_path(gbf.start)
     [(0, 0)]
     >>> gbf.search()  # doctest: +NORMALIZE_WHITESPACE
-    [(0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (4, 1), (5, 1), (6, 1),
-     (6, 2), (6, 3), (5, 3), (5, 4), (5, 5), (6, 5), (6, 6)]
+    [(0, 0), (1, 0), (2, 0), (2, 1), (3, 1), (4, 1), (4, 2), (4, 3),
+     (4, 4)]
     """
 
-    def __init__(self, start: tuple[int, int], goal: tuple[int, int]):
+    def __init__(
+        self, grid: list[list[int]], start: tuple[int, int], goal: tuple[int, int]
+    ):
+        self.grid = grid
         self.start = Node(start[1], start[0], goal[1], goal[0], 0, None)
         self.target = Node(goal[1], goal[0], goal[1], goal[0], 99999, None)
 
@@ -114,14 +139,6 @@ def search(self) -> Path | None:
 
                 if child_node not in self.open_nodes:
                     self.open_nodes.append(child_node)
-                else:
-                    # retrieve the best current path
-                    better_node = self.open_nodes.pop(self.open_nodes.index(child_node))
-
-                    if child_node.g_cost < better_node.g_cost:
-                        self.open_nodes.append(child_node)
-                    else:
-                        self.open_nodes.append(better_node)
 
         if not self.reached:
             return [self.start.pos]
@@ -131,28 +148,22 @@ def get_successors(self, parent: Node) -> list[Node]:
         """
         Returns a list of successors (both in the grid and free spaces)
         """
-        successors = []
-        for action in delta:
-            pos_x = parent.pos_x + action[1]
-            pos_y = parent.pos_y + action[0]
-
-            if not (0 <= pos_x <= len(grid[0]) - 1 and 0 <= pos_y <= len(grid) - 1):
-                continue
-
-            if grid[pos_y][pos_x] != 0:
-                continue
-
-            successors.append(
-                Node(
-                    pos_x,
-                    pos_y,
-                    self.target.pos_y,
-                    self.target.pos_x,
-                    parent.g_cost + 1,
-                    parent,
-                )
+        return [
+            Node(
+                pos_x,
+                pos_y,
+                self.target.pos_x,
+                self.target.pos_y,
+                parent.g_cost + 1,
+                parent,
+            )
+            for action in delta
+            if (
+                0 <= (pos_x := parent.pos_x + action[1]) < len(self.grid[0])
+                and 0 <= (pos_y := parent.pos_y + action[0]) < len(self.grid)
+                and self.grid[pos_y][pos_x] == 0
             )
-        return successors
+        ]
 
     def retrace_path(self, node: Node | None) -> Path:
         """
@@ -168,18 +179,21 @@ def retrace_path(self, node: Node | None) -> Path:
 
 
 if __name__ == "__main__":
-    init = (0, 0)
-    goal = (len(grid) - 1, len(grid[0]) - 1)
-    for elem in grid:
-        print(elem)
-
-    print("------")
-
-    greedy_bf = GreedyBestFirst(init, goal)
-    path = greedy_bf.search()
-    if path:
-        for pos_x, pos_y in path:
-            grid[pos_x][pos_y] = 2
+    for idx, grid in enumerate(TEST_GRIDS):
+        print(f"==grid-{idx + 1}==")
 
+        init = (0, 0)
+        goal = (len(grid) - 1, len(grid[0]) - 1)
         for elem in grid:
             print(elem)
+
+        print("------")
+
+        greedy_bf = GreedyBestFirst(grid, init, goal)
+        path = greedy_bf.search()
+        if path:
+            for pos_x, pos_y in path:
+                grid[pos_x][pos_y] = 2
+
+            for elem in grid:
+                print(elem)

### Describe your change:

fixes: #8770 

* [ ] Add an algorithm?
* [X] Fix a bug or typo in an existing algorithm?
* [ ] Documentation change?

### Checklist:
* [X] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Python/blob/master/CONTRIBUTING.md).
* [X] This pull request is all my own work -- I have not plagiarized.
* [X] I know that pull requests will not be merged if they fail the automated tests.
* [X] This PR only changes one algorithm file.  To ease review, please open separate PRs for separate algorithms.
* [X] All new Python files are placed inside an existing directory.
* [X] All filenames are in all lowercase characters with no spaces or dashes.
* [X] All functions and variable names follow Python naming conventions.
* [X] All function parameters and return values are annotated with Python [type hints](https://docs.python.org/3/library/typing.html).
* [X] All functions have [doctests](https://docs.python.org/3/library/doctest.html) that pass the automated testing.
* [X] All new algorithms include at least one URL that points to Wikipedia or another similar explanation.
* [X] If this pull request resolves one or more open issues then the commit message contains `Fixes: #{$ISSUE_NO}`.
