1
\$\begingroup\$

I'm working on a personal project to build a website that quizzes users on chess opening theory moves. I know my code is not very object-oriented but I am working on refactoring it right now. I just wanted to get the basics of it working before I started to restructure everything.

Here is the link to the repo to see all of the code. The website is live on Github pages if you want to try it out right now (I have not added anything to the Results section yet).

My question is how can I improve my JavaScript code to make it shorter for the menuJQeuryFunctions.js file? The file is over 1000 lines of just JQuery functions, there must be a way to truncate this code.

Here is a snippet of my HTML code:

        <div id="container">
            <div id="flex-div nav">
                <nav class="openings-menu">
                    <div class="text">Openings Menu</div>
                    <ul class="parent">
                        <li><a href="#" class="level-1-btn" id="kings-pawn-opening">King's Pawn Opening<span class="fas fa-angle-down kings-pawn-arrow"></span></a></li>
                            <ul class="level-2-class" id="kings-pawn-show">
                                <li><a href="#" class="level-2-btn" id="sicilian-defence">Sicilian Defence<span class="fas fa-angle-down"></a></li>
                                    <ul class="level-3-class" id="sicilian-defence-show">
                                        <li><a href="#" class="level-3-btn" id="open-sicilian">Open Sicilian<span class="fas fa-angle-down"></a></li>
                                            <ul class="level-4-class" id="open-sicilian-show">
                                                <li><a href="#" class="level-4-btn" id="najdorf-variation">Najdorf Variation<span class="fas fa-angle-down"</a></li>
                                                    <ul class="level-5-class" id="najdorf-variation-show">
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-classical">Classical Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-english">English Attack</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-lipnitzky">Lipnitzky Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-opocensky">Opocensky Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-amsterdam">Amsterdam Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-adams">Adams Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-argentine">Argentine Variation</a></li>
                                                    </ul>
                                                <li><a href="#" class="level-4-btn" id="dragon-variation">Dragon Variation<span class="fas fa-angle-down"></a></li>
                                                    <ul class="level-5-class" id="dragon-variation-show">
                                                        <li><a href="#" class="level-5-btn" id="dragon-positional">Positional Line</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-yugoslav">Yugoslav Attack</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-soltis">Soltis Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-classical">Classical Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-levenfish">Levenfish Attack</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-harrington-glek">Harrington-Glek Variation</a></li>

Here is what a snippet of my script.js code looks like. This code runs the main chess game after it knows what opening is selected.

let board = null
let $board = $('#board')
const game = new Chess()
let squareClass = 'square-55d63'
let squareToHighlight = null
let colorToHighlight = null
let $status = $('#status')
let $fen = $('#fen')
let $pgn = $('#pgn')
let variation = []
let attempt = []
let totalMoves = 0


// updates three variables which are the colour's turn, FEN, and PGN
// after each move is made and prints to the HTML tags
function updateStatus () {
    let status = ''
    let moveColor = 'White'

    if (game.turn() === 'b') {
        moveColor = 'Black'
    }

    // checkmate?
    if (game.in_checkmate()) {
        status = 'Game over, ' + moveColor + ' is in checkmate.'
    }

    // draw?
    else if (game.in_draw()) {
        status = 'Game over, drawn position'
    } else { // game still on
        status = moveColor + ' to move'

        // check?
        if (game.in_check()) {
          status += ', ' + moveColor + ' is in check'
        }
    }

    // update html id tags
    $status.html(status)
    $fen.html(game.fen())
    $pgn.html(game.pgn())
}

function removeHighlights (color) {
    $board.find('.' + squareClass).removeClass('highlight-' + color)
}

function onDragStart (source, piece, position, orientation) {
    // do not pick up pieces if the game is over
    if (game.game_over()) return false

    if (variation.length === 0) {
        if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
            (game.turn() === 'b' && piece.search(/^w/) !== -1)) {
            return false
        }
    } else {
        // only pick up pieces for White
        if (piece.search(/^b/) !== -1) return false
    }
}

function onDrop (source, target) {
    // see if the move is legal
    let move = game.move({
        from: source,
        to: target,

        // not necessary to have this i think
        // promotion: 'q' // NOTE: always promote to a queen for example simplicity
    })

    // illegal move
    if (move === null) return 'snapback'

    attempt = game.history()

    if (variation.length !== 0) {
        if (attempt[attempt.length-1] !== variation[attempt.length-1]) {
            game.undo()
        } else {
            // highlight white's move
            removeHighlights('white')
            removeHighlights('hint')
            $board.find('.square-' + source).addClass('highlight-white')
            $board.find('.square-' + target).addClass('highlight-white')

            // make random move for black
            window.setTimeout(makeBlackMove, 250)
        }
    } else {
        if (move.color === 'w') {
            removeHighlights("white")
            $board.find('.square-' + move.from).addClass('highlight-white')
            squareToHighlight = move.to
            colorToHighlight = 'white'
        }
        if (move.color === "b") {
            removeHighlights("black")
            $board.find('.square-' + move.from).addClass('highlight-black')
            squareToHighlight = move.to
            colorToHighlight = 'black'
        }
    }
    updateStatus()

}

function highlightSquare() {
    // will possibly use this later
}

function makeBlackMove() {
    game.move(variation[attempt.length])
    let blackMove = game.history({verbose: true})
    // console.log(blackMove)
    console.log(blackMove[attempt.length])

    // highlight black's move
    removeHighlights('black')
    $board.find('.square-' + blackMove[attempt.length].from).addClass('highlight-black')
    squareToHighlight = blackMove[attempt.length].to

    // update the board to the new position
    board.position(game.fen())

    attempt = game.history()
}

function onMoveEnd() {
    $board.find('.square-' + squareToHighlight).addClass('highlight-black')
    updateStatus()
}

// update the board position after the piece snap
// for castling, en passant, pawn promotion
function onSnapEnd() {
    if (variation.length === 0) {
        $board.find('.square-' + squareToHighlight).addClass('highlight-'+ colorToHighlight)
    }
    board.position(game.fen())
}

function showHint() {
    if (variation.length !== 0 && game.turn() === "w") {
        let hintSquare = game.move(variation[attempt.length])
        hintSquare = hintSquare.from
        $board.find('.' + squareClass).removeClass('highlight-hint')
        $board.find('.square-' + hintSquare).addClass('highlight-hint')
        game.undo()
    }
}

function flipBoard() {
    // NEED TO FIX PIECE HIGHLIGHTING WHEN FLIPPING THE BOARD
    if (board.orientation() === "white") {
        board.orientation("black")
        $board.find('.square-' + squareToHighlight).addClass('highlight-'+colorToHighlight)
    } else {
        board.orientation("white")
        $board.find('.square-' + squareToHighlight).addClass('highlight-'+colorToHighlight)
    }
}

function startGame() {
    let config = {
        draggable: true,
        position: 'start',
        onDragStart: onDragStart,
        onDrop: onDrop,
        onSnapEnd: onSnapEnd,
        onMoveEnd: onMoveEnd
    }
    variation = []
    attempt = []
    board = Chessboard('board', config)
    game.reset()
    updateStatus()
    totalMoves = 0
}

// this function is called after every move is made and updates the turn status,
// FEN and PGN
updateStatus()

// when page loads, initialize the chess board to the starting position
$(document).ready(startGame)

// when the reset button is pressed it resets the game state,
// and resets the status variables
$('#resetBtn').click(startGame)

$('#hintBtn').click(showHint)

$('#flipBoardBtn').click(flipBoard)

Lastly, here is the JQuery code for each time the menu item opening variation is clicked on. The fact that the code is over 1000 lines (but I'm only going to show a portion of it because it's very repetitive code) of just almost the same JQuery functions but with different opening variation names makes me think I can shorten it.

// openings menu scripts
$("#kings-pawn-opening").click(function() {
    $("#kings-pawn-show").toggleClass("show");
    // $("#kings-pawn-arrow").toggleClass("rotate");
});

// SICILIAN DEFENCE
$("#sicilian-defence").click(function() {
    $("#sicilian-defence-show").toggleClass("show");
});

$("#open-sicilian").click(function() {
    $("#open-sicilian-show").toggleClass("show");
});
$("#najdorf-variation").click(function() {
    $("#najdorf-variation-show").toggleClass("show");
});

$("#sicilian-najdorf-classical").click(function() {
    startGame()
    variation = sicilianNajdorfClassicalMainLine
    console.log(variation)
});

$("#sicilian-najdorf-english").click(function() {
    startGame()
    variation = sicilianNajdorfEnglishAttack
    console.log(variation)
});

$("#sicilian-najdorf-lipnitzky").click(function() {
    startGame()
    variation = sicilianNajdorfLipnitzkyAttack
    console.log(variation)
});
$("#sicilian-najdorf-opocensky").click(function() {
    startGame()
    variation = sicilianNajdorfOpocensky
    console.log(variation)
});
$("#sicilian-najdorf-amsterdam").click(function() {
    startGame()
    variation = sicilianNajdorfAmsterdam
    console.log(variation)
});

Here is a snippet of the chess opening variation arrays that I am using:



// ----------------------- OPEN SICILIAN -----------------------
// sicilian najdorf 
const sicilianNajdorfClassicalMainLine = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Bg5", "e6", "f4", "Be7", "Qf3", "Qc7", "O-O-O", "Nbd7", "g4"]
const sicilianNajdorfArgentine = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Bg5", "e6", "f4", "Be7", "Qf3", "Qc7", "h6", "Bh4", "g5", "fxg5", "Nfd7"] // maybe not include this one
const sicilianNajdorfEnglishAttack = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Be3", "e5", "Nb3", "Be6", "f3"]
const sicilianNajdorfLipnitzkyAttack = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Bc4", "e6", "Bb3", "b5"]
const sicilianNajdorfOpocensky = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Be2", "e6"] // maybe not include this one
const sicilianNajdorfAmsterdam = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "f4", "e5", "Nf3", "Nbd7", "a4", "Be7", "Bd3", "O-O"]
const sicilianNajdorfAdams = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "h3", "e5", "Nde2", "h5"]

// sicilian dragon 
const sicilianDragonPositional = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'g6', 'Be3', 'Bg7', 'f3', 'O-O', 'Qd2', 'Nc6', 'O-O-O']
const sicilianDragonYugoslav = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "g6", "Be3", "Bg7", "f3", "O-O", "Qd2", "Nc6", "Bc4", "Bd7", "O-O-O", "Rc8", "Bb3", "Ne5", "h4", "Nc4", "Bxc4", "Rxc4", "h5", "Nxh5", "g4", "Nf6", "Bh6"]
const sicilianDragonSoltis = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'g6', 'Be3', 'Bg7', 'f3', 'O-O', 'Qd2', 'Nc6', 'Bc4', 'Bd7', 'O-O-O', 'Rc8', 'Bb3', 'Ne5', 'h4', 'h5']
const sicilianDragonClassical = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "g6", "Be2", "Bg7", "Be3", "Nc6", "O-O", "O-O", "Nb3", "d5"]
const sicilianDragonLevenfish = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "g6", "f4", "Nc6", "e5"]
const sicilianDragonHarrington = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'g6', 'Be3', 'Bg7', 'Be2', 'O-O', 'Qd2', 'Nc6', 'O-O-O']

// sicilian classical
const sicilianRichter = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Bg5', 'e6', 'Qd2']
const sicilianFischerSozin = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Bc4', 'e6', 'Bb3', 'a6', 'O-O']
const sicilianVelimirovic = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Bc4', 'e6', 'Be3', 'Be7', 'Qe2']
const sicilianBoleslavsky = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Be2', 'e5', 'Nf3', 'h6', 'O-O', 'Be7', 'Re1', 'O-O', 'h3']
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Please check that I haven't misrepresented your code, and correct it if I have. \$\endgroup\$ Sep 30 at 7:57

Your Answer

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

Browse other questions tagged or ask your own question.