I have this little Pacman game made in JavaScript
Whats is happening is when i call a random item from the array this is what the game return:
Video here
The game show all the items from the array, before display only one of then...
A part of the code
if (gameOver || gameWin) {
//display this array if game win
text = textOptionsWin[Math.floor(Math.random() * textOptionsWin.length)];;
if (gameOver) {
//display this array if game over
text = textOptions[Math.floor(Math.random() * textOptions.length)];;
//go back to the first level if lost
setTimeout(function () {
if (tileMap.fase == 1) {
location.href = "/?fase=1";
// text = "O COVID-19 TE PEGOU! 😷";
} else if (tileMap.fase == 2) {
location.href = "/?fase=1";
} else if (tileMap.fase == 3) {
location.href = "/?fase=1";
}
}, 2500);
//Delay to change the level
}
}
I'm missing something to this happen? any tip can be useful
I don't fully understand, but I think this is the answer:
var a = ["end1", "end2", "end3"]
console.log(a[Math.floor(Math.random() * 3)])
This prints a random item in the array 'a' to console.
Related
I am working on a tic-tac-toe algo and am using regexes to solve for the win conditions.
the 9 squares are given the 0-8 values:
[0][1][2]
[3][4][5]
[6][7][8]
Each time player 1 or 2 clicks a square the value is pushed to an array and after 3 values are collected the regex starts testing to see if a player has won.
the problem.. for example the regex test to see if any order of 012 102 exist but it can't match 03142.
How can I fix my Regex to look for the 3 numbers even if separated by other numbers?
Let regexWin = /(?:^|\W)[012][012][012](?:$|\W)/gm,
You could keep track of the board state, so you don't need to rely on the moves list: define board as an array of length 9, initialised with all 0 (indicating each cell is empty). Then when a move is played set the corresponding slot to either "1" or "2", depending on which player plays that move.
var board = Array(9).fill(0); // initial board
var moves = []; // initial move list
var turn = 1; // first player to move (other player is identified as 2)
// ...
function play(move) { // move is an index in board (0..8)
board[move] = turn; // turn is 1 or 2
moves.push(move); // this is the list you already have
// Use regular expression to detect any 3-in-a-row
let isWin = /^(?:...)*([12])\1\1|^.?.?([12])..\2..\2|^([12])...\3...\3|^..([12]).\4.\4/.test(board.join(""));
console.log("is winning move?", isWin);
turn = 3 - turn; // toggle the player that is to move
}
This way you also can use board to update the display.
For a full implementation, with rendering, and a minimax algorithm for generating a "best" move, see this answer.
Assuming the squares occupied are pushed into the object moves, which contains an array for each player, p1 and p2, just sort the arrays after each push. That way, can guarantee the indices are compared in ascending order.
let moves = {p1: [], p2: []};
function move(player, spaceIndex) {
moves[player].push(spaceIndex);
moves[player].sort();
if (/012|345|678|036|147|258|048|246/.test(moves[player].join('')) {
//win!
}
}
From the details given in your question it doesn't sound like you've realised that you need two arrays, not one, otherwise the win algo won't know which player occupies which space, and will report a win merely for three spaces in a row being occupied, even if they're shared between different players.
I did not find the Regex that worked, so I switched to a different idea.
Based on the article by Alvaro Saburido I learned how to take the winArray and the 1&2 playerArray for an intersection and test for a win.
The article is great and i'll keep searching for a regex solution just for coding fun.
https://medium.com/#alvaro.saburido/set-theory-for-arrays-in-es6-eb2f20a61848
let win = ["012", "345", "678", "036", "147", "258", "048", "246"];
function endGameEvaluation() {
if (joueur1Turn) {
resultMessage.innerHTML = `<div id="resultMessage">Player 1 Wins!! End of the game</div>`;
gameWon = true;
playerTurnMsg.innerHTML = "";
} else if (joueur2Turn) {
resultMessage.innerHTML = `<div id="resultMessage">Player 2 Wins!! End of the game</div>`;
gameWon = true;
playerTurnMsg.innerHTML = "";
}
}
function winner(player) {
for (var i = 0; i < 8; i++) {
let won = win[i]
let inCommon = player.filter(x => won.includes(x));
if (inCommon.length == 3) {
endGameEvaluation();
}
}
}
tdClickArea.forEach(item => {
item.addEventListener('click', e => {
let btnArea = e.target;
let player;
if (btnArea.innerHTML == "X" || btnArea.innerHTML == "O") {
alert("tricheur! Choisi une autre case")
} else {
if (joueur1Turn) {
btnArea.innerHTML = "X";
joueur1Sq.push(btnArea.getAttribute("value"));
player = joueur1Sq;
} else if (joueur2Turn) {
btnArea.innerHTML = "O";
joueur2Sq.push(btnArea.getAttribute("value"));
player = joueur2Sq;
}
}
if (joueur1Sq.length >= 3 || joueur2Sq.length >= 3) {
winner(player);
}
counter++;
changeTurn();
// Here we end the game if nobody won until the last posibble move
if (counter == 9 && gameWon == false) {
resultMessage.innerHTML = `<div id="resultMessage">End of the game</div>`;
}
})
});
I am having an issue with the following code when trying to iterate through the items in a form and delete them to make way for new sections/questions. However, I sometimes get the following error "Invalid data updating form". I have worked around this multiple times now, but it keeps coming back up. My current workaround has been to set the section title to "", which made it available to delete. Previously, I didn't need to do this until today.
My question: What is the best way to iterate through the items in a form and delete them from a starting point and not encounter this error?
Reference:
f = the current active form
f_items = all of the items of the form in an array
function clearForm()
{
var clearQ = find(f_items, "Select Appointment Date/Time")+1;
var f_i_len = f.getItems().length-1;
var clear = clearQ;
while(clear <= f_i_len && clear >= clearQ)
{
var item = f.getItems()[clear];
Logger.log(item.getTitle() + " | " + item.getType());
Logger.getLog();
if(item.getType() == "PAGE_BREAK")
{ item.asPageBreakItem().setTitle(""); }
f.deleteItem(clear);
f_i_len = f.getItems().length-1;
clear++;
}
}
function find(src, name)
{
var s_len = src.length;
for(var iter = 0; iter < s_len; iter++)
{
var s = src[iter].getTitle();
if(s == name)
{ return iter; }
}
return -1;
}
The issue I had with this was that the PageBreakItem I was trying to delete was the destination for a conditional answer earlier in the form.
Below is my code where I needed to delete everything after a certain item, which linked to the sections I needed to delete, so I was able to iterate backwards with a while loop.
function getParentNameItem_(form, form_items){
//finds the item with conditional navigation to what you want to delete
var parent_name_item = find_(form_items, "Your Name");
parent_name_item = parent_name_item.asListItem();
//clears all choices which breaks the navigation dependency
//this frees up the items to be deleted
parent_name_item.setChoices([parent_name_item.createChoice("")]);
var size = form_items.length - 1;
//iterates from the end back to the last question I want to keep
while(form_items[size].getTitle() != "Your Name"){
//this can take either the item itself or the index as I've done
form.deleteItem(size);
size--;
}
/*I rebuild the choices for parent_name_item
later based on information from a spreadsheet
which I also use to determine the content of
the PageBreakItems I just deleted*/
return parent_name_item;
}
I found out the issue! It was the clear++ at the end of the loop. With the number of items in the going down with each iteration, the clear++ was causing it to skip over the page break items. Below is my finished code:
function clearForm()
{
var clearQ = find(f_items, "Select Appointment Date")+1;
var f_i_len = f.getItems().length-1;
var clear = clearQ;
while(clear <= f_i_len && clear >= clearQ)
{
var item = f.getItems()[clear];
if(item.getType() == "PAGE_BREAK")
{ item.asPageBreakItem().setTitle(""); }
f.deleteItem(clear); //}
f_i_len = f.getItems().length-1;
}
}
I am building a little project: A random quote generator.
I have 6 quotes stored as objects in a file, quotes.js. Each quote object has a quote and source. Some of them also have a citation and year.
I have an html page (plus CSS) that displays a quote on the screen. There is also a button to click: click to get a new quote.
My code largely runs, when I click the button on my page, it loads a new quote at random. The majority of the time...
However, I am also aiming to NOT display a random quote more than once until ALL quotes from the array have been displayed first.
This is not happening yet.
My button, at random, does not work. I may get 5 successful button clicks, a miss and then another success at random. I'm not sure why this is happening at all.
Can you please suggest what to do here? No errors are being caught in the console.
ACTUALLY, I suppose that the button IS working everytime, it's just loading the same quote again.
Here is my main code:
// event listener to respond to "Show another quote" button clicks
// when user clicks anywhere on the button, the "printQuote" function is called
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
// prints quote
function printQuote(){
var finalQuote = buildQuote();
document.getElementById('quote-box').innerHTML = finalQuote;
}
// builds message for html, adding on citation and/or year if necessary
function buildQuote(){
var quote2Print = getQuote();
var message;
message = "<p class='quote'>" + quote2Print.quote + "</p><p class='source'>" + quote2Print.source;
if(quote2Print.hasOwnProperty('citation') === true){
citation = quote2Print.citation;
message += "<span class='citation'>" + quote2Print.citation + "</span>";
if(quote2Print.hasOwnProperty('year') === true){
year = quote2Print.year;
message += "<span class='year'>" + quote2Print.year + "</span></p>";
return message;
} else {
return message += "</p>";
}
}else {
return message;
}
}
// makes sure that if all 6 quotes haven't been printed, getRandomQuote is called again until a new one is found
function getQuote(){
var countArray = [];
var quote;
if(countArray.length < 6){
quote = getRandomQuote();
while(countArray.indexOf(quote) === -1)
{
if(countArray.indexOf(quote) === -1) {
countArray.push(quote);
return quote;
} else{
quote = getRandomQuote();
}
}
} else {
quote = getRandomQuote();
return quote;
}
}
// With random number, goes through array of quotes and chooses one. random number = index position
function getRandomQuote(){
var randomQuoteNum = randomQuoteNo();
var quote = quotes[randomQuoteNum];
return quote;
}
// Gets a random number
function randomQuoteNo() {
var randomNumber = Math.floor(Math.random() * 6);
return randomNumber;
}
Going about this the easy way is, ofc, the easy way. So that's what I've done.
Basically you have an array of quotes that you load from somewhere. This you want shuffled (or randomised or whatever). And then you want to add one quote at a time to the quotes that are to be displayed? I have read your question as such and done a solution for that.
Here is a plnkr: http://plnkr.co/edit/CfdqQv1nGwdaIfYrbXr4?p=preview
And here is the code:
var quotes = [];
quotes.push(createQuote(1));
quotes.push(createQuote(2));
quotes.push(createQuote(3));
quotes.push(createQuote(4));
quotes.push(createQuote(5));
quotes.push(createQuote(6));
quotes.push(createQuote(7));
function createQuote(number) {
return {
id: number,
text: "text" + number,
author: "author" + number
};
}
var printedQuotes = [];
var nonPrintedQuotes = [];
init();
function init() {
nonPrintedQuotes = shuffle(quotes);
printVars();
}
function addQuoteToPrint() {
if (nonPrintedQuotes.length > 0) {
console.log("ADD QUOTE!");
var quote = nonPrintedQuotes.slice(-1, nonPrintedQuotes.length)
nonPrintedQuotes = nonPrintedQuotes.splice(0, nonPrintedQuotes.length - 1);
printedQuotes.push(quote[0]);
printVars();
} else {
console.log("No more quotes to print. Sorry. :/")
}
}
function shuffle(array) {
var m = array.length;
var shuffled = array.slice(); // Copy the array
// While there remain elements to shuffle…
while (m) {
// Pick a remaining element…
var i = Math.floor(Math.random() * m--);
// And swap it with the current element.
var t = shuffled[m];
shuffled[m] = shuffled[i];
shuffled[i] = t;
}
return shuffled;
}
function printVars() {
console.log(quotes);
console.log(nonPrintedQuotes);
console.log(printedQuotes);
}
So basically, you load up your quotes somehow (I've created a little helper function just to easily create some fake quote objects). Then you create a shuffled array of those (don't know if you want to keep the original array sorted or not, so I left it sorted). Then when you say you want a quote, you take one element from the shuffled array and put in in the printed array.
I've used a fisher yates shuffle (as per EvanTrimboli's suggestion).
When you've loaded all the quotes, you can trigger your function to fetch more.
I'm having a problem with a statement that gets skipped, and also an infinite loop which I can't figure out why it's infinite since it appears to end when the correct input has been given.
Here's a fiddle so you can understand what's happening easier: http://jsfiddle.net/z03ffn2j/
In the else statement I'm running a while loop that runs as long as the current player tries to ask himself the question in the askPlayer function. So if a player is named "chris" and that player enters "chris", the prompt comes up again.
All good and well, but.. When I don't type "chris" the first time and instead type, let's say "tommy", it skips the var card statement which asks for a value. However, when I enter "chris" the first time, it re-prompts cuz it's myself, and then I enter "tommy", it doesn't skip the var code statement. So my question is, why does it skip it when I enter a correct name the first time, but not if I first enter a false name and then a correct one?
var playerArray = []; //Contains player objects
var turn = 0; //Keeps track of whose turn it is
function askPlayer() {
var askedPlayer = prompt('Which player do you want to ask?');
return askedPlayer;
}
//While the pairCount is less than 13(maximum possible pairs)
while (pairCount < maxPairs) {
if (playerArray[turn].totalCards == 0) {
drawCard();
}
else {
var wrongInput = true;
var player = askPlayer();
while (wrongInput) {
if (player === playerArray[turn].name) {
player = askPlayer();
if (player != playerArray[turn].name) {
wrongInput = false;
}
}
}
var card = askCard(player); //<--- This statement gets skipped
}
pairCount = 13; //Prevents infinite loop for now
turn++;
if (turn == playerNum - 1) { //If everyone has made their turn, reset to player1 again
turn = 0;
}
}
When you enter a player name that isn't equal to the current turn's player name, you'll enter an infinite loop.
You have:
var wrongInput = true;
var player = askPlayer();
while (wrongInput) {
if (player === playerArray[turn].name) {
player = askPlayer();
if (player != playerArray[turn].name) {
wrongInput = false;
}
}
}
var card = askCard(player);
As you can see, the 1st time the loop is entered, wrongInput will be true. Assuming the player's names are a and b respectively and you answered b to askPlayer(), the 1st if statement will be false (player is b and playerArray[0].name is a).
Since you have no other code inside the loop, it'll jump right to the while (wrongInput) evaluation... and now you're stuck in a never-ending loop.
So, it seems you forgot one closing bracket after player = askPlayer().
To fix it, instead of:
if (player === playerArray[turn].name) {
player = askPlayer();
if (player != playerArray[turn].name) {
wrongInput = false;
}
}
... write:
if (player === playerArray[turn].name) {
player = askPlayer();
}
if (player != playerArray[turn].name) {
wrongInput = false;
}
Or, better yet:
if (player === playerArray[turn].name) {
player = askPlayer();
} else {
wrongInput = false;
}
I am building an IRC client and I am hoping to implement a solution to tab complete names. I have a list of users in the form of an array. When the user presses the tab key it completes the username. When they press the key again it completes with the next user.
I have a working solution here, but I feel like it could be a little more optimized and terse. I would be grateful for any suggestions.
// Get Active Window
var channel = irc.chatWindows.getActive();
// Get users input
var sentence = $('#chat-input').val().split(' ');
// Get the last word in the sentence
var partialMatch = sentence.pop();
// Get list of users
var users = channel.userList.getUsers();
// Set default index for loop
var userIndex=0;
//Persist the match
//Store the partialMatch to persist next time the user hits tab
if(window.partialMatch === undefined) {
window.partialMatch = partialMatch;
} else if(partialMatch.search(window.partialMatch) !== 0){
window.partialMatch = partialMatch;
} else {
if (sentence.length === 0) {
userIndex = users.indexOf(partialMatch.substr(0, partialMatch.length-1));
} else {
userIndex = users.indexOf(partialMatch);
}
}
//Cycle through userlist from last user or beginning
for (var i=userIndex; i<users.length; i++) {
var user = users[i] || '';
//Search for match
if (window.partialMatch.length > 0 && user.search(window.partialMatch, "i") === 0) {
//If no match found we continue searching
if(user === partialMatch || user === partialMatch.substr(0, partialMatch.length-1)){
continue;
}
//If we find a match we return our match to our input
sentence.push(user);
//We decide whether or not to add colon
if (sentence.length === 1) {
$('#chat-input').val(sentence.join(' ') + ":");
} else {
$('#chat-input').val(sentence.join(' '));
}
//We break from our loop
break;
}
}
You may want to look into the trie data structure, which is excellently structured for exactly this problem. With a trie, you can list off all of the strings that start with a given prefix very efficiently and without having to look at all the words in the word list. You can also do other nice operations with the trie, such as fast lookups, fast successor and predecessor search, and fast insertion/deletion.
Hope this helps!