Calculate the f cost in A*(A-star) algorithm on coordinated undirected graph

I’m trying to implement A* algorithm in react.js but I’m quite stuck when it comes to implement the fScore function. I know that f=g+h where g is the gScore from the start node till the current node and h is the heuristic distance from the currentNode till the end node. I calculated the heuristic using the euclidean distance where I’m sending the coordinates of the current and End nodes but I don’t know how to calculate the gScore. Each node in my graph has: id, name, x, y, connectedToIds:[] //list of neihbours or connectedNodes. Update: I added the variables parentId, fscore, gscore, hscore to each node. So now each node has the variables : id, name, x, y, connectedToIds:[], fscore: 0, gscore: 0, hscore: 0, parentId: null. Update2: originLocationId is the id of the start node. destinationLocationId is the id of the end node. locations is a list of all nodes. my code:

export default class TurnByTurnComponent extends React.PureComponent {
    constructor(props) {
        super(props);
    }

    render() {
        const {
            destinationLocationId,
            locations,
            originLocationId
        } = this.props;
        console.log(locations)
        console.log(originLocationId)
        console.log(destinationLocationId)


        var openedList = [];
        var closedList = [];

        if (destinationLocationId != null && originLocationId != null) {
            openedList.push(originLocationId);
            while (openedList.length != 0) {
                var currentLoc = openedList[0]; //minFvalue
                const currIndex = openedList.indexOf(currentLoc);
                openedList.splice(currIndex, 1); //deleting currentNode from openedList
                closedList.push(currentLoc) //adding currentNode to closedList

                if (currentLoc == destinationLocationId) {
                    //return path
                }

                

            }

        }

        function heuristic(currentNode, endNode) { //euclidean distance
            var x = Math.pow(endNode.x - currentNode.x, 2);
            var y = Math.pow(endNode.y - currentNode.y, 2);
            var dist = Math.sqrt(x + y);
            return dist;
        }

        function gScore(startNode, currentNode) {

        }




        return (
            <div className="turn-by-turn-component">
                {locations.map(loc => (
                    <li key={loc.id}>
                        {loc.name}
                    </li>
                ))}

                <TodoList
                    title="Mandatory work"
                    list={[
                      
                    ]}
                />
                <TodoList
                    title="Optional work"
                    list={[
                      
                    ]}
                />
            </div>
        );
    }
}

TurnByTurnComponent.propTypes = {
    destinationLocationId: PropTypes.number,
    locations: PropTypes.arrayOf(PropTypes.shape({
        id: PropTypes.number.isRequired,
        name: PropTypes.string.isRequired,
        x: PropTypes.number.isRequired,
        y: PropTypes.number.isRequired,
        connectedToIds: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
    })),
    originLocationId: PropTypes.number
};

Update3: New version of my code

export default class TurnByTurnComponent extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = { shortestPath: [] }
    }


    render() {
        const {
            destinationLocationId,
            locations,
            originLocationId
        } = this.props;


        if (destinationLocationId != null && originLocationId != null) {

            if (originLocationId == destinationLocationId) { //check if the startNode node is the end node
                return originLocationId;
            }

            var openList = [];
            let startNode = getNodeById(originLocationId);
            let endNode = getNodeById(destinationLocationId)

            startNode.gcost = 0
            startNode.heuristic = manhattanDistance(startNode, endNode)
            startNode.fcost = startNode.gcost + startNode.heuristic;


            //start A*
            openList.push(startNode); //starting with the startNode 
            while (openList.length) {
                console.log("inside while")

                var currentNode = getNodeOfMinFscore(openList);

                if (currentIsEqualDistanation(currentNode)) {
                    var path = getPath(currentNode)
                    this.setState({
                        shortestPath: path,
                    });
                    return path //todo
                }
                deleteCurrentFromOpenList(currentNode, openList);

                for (let neighbourId of currentNode.connectedToIds) {

                    var neighbourNode = getNodeById(neighbourId);
                    var currentNodeGcost = currentNode.gcost + manhattanDistance(currentNode,         neighbourNode);
                    console.log(currentNodeGcost)
                    console.log(neighbourNode.gcost)
                    if (currentNodeGcost < neighbourNode.gcost) {
                        console.log("Helloooo")
                        neighbourNode.parentId = currentNode.id;
                        // keep track of the path
                        // total cost saved in neighbour.g
                        neighbourNode.gcost = currentNodeGcost;
                        neighbourNode.heuristic = manhattanDistance(neighbourNode, endNode);
                        neighbourNode.fcost = neighbourNode.gcost + neighbourNode.heuristic;
                        if (!openList.includes(neighbourId)) {
                            openList.push(neighbourNode);
                        }
                    }
                }
            }
            return null;
        }


        function deleteCurrentFromOpenList(currentNode, openList) {
            const currIndex = openList.indexOf(currentNode);
            openList.splice(currIndex, 1); //deleting currentNode from openList
        }

        function currentIsEqualDistanation(currentNode) {
            //check if we reached out the distanation node
            return (currentNode.id == destinationLocationId)
        }

        function getNodeById(id) {
            var node;
            for (let i = 0; i < locations.length; i++) {
                if (locations[i].id == id) {
                    node = locations[i]
                }
            }
            return node
        }

        function getPath(endNode) {
            var path = []
            while (endNode.parentId) {
                path.push(endNode.name)
                endNode = endNode.parentId;
            }
            return path;
        }

        function getNodeOfMinFscore(openList) {
            var minFscore = openList[0].fcost; //initValue
            var nodeOfminFscore;
            for (let i = 0; i < openList.length; i++) {

                if (openList[i].fcost <= minFscore) {

                    minFscore = openList[i].fcost //minFvalue
                    nodeOfminFscore = openList[i]
                }
            }

            return nodeOfminFscore
        }

        //manhattan distance is for heuristic and gScore. Here I use Manhattan instead of Euclidean 
        //because in this example we dont have diagnosal path.
        function manhattanDistance(startNode, endNode) {
            var x = Math.abs(endNode.x - startNode.x);
            var y = Math.abs(endNode.y - startNode.y);
            var dist = x + y;
            return dist;
        }


        return (
            <div className="turn-by-turn-component">
                {locations.map(loc => (
                    <li key={loc.id}>
                        {JSON.stringify(loc.name)},
                    </li>
                ))}
                <TodoList
                    title="Mandatory work"
                    list={
                        this.state.shortestPath
                    }
                />
                <TodoList
                    title="Optional work"
                    list={[

                    ]}
                />
            </div>
        );
    }
}

TurnByTurnComponent.propTypes = {
    destinationLocationId: PropTypes.number,
    locations: PropTypes.arrayOf(PropTypes.shape({
        id: PropTypes.number.isRequired,
        name: PropTypes.string.isRequired,
        x: PropTypes.number.isRequired,
        y: PropTypes.number.isRequired,
        connectedToIds: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
    })),
    originLocationId: PropTypes.number
};

Answer

While h is the heuristic, a plausible guess of the possible cost it will be needed to reach the end node, g is the actual cost spent to reach the current node. In your case it could be even the same euclidian distance you use for h.

In a real case scenario, using euclidian distance, a graph connecting different cities, h is the air-distance of two cities while g is their road-distance.

Furthermore, if you are using a monotonic heuristic (or an underestimating heuristic, such as the euclidian distance) you will not need the close list, since it is provent that the first found path will also be the shortest: longer or already visited paths will be dropped before being explored.

Probably what is confusing is the fact that you need to keep track of g during the exploration of the graph, while h just measure a straight line between current and end nodes, g measure all the lines between the nodes you explored to reach the current.

// h
function heuristic(n1, n2) {
    return Math.sqrt(
        Math.pow(n1.x - n2.x, 2) +
        Math.pow(n1.y - n2.y, 2)
    );
}
// g - actually is the same as h
const cost = heuristic;
function astar(start, end, graph, h, g) {
    if (start.id == end.id) { return [ start.id ] }

    // omitted CLEAN-UP of the graph

    // close is not needed with an optimistic heuristic 
    // so I've commented the "close" parts.
    // An optimistic heuristic works also if you decomment them

    // var close = [];
    var open  = [];

    start.g = 0;
    start.h = h(start, end);
    start.f = start.g + start.h;

    open.push(start);

    while (open.length) {
        // since open is sorted, by popping
        // the last element we take the cheapest node
        var curr = open.pop();

        if (curr == end) { return resolvePath(curr, graph); }
        // close.push(curr);
        for (let nid of curr.connectedToIds) {
            // if (close.some(n => n.id == nid)) { continue; }
            var neighbour = graph.find(n => n.id == nid);
            
            // HERE you compute and store
            // the current g of the node 
            var current_g = curr.g + g(curr, neighbour);

            var isBetter_g = false;
            var isInOpen = open.some(n => n.id == nid);

            // Some implementations skip this check 
            // because they assume that the cost function
            // is a non-negative distance.
            // if so you could check just the two nodes g
            // and insert the node if not already in the open set
            // because the default g of a node is 0
            if (!isInOpen) {
                // unexplored node, maybe we should explore it
                // later, so we add to the open set and
                // we update it with the current path cost
                open.push(neighbour)
                isBetter_g = true;
            }
            else if (current_g < neighbour.g) {
                // the current path is better than
                // those already explored, we need to 
                // update the neighbour with the current path cost
                isBetter_g = true;
            }
            if (isBetter_g) {
                // === path cost update ===

                // track current path
                neighbour.parent = curr.id;
           
                // HERE you keep track of the path
                // total cost saved in neighbour.g
                neighbour.g = current_g;
           
                // neighbour.h is redundant, can be stored directly in f
                // but keep it for debugging purpose
                neighbour.h = h(neighbour, end);

                neighbour.f = neighbour.g + neighbour.h;
                
                if (!isInOpen) {
                    // sorting makes the last element of
                    // open the cheapest node. We sort after
                    // the path cost update to ensure this property
                    open.sort((n1, n2) => n2.f - n1.f)
                }
            }
        }
    }

    // failure
    return []; // or return null
}
// utility to retrieve an array of ids
// from the tracked path
function resolvePath(end, graph) {
    let path = [ end.id ];
    while (end && end.parent >= 0) {
        path.unshift(end.parent);
        end = graph.find(n => n.id == end.parent);
    }
    return path;
}
// example of using the function
astar(startNode, endNode, locations, heuristic, cost);