public static void main(String[] args) throws IOException {
    System.out.println("Welcome to Pac Man problem !!");

    Pacman obj = new Pacman();
    int selection = Integer.parseInt(args[0]);
    String[] files = {
      "smallSearch.txt", "trickySearch.txt",
    };

    File mazeFile = new File(files[selection]);
    BufferedReader br = new BufferedReader(new FileReader(mazeFile));
    String line;
    int M = 0;
    int N = 0;
    while ((line = br.readLine()) != null) {
      M++;
      String[] items = line.split("");
      N = items.length;
    }
    br.close();

    char[][] maze = new char[M][N];

    // Initialize start point and read maze
    obj.readMaze(mazeFile, maze, start);

    // Print maze
    obj.printMaze(maze);

    // Get goals for the start state
    start.goals = obj.goals(maze);

    // Run A star search
    obj.astar(maze);
  }
  // jai mata di
  private void astar(char[][] maze) {
    // HashMap for storing frontier for efficient search
    int nodes_expanded = 0;
    HashMap<PacPoint, Integer> map = new HashMap<PacPoint, Integer>();
    PriorityQueue<PacPoint> frontier = new PriorityQueue<PacPoint>();
    frontier.add(start);
    map.put(start, getFunctionValue(start));
    int M = maze.length;
    int N = maze[0].length;

    while (!frontier.isEmpty()) {
      PacPoint current = frontier.remove();
      map.remove(current);
      // check if it is a .

      // check if you have reached a goal
      if (checkGoal(current)) {
        System.out.println("Reached The Goal !!");
        System.out.println("Number of Nodes Expanded : " + nodes_expanded);
        print_solution(current, maze);
        return;
      }

      nodes_expanded++;

      // Move Right
      if (current.p.y + 1 < N && current.p.x < M && maze[current.p.x][current.p.y + 1] != '%') {
        PacPoint next = new PacPoint(current.p.x, current.p.y + 1);

        // copy goals from current
        for (int i = 0; i < current.goals.size(); i++) {
          next.goals.add(current.goals.get(i));
        }

        if (next.goals.contains(next.p)) next.goals.remove(next.p);

        boolean shouldAdd = true;
        next.parent = current;
        next.pathCost = current.pathCost + 1;
        next.heuristic = computeHeuristic(next.p, current.goals);

        if (checkIfExistsHigherCost(next, map)) {
          frontier.remove(next);
          map.remove(next);
        } else if (checkIfExistsLowerCost(next, map)) {
          shouldAdd = false;
        }

        if (shouldAdd) {
          frontier.add(next);
          map.put(next, getFunctionValue(next));
        }
      }

      // Move Left
      if (current.p.y - 1 >= 0 && current.p.x < M && maze[current.p.x][current.p.y - 1] != '%') {
        PacPoint next = new PacPoint(current.p.x, current.p.y - 1);

        // copy goals from current
        for (int i = 0; i < current.goals.size(); i++) {
          next.goals.add(current.goals.get(i));
        }

        if (next.goals.contains(next.p)) next.goals.remove(next.p);

        boolean shouldAdd = true;
        next.parent = current;
        next.pathCost = current.pathCost + 1;
        next.heuristic = computeHeuristic(next.p, current.goals);

        if (checkIfExistsHigherCost(next, map)) {
          frontier.remove(next);
          map.remove(next);
        } else if (checkIfExistsLowerCost(next, map)) {
          shouldAdd = false;
        }

        if (shouldAdd) {
          frontier.add(next);
          map.put(next, getFunctionValue(next));
        }
      }

      // Move Up
      if (current.p.x - 1 >= 0 && current.p.y < N && maze[current.p.x - 1][current.p.y] != '%') {
        PacPoint next = new PacPoint(current.p.x - 1, current.p.y);

        // copy goals from current
        for (int i = 0; i < current.goals.size(); i++) {
          next.goals.add(current.goals.get(i));
        }

        if (next.goals.contains(next.p)) next.goals.remove(next.p);

        boolean shouldAdd = true;
        next.parent = current;
        next.pathCost = current.pathCost + 1;
        next.heuristic = computeHeuristic(next.p, current.goals);

        if (checkIfExistsHigherCost(next, map)) {
          frontier.remove(next);
          map.remove(next);
        } else if (checkIfExistsLowerCost(next, map)) {
          shouldAdd = false;
        }

        if (shouldAdd) {
          frontier.add(next);
          map.put(next, getFunctionValue(next));
        }
      }

      // Move down
      if (current.p.x + 1 < M && current.p.y < N && maze[current.p.x + 1][current.p.y] != '%') {
        PacPoint next = new PacPoint(current.p.x + 1, current.p.y);

        // copy goals from current
        for (int i = 0; i < current.goals.size(); i++) {
          next.goals.add(current.goals.get(i));
        }

        if (next.goals.contains(next.p)) next.goals.remove(next.p);

        boolean shouldAdd = true;
        next.parent = current;
        next.pathCost = current.pathCost + 1;
        next.heuristic = computeHeuristic(next.p, current.goals);

        if (checkIfExistsHigherCost(next, map)) {
          frontier.remove(next);
          map.remove(next);
        } else if (checkIfExistsLowerCost(next, map)) {
          shouldAdd = false;
        }

        if (shouldAdd) {
          frontier.add(next);
          map.put(next, getFunctionValue(next));
        }
      }
    }
  }