0
\$\begingroup\$

I'm new to JS, React and functional programming and am trying to make the Game of Life in React. My cycle function looks like iterative sprawl but all my attempts to refactor have been equally bad. The full code is here.

Any recommendations to make the function more elegant or efficient or best practices tips?

cycle() {
    //a large array representing the grid with "X" for alive and "O" for dead
    let s = this.state.squares;
    let adjacents = [];
    let neighborCount = 0;
    let n = Math.sqrt(this.size);
    let births = [];
    let deaths = [];

    
    for (let i=0; i<s.length; i++) {

        //finds the eight neighboring squares for each square 
        adjacents.push(i-1, i+1, i-n-1, i-n, i-n+1, i+n-1, i+n, i+n+1);
        for (let j=0; j<adjacents.length; j++) {
            if (s[adjacents[j]] == "X") {
              neighborCount++;
            }
        }

        //determines if the central square will be born or die in this round
        if (s[i] == "O" && neighborCount == 3) {
          births.push(i);
        }
        else if ((s[i] == "X" && neighborCount < 2)
        || (s[i] == "X" && neighborCount > 3))
        {
          deaths.push(i);
        } 
        neighborCount = 0;
        adjacents = [];  
    }

    //the grid array updates after all births and deaths for the round have been computed
    for (let k=0; k<births.length; k++) {
      s[births[k]] = "X";
    }
      
    for (let k=0; k<deaths.length; k++) {
      s[deaths[k]] = "O";
    }

    births = [];
    deaths = [];

    this.setState({
    squares: s
    })
}

\$\endgroup\$
2
\$\begingroup\$

Functional Techniques

The post was tagged with but the example doesn't appear to make use of many functional-programming approaches.

You could use functional approaches when iterating over the states, like using Array.forEach(), Array.filter(), but bear in mind that each iteration involves calling a function so it won't be as efficient as using the for loops - especially considering that there are 4900 states!

For example, the loop starting with:

for (let i=0; i<s.length; i++) {
    //check adjacents to determine if death or birth
}

Could be rewritten as:

this.states.forEach(function(state, i) {
    //check adjacents to determine if death or birth
});

And this block:

for (let j=0; j<adjacents.length; j++) {
    if (s[adjacents[j]] == "X") {
        neighborCount++;
    }
}

Could be re-written utilizing Array.filter():

const neighborCount = adjacents.filter(function(adjacentIndex) {
    return s[adjacentIndex] == 'X';
  }).length;

which can eliminate the lines for initial assignment (i.e. let neighborCount = 0;) and re-assignment (i.e. neighborCount = 0;) at the end of each iteration. Note that const is used there because the value is not re-assigned (within the context of the loop).

These functional JS exercises are really helpful for those who want to learn more about using functional programming in JavaScript.

Single assignment for adjacent squares

Correct me if this leads to a difference in functionality but the array adjacents could be set with the following line:

const adjacents = [i-1, i+1, i-n-1, i-n, i-n+1, i+n-1, i+n, i+n+1];

That way it doesn't need to be re-assigned (and cleared after evaluating the neighbors) in every iteration (and the initial line let adjacents = []; can be removed from the start of cycle()).

\$\endgroup\$
  • \$\begingroup\$ Thanks! I wanted to use functional approaches and made a mess. \$\endgroup\$ – ashlynn Dec 11 '17 at 20:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.