1

I have written a Javascript program that solves a puzzle game using a recessive technique.

That is, function solvePuzzle() calls function solvePuzzle() for a simpler puzzle until the solution is found. It alters the data in the board object.

I also have a function board.draw() that can display the state of the puzzle

It draws the initial game board as I expect and once I click on a button (triggering execution of solvePuzzle()) it draws the solved game board again as I expect.

However, I would like to show the intermediate puzzle states.

Initially, I inserted calls to board.draw() in the solvePuzzle() function but this does not do anything.

Researching Javascript animation has led me to create and execute this function

function animationLoop(timestamp) {
    // 1 - Clear
    ctx.clearRect(0, 0, c.width, c.height);

    // 2 Draw
    board.draw();
    pieces.draw();

    // call again mainloop after 16.6 ms (60 frames/s)
    requestId = requestAnimationFrame(animationLoop);
}   

requestId = requestAnimationFrame(animationLoop);

I am confident this is working as this only place I now call board.draw() and it show the initial state and switches to show the solved state after I press the solve button but... still no intermediate states are shown.

I then hypothesised the issue was that solution was so quick that it happens between frames but discounted this by placing this 'delay' in solvePuzzle

    if (solutionCount%1000 == 0) {
        confirm("Are you sure you wish to continue?");
    };

I am now hypothesising solvePuzzle must run to completion before animationLoop can progress.

Is this hypothesis correct?

If so, how can I resolve my issue?

I am thinking I sort of need to continually end and resume my reclusive function at each state but cannot get my head around how I might do this.

Note: another reason I am confident the animation is working is that if I alter board from the console with say a statement like

board.layout[7].available = true;

the expected change is made to the display

1 Answer 1

1

JavaScript is single-threaded, and shares this thread with UI updates. Thus, when a function is started from top level, the browser does not do anything else until that function exits. This includes animation frame - animation is happening any time the page's thread is idle and an animation can be scheduled, but while your code is executing it can't.

If your calculation takes time, you need to split it into discrete pieces and let the browser breathe in between if you want UI updated (normally using setTimeout(f, 0), or inside requestAnimationFrame handler).

Another possibility is using Web Workers. They are a way to launch JavaScript in a separate thread. However, they cannot interact with the DOM at all, and can only communicate with messages. So, you can launch your calculation in a Web Worker, then from the worker periodically send messages to your main JS code in order to make it update the DOM in accordance to the results (both interim and final).

Thanks Alexander O'Mara and Kaiido for making me cover cases I forget.

Sign up to request clarification or add additional context in comments.

2 Comments

"you need to split it into discrete pieces..." ... or use a worker.
I don't see the point of using setTimeout if there are already rAF. What should be done, is indeed to split the calculations into pieces, but only call one iteration of the recursive function at each animation frame.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.