What causes this event handler to keep running?, and why does it halt when I try to add a condition?

122 views Asked by At

I'm making a chess opening trainer. I have a working game using cm-chessboard based on an example, and I'm using an API to get the computer's moves. I have condensed my code and removed this API so it's easier to read. In this version, the computer makes random moves from all valid chess moves.

The idea is, the API gets the best move, and then the player tries to input that move by moving a piece. If the player is correct, the computer moves for their next go, but if the player incorrectly guesses the best move, they are told 'Incorrect!' and are able to try again.

However, my code works fine when they are correct, but breaks when they are incorrect.

Here's what I have done:

<!-- Condensed Version -->     

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Chess Opening Trainer</title>
    <meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0"/>
    <link rel="stylesheet" href="https://alftheelf.github.io/Chess-Trainer/cm-chessboard/styles/cm-chessboard.css"/> 
    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500&display=swap" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.2/chess.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

</head>
<body>

<div class="board" id="board" style="width: 800px; max-width: 800px;"></div>

<script type="text/javascript">

function getBestMove(fen){
    //This function has been simplified
    var bestMove = "e5"
    return bestMove
}

</script>

<script type="module">

    var DATA;

    var side = 'black' //select which side to play as


    
    import {INPUT_EVENT_TYPE, COLOR, Chessboard, MARKER_TYPE} from "https://alftheelf.github.io/Chess-Trainer/cm-chessboard/src/cm-chessboard/Chessboard.js"
    import {BORDER_TYPE} from "https://alftheelf.github.io/Chess-Trainer/cm-chessboard/src/cm-chessboard/Chessboard.js"


    const chess = new Chess() //Creates a new Chess() object. Add a FEN string as an argument to start from a paticular FEN.

    function inputHandler(event) {
        console.log("event", event)
        event.chessboard.removeMarkers(undefined, MARKER_TYPE.dot)


        //Before move. Clicking about, and showing dot for possible moves and such.
        if (event.type === INPUT_EVENT_TYPE.moveStart) {
            const moves = chess.moves({square: event.square, verbose: true});
            for (const move of moves) {
                event.chessboard.addMarker(move.to, MARKER_TYPE.dot)
            }
            return moves.length > 0

        //Here is once a move has been attempted    
        } else if (event.type === INPUT_EVENT_TYPE.moveDone) {
            const move = {from: event.squareFrom, to: event.squareTo} //gets which move was attempted from event
            const result = chess.move(move) //gets result of move

            var correctAnswer = getBestMove(chess.fen());

            if (result.san == correctAnswer){console.log('correct!')}else{console.log('Incorrect!')}

            //Makes moves for the player
            if (result && result.san == correctAnswer) {

                event.chessboard.disableMoveInput()
                event.chessboard.setPosition(chess.fen())

                //Makes moves for the computer
                const possibleMoves = chess.moves({verbose: true})
                if (possibleMoves.length > 0) {
                    const randomIndex = Math.floor(Math.random() * possibleMoves.length)
                    const randomMove = possibleMoves[randomIndex]
                    setTimeout(() => { // smoother with 500ms delay
                        chess.move({from: randomMove.from, to: randomMove.to})
                        if(side === 'white') {
                            event.chessboard.enableMoveInput(inputHandler, COLOR.white)
                        }
                        else {
                            event.chessboard.enableMoveInput(inputHandler, COLOR.black)
                        }
                        event.chessboard.setPosition(chess.fen())
                    }, 500)
                }
            } else { //If result returns null, then we will loop back to the begining of the function to have another go.
                console.warn("invalid move", move)
            }
            return result
        }
    }


    if (side == 'white'){
        const board = new Chessboard(document.getElementById("board"), {
            position: chess.fen(),
            sprite: {url: "https://alftheelf.github.io/Chess-Trainer/cm-chessboard/assets/images/chessboard-sprite-staunty.svg"},
            style: {moveMarker: MARKER_TYPE.square, hoverMarker: undefined},
            orientation: COLOR.white
        })
        board.enableMoveInput(inputHandler, COLOR.white)
    }
    else{
        const board = new Chessboard(document.getElementById("board"), {
            position: chess.fen(),
            sprite: {url: "https://alftheelf.github.io/Chess-Trainer/cm-chessboard/assets/images/chessboard-sprite-staunty.svg"},
            style: {moveMarker: MARKER_TYPE.square, hoverMarker: undefined},
            orientation: COLOR.black
        })


        const possibleMoves = chess.moves({verbose: true})
        if (possibleMoves.length > 0) {
            const randomIndex = Math.floor(Math.random() * possibleMoves.length)
            const randomMove = possibleMoves[randomIndex]
            setTimeout(() => { // smoother with 500ms delay
                chess.move({from: randomMove.from, to: randomMove.to});                
                board.enableMoveInput(inputHandler, COLOR.black)
                board.setPosition(chess.fen())

            }, 500)
        }

    }

</script>
</body>
</html>

I've made a simple function, getBestMove(fen) to replace what the API would do to get the next best move. In this case I want the first move to be "pawn e5", after that, all moves will be incorrect, but it should allow me to keep trying to find the correct move instead of halting.

I'm not sure I'm understanding how this event loop repeats. At first I thought the function was being called with the line event.chessboard.enableMoveInput(inputHandler, COLOR.black) but after a while I realised that it still loops even if result == null and so I'm very confused.

I have live versions on Github you can check out to see it working (or not working):

I've tried this so many ways for the last couple of days. I think I'm missing something because this is the most advanced Javascript project I've ever done (I'm learning so much though).

I've tried debugging with a browser, but it's very confusing and I couldn't work anything out that way.

What do I need to do to get this working? What exactly is it in the original version that calls the function again so the player can play another move, but doesn't allow this in the edited version? I don't get it.

1

There are 1 answers

0
elite-robz On BEST ANSWER

I played around a bit and I was able to use this to get it to work. This is around line 90 of your code. It uses your code to check if the move is not the correct one and resets it back until you do the correct move

    else { //If result returns null, then we will loop back to the 
    //begining of the function to have another go.
        chess.undo();
        event.chessboard.setPosition(chess.fen());
         }