javascriptdomq-learning

Update DOM from loop in JavaScript


I am making a maze solver via Q Learning algorithm. I have a width X height maze that is generated randomly. Each cell of the maze is a div. I have CSS code for different type cells.

.wall {
        background-color: red;
}
.currentPosition {
        background-color: yellow;
}

I want to tell Q Learning briefly for those who don't know, basically our agent(or mouse, what do you call) changes its position very fastly until solve the maze.

enter image description here

I'm expecting a result like the gif above. I add 'currentPosition' to classlist of the cell where the agent is.

Here the my pseudo code:

trainAgent()

function trainAgent(){
    for(let i = 0; i < generation number(like 1000000); i++){
        while(until agent goes to the goal or walls){
            // Do some calculations
            // Update some numbers in q matrix
            // Change current position of agent and add 'currentPosition' class to the new div
        }
    }
}
function setCurrentPoint(row, column){
if(currentPoint.div)
currentPoint.div.classList.remove("currentPoint")
currentPoint.row = row
currentPoint.column = column
currentPoint.div = mapMatrix[row][column]
currentPoint.div.classList.add('currentPoint')
}

My problem starts here. Until the loops finishes the browser freezes! So I can't see the instant position of agent. I tried add setTimeout() but nothing has changed. If I was doing this project in Java I would do them in separate threads but I don't know what can I do in JavaScript.


Solution

  • Maybe I don't understand your question but how I interpreted it you actually want to see every step of every process? Because then you need to dive in Async/Await. This is an example you can use in your code base. Here I create a simple 3x3 grid and I change the background color while looping.

    async function runner() {
      const elements = document.getElementsByClassName("tableItem");
      let color = "hotpink";
      for (let j = 0; j < 300; j++) {
        for (let i = 0; i < 9; i++) {
    
          const element = elements[i];
          window.requestAnimationFrame(() => {
            element.style.backgroundColor = color;
          } );
          await sleep();
        }
            color = getRandomColor();
      }
    }
    
    async function sleep() {
      return new Promise((resolve) => setTimeout(resolve, 300));
    }
    
    function getRandomColor() {
      var letters = '0123456789ABCDEF';
      var color = '#';
      for (var i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
      }
      return color;
    }
    .table {
      display: grid;
      grid-template-columns: repeat(3, 100px);
      grid-template-rows: repeat(3, 100px);
      gap: 10px;
    }
    
    .table div {
      background-color: red;
    
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    
      <link rel="stylesheet" href="./test.css">
      <script src="./test.js"></script>
    </head>
    <body onload="runner()">
    
      <div class="table">
        <div class="tableItem"></div>
        <div class="tableItem"></div>
        <div class="tableItem"></div>
        <div class="tableItem"></div>
        <div class="tableItem"></div>
        <div class="tableItem"></div>
        <div class="tableItem"></div>
        <div class="tableItem"></div>
        <div class="tableItem"></div>
      </div>
      
    </body>
    </html>

    The sleep function is just to simulate calculations and to show the step after the change. Without the Async/Await you will see a white page and after everything is done then you see the last color.