I have 2 slight issues with scoping in my function:
First is with scoping of the liberties argument. Everything goes fine until it reaches the main 'else' block when the variable gets reset when returning to a previous recursion. Putting liberties as a global variable fixes the problem, but that's not how it should be done...
the last return in the function gives undefined. Even though I can easily console.log those variables (they are correct in all cases, besides liberties if not global). I don't see any asynchronous behaviour here and it puzzles me how does it work.
function getGroup(position, board, visited = [], group = [], liberties = 0) {
let pointNotVisited = visited.reduce((acc, cur) => (cur.x !== position.x || cur.y !== position.y) && acc, true)
if (pointNotVisited) {
let neighbours = getNeighbours(position, board)
group.push(position)
visited.push(position)
let unvisitedNeighbours = neighbours.reduce((acc, cur) => {
let neighbourVisited = visited.filter(el => (el.x === cur.x && el.y === cur.y))
if (neighbourVisited.length > 0) {
return acc
} else {
return acc.concat(cur)
}
}, [])
unvisitedNeighbours.forEach(stone => {
if (stone.color == 'empty') {
liberties++
visited.push(stone)
} else if (stone.color != position.color) {
visited.push(stone)
}
return getGroup(stone, board, visited, group)
})
} else {
return {
'group': group,
'liberties': liberties
}
}
}
NOTE: position has a format of: { x: 1, y: 3, color: "white" }, board is used for the neighbours function. Let me know if you need any other info :) Please advice. Thanks in advance!
EDIT: Thanks to Jaromanda X I fixed the return value issue by:
unvisitedNeighbours.forEach(stone => {
if (stone.color == 'empty') {
liberties++
visited.push(stone)
// console.log('liberties after increment', liberties)
} else if (stone.color != position.color) {
visited.push(stone)
}
// console.log('liberties before recursion', liberties)
getGroup(stone, board, visited, group, liberties)
})
return {
"group": group,
"liberties": liberties
}
however the liberties scoping issue is still there
You can capture the
liberties
variable in a closure using an inner function rather than trying to pass it around. It would look something like this:Here
myInnerFn
should perform all the logic you have in yourgetGroups
, onlyliberties
has been moved out. You may want to consider moving out other variables too, I'm not sure you need to pass aroundboard
,visited
orgroup
once you have a closure. I'm also guessing thatvisited
andgroup
will no longer be needed as arguments of the outer function, they can be created as variables just likeliberties
.By using two functions we introduce an extra level to our variable scoping, allowing us to push the variable up out of the inner function without having to go all the way to global.