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

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/

Related

Hit register for a 1d Battleship game. Using array to record previous user inputs, then cross-checking them with current input

I am a novice programmer. I have started teaching myself JavaScript. I made a rudimentary battleship game. Problem is that if the user enters the same location(if it's a hit) 3 times the battleship sinks. To avoid that I added an array "userchoices" to record user inputs and then cross-check by iterating through a for-loop. the for loop, in turn, contains an If statement that should alert the user if they have already fired at the location before. Problem is that the if statement gets executed each time.
Please review the code below and suggest corrections. Thank you.
var randomloc = Math.floor(Math.random() * 5);
var location1 = randomloc;
var location2 = location1 + 1;
var location3 = location2 + 1;
var guess;
var userchoices = [];
var hits = 0;
var guesses = 0;
var issunk = false;
function battleship() {
while(issunk == false)
{
guess = prompt("Ready,Aim,Fire! (Enter a number 0-6):");
console.log("users input = " + guess);
if (guess == null)
break;
if (guess < 0 || guess > 6){
alert("Please enter a valid cell number. No of guesses has been
incremented.")
}
else{
guesses++;
userchoices[guesses] = guess;
console.log("users choices = " + userchoices);
}
/* for(var i = 0; i <= guesses; i++)
{
if(userchoices[guesses] = guess)
console.log("you have already fired at this location");
} */
if (guess == location1 || guess == location2 || guess == location3){
alert("Enemy Battleship HIT");
hits = hits + 1;
if (hits == 3){
issunk = true;
alert("Enemy battleship sunk")
}
}
else{
alert("You Missed");
}
}
if (issunk){var stats = "you took " + guesses + " guesses to sink the battleship. You accuracy was " + (3/guesses);alert(stats);}
else{alert("You Failed!"); issunk = false;}
}
This is the part that is causing an error
for(var i = 0; i<=guesses; i++)
{
if (userchoices[guesses] = guess){
console.log("you have fired at this location already");
}}
The if statement should execute only when the user enters a grid number that he already has fire upon, no matter hit or miss.
You are accessing the array by the wrong index. Try userchoices[i] instead of userchoices[guesses]. Also equality comparison is performed using 2 equal signs ==:
for(var i = 0; i<=guesses; i++)
{
if (userchoices[i] == guess){
console.log("you have fired at this location already");
}
}
This can also be expressed as:
if (userchoices.includes(guess)){
console.log("you have fired at this location already");
}
Also guesses should be incremented after adding the first value:
else{
userchoices[guesses] = guess;
guesses++;
console.log("users choices = " + userchoices);
}
EDIT
There is a logic error here as you are checking the array for the element after inserting it into the array, perform the check in the else statement before inserting the element. Combining all of the above:
else if (userchoices.includes(guess)){
console.log("you have fired at this location already");
} else {
userchoices[guesses] = guess;
guesses++;
console.log("users choices = " + userchoices);
}
After much-needed help from Avin Kavish and bit of tinkering of my own, I can now present an answer to my own question for future viewers.
Edit: More like my final program
function battleship()
{
var guess; //Stores user's guess
var userchoices = []; //records user's guess until ship is sunk or user chickens out
var issunk = false; //status of ship
var hits = 0; //number of hits
var guesses = 0; //number of guesses
var randomloc = Math.floor(Math.random() * 5); //Random Number Generator
var location1 = randomloc;
var location2 = location1 + 1;
var location3 = location2 + 1;
while(issunk == false)
{
guess = prompt("Ready,Aim,Fire! (Enter a number 0-6):");
console.log("users input = " + guess);
if(guess == null) // If users presses 'OK' without entering anything or the 'Cancel' this would break the loop.
break;
if (guess < 0 || guess > 6){
alert("Please enter a valid cell number. No of guesses has been incremented.");
guesses++; //Gotta punish the player.
}
else if (userchoices.includes(guess) == false) /*instead of doing what i did yo u
can change this line to "else if (userchoices.includes(guess)) and then put the
following oprations in its else clause. */
{
guesses++;
userchoices[guesses] = guess;
console.log("User choices = " + userchoices);
if (guess == location1 || guess == location2 || guess == location3)
{
alert("Enemy Battleship HIT");
hits = hits + 1;
if (hits == 3)
{
issunk = true;
alert("Enemy battleship sunk");
}
}
else
{
alert("You Missed");
}
}
else
{
alert("you have already fired at this location.")
}
if (issunk) //writing issunk == true is overkill
{
var stats = "you took " + guesses + " guesses to sink the battleship. You
accuracy was " + (3/guesses);
alert(stats);
}
}
if(guess == null && issunk == false)
console.log("You failed"); //Humiliate the user for chickening out.
userchoices = []; //Empties the array so user can start over again without relaoding the page
issunk = false; //sets issunk to false for a new game
var randomloc = Math.floor(Math.random() * 5); //creates new random numbers for ship coordinates
}
2D 7X7 version coming soon. Will post here.

Why does my setInterval seem to run one last time after an alert message?

I am writing a simple n-back game, and at the end of a session I have an alert message popping up to tell the user their n-back level is being increased if they score 75% or better. For some reason though, after the user clicks OK or hits enter, the setInterval function seems to be running through one more time. On the grid I have created, one more square lights up, even though the session is supposed to be over. I will post the relevant game code below:
$('#start').click(function()
{
let counter = 0;
message_switch = true;
$('#start').blur();
$('#score-output').text(0);
$('#percentage').text('%');
var intervalID = setInterval(function()
{
counter++;
show_card(get_cardID(cardIDs));
if (counter === 30)
{
window.clearInterval(intervalID);
message_switch = false;
var score = Math.round((playerMatches.length / matches.length) * 100);
score = score - (error_count * 3);
update_score(score);
if (score < 50)
{
if (n_back < 2)
{
n_back = 1;
} else {
n_back = n_back - 1;
}
} else if (score < 75 && score >= 50)
{
n_back = n_back;
} else if (score >= 75) {
n_back = n_back + 1;
};
$('#nback').text(n_back);
reset_game_values();
if (score >= 75) //here there is some issue
{
window.alert("Congratulations, you will move up to " + n_back + " back.");
score = 0;
return;
} else {
score = 0;
}
}
}, 3500);
})
I know this is a lot of code and there is also a lot of code I haven't provided, mainly just in an attempt to be brief. Does anyone see anything obvious that I am not seeing? If you feel you need to see more of the program I can provide it. Thanks.

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

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!");
}
});

What is the error in syntax, Why Non-active player gets points counted

I am building a simple dice game. I am having an issue with the score counting on the player that is not active. When it switches players it still counts for the player that is not active. I have looked over it a lot and I just can't find it. I even took a little break and moved a little ahead and came back and still could not find it. Here is my code.
var scores, roundScore, activePlayer;
scores = [0, 0];
roundScore = 0;
activePlayer = 1;
document.querySelector('.dice').style.display = 'none';
document.getElementById('score-0').textContent = '0';
document.getElementById('score-1').textContent = '0';
document.getElementById('current-0').textContent = '0';
document.getElementById('current-1').textContent = '0';
document.querySelector('.btn-roll').addEventListener('click', function
() {
//ran. number
var dice = Math.floor(Math.random() * 6) + 1;
// displaying result
var diceDom = document.querySelector('.dice');
diceDom.style.display = 'block';
diceDom.src = 'Assets/dice-' + dice + '.png';
// update round score IF the rolled # was not a 1
if (dice !== 1) {
roundScore += dice;
document.querySelector('#current-' + activePlayer).textContent =
roundScore;
} else {
//go to next player
nextPlayer();
}
});
document.querySelector('.btn-hold').addEventListener('click', function()
{
// add current score to global
scores[activePlayer] += roundScore;
//update UI
document.querySelector('#score-' + activePlayer).textContent =
scores[activePlayer];
//check if player won the game
//next player
nextPlayer();
});
function nextPlayer() {
//go to next player
activePlayer === 0 ? activePlayer = 1 : activePlayer = 0;
roundScore = 0;
document.getElementById('current-0').textContent = '0';
document.getElementById('current-1').textContent = '0';
document.querySelector('.player-0-
panel').classList.toggle('active');
document.querySelector('.player-1-
panel').classList.toggle('active');
//hide dice when player rolls 1
document.querySelector('.dice').style.display = 'none';
}

for loop getting skipped in javascript

I am trying to make a simple JavaScript guessing game, and my for loop keeps getting skipped! Here is the part of my code that is getting skipped:
for (i = 0; i === tries; i += 1) {
isSkipped = false;
var guessedNumber = prompt("Guess your number now.");
console.log("User guessed number " + guessedNumber);
//check if number is correct
if (guessedNumber === numberToGuess) {
confirm("Hooray, you have guessed the number!");
break;
} else if (guessedNumber > numberToGuess) {
confirm("A little too high...");
} else {
confirm("A little too low...");
}
}
and here is the full code:
//declaring variables
var numberToGuess;
var tries;
var i;
var isSkipped = true;
var confirmPlay = confirm("Are you ready to play lobuo's guessing game? The number for you to guess will be a number ranging from 1 to 25."); //does the user want to play?
if (confirmPlay === true) {
console.log("User wants to play");
} else {
window.location = "http://lobuo.github.io/pages/experiments.html";
} //if user wants to play, let them play, else go to website homepage
numberToGuess = Math.floor((Math.random() * 25) + 1); //sets computer-generated number
tries = prompt("How many tries would you like?"); //gets amount of tries
tries = Math.floor(tries); //converts amount of tries to integer from string
for (i = 0; i === tries; i += 1) {
isSkipped = false;
var guessedNumber = prompt("Guess your number now.");
console.log("User guessed number " + guessedNumber);
//check if number is correct
if (guessedNumber === numberToGuess) {
confirm("Hooray, you have guessed the number!");
break;
} else if (guessedNumber > numberToGuess) {
confirm("A little too high...");
} else {
confirm("A little too low...");
}
}
if (isSkipped === true) {
console.log("Oh no! The for loop has been skipped!");
}
If you need any further details, just ask.
Shouldn't the for be like this?:
for (i = 0; i < tries; i += 1) {
When you write:
for (i = 0; i === tries; i += 0) {
the loop repeats as long as the condition i === tries is true. If tries is 3, for instance, this condition is not true on the first iteration, and the loop ends immediately.
You should write:
for (i = 0; i < tries; i++) {
Also you need to use parseInt() function on user's input.
var guessedNumber = parseInt(prompt("Guess your number now."), 10);
instead of
var guessedNumber = prompt("Guess your number now.");

Categories