Memory game with javascript - javascript

I have a small problem that could ruin the game. Once you click a card you need to search for the other card with the same picture right? but the problem is you can also double click and it will think you found the other card. Anyone know how o solf this problem?
const cards = document.querySelectorAll(".cards .card");
cards.forEach((card) => {
card.addEventListener("click", () => {
card.classList.add("clicked");
if (counter === 0) {
firstSelection = card.getAttribute("meme");
counter++;
} else {
secondSelection = card.getAttribute("meme");
counter = 0;
if (firstSelection === secondSelection) {
const correctCards = document.querySelectorAll(".card[meme='" + firstSelection + "']");
score.innerHTML = parseInt(score.innerHTML) + 1
if (score.innerHTML >= 8)
correctCards[0].classList.add("checked");
correctCards[0].classList.remove("clicked");
correctCards[1].classList.add("checked");
correctCards[1].classList.remove("clicked");
} else {
const incorrectCards = document.querySelectorAll(".card.clicked");
incorrectCards[0].classList.add("red");
incorrectCards[1].classList.add("red");
setTimeout(() => {
incorrectCards[0].classList.remove("red");
incorrectCards[0].classList.remove("clicked");
incorrectCards[1].classList.remove("red");
incorrectCards[1].classList.remove("clicked");
}, 600);
}
}
});
});

You can set 2 global vars firstClickedCard and secondClickedCard, and on click, assign the card element (event.currentTarget) to these variables. Then on second click, check if (secondClickedCard === firstClickedCard) before any of your other logic, and reject the click event if this is true.
This should verify if the actual clicked element (not just the meme attribute) are the same or not.
Note: this is untested, and would be easier to verify if your question included a minimal, reproducible example.
const cards = document.querySelectorAll(".cards .card");
var firstClickedCard;
var secondClickedCard;
cards.forEach((card) => {
card.addEventListener("click", (e) => {
card.classList.add("clicked");
if (counter === 0) {
firstClickedCard = e.currentTarget;
firstSelection = card.getAttribute("meme");
counter++;
} else {
secondClickedCard = e.currentTarget;
// reject this click
if (secondClickedCard === firstClickedCard) {
secondClickedCard = null;
return false;
}
secondSelection = card.getAttribute("meme");
counter = 0;
if (firstSelection === secondSelection) {
const correctCards = document.querySelectorAll(".card[meme='" + firstSelection + "']");
score.innerHTML = parseInt(score.innerHTML) + 1
if (score.innerHTML >= 8)
correctCards[0].classList.add("checked");
correctCards[0].classList.remove("clicked");
correctCards[1].classList.add("checked");
correctCards[1].classList.remove("clicked");
} else {
const incorrectCards = document.querySelectorAll(".card.clicked");
incorrectCards[0].classList.add("red");
incorrectCards[1].classList.add("red");
setTimeout(() => {
incorrectCards[0].classList.remove("red");
incorrectCards[0].classList.remove("clicked");
incorrectCards[1].classList.remove("red");
incorrectCards[1].classList.remove("clicked");
}, 600);
}
}
});
});

Although there is a double click event (dblclick), it is not supported by all browsers. The way around this is to test for double clicks within your click event handlers and use a timer function (to see if two clicks happened within a select amount of time). I use 300ms for the timer, but you may have to play around with that a bit.
const cards = document.querySelectorAll(".cards .card");
let clickCount = 0;
cards.forEach((card) => {
card.addEventListener("click", () => {
clickCount ++;
if (clickCount == 1) {
clickTimer = setTimeout(() => {
clickCount = 0;
//single click functionality here
card.classList.add("clicked");
if (counter === 0) {
firstSelection = card.getAttribute("meme");
counter++;
} else {
secondSelection = card.getAttribute("meme");
counter = 0;
if (firstSelection === secondSelection) {
const correctCards = document.querySelectorAll(".card[meme='" + firstSelection + "']");
score.innerHTML = parseInt(score.innerHTML) + 1
if (score.innerHTML >= 8)
correctCards[0].classList.add("checked");
correctCards[0].classList.remove("clicked");
correctCards[1].classList.add("checked");
correctCards[1].classList.remove("clicked");
} else {
const incorrectCards = document.querySelectorAll(".card.clicked");
incorrectCards[0].classList.add("red");
incorrectCards[1].classList.add("red");
setTimeout(() => {
incorrectCards[0].classList.remove("red");
incorrectCards[0].classList.remove("clicked");
incorrectCards[1].classList.remove("red");
incorrectCards[1].classList.remove("clicked");
}, 600);
}
}
}, 300);
} else if (clickCount == 2) {
clearTimeout(clickTimer);
clickCount = 0;
console.log("This was a double click!");
}
});
});

Related

Reset Valuable and repeated action

I am building a game, where the computer makes a patter of four colors and you have to remember the pattern and repeat it.
And it works almost fine, but there is one error which i cant figure out.
When i played a round and lost and the game restarts the level value goes to 2 instead of 1.
And when the new game starts the first two buttons get pressed at the same time.
At the first round everything works fine but the next round not.
var gamePattern = [];
var playerPattern = [];
var buttonColors = ["red", "blue", "green", "yellow"]
var level = 0;
$(".btn").click(function () {
if (patternDone) {
pressButton(this.id);
playerPattern.push(this.id);
checkAnswer();
}
});
function resetGame() {
gamePattern = [];
playerPattern = [];
gamePattern.length = 0;
playerPattern.length = 0;
patternDone = false;
level = 0;
$("h1").html("Press A Key to Start")
$(document).keypress(startGame);
}
//start
$(document).keypress(startGame);
//start Game
function startGame() {
level = level + 1;
console.log("level " + level);
console.log(level);
gamePattern = [];
playerPattern = [];
createLevel();
console.log(gamePattern)
playPattern();
patternDone = true;
$("h1").html("Level " + level)
}
//play the patter
async function playPattern() {
for (k = -1; k < level; k++) {
d = level - k;
// console.log(gamePattern);
abcColor = gamePattern[gamePattern.length - d];
console.log(abcColor);
await delay(1000);
pressButton(abcColor);
d = 0;
}
}
//create the level
function createLevel() {
for (y = 0; y <= level; y++) {
var randomColor = buttonColors[Math.floor(Math.random() * buttonColors.length)];
gamePattern.push(randomColor);
}
}
//update h1
function h1Level() {
levelCopy = level + 1;
$("h1").html("level " + levelCopy);
}
//pressButton
function pressButton(colord) {
// console.log(colord);
animatePress(colord);
playSound(nameSound = colord);
}
// Sound
function playSound(nameSound) {
var audio = new Audio("sounds/" + nameSound + ".mp3");
audio.play();
}
// animateClick
function animatePress(currentColor) {
$("#" + currentColor).addClass("pressed");
// console.log(currentColor);
setTimeout(function () {
$("#" + currentColor).removeClass("pressed");
}, 100);
}
//delay
const delay = millis => new Promise((resolve, reject) => {
setTimeout(_ => resolve(), millis)
});
//Button click and deciding if its right
async function checkAnswer() {
if (playerPattern.length === gamePattern.length) {
if (playerPattern.join(',') === gamePattern.join(',')) {
$("h1").html("Correct!");
console.log("correct");
await delay(1000);
startGame();
} else if (playerPattern.join(',') !== gamePattern.join(',')) {
$("h1").html("Wrong!");
level = 0;
console.log("wrong");
await delay(3000);
resetGame();
}
}
}

Why my javascript dispatchEvent is not working

below is my javascript code. previousPage and NextPage are working properly with HTML button elements.
But I am not sure why addEventListener('wheel') is not working. So I inserted some console.log, then I realize var delta is corret. But, I guess there is a problem 'if (delta ~ ~' area...
const pageList = document.querySelectorAll('.verticalPaging');
const previousPage = document.querySelector('#previousScroller');
const nextPage = document.querySelector('#nextScroller');
const idlePeriod = 100;
const animationDuration = 1000;
let lastAnimation = 0;
let pageIndex = 0;
previousPage.addEventListener('click', ()=> {
if (pageIndex < 1) return;
pageIndex--;
pageList.forEach((section, i) => {
if (i === pageIndex) {
section.scrollIntoView({behavior: "smooth"});
}
});
});
nextPage.addEventListener('click', () => {
if (pageIndex > 4) return;
pageIndex++;
pageList.forEach((section, i) => {
if (i === pageIndex) {
section.scrollIntoView({behavior: "smooth"});
}
})
});
document.addEventListener('wheel', event => {
var delta = event.wheelDelta;
var timeNow = new Date().getTime();
// Cancel scroll if currently animating or within quiet period
if(timeNow - lastAnimation < idlePeriod + animationDuration) {
event.preventDefault();
return;
}
if (delta < 0) {
var event = new Event('click');
nextPage.dispatchEvent(event);
} else {
var event = new Event('click');
previousPage.dispatchEvent(event);
}
lastAnimation = timeNow;
},{passive: false});
The wheel event doesn't have a wheelDelta property, but it has deltaY which I guess you are actually after.
document.addEventListener('wheel', event => {
const timeNow = new Date().getTime();
// Cancel scroll if currently animating or within quiet period
if(timeNow - lastAnimation < idlePeriod + animationDuration) {
event.preventDefault();
return;
}
const clickEvent = new Event('click')
if (event.deltaY < 0) {
nextPage.dispatchEvent(clickEvent);
} else {
previousPage.dispatchEvent(clickEvent);
}
lastAnimation = timeNow;
},{passive: false});
I took the liberty to get rid of var

Can someone please assist with a JS function for var length

i am trying to display a modal based on a number of matched cards in a memory game.
i have already set var to be
let matchedCards = document.querySelectorAll('.match');
and then checking if matchedCards.length == 4 display a a modal (function) but I am unable to even enter that function for some reason.
// function to intialise game
function initGame() {
//set initial timer value
timer.innerHTML = '0 mins 0 secs';
//set initial star rating
for (var i = 0; i < stars.length; i++) {
stars[i].style.color = "#FFD700";
stars[i].style.visibility = "visible";
}
//deck selection and populating with generated card
let deck = document.querySelector('.deck');
let cardHTML = shuffle(cards).map(function(card) {
return generatedCard(card);
});
deck.innerHTML = cardHTML.join('');
allCards = document.querySelectorAll('.card');
//card function
allCards.forEach(function(card) {
card.addEventListener('click', function(e) {
openCards.push(card);
card.classList.add('open', 'show', 'disabled');
// setting move counter and matched/unmatched cards
if (openCards.length === 2) {
movesCounter();
if (openCards[0].dataset.card === openCards[1].dataset.card) {
matched();
} else {
unmatched();
}
} else {
allMatched();
}
})
});
};
//function for all matched
function allMatched() {
let matchedCards = document.querySelectorAll('.match');
if (matchedCards.length === 4) {
console.log(fourcards);
congratulations();
}
}
// match the 2 cards that are open if they are of the same type
function matched() {
openCards[0].classList.add("match", "disabled");
openCards[1].classList.add("match", "disabled");
openCards = [];
}
expecting to see the congrats modal popup if there are 4 matched cards on the deck.

Run function only once until onmouseout

I have an anchor tag that plays a sound everytime the link is hovered:
<a onmouseenter="playAudio();">LINK</a>
However, when hovered, the link creates some characters that, if I keep moving the mouse inside the element, it keeps playing the sound over and over again.
Is there a way to play the onmouseenter function only once until it has detected the event onmouseout?
I've tried adding:
<a onmouseenter="playAudio();this.onmouseenter = null;">LINK</a>
but then it only plays the sound once.
Here goes the TextScramble animation function:
// ——————————————————————————————————————————————————
// TextScramble
// ——————————————————————————————————————————————————
class TextScramble {
constructor(el) {
this.el = el
this.chars = '!<>-_\\/[]{}—=+*^?#________'
this.update = this.update.bind(this)
}
setText(newText) {
const oldText = this.el.innerText
const length = Math.max(oldText.length, newText.length)
const promise = new Promise((resolve) => this.resolve = resolve)
this.queue = []
for (let i = 0; i < length; i++) {
const from = oldText[i] || ''
const to = newText[i] || ''
const start = Math.floor(Math.random() * 40)
const end = start + Math.floor(Math.random() * 40)
this.queue.push({
from,
to,
start,
end
})
}
cancelAnimationFrame(this.frameRequest)
this.frame = 0
this.update()
return promise
}
update() {
let output = ''
let complete = 0
for (let i = 0, n = this.queue.length; i < n; i++) {
let {
from,
to,
start,
end,
char
} = this.queue[i]
if (this.frame >= end) {
complete++
output += to
} else if (this.frame >= start) {
if (!char || Math.random() < 0.28) {
char = this.randomChar()
this.queue[i].char = char
}
output += `<span class="dud">${char}</span>`
} else {
output += from
}
}
this.el.innerHTML = output
if (complete === this.queue.length) {
this.resolve()
} else {
this.frameRequest = requestAnimationFrame(this.update)
this.frame++
}
}
randomChar() {
return this.chars[Math.floor(Math.random() * this.chars.length)]
}
}
// ——————————————————————————————————————————————————
// Configuration
// ——————————————————————————————————————————————————
const phrases = [
'MAIN_HUB'
]
const el = document.querySelector('.link_mainhub')
const fx = new TextScramble(el)
let counter = 0
const next = () => {
fx.setText(phrases[counter]).then(() => {});
}
el.addEventListener('mouseenter', next);
<a class="link_mainhub" onmouseenter="playAudio();">LINK</a>
Thanks.
Set a variable when you start playing the audio, and check for this before playing it again. Have the animation unset the variable when it's done.
function audioPlaying = false;
function playAudio() {
if (!audioPlaying) {
audioPlaying = true;
audioEl.play();
}
}
const next = () => {
fx.setText(phrases[counter]).then(() => {
audioPlaying = false;
});
}

I want the whatsapp web bot to reply with an image pulled from a url how do I add the function?

The bot replies well when a command is sent.
How do I make the WhatsApp web bot to reply with an image pulled from a URL? I want it to be able to reply with an image pulled from a URL, for example, www.school.com/pic.jpg. On the code if a user text #time it replies with time and Date but I want it to reply with an image.
//
// FUNCTIONS
//
// Get random value between a range
function rand(high, low = 0) {
return Math.floor(Math.random() * (high - low + 1) + low);
}
function getElement(id, parent){
if (!elementConfig[id]){
return false;
}
var elem = !parent ? document.body : parent;
var elementArr = elementConfig[id];
for (var x in elementArr){
var pos = elementArr[x];
if (isNaN(pos*1)){ //dont know why, but for some reason after the last position it loops once again and "pos" is loaded with a function WTF. I got tired finding why and did this
continue;
}
if (!elem.childNodes[pos]){
return false;
}
elem = elem.childNodes[pos];
}
return elem;
}
function getLastMsg(){
var messages = document.querySelectorAll('.msg');
var pos = messages.length-1;
while (messages[pos] && (messages[pos].classList.contains('msg-system') || messages[pos].querySelector('.message-out'))){
pos--;
if (pos <= -1){
return false;
}
}
if (messages[pos] && messages[pos].querySelector('.selectable-text')){
return messages[pos].querySelector('.selectable-text').innerText;
} else {
return false;
}
}
function getUnreadChats(){
var unreadchats = [];
var chats = getElement("chats");
if (chats){
chats = chats.childNodes;
for (var i in chats){
if (!(chats[i] instanceof Element)){
continue;
}
var icons = getElement("chat_icons", chats[i]).childNodes;
if (!icons){
continue;
}
for (var j in icons){
if (icons[j] instanceof Element){
if (!(icons[j].childNodes[0].getAttribute('data-icon') == 'muted' || icons[j].childNodes[0].getAttribute('data-icon') == 'pinned')){
unreadchats.push(chats[i]);
break;
}
}
}
}
}
return unreadchats;
}
function didYouSendLastMsg(){
var messages = document.querySelectorAll('.msg');
if (messages.length <= 0){
return false;
}
var pos = messages.length-1;
while (messages[pos] && messages[pos].classList.contains('msg-system')){
pos--;
if (pos <= -1){
return -1;
}
}
if (messages[pos].querySelector('.message-out')){
return true;
}
return false;
}
// Call the main function again
const goAgain = (fn, sec) => {
// const chat = document.querySelector('div.chat:not(.unread)')
// selectChat(chat)
setTimeout(fn, sec * 1000)
}
// Dispath an event (of click, por instance)
const eventFire = (el, etype) => {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(etype, true, true, window,0, 0, 0, 0, 0, false, false, false, false, 0, null);
el.dispatchEvent(evt);
}
// Select a chat to show the main box
const selectChat = (chat, cb) => {
const title = getElement("chat_title",chat).title;
eventFire(chat.firstChild.firstChild, 'mousedown');
if (!cb) return;
const loopFewTimes = () => {
setTimeout(() => {
const titleMain = getElement("selected_title").title;
if (titleMain !== undefined && titleMain != title){
console.log('not yet');
return loopFewTimes();
}
return cb();
}, 300);
}
loopFewTimes();
}
// Send a message
const sendMessage = (chat, message, cb) => {
//avoid duplicate sending
var title;
if (chat){
title = getElement("chat_title",chat).title;
} else {
title = getElement("selected_title").title;
}
ignoreLastMsg[title] = message;
messageBox = document.querySelectorAll("[contenteditable='true']")[0];
//add text into input field
messageBox.innerHTML = message.replace(/ /gm,'');
//Force refresh
event = document.createEvent("UIEvents");
event.initUIEvent("input", true, true, window, 1);
messageBox.dispatchEvent(event);
//Click at Send Button
eventFire(document.querySelector('span[data-icon="send"]'), 'click');
cb();
}
//
// MAIN LOGIC
//
const start = (_chats, cnt = 0) => {
// get next unread chat
const chats = _chats || getUnreadChats();
const chat = chats[cnt];
var processLastMsgOnChat = false;
var lastMsg;
if (!lastMessageOnChat){
if (false === (lastMessageOnChat = getLastMsg())){
lastMessageOnChat = true; //to prevent the first "if" to go true everytime
} else {
lastMsg = lastMessageOnChat;
}
} else if (lastMessageOnChat != getLastMsg() && getLastMsg() !== false && !didYouSendLastMsg()){
lastMessageOnChat = lastMsg = getLastMsg();
processLastMsgOnChat = true;
}
if (!processLastMsgOnChat && (chats.length == 0 || !chat)) {
console.log(new Date(), 'nothing to do now... (1)', chats.length, chat);
return goAgain(start, 3);
}
// get infos
var title;
if (!processLastMsgOnChat){
title = getElement("chat_title",chat).title + '';
lastMsg = (getElement("chat_lastmsg", chat) || { innerText: '' }).innerText; //.last-msg returns null when some user is typing a message to me
} else {
title = getElement("selected_title").title;
}
// avoid sending duplicate messaegs
if (ignoreLastMsg[title] && (ignoreLastMsg[title]) == lastMsg) {
console.log(new Date(), 'nothing to do now... (2)', title, lastMsg);
return goAgain(() => { start(chats, cnt + 1) }, 0.1);
}
// what to answer back?
let sendText
if (lastMsg.toUpperCase().indexOf('#HELP') > -1){
sendText = `
Cool ${title}! Some commands that you can send me:
1. *#TIME*
2. *#JOKE*`
}
if (lastMsg.toUpperCase().indexOf('#About') > -1){
sendText = `
Cool ${title}! Some commands that you can send me:
*${new Date()}*`
}
if (lastMsg.toUpperCase().indexOf('#TIME') > -1){
sendText = `
Don't you have a clock, dude?
*${new Date()}*`
}
if (lastMsg.toUpperCase().indexOf('#JOKE') > -1){
sendText = jokeList[rand(jokeList.length - 1)];
}
// that's sad, there's not to send back...
if (!sendText) {
ignoreLastMsg[title] = lastMsg;
console.log(new Date(), 'new message ignored -> ', title, lastMsg);
return goAgain(() => { start(chats, cnt + 1) }, 0.1);
}
console.log(new Date(), 'new message to process, uhull -> ', title, lastMsg);
// select chat and send message
if (!processLastMsgOnChat){
selectChat(chat, () => {
sendMessage(chat, sendText.trim(), () => {
goAgain(() => { start(chats, cnt + 1) }, 0.1);
});
})
} else {
sendMessage(null, sendText.trim(), () => {
goAgain(() => { start(chats, cnt + 1) }, 0.1);
});
}
}
start();

Categories

Resources