Checkmating with a queen

Details

Author:Mark
Rating:
Difficulty:Beginner
Date:3rd January 2021
Description:In this lesson we learn how to checkmate using only a king and a queen to push the opponents king to a corner.

Code

//Please feel welcome to copy this code for your own creations.
fromFen("8/8/8/4k3/8/8/2Q5/1K6 w - - 0 1");

var steps = [];
steps.push(function () {
    info("The easiest way to checkmate using only a king and queen is to use our queen to push the opponents king to a corner.");
    showNextButton(true);
});

let queen = "c2";
let ourKing = "b1";
let theirKing = "e5";

steps.push(function () {
    info("We do this by always keeping a \"Knight's Distance\" away from the opponents king.\
   <br>Play Qc4 or Qd3 to continue.");

    let kingSqDistance = squareDistance(theirKing, "h8");

    onPieceClicked(function (squareName) {
        if (squareName == queen) {
            return true;
        }

        highlightSquareRed(squareName);
        return false;
    });

    onMoveAttempted(function (san) {
        if(sourceOfSan(san) != queen) {
            return false;
        }

        if (squareDistance(theirKing, destOfSan(san)) != 5) {
            return false;
        }

        queen = destOfSan(san);

        setTimeout(function () {
            for (let move of getPossibleMoves(theirKing)) {
                if (squareDistance(destOfSan(move), "h8") < kingSqDistance) {
                    theirKing = destOfSan(move);
                    performMove(move);
                    break;
                }
            }

            if(theirKing == "h8") {
                next();
                return;
            }

            setTimeout(function () {
                let possible = [];
                for (let move of getPossibleMoves(queen)) {
                    if (squareDistance(theirKing, destOfSan(move)) == 5) {
                        if(isCloser(theirKing, destOfSan(move), "h8")) {
                            possible.push(move);
                        }
                    }
                }
                switch(possible.length)
                {
                    case 1:
                        info("Play " + possible[0] + " to continue");
                        break;
                    case 2:
                        info("Play " + possible[0] + " or " + possible[1] + " to continue");
                        break;
                    default:
                        throw new Error();
                }
            }, 250);
        }, 300);

        return true;
    });
});

function isCloser(first, second, dest) {
    let manhattan1 = manhattanDistance(first, dest);
    let manhattan2 = manhattanDistance(second, dest);
    
    return manhattan1[0] <= manhattan2[0] && manhattan1[1] < manhattan2[1];
}

steps.push(function() {
    info("Next we move our king to backup the queen\
    <br>Move the king to f6 to continue.");

    onPieceClicked(function (squareName) {
        if (squareName == ourKing) {
            return true;
        }

        highlightSquareRed(squareName);
        return false;
    });

    onMoveAttempted(function (san) {
        if(sourceOfSan(san) != ourKing) {
            return false;
        }

        if(destOfSan(san) == "f6") {
            nextDelayed();
        }
        
        setTimeout(function() {
            let move = getPossibleMoves(theirKing)[0];
            theirKing = destOfSan(move);
            performMove(move);
        }, 200);

        ourKing = destOfSan(san);
        return true;
    });
});

steps.push(function() {
    info("Finally we move our queen to g7 for checkmate");

    onPieceClicked(function (squareName) {
        if (squareName == queen) {
            return true;
        }

        highlightSquareRed(squareName);
        return false;
    });

    onMoveAttempted(function (san) {
        if(sourceOfSan(san) != queen) {
            return false;
        }

        if(destOfSan(san) == "g7") {
            nextDelayed();
        }
        
        return true;
    });
});

steps.push(function() {
    info("Checkmate");
    complete();
});

onNextClicked(function () {
    showNextButton(false);
    next();
});

function nextDelayed() {
    setTimeout(next, 400);
}

function next() {
    if (steps.length > 0) {
        //remove the first function from the array and call it
        steps.shift()();
    }
}

next();