Changing the global scope variable inside of a function with click handlers - javascript

So I'm building a turn based game with javascript and jquery and I'm currently struggling with limiting player movement.
So this is what I have:
let playerOneMoves = 0;
let playerTwoMoves = 0;
function movePlayerOne(){
$(tile).click(function(){
playerOneMoves += 1;
if(playerOneMoves < 4){
$(".active").append(playerOne);
}else if(playerOneMoves == 4){
alert("No more moves, players two turn!");
playerTwoMoves = 0;
movePlayerTwo();
}
})
}
function movePlayerTwo(){
$(tile).click(function(){
playerTwoMoves += 1;
if(playerTwoMoves < 4){
$(".active").append(playerTwo);
}else if(playerTwoMoves == 4){
playerOneMoves = 0;
alert("No more moves, players one turn!")
movePlayerOne();
}
})
}
So as player 2 finishes his move, and the next function (moveplayerone) is loaded, I only have 1 move with player 1. After a few more clicks, it starts appending both players to the same field.
So my question is, why can't I reset the value of "let playerOneMoves = 0;" inside of a function?
If you want to see the code more in-depth, you can check it on CodePen:
https://codepen.io/ronydkid/pen/oyqxJY
Btw, I've checked all the other similar questions but they weren't helpful.

So we're going to semantically read your functions from top to bottom
movePlayerOne
Assign a click handler
movePlayerTwo
Assign a click handler
That doesn't seem like the intended functionality you're after! I'm guessing what you wanted was that on click, you need to check your moves, and then assign which player is the active player. This should be handled with a single click handler that has knowledge of which player's turn it is. To achieve this lets go ahead and make a DIFFERENT click handler called movePlayer and a new global called currentPlayer
let currentPlayer = playerOne;
let playerOneMoves = 0;
let playerTwoMoves = 0;
let active = $(".active"); // we don't want to crawl DOM every time unless needed,
// so unless you're destroying the ".active" DOM object every time, you should be fine here
function movePlayer(){
let currentMoves = currentPlayer == playerOne
? ++playerOneMoves
: ++playerTwoMoves;
if ( currentMoves < 4 ){
active.append(currentPlayer);
} else { // basically if we get here we've reached 4 moves
if (currentPlayer == playerOne) {
currentPlayer = playerTwo;
playerOneMoves = 0;
alert("No more moves, players two's turn!");
} else {
currentPlayer = playerOne;
playerTwoMoves = 0;
alert("No more moves, players one turn!");
}
}
}
$(tile).click(movePlayer)
Now whenever you click on a tile only one function gets run, and this function handles moves for BOTH players and it doesn't register more click handlers
Some of the shortcuts used:
Ternary
if (condition) {
console.log('true')
} else {
console.log('false')
}
can be rewritten with a ternary as
console.log( condition ? 'true' : 'false' )
Increment
var i = 0;
console.log(i++) // 0
console.log(i) // 1
console.log(++i) // 2
console.log(i) // 2
Notes on other changes you can make
If you don't need the extra references to individual player moves variables, take a look at #geekley 's answer below. It's a little smaller and features hoisting of non evaluated variables, short circuiting the function in a conditional, and less variables.

Maybe this is what you mean?
let playerMoves = 0;
let currentPlayer = 1;
$(tile).click(movePlayer);
function movePlayer() {
playerMoves += 1;
if (playerMoves < 4) {
$(".active").append(currentPlayer == 1 ? playerOne : playerTwo);
return;
}
// if (playerMoves >= 4) {
if (currentPlayer == 1) {
alert("No more moves, player two's turn!");
currentPlayer = 2;
} else { // currentPlayer == 2
alert("No more moves, player one's turn!");
currentPlayer = 1;
}
playerMoves = 0;
// }
}

The problem is not the let... the problem is your code structure:
let playerMoves = 0;
let player = 1;
$(tile).click(function() {
if (playerMoves < 4) {
$(".active").append(player == 1 ? playerOne : playerTwo);
playerMoves += 1;
}
if (playerMoves == 4) {
playerMoves = 0;
player == 1 ? player = 2 : player = 1;
alert("No more moves, " + player + "'s turn!");
}
});

Related

Click listener firing multiple times in react [duplicate]

I add event handlers to all my inputs in a sudoku game using addEventListener.
Every time that I write a number inside an input handler is running 3 times, why?
I want it to run only once for each element.
How can I do that?
// passing the board game
function addListener(game) {
counter = 0;
for (let i = 0; i < 81; i++) {
//add evenListener to all the input filds
document.querySelectorAll('input')[i].addEventListener('input', function() {
//save the innerHtml of the value that we write
let inputInnerHTML = Number(this.value);
//save the id of the input that we write in
let index = this.id;
checkIfCorrect(inputInnerHTML, index, game)
})
};
}
function checkIfCorrect(inputInnerHTML, index, game) {
for (let i = 0; i < game.length; i++) {
//if the original number is the same, the number will be black
if (inputInnerHTML === 0) {
// if the input is erased remove the classes
document.getElementById(index).classList.remove('wrong');
document.getElementById(index).classList.remove('correct');
}
if (game[i] === inputInnerHTML) {
document.getElementById(index).classList.add('correct');
break;
} else if (game[i] !== inputInnerHTML && inputInnerHTML !== 0) {
//if the number is not the same, the number will be red
//and if we did not erase the number add red and count
document.getElementById(index).classList.add('wrong');
counter++
if (counter === 1) {
document.getElementById('mistakes').innerHTML = 'Mistakes: 1/3';
}
if (counter === 2) {
document.getElementById('mistakes').innerHTML = 'Mistakes: 2/3';
}
if (counter === 3) {
//go to you lose
document.getElementById('mistakes').innerHTML = 'Mistakes: 3/3';
youLose();
}
}
}
}
You are calling addEventListener every time you select a difficultyButton. This means that each time you click a button, you'll be adding an eventListener.
Fix this by calling removeEventListener, before calling addEventListener.
I think the problem is the checkIfCorrect function, after it is detected correct or not it doesn't stop and keep searching creating confusion.
By adding the break to the else if we block the search if the error has already been detected and notified.
function checkIfCorrect(inputInnerHTML, index, game) {
for (let i = 0; i < game.length; i++) {
//if the original number is the same, the number will be black
if (inputInnerHTML === 0) {
// if the input is erased remove the classes
document.getElementById(index).classList.remove('wrong');
document.getElementById(index).classList.remove('correct');
}
if (game[i] === inputInnerHTML) {
document.getElementById(index).classList.add('correct');
break;
} else if (game[i] !== inputInnerHTML && inputInnerHTML !== 0) {
//if the number is not the same, the number will be red
//and if we did not erase the number add red and count
document.getElementById(index).classList.add('wrong');
counter++
if (counter === 1) {
document.getElementById('mistakes').innerHTML = 'Mistakes: 1/3';
}
if (counter === 2) {
document.getElementById('mistakes').innerHTML = 'Mistakes: 2/3';
}
if (counter === 3) {
//go to you lose
document.getElementById('mistakes').innerHTML = 'Mistakes: 3/3';
youLose();
}
break; // FIX
}
}
}

javascript recursive function does not stop execution

Inside of my progress function, it will hit the base of the recursion, but the value im expecting to have returned does not change.
let graph = [[1,1,1],[1,1,1,],[1,1,1]]
function findPath(graph){
function progress(row, col){
if(row == graph.length-1 && graph[row][col]== 1) {
console.log('makes it here but does not return true !?')
return true;
}
//check right
if(graph[row][col+1] == 1) {
graph[row][col] = 2
progress(row, col+1);
}
// check left
if(graph[row][col-1] == 1) {
graph[row][col] = 2
progress(row, col-1);
}
// check down
if(graph[row+1][col] == 1){
graph[row][col] = 2
progress(row+1, col)
}
}
for(let i = 0; i < graph[0].length; i++) {
if(graph[0][i] == 1) {
if(progress(0, i)) {
return true;
}
}
}
return false;
}
console.log(findPath(graph))
This should return true, it hits the condition (logs the text) but then keeps moving, and always returns false.
Ok, recursion works with an stack, each call is stacked and just continues your execution after all the other call stacked after are done.
Like:
call1 -> call2 -> call3 -> callN
after reach the last call (callN), all the calls will be unstacket from back to front.
You just return true on the last call, but this value get lost when the function calls is unstacked
In other words, to your example works, you need to always return the value from the progress function.
I tried to adapty your code to work better:
let graph = [[1,1,1],[1,1,1,],[1,1,1]]
function findPath(graph){
function progress(row, col){
if(row == graph.length-1 && graph[row][col]== 1) {
return true;
}
//check right
if(graph[row][col+1] == 1) {
graph[row][col] = 2
var right = progress(row, col+1);
}
// check left
if(graph[row][col-1] == 1) {
graph[row][col] = 2
var left = progress(row, col-1);
}
// check down
if(graph[row+1][col] == 1){
graph[row][col] = 2
var down = progress(row+1, col)
}
// propagate result
return (right || left || down)
}
for(let i = 0; i < graph[0].length; i++) {
if(graph[0][i] == 1) {
if(progress(0, i)) {
return true;
}
}
}
return false;
}
console.log(findPath(graph))
I only look to the recursion part, and not for the problem it self, in my example, if in any path (right, left or down) i grab that value and pass back untill it reach my first function call. That way, the true value will be propagate until the end
Hope i have helped

I need help for a Tic Tac Toe game i cant change the turns

I need help to swap Player after each turn. That is first click is player 1 (X) then second clicks becomes player 2(0).Right now each clicks puts an X.
const player1 = 'X'
const player2 = 'O'
CurrentPlayer = 1
if(CurrentPlayer == 1) {
$("document").ready (function(){
$(".grid-item").click (function(){
$(this).html(player1);
$("#player").html("2")
CurrentPlayer = 2
})
});
}
if ( CurrentPlayer == 2) {
$("document").ready (function(){
$(".grid-item").click (function(){
$(this).html(player2);
$("#player").html("3")
})
});
}
There are so many mistake in your code. For a start,
$("document").ready (function(){
});
should be for the file not for each click, another issue is the event
$(".grid-item").click (function(){
//
});
should be init only once, inside that event only we need to check for the player status.
You code should look something like this
$("document").ready (function(){
const player1 = 'X'
const player2 = 'O'
var CurrentPlayer = 1
$(".grid-item").click (function(){
if(CurrentPlayer == 1) {
//do your stuff for player 1
CurrentPlayer = 2
}
else if(CurrentPlayer == 2) {
//do your stuff for player2
CurrentPlayer = 1
}
});
});
You were attaching ready function twice, depending on the current value of CurrentPlayer which you have intialized with 1, so your method for player-2 never gets attached.
You can try the following
const player1 = 'X';
const player2 = 'O';
let CurrentPlayer = 1;
$("document").ready(function () {
$(".grid-item").click(function () {
if (CurrentPlayer === 1) {
// put X for palyer-1
$(this).html(player1);
$("#player").html("2");
// finally toggle CurrentPlayer
CurrentPlayer = 2;
} else {
// put O for palyer-2
$(this).html(player2);
$("#player").html("3");
// finally toggle CurrentPlayer
CurrentPlayer = 1;
}
})
});

Javascript Pacman-style Game - not able to store scores in horizontal path

I'm doing this exercise with JavaScript and we're supposed to create a ninja pacman-style game with Javascript and then keep score. The ninja eats sushis and I'm doing one point per sushi.
The current behavior is that I can store scores when the ninja goes up or down. Problem is that when the ninja moves horizontally, the score only counts the first sushi. Second and third sushis aren't counted. I did use the same logic for vertical and horizontal moving around.
Here is my code. Added the whole code for context, but the problematic part is after "document.onkeydown = function(e) {".
<script type="text/javascript">
var world = [
[1,1,1,1,1],
[1,0,2,2,1],
[1,2,1,2,1],
[3,2,2,2,3],
[1,2,1,2,1],
[1,2,2,2,1],
[3,2,1,2,3],
[1,2,2,2,1],
[1,1,1,3,1],
]
var worldDict = {
0 : 'blank',
1 : 'wall',
2 : 'sushi',
3 : 'onigiri'
}
var ninjaScore = 0;
function drawWorld() {
var output = "";
for (var row = 0; row < world.length; row++) {
output += "<div class='row'></div>"
for (var x = 0; x <world[row].length; x++) {
output += "<div class='" + worldDict[world[row][x]]+"'></div>"
}
output += "</div>"
}
document.getElementById('world').innerHTML = output;
}
drawWorld();
var ninjaman = {
x: 1,
y: 1
}
function drawNinjaMan() {
document.getElementById('ninjaman').style.top = ninjaman.y * 40 + "px"
document.getElementById('ninjaman').style.left = ninjaman.x * 40 + "px"
}
drawNinjaMan();
document.onkeydown = function(e) {
if (e.keyCode == 40) { //DOWN
if (world[ninjaman.y + 1][ninjaman.x] != 1) {
ninjaman.y++;
if (world[ninjaman.y + 1][ninjaman.x] == 2) { //Checking if next block is sushi; adding to score
ninjaScore = ninjaScore + 1;
}
}
}
if (e.keyCode == 38) { //UP
if (world[ninjaman.y - 1][ninjaman.x] != 1) {
ninjaman.y--;
if (world[ninjaman.y - 1][ninjaman.x] == 2) { //Checking if next block is sushi; adding to score
ninjaScore = ninjaScore + 1;
}
}
}
if (e.keyCode == 37) { //LEFT
if (world[ninjaman.y][ninjaman.x - 1] != 1) {
ninjaman.x--;
if (world[ninjaman.y][ninjaman.x - 1] == 2) { //Checking if next block is sushi; adding to score
//Somehow this is returning false on the second key press; need to check why
ninjaScore = ninjaScore + 1;
}
}
}
if (e.keyCode == 39) { //RIGHT
if (world[ninjaman.y][ninjaman.x + 1] != 1) {
ninjaman.x++;
if (world[ninjaman.y][ninjaman.x + 1] == 2) { //Checking if next block is sushi; adding to score
//Somehow this is returning false on the second key press; need to check why
ninjaScore = ninjaScore + 1;
}
}
}
world[ninjaman.y][ninjaman.x] = 0;
drawWorld()
drawNinjaMan()
}
Could anyone please point out what I'm getting wrong?
Also, to give credit: This is an exercise from the pre-bootcamp course at Coding Dojo (https://www.codingdojo.com/). They came up with most of the code and the exercise itself.
I think it's because you're moving the ninja on top of a sushi, and then checking the block ahead of the block you are on in the direction you are moving. And all your motions are wrong, up, down, left and right.
This should fix it.
https://plnkr.co/edit/VCsa2cTWYaUn2jiTgmS4?p=preview
if (world[ninjaman.y][ninjaman.x-1] == 2) { //Checking if
should be
if (world[ninjaman.y][ninjaman.x] == 2) { //Checking if

Game loop for card game, winner starts, 1 user controlled player

I'm looking to program a card game where there is one user-controlled player, playing against 3 a.i opponents. It is a game of Euchre, you can find a similar example here:
https://cardgames.io/euchre/
In this card game, the player that wins the round, starts the next round. The game automatically continues
I am having trouble trying to find a way to handle the user event. The click event needs to action the user-controlled player playing a card, and then the other players in clockwise order.
The problem is that if the user-controlled player does not win the hand, the game must continue playing until the user-controlled player needs to play again, at which point they will be required to fire another click event.
What would be the best way to solve this problem? I have a JSFiddle which I think does what I want, but it's really not ideal:
https://jsfiddle.net/GerardSimpson/m736364e/18/
var player1 = {};
player1.hasPlayed = false;
var roundStarter = 0;
var i = 0;
var currentTurn = (i + roundStarter) % 4;
while(player1.hasPlayed === false) {
console.log("player[",currentTurn,"]", "plays a card");
i++;
currentTurn = (i + roundStarter) % 4;
if(i === 4) {
roundStarter = 2;
console.log("Round Over, player "+ roundStarter +" wins");
i = 0;
currentTurn = (i + roundStarter) % 4;
}
if(currentTurn === 0) {
console.log("player[ 0 ]s turn, exit loop and wait for new click event");
player1.hasPlayed = true;
}
}
I have managed to find a solution to my problem, the trick was to put the turn functionality into a function that modifies variables in the parent scope that keep a record of the game turn. I think I may need to add closures to this if I don't want to polute the global scope. I will update later, here is my code and fiddle:
var player1 = {};
player1.hasPlayed = false;
var roundStarter = 0;
var i = 0;
var currentTurn = (i + roundStarter) % 4;
$('.click-me').on('click', function(){
while(1) {
console.log("player[",currentTurn,"]", "plays a card");
i++;
currentTurn = (i + roundStarter) % 4;
if(i === 4) {
roundStarter = 3;
console.log("Round Over, player "+ roundStarter +" wins");
i = 0;
currentTurn = (i + roundStarter) % 4;
}
if(currentTurn === 0) {
console.log("player[ 0 ]s turn, exit loop and wait for new click event");
break;
}
}
});
http://jsfiddle.net/GerardSimpson/m736364e/23/

Categories