DEV Community

Cover image for One way to make wordle using Javascript
ozboware
ozboware

Posted on • Edited on

One way to make wordle using Javascript

Wordle has been gaining quite the following over the last couple of weeks. For those not yet in the know, Wordle is a game where you have 6 tries to guess a five letter word. The word is the same for everyone and only changes once a day. If a letter within your guess is a part of the original word, then the letter is highlighted orange, if it's in the same position of the daily word then it's highlighted green. Letters which aren't a part of the daily word are highlighted grey. You have a choice of using a keyboard or the keyboard printed on the screen to place your letters, each of which will highlight depending on whether or not each letter is in the word.

So I decided to make a version of it myself with some differences. In this version, words will be generated randomly with each play so the game can go on for as many plays as you like throughout the day. The list of available words will also be increased to include nearly 13,000 words as an oppose to the nearly 3,000 Wordle uses, however, for the purposes of this entry and to save space, I'll keep the word count down to just 5 but the full version can be downloaded from Github.

Okay, so let's begin.

First we'll set some variables in Javascript

let wordlist = ['ALPHA', 'GAMMA', 'DELTA', 'NINJA', 'SKILL'];
let currentRow = 0;
let nextRowBlock = 0;
let score = 0;
let remNotification = 0;
let gameFin = 0;
let keyPress;
let restart;
let restart2;
let enterClick;
let deleteClick;
let objArray = []
const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
Enter fullscreen mode Exit fullscreen mode

All of these are going to come into play throughout the script. countOccurences there is used to count the number of times a character shows in an array, I've used this to ensure the correct number of letters are highlighted grey, orange and green. The wordlist is only there for the purposes of this entry, in the full game I've placed the in a separate JS file.

Next, I added a container

let container = document.createElement('div');
container.id = 'container';
document.body.append(container);
Enter fullscreen mode Exit fullscreen mode

added in some style for the body and container

html, body{
    margin:0 auto;
    padding:0;
    width:100%;
    height:100%;
    overflow:hidden;
    font-family: fantasy;
}

#container{
    width: 100%;
    max-width: 600px;
    margin: 0 auto;
    height: 100%;
    display: flex;
    flex-direction: column;
    border-left: 1px solid;
    border-right: 1px solid;
}
Enter fullscreen mode Exit fullscreen mode

and called upon the gameStart function in Javascript we're about to create

gameStart();
Enter fullscreen mode Exit fullscreen mode

Next, we begin on the gameStart function which looks like this:

function gameStart(){
    container.innerHTML = '';
    gameFin = 0;
    currentRow = 0;
    nextRowBlock = 0;
    score = 0;
    remNotification = 0;
        let wordlist = ['ALPHA', 'GAMMA', 'DELTA', 'NINJA', 'SKILL'];
    let rand = Math.floor(Math.random() * wordlist.length);
    chosenWord = wordlist[rand];

    let logo = document.createElement('div');
    logo.className = 'logo';

    let domName = 'WORDLED';
    for(i = 0; i < domName.length; i++){
        let spanClass = (i == 0 || i % 2 == 0)? 'logo_green' : 'logo_gold';
        let logoSpan = document.createElement('span');
        logoSpan.className = spanClass;
        logoSpan.innerText = domName[i];
        logo.append(logoSpan);
    }

    container.append(logo);

    let navBar = document.createElement('div');
    navBar.className = 'nav_bar';
        let giveUpBtn = document.createElement('button');
        giveUpBtn.id = 'giveUpBtn';
        giveUpBtn.innerText = 'Give up';
        giveUpBtn.addEventListener("click", function quitClick(event) {
            if(gameFin == 0){
                notification.innerText = 'The word was ' + chosenWord + '. Press Enter to play again';
                gameOver();
            }
        });
    navBar.append(giveUpBtn);
    container.append(navBar);

    let gameArea = document.createElement('div');
    gameArea.className = 'game_area';
    for(i = 0; i < 6; i++){
        let row = document.createElement('div');
        row.className = 'row';
        for(j = 0; j < 5; j++){
            let rowBlock = document.createElement('div');
            rowBlock.className = 'row_block';
            row.append(rowBlock);
        }
        gameArea.append(row);
    }
    container.append(gameArea);

    let notification = document.createElement('div');
    notification.id = 'notification';
    notification.innerText = 'Start guessing!'
    container.append(notification);

    let keyLayoutTop = 'QWERTYUIOP';
    let keyLayoutMid = 'ASDFGHJKL';
    let keyLayoutBot = 'ZXCVBNM';

    let keyboard = document.createElement('div');
    keyboard.id = 'keyboard';

        let topKeys = document.createElement('div');
        topKeys.id = 'topKeys';
        addKeys(topKeys, keyLayoutTop, 'keyboardKey_s');
        keyboard.append(topKeys);

        let midKeys = document.createElement('div');
        midKeys.id = 'midKeys';
        addKeys(midKeys, keyLayoutMid, 'keyboardKey_m');
        keyboard.append(midKeys);

        let botKeys = document.createElement('div');
        botKeys.id = 'botKeys';
        let deleteKey = document.createElement('span');
        deleteKey.className = 'keyboardKey_l';
        deleteKey.innerHTML = '&#x2190;';
        deleteKey.addEventListener("click", function deleteClick(event) {
            if(gameFin == 0){
                let wordRow = document.getElementsByClassName('row')[currentRow];
                let rowBlockEl = wordRow.childNodes;
                deleteLetter(rowBlockEl);
            }
        });
        botKeys.append(deleteKey);
        addKeys(botKeys, keyLayoutBot, 'keyboardKey_s');
        let enterKey = document.createElement('span');
        enterKey.className = 'keyboardKey_l';
        enterKey.innerText = 'Enter';
        enterKey.addEventListener("click", enterClick = function(event) {
            if(gameFin == 0){
                let wordRow = document.getElementsByClassName('row')[currentRow];
                let rowBlockEl = wordRow.childNodes;
                submitWord(wordRow);
            }
        });
        botKeys.append(enterKey);
        keyboard.append(botKeys);

    container.append(keyboard);

    let alphabet = 'abcdefghijklmnopqrstuvwxyz';
    document.addEventListener('keyup', keyPress = function(event) {
        if(gameFin == 0){
            let wordRow = document.getElementsByClassName('row')[currentRow];
            let rowBlockEl = wordRow.childNodes;
            for(i = 0; i < alphabet.length; i++){
                if ((event.key === alphabet[i] || event.key === alphabet[i].toUpperCase())) {
                    addLetter(rowBlockEl, alphabet[i]);
                }
            }
            if (event.key === 'Enter') {
                submitWord(wordRow, keyPress);
            }
            if (event.key === 'Backspace') {
                deleteLetter(rowBlockEl);
            }
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

That's quite a bit to take in, so let's break down what the function is doing.

First, because the function also serves as a restart to the game, the container is emptied and the global variables are reset

container.innerHTML = '';
gameFin = 0;
currentRow = 0;
nextRowBlock = 0;
score = 0;
remNotification = 0;
Enter fullscreen mode Exit fullscreen mode

We then fetch a random number between 0 and the number of words in the list and use that to fetch a word from the list

let rand = Math.floor(Math.random() * wordlist.length);
chosenWord = wordlist[rand];
Enter fullscreen mode Exit fullscreen mode

Next, I placed in the logo which is basically just a word so there's no need for images here. I set the variable domName to the word I wanted to use and placed each letter within their own span so I could style them

let logo = document.createElement('div');
logo.className = 'logo';

let domName = 'WORDLED';
for(i = 0; i < domName.length; i++){
    let spanClass = (i == 0 || i % 2 == 0)? 'logo_green' : 'logo_gold';
    let logoSpan = document.createElement('span');
    logoSpan.className = spanClass;
    logoSpan.innerText = domName[i];
    logo.append(logoSpan);
}

container.append(logo);
Enter fullscreen mode Exit fullscreen mode

styling the logo

.logo{
    text-align: center;
    margin-top: 12px;
    cursor:pointer;
    text-shadow: 2px 3px 2px #000;
    transition:.5s
}

.logo:hover{
    filter: brightness(1.125);
}

.logo_green, .logo_gold{
    font-size: 26px;
    color: #fff;
    width: 49px;
    height: 35px;
    border-radius: 12px;
    margin: 3px;
    display: inline-block;
}

.logo_gold{
    background-color: #d7bf4a;
}

.logo_green{
    background-color: #35a535;
}
Enter fullscreen mode Exit fullscreen mode

Back to the JS, I then created the navBar area which currently only contains the give up button.

let navBar = document.createElement('div');
navBar.className = 'nav_bar';
    let giveUpBtn = document.createElement('button');
    giveUpBtn.id = 'giveUpBtn';
    giveUpBtn.innerText = 'Give up';
    giveUpBtn.addEventListener("click", function quitClick(event) {
        if(gameFin == 0){
            notification.innerText = 'The word was ' + chosenWord + '. Press Enter to play again';
            gameOver();
        }
    });
navBar.append(giveUpBtn);
container.append(navBar);
Enter fullscreen mode Exit fullscreen mode

Here, the give up button has a click event which calls on the gameOver function and changes the notification element to display the word of the play.

Then some more styling

.nav_bar{
    text-align: center;
    height: 33px;
    margin-top: 11px;
}

#giveUpBtn{
    padding: 5px 10px;
    font-size: 17px;
    cursor: pointer;
}
Enter fullscreen mode Exit fullscreen mode

Next we build the game area and the blocks/rows we'll be guessing within. 5 blocks x 6 rows

let gameArea = document.createElement('div');
gameArea.className = 'game_area';
for(i = 0; i < 6; i++){
    let row = document.createElement('div');
    row.className = 'row';
    for(j = 0; j < 5; j++){
        let rowBlock = document.createElement('div');
        rowBlock.className = 'row_block';
        row.append(rowBlock);
    }
    gameArea.append(row);
}
container.append(gameArea);
Enter fullscreen mode Exit fullscreen mode

and styled that

.game_area{
    margin-top:5px;
}

.row, .row_block{
    display: flex;
    justify-content: center;
    margin: 5px;
}

.row_block{
    font-size: 40px;
    border: 1px solid;
    width: 56px;
    height: 51px;
    border-radius: 12px;
}
Enter fullscreen mode Exit fullscreen mode

Next we add in the notification element

let notification = document.createElement('div');
notification.id = 'notification';
notification.innerText = 'Start guessing!'
container.append(notification);
Enter fullscreen mode Exit fullscreen mode

and its style

#notification{
    font-family: arial;
    text-align: center;
    letter-spacing: 1px;
    font-size: 19px;
    margin-top: 5px;
    margin-bottom: 5px;
    height: 22px;
}
Enter fullscreen mode Exit fullscreen mode

Then we add in the on screen keyboard

let keyLayoutTop = 'QWERTYUIOP';
let keyLayoutMid = 'ASDFGHJKL';
let keyLayoutBot = 'ZXCVBNM';

let keyboard = document.createElement('div');
keyboard.id = 'keyboard';

    let topKeys = document.createElement('div');
    topKeys.id = 'topKeys';
    addKeys(topKeys, keyLayoutTop, 'keyboardKey_s');
    keyboard.append(topKeys);

    let midKeys = document.createElement('div');
    midKeys.id = 'midKeys';
    addKeys(midKeys, keyLayoutMid, 'keyboardKey_m');
    keyboard.append(midKeys);

    let botKeys = document.createElement('div');
    botKeys.id = 'botKeys';
    let deleteKey = document.createElement('span');
    deleteKey.className = 'keyboardKey_l';
    deleteKey.innerHTML = '&#x2190;';
    deleteKey.addEventListener("click", function deleteClick(event) {
        if(gameFin == 0){
            let wordRow = document.getElementsByClassName('row')[currentRow];
            let rowBlockEl = wordRow.childNodes;
            deleteLetter(rowBlockEl);
        }
    });
    botKeys.append(deleteKey);
    addKeys(botKeys, keyLayoutBot, 'keyboardKey_s');
    let enterKey = document.createElement('span');
    enterKey.className = 'keyboardKey_l';
    enterKey.innerText = 'Enter';
    enterKey.addEventListener("click", enterClick = function(event) {
        if(gameFin == 0){
            let wordRow = document.getElementsByClassName('row')[currentRow];
            let rowBlockEl = wordRow.childNodes;
            submitWord(wordRow);
        }
    });
    botKeys.append(enterKey);
    keyboard.append(botKeys);

container.append(keyboard);
Enter fullscreen mode Exit fullscreen mode

Here, I separated the board into 3 different rows. I set variables for each row containing the letters in QWERTY order and inserted them using the addKeys function we will create shortly. The delete and enter keys were added in separately with each key coupled to their respective functions.

Styling for the keyboard

#keyboard{
    text-align:center;
    margin-top: 5px;
}

#topKeys, #midKeys, #botKeys{
    display: flex;
    justify-content:center;
}

.keyboardKey_s, .keyboardKey_m, .keyboardKey_l{
    background-color: #c5c5c5;
    font-size: 30px;
    height: 32px;
    padding: 5px 0;
    margin: 2.5px;
    display: flex;
    justify-content: center;
    font-family: arial;
    cursor: pointer;
}

.keyboardKey_s{
    width: 52px;
}

.keyboardKey_m{
    width: 58px;
}

.keyboardKey_l{
    width: 81px;
}
Enter fullscreen mode Exit fullscreen mode

The last thing to add to the stylesheet was the background colours for the tile change

.blockGreen{
    background-color: #35a535;
    color:#fff;
}

.blockGrey{
    background-color: #737373;
    color:#fff;
}

.blockGold{
    background-color: #d7bf4a;
    color:#fff;
}
Enter fullscreen mode Exit fullscreen mode

We won't need to add anything else to the stylesheet from here out. The rest is all Javascript.

Finally, back in the startGame function, I added the event listeners for keyboard use which basically runs through the alphabet, back space and enter and runs the respective function for each.

let alphabet = 'abcdefghijklmnopqrstuvwxyz';
document.addEventListener('keyup', keyPress = function(event) {
    if(gameFin == 0){
        let wordRow = document.getElementsByClassName('row')[currentRow];
        let rowBlockEl = wordRow.childNodes;
        for(i = 0; i < alphabet.length; i++){
            if ((event.key === alphabet[i] || event.key === alphabet[i].toUpperCase())) {
                addLetter(rowBlockEl, alphabet[i]);
            }
        }
        if (event.key === 'Enter') {
            submitWord(wordRow, keyPress);
        }
        if (event.key === 'Backspace') {
            deleteLetter(rowBlockEl);
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

And that's it for startGame. Next we'll add in the addKeys function which checks for a click on the on screen keyboard and runs the addLetter function we'll be creating shortly

function addKeys(el, layout, keyClass){
    for(i = 0; i < layout.length; i++){
        let j = i;
        let key = document.createElement('span');
        key.className = keyClass;
        key.id = 'keyboard_' + layout[i];
        key.innerText = layout[i];
        key.addEventListener("click", function keyboardPress(event) {
            if(gameFin == 0){
                let wordRow = document.getElementsByClassName('row')[currentRow];
                let rowBlockEl = wordRow.childNodes;
                addLetter(rowBlockEl, layout[j]);
            }
        });
        el.append(key);
    }
}
Enter fullscreen mode Exit fullscreen mode

Then we add in the addLetter function which clears the notification bar and adds a letter to each block in order. After adding a letter, it increases the nextRowBlock variable by 1. When this reaches 5, it prevents you from typing any more letters

function addLetter(rowBlockEl, letter){
    if(remNotification == 0){
        remNotification = 1;
        notification.innerText = '';
    }
    if(nextRowBlock < 5){
        rowBlockEl[nextRowBlock].innerText = letter.toUpperCase();
        nextRowBlock++;
    }
}
Enter fullscreen mode Exit fullscreen mode

Next we'll add in the deleteLetter function which does exactly what it says on the tin. It deletes the last letter on the row and reduces nextRowBlock by 1

function deleteLetter(rowBlockEl){
    if(nextRowBlock > 0){
        nextRowBlock--;
        rowBlockEl[nextRowBlock].innerText = '';
    }
}
Enter fullscreen mode Exit fullscreen mode

Next I added in a count function which counts the number of times a character appears in a string

function count(str, find) {
    return (str.split(find)).length - 1;
}
Enter fullscreen mode Exit fullscreen mode

Followed by the submitWord function

function submitWord(wordRow, keyPress){
    if(nextRowBlock > 0 && nextRowBlock % 5 == 0){
        let word = wordRow.innerText.replace(/[\n\r]/g, '');
        if(wordlist.includes(word)){
            let answer = [];
            for(i = 0; i < word.length; i++){
                let letter = word[i].toUpperCase();
                answer.push(letter);
                let blockClass = 'blockGrey';
                if(chosenWord.toUpperCase().includes(letter)){
                    if(chosenWord[i].toUpperCase() === letter){
                        score++;
                        blockClass = ' blockGreen';
                        if(count(word, letter) > count(chosenWord, letter)){
                            for(j = 0; j < wordRow.childNodes.length; j++){
                                if(wordRow.childNodes[j].innerText == letter && wordRow.childNodes[j].className == 'row_block  blockGold'){
                                    wordRow.childNodes[j].className = 'row_block  blockGrey';
                                    let index = answer.indexOf(letter);
                                    if (index !== -1) {
                                        answer.splice(index, 1);
                                    }
                                }
                            }
                        }
                    }else{
                        if(count(chosenWord, letter) > 0){
                            if(countOccurrences(answer, letter) <= count(chosenWord, letter)){
                                blockClass = ' blockGold';
                            }
                            else{
                                blockClass = ' blockGrey';
                            }
                        }
                    }
                }
                wordRow.childNodes[i].className = 'row_block ' + blockClass;
                let keyboard = document.getElementById('keyboard_' + letter);
                if(chosenWord.toUpperCase().includes(letter)){
                    keyboard.className += ' blockGreen';
                }
                else{
                    keyboard.className += ' blockGrey';
                }
            }

            if(score === 5){
                notification.innerText = 'Well done, you won! Enter to play again';
                gameOver();
            }
            else if(currentRow == 5){
                notification.innerText = 'You lost. The word was ' + chosenWord + '. Press Enter to play again';
                gameOver();
            }
            else{
                score = 0;
                nextRowBlock = 0;
                currentRow++;
            }
        }else{
            remNotification = 0;
            notification.innerText = 'Word not in list';
        }
    }else{
        remNotification = 0;
        notification.innerText = 'You must enter 5 characters';
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's break that function down to see what it does.

First we check to see if the row contains 5 letters by checking the nextRowBlock variable

if(nextRowBlock > 0 && nextRowBlock % 5 == 0){
Enter fullscreen mode Exit fullscreen mode

I then took the innerText of the wordRow element which is set on each call and removed all new lines

let word = wordRow.innerText.replace(/[\n\r]/g, '');
Enter fullscreen mode Exit fullscreen mode

I then checked to see if the word list contains the guess, ensuring the guess isn't just random letters typed in

if(wordlist.includes(word)){
Enter fullscreen mode Exit fullscreen mode

next we set an empty array variable to dump in each letter

let answer = [];
Enter fullscreen mode Exit fullscreen mode

followed by running through the guess, letter by letter

for(i = 0; i < word.length; i++){
Enter fullscreen mode Exit fullscreen mode

set a variable to contain the letter in uppercase so I didn't have to keep on typing word[i].toUpperCase()

let letter = word[i].toUpperCase();
Enter fullscreen mode Exit fullscreen mode

pushed each letter to the array

answer.push(letter);
Enter fullscreen mode Exit fullscreen mode

and set a variable for the blockClass which is going to change the background colour of the row block depending on whether or not the letter is in the word and in the correct place

let blockClass = 'blockGrey';
Enter fullscreen mode Exit fullscreen mode

Next I checked to see if the chosen word contains the letter

if(chosenWord.toUpperCase().includes(letter)){
Enter fullscreen mode Exit fullscreen mode

then checked to see if the current letter is in the same position as the chosen word

if(chosenWord[i].toUpperCase() === letter){
Enter fullscreen mode Exit fullscreen mode

if the letters are in equal positions, I increased the score by 1 and set blockClass to green, then checked to see if the guess contained more of the same letter than the chosen word

score++;
blockClass = ' blockGreen';
if(count(word, letter) > count(chosenWord, letter)){
Enter fullscreen mode Exit fullscreen mode

If the guess does contain more of the same letter, it iterates over the row's child elements, checks for all containing the same letter with the gold class, changes it to grey and removes the letter from the array we set earlier

for(j = 0; j < wordRow.childNodes.length; j++){
    if(wordRow.childNodes[j].innerText == letter && wordRow.childNodes[j].className == 'row_block  blockGold'){
        wordRow.childNodes[j].className = 'row_block  blockGrey';
        let index = answer.indexOf(letter);
        if (index !== -1) {
            answer.splice(index, 1);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Next, if the current letter isn't in the same position as the letter in the chosen word, we count the number of times the letter has already appeared from the guess and if it's lower than or equal to the number of times it's in the chosen word, we highlight it gold, else we highlight it grey

else{
    if(countOccurrences(answer, letter) <= count(chosenWord, letter)){
        blockClass = ' blockGold';
    }
    else{
        blockClass = ' blockGrey';
    }
}
Enter fullscreen mode Exit fullscreen mode

Then we update the classes of the blocks in the row

wordRow.childNodes[i].className = 'row_block ' + blockClass;
Enter fullscreen mode Exit fullscreen mode

Next, we want to highlight the keyboard on the screen to let the player know which letters are and aren't a part of the word. First we set the element to a variable

let keyboard = document.getElementById('keyboard_' + letter);
Enter fullscreen mode Exit fullscreen mode

Then we check to see if the letter of the board is in the word. If it is we'll add a green class, else we add in a grey

if(chosenWord.toUpperCase().includes(letter)){
    keyboard.className += ' blockGreen';
}
else{
    keyboard.className += ' blockGrey';
}
Enter fullscreen mode Exit fullscreen mode

Next we check out the score. If it equals 5, the player has guessed the word, the notification gets set with a congratulations and gameOver is called

if(score === 5){
    notification.innerText = 'Well done, you won! Enter to play again';
    gameOver();
}
Enter fullscreen mode Exit fullscreen mode

else if the player is on the last row, the player has lost, the notification set and game over is called

else if(currentRow == 5){
    notification.innerText = 'You lost. The word was ' + chosenWord + '. Press Enter to play again';
    gameOver();
}
Enter fullscreen mode Exit fullscreen mode

else the score is reset and the player moves onto the next try

else{
    score = 0;
    nextRowBlock = 0;
    currentRow++;
}
Enter fullscreen mode Exit fullscreen mode

The next else statement is for if the word isn't in the word list, in which case remNotification is set to 0 and the notification lets the player know the word doesn't exist

else{
    remNotification = 0;
    notification.innerText = 'Word not in list';
}
Enter fullscreen mode Exit fullscreen mode

and the final else statement is in case the player didn't enter 5 characters, in which case a warning pops up in the notifications

else{
    remNotification = 0;
    notification.innerText = 'You must enter 5 characters';
}
Enter fullscreen mode Exit fullscreen mode

Finally we add in the gameOver function which removes all event listeners, then changes the listener for the Enter key to start the game again

function gameOver(){
    gameFin = 1;
    document.removeEventListener('keyup', deleteClick, false);
    document.removeEventListener('keyup', enterClick, false);
    document.removeEventListener('keyup', keyPress, false);
    document.removeEventListener('keyup', restart, false);
    document.addEventListener('keyup', restart = function(event) {
        if (event.key === 'Enter') {
            document.removeEventListener('keyup', restart, false);
            gameStart();
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

And that's it. You should have a functioning Wordle based game that you can play whenever you like and something like this:

Wordled game board

The full game can be downloaded from Github here or it can be played online here

The full code:

Javascript

let wordlist = ['ALPHA', 'GAMMA', 'DELTA', 'NINJA', 'SKILL'];
let currentRow = 0;
let nextRowBlock = 0;
let score = 0;
let remNotification = 0;
let gameFin = 0;
let keyPress;
let restart;
let restart2;
let enterClick;
let deleteClick;
let objArray = []
const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);

let container = document.createElement('div');
container.id = 'container';
document.body.append(container);

gameStart();

function gameOver(){
    gameFin = 1;
    document.removeEventListener('keyup', deleteClick, false);
    document.removeEventListener('keyup', enterClick, false);
    document.removeEventListener('keyup', keyPress, false);
    document.removeEventListener('keyup', restart, false);
    document.addEventListener('keyup', restart = function(event) {
        if (event.key === 'Enter') {
            document.removeEventListener('keyup', restart, false);
            gameStart();
        }
    });
}

function gameStart(){
    container.innerHTML = '';
    gameFin = 0;
    currentRow = 0;
    nextRowBlock = 0;
    score = 0;
    remNotification = 0;
    let rand = Math.floor(Math.random() * wordlist.length);
    chosenWord = wordlist[rand];

    let logo = document.createElement('div');
    logo.className = 'logo';

    let domName = 'WORDLED';
    for(i = 0; i < domName.length; i++){
        let spanClass = (i == 0 || i % 2 == 0)? 'logo_green' : 'logo_gold';
        let logoSpan = document.createElement('span');
        logoSpan.className = spanClass;
        logoSpan.innerText = domName[i];
        logo.append(logoSpan);
    }

    container.append(logo);

    let navBar = document.createElement('div');
    navBar.className = 'nav_bar';
        let giveUpBtn = document.createElement('button');
        giveUpBtn.id = 'giveUpBtn';
        giveUpBtn.innerText = 'Give up';
        giveUpBtn.addEventListener("click", function quitClick(event) {
            if(gameFin == 0){
                notification.innerText = 'The word was ' + chosenWord + '. Press Enter to play again';
                gameOver();
            }
        });
    navBar.append(giveUpBtn);
    container.append(navBar);

    let gameArea = document.createElement('div');
    gameArea.className = 'game_area';
    for(i = 0; i < 6; i++){
        let row = document.createElement('div');
        row.className = 'row';
        for(j = 0; j < 5; j++){
            let rowBlock = document.createElement('div');
            rowBlock.className = 'row_block';
            row.append(rowBlock);
        }
        gameArea.append(row);
    }
    container.append(gameArea);

    let notification = document.createElement('div');
    notification.id = 'notification';
    notification.innerText = 'Start guessing!'
    container.append(notification);

    let keyLayoutTop = 'QWERTYUIOP';
    let keyLayoutMid = 'ASDFGHJKL';
    let keyLayoutBot = 'ZXCVBNM';

    let keyboard = document.createElement('div');
    keyboard.id = 'keyboard';

        let topKeys = document.createElement('div');
        topKeys.id = 'topKeys';
        addKeys(topKeys, keyLayoutTop, 'keyboardKey_s');
        keyboard.append(topKeys);

        let midKeys = document.createElement('div');
        midKeys.id = 'midKeys';
        addKeys(midKeys, keyLayoutMid, 'keyboardKey_m');
        keyboard.append(midKeys);

        let botKeys = document.createElement('div');
        botKeys.id = 'botKeys';
        let deleteKey = document.createElement('span');
        deleteKey.className = 'keyboardKey_l';
        deleteKey.innerHTML = '&#x2190;';
        deleteKey.addEventListener("click", function deleteClick(event) {
            if(gameFin == 0){
                let wordRow = document.getElementsByClassName('row')[currentRow];
                let rowBlockEl = wordRow.childNodes;
                deleteLetter(rowBlockEl);
            }
        });
        botKeys.append(deleteKey);
        addKeys(botKeys, keyLayoutBot, 'keyboardKey_s');
        let enterKey = document.createElement('span');
        enterKey.className = 'keyboardKey_l';
        enterKey.innerText = 'Enter';
        enterKey.addEventListener("click", enterClick = function(event) {
            if(gameFin == 0){
                let wordRow = document.getElementsByClassName('row')[currentRow];
                let rowBlockEl = wordRow.childNodes;
                submitWord(wordRow);
            }
        });
        botKeys.append(enterKey);
        keyboard.append(botKeys);

    container.append(keyboard);

    let alphabet = 'abcdefghijklmnopqrstuvwxyz';
    document.addEventListener('keyup', keyPress = function(event) {
        if(gameFin == 0){
            let wordRow = document.getElementsByClassName('row')[currentRow];
            let rowBlockEl = wordRow.childNodes;
            for(i = 0; i < alphabet.length; i++){
                if ((event.key === alphabet[i] || event.key === alphabet[i].toUpperCase())) {
                    addLetter(rowBlockEl, alphabet[i]);
                }
            }
            if (event.key === 'Enter') {
                submitWord(wordRow, keyPress);
            }
            if (event.key === 'Backspace') {
                deleteLetter(rowBlockEl);
            }
        }
    });
}

function deleteLetter(rowBlockEl){
    if(nextRowBlock > 0){
        nextRowBlock--;
        rowBlockEl[nextRowBlock].innerText = '';
    }
}

function count(str, find) {
    return (str.split(find)).length - 1;
}

function submitWord(wordRow, keyPress){
    if(nextRowBlock > 0 && nextRowBlock % 5 == 0){
        let word = wordRow.innerText.replace(/[\n\r]/g, '');
        if(wordlist.includes(word)){
            let answer = [];
            for(i = 0; i < word.length; i++){
                let letter = word[i].toUpperCase();
                answer.push(letter);
                let blockClass = 'blockGrey';
                if(chosenWord.toUpperCase().includes(letter)){
                    if(chosenWord[i].toUpperCase() === letter){
                        score++;
                        blockClass = ' blockGreen';
                        if(count(word, letter) > count(chosenWord, letter)){
                            for(j = 0; j < wordRow.childNodes.length; j++){
                                if(wordRow.childNodes[j].innerText == letter && wordRow.childNodes[j].className == 'row_block  blockGold'){
                                    wordRow.childNodes[j].className = 'row_block  blockGrey';
                                    let index = answer.indexOf(letter);
                                    if (index !== -1) {
                                        answer.splice(index, 1);
                                    }
                                }
                            }
                        }
                    }else{
                        if(countOccurrences(answer, letter) <= count(chosenWord, letter)){
                            blockClass = ' blockGold';
                        }
                        else{
                            blockClass = ' blockGrey';
                        }
                    }
                }
                wordRow.childNodes[i].className = 'row_block ' + blockClass;
                let keyboard = document.getElementById('keyboard_' + letter);
                if(chosenWord.toUpperCase().includes(letter)){
                    keyboard.className += ' blockGreen';
                }
                else{
                    keyboard.className += ' blockGrey';
                }
            }

            if(score === 5){
                notification.innerText = 'Well done, you won! Enter to play again';
                gameOver();
            }
            else if(currentRow == 5){
                notification.innerText = 'You lost. The word was ' + chosenWord + '. Press Enter to play again';
                gameOver();
            }
            else{
                score = 0;
                nextRowBlock = 0;
                currentRow++;
            }
        }else{
            remNotification = 0;
            notification.innerText = 'Word not in list';
        }
    }else{
        remNotification = 0;
        notification.innerText = 'You must enter 5 characters';
    }
}

function addKeys(el, layout, keyClass){
    for(i = 0; i < layout.length; i++){
        let j = i;
        let key = document.createElement('span');
        key.className = keyClass;
        key.id = 'keyboard_' + layout[i];
        key.innerText = layout[i];
        key.addEventListener("click", function keyboardPress(event) {
            if(gameFin == 0){
                let wordRow = document.getElementsByClassName('row')[currentRow];
                let rowBlockEl = wordRow.childNodes;
                addLetter(rowBlockEl, layout[j]);
            }
        });
        el.append(key);
    }
}

function addLetter(rowBlockEl, letter){
    if(remNotification == 0){
        remNotification = 1;
        notification.innerText = '';
    }
    if(nextRowBlock < 5){
        rowBlockEl[nextRowBlock].innerText = letter.toUpperCase();
        nextRowBlock++;
    }
}
Enter fullscreen mode Exit fullscreen mode

CSS

html, body{
    margin:0 auto;
    padding:0;
    width:100%;
    height:100%;
    overflow:hidden;
    font-family: fantasy;
}

#container{
    width: 100%;
    max-width: 600px;
    margin: 0 auto;
    height: 100%;
    display: flex;
    flex-direction: column;
    border-left: 1px solid;
    border-right: 1px solid;
}

.logo{
    text-align: center;
    margin-top: 12px;
    cursor:pointer;
    text-shadow: 2px 3px 2px #000;
    transition:.5s
}

.logo:hover{
    filter: brightness(1.125);
}

.logo_green, .logo_gold{
    font-size: 26px;
    color: #fff;
    width: 49px;
    height: 35px;
    border-radius: 12px;
    margin: 3px;
    display: inline-block;
}

.logo_gold{
    background-color: #d7bf4a;
}

.logo_green{
    background-color: #35a535;
}

.nav_bar{
    text-align: center;
    height: 33px;
    margin-top: 11px;
}

#giveUpBtn{
    padding: 5px 10px;
    font-size: 17px;
    cursor: pointer;
}

.game_area{
    margin-top:5px;
}

.row, .row_block{
    display: flex;
    justify-content: center;
    margin: 5px;
}

.row_block{
    font-size: 40px;
    border: 1px solid;
    width: 56px;
    height: 51px;
    border-radius: 12px;
}

#notification{
    font-family: arial;
    text-align: center;
    letter-spacing: 1px;
    font-size: 19px;
    margin-top: 5px;
    margin-bottom: 5px;
    height: 22px;
}

#keyboard{
    text-align:center;
    margin-top: 5px;
}

#topKeys, #midKeys, #botKeys{
    display: flex;
    justify-content:center;
}

.keyboardKey_s, .keyboardKey_m, .keyboardKey_l{
    background-color: #c5c5c5;
    font-size: 30px;
    height: 32px;
    padding: 5px 0;
    margin: 2.5px;
    display: flex;
    justify-content: center;
    font-family: arial;
    cursor: pointer;
}

.keyboardKey_s{
    width: 52px;
}

.keyboardKey_m{
    width: 58px;
}

.keyboardKey_l{
    width: 81px;
}


.blockGreen{
    background-color: #35a535;
    color:#fff;
}

.blockGrey{
    background-color: #737373;
    color:#fff;
}

.blockGold{
    background-color: #d7bf4a;
    color:#fff;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
jmacs profile image
MacLaren Scott

Dope!