nodejs javascript find with condition - javascript

Hello I have a queue of players and wanted to get the first player that met one of my two conditions, but I am unsure how to do that.
First I get the value of a player (mmr)
and wanted to get one (only one) player from the queue that had 5% more or less of this value
My condition I think is this to get 5% more or less:
const condition = (5/100)*playerOne.mmr + playerOne.mmr
const condition2 = (5/100)*playerOne.mmr - playerOne.mmr
my function:
makeMatch(playerOne) {
// make matched players
const condition = (5/100)*playerOne.mmr + playerOne.mmr
const condition2 = (5/100)*playerOne.mmr - playerOne.mmr
const player = playerOne;
const matchedPlayer = this.players.find();
// remove matched players from this.players
this.removePlayers(matchedPlayers);
// return new Match with matched players
return new Match(matchedPlayers);
}
I have questions as I would get 5% more or less within my find

Check out the documentation for the find function it details this use case. Here's the line that you would want for the desired result.
const matchedPlayer = this.players.find((playerTwo) => playerTwo.mmr > condition || playerTwo.mmr > condition2);

You can try something like this:
if (player.condition1 > condition1*0.95 && player.condition1 < condition1*1.05) {
// then you keep the player
} else {
// else you remove it from the list
}
Also, I would highly reccomend you to give better identifiers to the variables. Instead of condition1, something like age, height, weight.

Related

Using strings to improve efficiency of a JavaScript

I'm writing a plugin for an open source utility in JavaScript, where the module I'm writing will interact with an audio interface. I've started coding functionality of some mutes. Instead of writing 32 separate pieces of code I'd like to use a variable to identify the channel that has been changed. For example:
if (address.match('/flx_mute/1')) {
var mutestatus = message.args[0].value;
if (mutestatus === 1) {
this.flexmute1 = "Muted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
} else {
this.flexmute1 = "Unmuted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
}
}
I know in other languages I could write something like this:
let i = ""
// Code here to determine the channel that needs its mute status changed...
let flexchannelmute = "flexmute" + i
if (mutestatus === 1) {
this.[flexchannelmute] = "Muted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
} else {
this.[flexchannelmute] = "Unmuted"
console.log(`Flex Channel 1 is: ${this.flexmute1}`);
}
The first question is what is this kind of string substitution called? Secondly, is what I'm describing possible?
You can create an object (flexChannels) and a ternary statement to store the current status.
let flexChannels = {};
let mutestatus = 1;
let i = 1;
let flexchannelmute = "flexmute" + i
flexChannels[flexchannelmute] = (mutestatus === 1) ? "Muted" : "Unmuted";
console.log(`Flex Channel ${i} is: ${flexChannels[flexchannelmute]}`);
I could not make out exactly what you are trying to do, but you can try this.
In your top level you appear to be detecting if a message was sent to a particular address.
I assume that the part after the first slash denotes that the message is related to the mutes in question and that the number after the second slash is number of the mute the message is for.
You can use a regex to match this and get the required info.
The method of accessing a property on an object using a variable as the key is called "bracket notation".
const addressRegex = /\/flx_mute\/(\d+)/; // Matches "/flx_mute/" followed by a number
const matchResult = address.match(addressRegex);
// If a match was found...
if (matchResult) {
const muteStatus = message.args[0].value;
const muteNumber = matchResult[1]; // This is the number in the address.
const muteName = "flexmute" + muteNumber;
if (muteStatus === 1) {
this[muteName] = "Muted";
console.log(`Flex Channel ${muteNumber} is: ${this[muteName]}`);
} else {
this[muteName] = "Unmuted";
console.log(`Flex Channel ${muteNumber} is: ${this[muteName]}`);
}
}
You can simplify the code inside the if block by using a ternary expression and a temporary variable:
if (matchResult) {
const muteStatus = message.args[0].value;
const muteNumber = matchResult[1];
const muteName = "flexmute" + muteNumber;
const muteState = muteStatus === 1 ? "Muted" : "Unmuted";
this[muteName] = muteState;
console.log(`Flex Channel ${muteNumber} is: ${muteState}`);
}

Discord.js Sorting through all text channels on a server

module.exports = {
name: 'cleartextchats',
description:
'clears desired amount of text chats created by the bot. usage: cleartextchats <amount>',
execute(message, args) {
var channelAmount = args[0];
console.log('executing cleartextchats');
for (var i = 0; i < channelAmount; i++) {
var textChat = message.guild.channels.cache
.filter((ch) => ch.type === 'text')
.find(
(targetch) => targetch.topic == 'volturnbot' && targetch.deleted == false
);
message.channel.send(`deleting ` + textChat.name);
textChat.delete();
}
},
};
The for loop does not advance past the first deleted channel.
I presume this is because the cache does not update unless I use a different/new message but the command is supposed to run from a message. I cant think of a way to implement this that would work for any amount of channels.
Currently whenever my bot creates text channels it updates the topic to include "volturnbot" so that it can delete its own channels without a category.
I presume this is because the cache does not update unless I use a different/new message but the command is supposed to run from a message.
I believe that assumption is correct. It is probably because the channel.deleted property is still false even after you delete the channel in the for loop, since there is probably a slight delay associated with channel deletion. There are two solutions I can think of:
A) Instead of using a for loop, you could perhaps use setInterval as a loop with a delay of 1000 milliseconds or so (might have to increase or decrease that depending on what works). You would need to create two new variables: one to contain the setInterval loop, and another to keep track of how many iterations of the loop have occurred. When the iterations variable is equal to the channelAmount variable, that would be when you use return clearInterval(intervalVariable) where intervalVariable is the variable containing the loop. (This is assuming a timeout gives the cache enough time to update after the channel is deleted).
B) Loop through the cached text channels instead of fetching one channel from the cache each time. Example:
var channelAmount = Number(args[0]);
console.log("executing cleartextchats")
var channels = message.guild.channels.cache.filter(ch => ch.deleted == false && ch.type === 'text' && ch.topic && ch.topic.match("volturnbot"));
var iterations = 0;
for (var textChat of channels) {
iterations++;
message.channel.send(`deleting ` + textChat.name)
textChat.delete()
if (iterations == channelAmount) break;
}
Honestly I prefer option B, and I am positive option B would work much better in terms of what you want to achieve here. You also mentioned that the channel topic "includes" the phrase "volturnbot", I'm not sure if that indicates the description could be more than exactly "volturnbot" so I made option B use topic.match("volturnbot") for that reason.
Because guild.channels.cache returns a collection, you have to use .array()
also, instead of finding a single channel and then searching through the same cache, put all channels in a single array and loop through that.
var channelAmount = Number(args[0]);
var textChats = message.guild.channels.cache
.filter((ch) => ch.type === 'text' && ch.topic === 'volturnbot')
.array()
for (var i = 0; i <= channelAmount; i++) {
message.channel.send("deleting " + textChats[i].name)
//textChats[i].delete()
}

Algorithm to Sort a List of n Number of Items by Comparing them Against One Another in Pairs

I will try to be specific as possible as I can't find anything on this through the Google gods.
I have a list of 10 movies. I would like to display the movies in pairs. The user picks their favorite of the two. The next pair is displayed. The user picks their favorite of those two, so on and so on until I can faithfully output the list in their order of preference from 1-10.
I'm doing this in Javascript, but even just a way to do it that is language agnostic would be great. No need to worry about syntax or UI stuff.
With three movies it's pretty easy (initial order of movies and order of pairs shouldn't matter):
1.sw
2.esb
3.rotj
example 1
1vs2: winner = 2
2vs3: winner = 2
1vs3: winner = 1
Sorted List: 2,1,3
example 2
1vs3: winner = 1
1vs2: winner = 2
2vs3: winner = 2
Sorted List: 2,1,3
First time posting so if I need to be more specific, need to have exact syntax, etc., please don't hesitate to let me know.
The minimum number of comparisons required to sort 10 items is 22. (See https://oeis.org/A036604). Do you really think your users will suffer through 22 "which movie do you like better?" questions? And do you honestly believe that the result will be useful? You'll have many cases where a user will say that he liked movie A better than B, and B better than C, but he liked movie C better than he liked movie A. So now you have the problem that:
A > B
B > C
C > A
And there's no reasonable way to resolve that conflict.
In short, your user interface is flawed. You can try to build it, but your users won't like it and your results will not be reliable.
A better interface would be to list the 10 movies and allow the users to arrange them in order of preference. Or let the user rate the movies on a scale from 1 to 5. But expecting users to answer 22 questions and get a complete ordering is a fool's errand.
The basic problem is easy. We have a ton of sorting algorithms that will work with O(n log(n)) comparisons. For instance mergesort:
// Split the array into halves and merge them recursively
function mergeSort (arr) {
if (arr.length === 1) {
// return once we hit an array with a single item
return arr
}
const middle = Math.floor(arr.length / 2) // get the middle item of the array rounded down
const left = arr.slice(0, middle) // items on the left side
const right = arr.slice(middle) // items on the right side
return merge(
mergeSort(left),
mergeSort(right)
)
}
// compare the arrays item by item and return the concatenated result
function merge (left, right) {
let result = []
let indexLeft = 0
let indexRight = 0
while (indexLeft < left.length && indexRight < right.length) {
if (left[indexLeft] < right[indexRight]) {
result.push(left[indexLeft])
indexLeft++
} else {
result.push(right[indexRight])
indexRight++
}
}
return result.concat(left.slice(indexLeft)).concat(right.slice(indexRight))
}
So in principle you need to simply replace left[indexLeft] < right[indexRight] with an arbitrary comparison function that asks the user, gets an answer, and then continues.
Now there is a catch. The catch is that you need to make this code asynchronous. When you go to ask the user, you need to ask the user, then return to inside your code. If you're using node at the console, then you can do this with async/await. If you are not, then you'll need to figure out how to do it with promises. Modifying mergeSort is easy, just make the end into:
return Promise.all([mergeSort(left), mergeSort(right)]
).then(function (values) {return merge(values[0], values[1])});
The trick is in turning the loop inside of merge into a function that takes the current state of your iteration, and returns a promise that asks the question, then either returns the final sorted array, or returns a promise that handles the next iteration.
Since this looks like homework, whose whole purpose is to make you face that mental challenge, I'll leave my answer off here. Fair warning, I gave you a hint about how to do it, but if you're just learning about async code your head is SUPPOSED to spin as you figure it out.
To determine all possible combinations from your array try the following loop. Assuming order does not matter and we do not want repeats:
var arr = [1,2,3,4,5,6,7,8,9,10]
var arr_count = arr.length
var combinations_array = []
for (i = 0; i < arr_count; i++) {
var combinations = arr_count - (i+1)
for (y = 0; y < combinations; y++) {
combination = [arr[i],arr[(combinations - y)]];
combinations_array.push(combination);
}
}
In your example I'd pass Movie ID's into arr then iterate through the combinations_array to determine which combination of movies should be displayed next.
To produce a list of pairs, I would use a nested loop like this:
var items = [1,2,3,4,5,6,7,8,9,10],
result = [],
x = 0,
y = 0;
for (x = items.length; x--;)
{
for(y = x; y--;)
{
result.push({ a: items[x], b: items[y] });
}
}
console.debug(result);
The second loop is initialised from the outer loops incrementor so that you don't end up with duplicates.
Once you have the pairs, you should be able to build the ui from that.
Hope it helps!

JavaScript Help (Loops and Arrays in Particular)

So I am doing an assignment for a required javascript class and am stuck on a couple of parts specifically. We are supposed to create a guessing game with an array where we prompt the user to guess names and if they match anything in the array to tally it up as points.
Anyway here is the main code, the part that I am stuck on is figuring out how to loop the code so when the user is prompted 3 times for a guess and each guess is taken into account
var sportsArray = ["Football","Basketball","Rollerblading","Hiking","Biking","Swimming"];
var name = prompt("Please enter your name.", "Enter Here");
var arrayGuess = prompt("Guess a sport.", "Enter Here");
var counter;
for (counter = 0; counter < sportsArray.length; counter++) {
if (arrayGuess === "Football"||"Basketball"||"Rollerblading"||"Hiking"||"Biking"||"Swimming"){
alert("Good Job");
} else {
arrayGuess;
}
}
So the goal is to prompt the user to guess a part of the original array and if they do let them know that, but if they don't take points away and make them guess again until they have guessed 3 times.
Anyway if someone could lend a hand it would be appreciated.
You cannot simultaneously compare one item to a whole bunch of things like this:
if (arrayGuess === "Football"||"Basketball"||"Rollerblading"||"Hiking"||"Biking"||"Swimming")
Instead, you have to compare it to each individual item:
if (arrayGuess === "Football"||
arrayGuess === "Basketball"||
arrayGuess === "Rollerblading"||
arrayGuess === "Hiking"||
arrayGuess === "Biking"||
arrayGuess === "Swimming")
Or, there are more effective ways to compare to multiple items such as:
if (" Football Basketball Rollerblading Hiking Biking Swimming ".indexOf(" " + arrayGuess + " ") !== -1)
Or, using an array:
if (["Football","Basketball","Rollerblading","Hiking","Biking","Swimming"].indexOf(arrayGuess) !== -1)
Or, if this comparison happened a lot, you'd build an object ahead of time and use it for a lookup:
var items = {"Football":true,"Basketball":true,"Rollerblading":true,"Hiking":true,"Biking":true,"Swimming":true};
if (items[arrayGuess] === true)
If you want to compare without regards for proper case, then you can lowercase what the user entered and compare that to lower case test values:
var items = {"football":true,"basketball":true,"rollerblading":true,"hiking":true,"biking":true,"swimming":true};
if (items[arrayGuess.toLowerCase()] === true)
FYI, it's also not clear why you're using a loop here at all. No loop is needed to prompt once and test against all the possible sports values.
If you have to cycle through an array with a loop, then you can do this:
var items = ["football","basketball","rollerblading","hiking","biking","swimming"];
var testVal = arrayGuess.toLowerCase();
var match = -1;
for (var i = 0; i < items.length; i++) {
if (testVal === items[i]) {
// found a match
match = i;
break;
}
}
if (match !== -1) {
// items[match] was the match
} else {
// no match
}
I see a couple of things wrong here, as was already mentioned, your comparison in the if statement needs to reference the variable each time it is compared. But additionally, since you are in a loop based on the length of your sportsArray variable, it would be better to not reference strings at all in the if statement, and instead do something more like the following:
if (arrayGuess === sportsArray[counter]) {
// Do stuff here
} else {
// Do other stuff here
}
Additionally, your else clause isn't going to behave quite like you are expecting it to. You are going to have to assign a new value to it, probably by way of another call to prompt. As of now you are only referencing the variable, which will do nothing. If you need to take three guesses, I would add an 'else if' clause into the mix where you get a new value for the variable, an let the else clause display a score and break out of the loop.
if (arrayGuess === sportsArray[counter]) {
// Add to the score
} else if (counter < 2) {
// We prompted for the first guess before the loop,
// so take the second and third here
arrayGuess = prompt("Guess a sport.", "Enter Here");
} else {
// Display score then break to exit the loop
break;
}

How to pick random element in an array AVOIDING (EXCEPT if it's) a certain value?

For example, when users are connecting to this application they are given a userid var, then it's inserted into the array. So, i'm using
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
to pick another random user. But i need to make sure it doesn't pick the userID they personally were assigned so they don't end up getting themselves.
how would i use that code but tell it to "remember, make sure you don't pick userid"
maybe I could do something like
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
if (chosenUser = userid)
{
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
} else
{
//next part of mycode
}
Maybe that should be a while (chosenUser = userid) incase it gets it twice...
But, i'm thinking i could skip all that if there is a efficent way just to make sure it doesn't pick it in the first place.
Sorry, i'm not quite sure how I should have phrased the question or if there is a term i'm unaware of to refer to what i'm trying to do.
using Math.round() can lead to returning "undefined" since you're allowing it to choose usersOnlineArray.length, which is not indexed. use Math.floor() instead.
you could move the item you don't want to match to the end of the array and then select at random an element from the array except for the last element:
//Users Array
var usersArray:Array = new Array("JoeID", "MaryID", "UserID", "JohnID", "SusanID");
//Find UserID And Push It To The End
usersArray.push(usersArray.splice(usersArray.indexOf("UserID"), 1));
//Randomly Select Companion From usersArray Except For UserID (Last Element)
var companion:String = usersArray[Math.floor(Math.random() * (usersArray.length - 1))];
trace(companion);
You are on good way, just call again your method for example
public void Something(){ string user = GetUser(); }
public string GetUser(){
chosenUser = usersOnlineArray[Math.round((Math.random()*usersOnlineArray.length))];
if (chosenUser == userid)
{
return GetUser();
}
return chosenUser;
}
Since Flash is same ECMA branch of languages as JavaScript and there is not a JS answer (and ActionScript is kind of extinct species) here is the answer (without recursion) in JS:
var getRandomExcept = function(elements, exceptElement){
if(elements.length <= 0){
return null;
}else if(typeof exceptElement !== 'undefined' && elements.length == 1){
if(elements[0] === exceptElement) return null;
}
var n = Math.floor(Math.random() * elements.length);
if(elements[n] === exceptElement){
// make one random trip around elements but stop (<elements.length) before the exceptElement
n = (n + Math.floor(Math.random() * elements.length)) % elements.length;
}
return elements[n];
};

Categories