Passing hands of cards around a table in Javascript - javascript

This seems like a stupidly simple thing to do, but I can't figure out what I'm doing wrong. The goal is to have an array of 8 other arrays, which each contain hands of cards (in the example, the arrays just contain arbitrary numbers). Then, depending on whether passDirection is set to -1 or 1, each array is cycled through and replaced with the one next to it. The desired end result is that the values of playerList essentially shift by 1 either up or down, and this can be repeated several times without issue.
What's actually happening with the code I have below, though, is that all the arrays are just being replaced with what's at index 0, except for the first one. How can I fix this?
var playerList = new Array;
var passDirection = -1;
for(i = 0; i < 8; i++) {
playerList.push([playerList.length,i]); // Fill Arrays with arbitrary data
}
for (i=0; i< playerList.length; i++) {
console.log(i + ": " + playerList[i]); // Check their values before anything is done to them
}
for(q=0; q < 5; q++){ // Repeat the process 5 times, just because.
var bufferArray = playerList[0]; // Put Array Element 0's value in a buffer as it will be replaced first
for(i = 0; i < playerList.length && i > (playerList.length * -1); i += passDirection) {
var catcher = i; // 'catcher' should be the array that gets replaced
var passer = catcher - passDirection; // 'passer' should be the one it gets replaced with
if (catcher < 0) {
catcher = catcher + playerList.length;
}
if (passer < 0) {
passer = passer + playerList.length;
} else if (passer >= playerList.length) {
passer = passer - playerList.length;
}
if (passer == 0) {
playerList[catcher] = bufferArray;
} else {
playerList[catcher] = playerList[passer];
}
}
for (i=0; i< playerList.length; i++) {
console.log(i + ": " + playerList[i]);
}
console.log("...");
}
https://jsfiddle.net/3r1Lhwc5

You have two errors in your code:
if (passer = 0) is performing an assignment. You need if (passer === 0).
The passer index is looking at the wrong side of the value. Currently you are first getting from 1 and putting at 0, then getting from 0 and putting at 7 (i.e. -1). Notice how you are moving the same value in the second iteration. You need to change passer = catcher - passDirection to passer = catcher + passDirection
Note that all this can be done much easier with the splice, shift, unshift, pop and push Array methods (on the main playerList).

You can make your life easier by using Array methods to move elements from the beginning to end of an array or vice versa. Using this in the body of your for loop should do the trick:
if (passDirection === -1) {
const first = playerList.shift();
playerList.push(first);
}
else {
const last = playerList.pop();
playerList.unshift(last);
}

Related

How to omit 0 from array of randomly generated numbers using Javascript?

I have done a code where it will generate 7 random numbers from 0 to 49.
HTML
<button id="btn_generate" onClick="getMyLuckyNumbers()">GENERATE NUMBERS</button>
<div id="display"></div>
JS
function getMyLuckyNumbers() {
for (var allNumbers=[],i=0;i<50;++i) allNumbers[i]=i;
function shuffle(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
allNumbers = shuffle(allNumbers);
var luckyNumbers = "";
var g;
for (g = 0; g < 7; g++) {
luckyNumbers += allNumbers[g] + "<br>";
}
document.getElementById("display").innerHTML = luckyNumbers;
}
I would like to know how I can omit 0?
I attempted two ways, but both failed.
Attempt 1:
Changed the i=0 to i=1.
for (var allNumbers=[],i=1;i<50;++i)
allNumbers[i]=i;
This did omit 0 but when 0 was randomly supposed to appear, it shows as undefined.
Attempt 2:
I tried to do an if statement.
if(allNumbers != 0) {
allNumbers = shuffle(allNumbers);
}
But this still displays 0 if it happens to be randomly generated.
So, how do I omit 0?
The issue with starting i from 1 is that the 0th index will be empty, and so when accessed gives undefined.
So, if you want to avoid the number 0, you can make i start at 1, but you would need to change the way you add numbers to your array. Instead of adding your numbers to your array by placing them at a specific index, you can .push() them to the end of your array each iteration like so:
// \/------ start at i = 1, the 1st number to be added to your array
for (var allNumbers=[],i=1;i<50;++i)
allNumbers.push(i);
This way, you will fill up your array with numbers from 1 to 49 which can them be shuffled.

Increment counts of sites visited including TLDs and subdomains outputted to JSON

So I was asked to create an algorithm that when given a basic input of an array of counts and sites, it will output the accumulated visits to each TLD and Subdomain represented in a JSON object that will yield data like:
1120 com
800 google.com
310 reddit.com
60 mail.yahoo.com
10 mobile.sports.yahoo.com
50 sports.yahoo.com
10 stackoverflow.com
3 org
3 wikipedia.org
2 en.wikipedia.org
2 es.wikipedia.org
1 mobile.sports
1 sports
The input is something like:
// visits = [ "800,google.com",
// "60,mail.yahoo.com",
// "10,mobile.sports.yahoo.com",
// "40,sports.yahoo.com",
// "310,reddit.com",
// "10,stackoverflow.com",
// "2,en.wikipedia.org",
// "1,es.wikipedia.org",
// "1,mobile.sports" ]
My code looks like this so far and I know its wrong, but my brain is melted at the moment and I am not sure how to proceed. I am not necessarily looking for you to write the algorithm for me, but I do want to understand logically how I could break this down.
function getDomainHits(arr){
var splitCount = [];
var splitDomains = [];
var domainCountDict = {"Domains" : [],"Count" : 0};
for (var i = 0; i < arr.length; i++){
splitCount = arr[i].split(",");
splitDomains = splitCount[1].split(".");
for (var j = 0; j < splitDomains.length; j++){
if (!domainCountDict.Domain.includes(splitDomains[j])){
domainCountDict.Domain.push(splitDomains[j]);
}
}
}
console.log(domainCountDict);
}
As you can see I stopped here because I couldn't think of the best way to split these into different key, value pairs - one being domains and the other being the counts. Also my algorithm doesn't exactly follow the requirements.
So I figured out the algorithm. Define a variable - initialize it as an Array, and a dictionary to store the processed array data.
var splitCount = [];
var domainCountDict = {};
Then you need to take the Array of strings (arr - the function parameter) and iterate through it. On each iteration you need to split the string element into another Array to further process it.
for (var i = 0; i < arr.length; i++){
splitCount = arr[i].split(",");
...
}
So for the example input data of
// visits = [ "800,google.com",
// "60,mail.yahoo.com",
// "10,mobile.sports.yahoo.com",
// "40,sports.yahoo.com",
// "310,reddit.com",
// "10,stackoverflow.com",
// "2,en.wikipedia.org",
// "1,es.wikipedia.org",
// "1,mobile.sports" ]
Iteration 0 would be split into an Array of ["800","google.com"] and assigned to Var splitCount. You would then need to access splitCount and because of the input formatting you don't need to create a for loop. I created a variable to store the current count of the site - which will always be element 0 because of the format of the input data.
I didn't bother with input sanitation here because I didn't have time to create a map function that will turn the number elements into - well... numbers. I relied on the assumption that the input data will always have a number in the 0th index - which is terrible. Don't do this.
var curCnt = 0;
if (splitCount[0]){
curCnt = splitCount[0];
}
This next chunk of logic hurt my brain a little bit because I needed to find a way to store each domain component and its count in the dict and determine if the other domains contained components that already existed and if so increment those. Lets make some more Arrays!
var domain = [];
var currentDom = [];
if (splitCount[1] != undefined && splitCount[1]){
domain = splitCount[1].split(".");
for (var j = domain.length - 1; j >= 0; j--){
...
}
}
Above you will see that created an Array to hold the domain components called domain and another called currentDom to hold the components that are being worked and have already been worked, because we want to make sure that we count com and google.com. Lets look inside of the for loop.
for (var j = domain.length - 1; j >= 0; j--){
currentDom.unshift(domain.pop());
/*console.log("current iter: " + k + "\n"
+ "currentDom: " + currentDom.join(".") + "\n"
+ "current count: " + curCnt + "\n");*/
if (currentDom.join(".") in domainCountDict){
/*console.log("currentDom2: " + currentDom.join("."));
console.log("increment existing");*/
domainCountDict[currentDom.join(".")] += parseInt(curCnt);
}
if (!(currentDom.join(".") in domainCountDict)){
/*console.log("currentDom3: " + currentDom.join("."));
console.log("increment new");*/
domainCountDict[currentDom.join(".")] = parseInt(curCnt);
//console.log(domainCountDict);
}
}
Above you will see that I am iterating backwards in this loop to work the TLD first and then the domains/subdomains. I chose to pop the last element off the end of the current array and unshift it to the beginning of the new Array, currentDom. This will effectively let me work on a portion of the entire FQDN to determine if it has been included in the dictionary.
I have a few if statements to determine if the currentDom is included in the array. I had to use Array.join() to accurately check if the string of the current domain components have been included in the dictionary. If not then the string of currentDom would be added as a key and the curCnt would be the value assigned. If so, then the value would be incremented. Because of my lazy input sanitation in the curCnt assignment I had to parse these as Int because JS dynamic types. I am sure there is a better way, but my brain hurts now.
Finally make sure that you return the created dictionary on the outside of all of these for loops.
The full algorithm is below
// Sample output (in any order/format):
// getTotalsByDomain(counts)
// 1320 com
// 900 google.com
// 410 yahoo.com
// 60 mail.yahoo.com
// 10 mobile.sports.yahoo.com
// 50 sports.yahoo.com
// 10 stackoverflow.com
// 3 org
// 3 wikipedia.org
// 2 en.wikipedia.org
// 1 es.wikipedia.org
// 1 mobile.sports
// 1 sports
let counts = [ "900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"2,en.wikipedia.org",
"1,es.wikipedia.org",
"1,mobile.sports" ];
console.log(getDomainHits(counts));
function getDomainHits(arr){
var splitCount = [];
var domainCountDict = {};
for (var i = 0; i < arr.length; i++){
splitCount = arr[i].split(",");
var curCnt = 0;
if (splitCount[0]){
curCnt = splitCount[0];
}
var domain = [];
var currentDom = [];
if (splitCount[1] != undefined && splitCount[1]){
domain = splitCount[1].split(".");
for (var j = domain.length - 1; j >= 0; j--){
currentDom.unshift(domain.pop());
/*console.log("current iter: " + k + "\n"
+ "currentDom: " + currentDom.join(".") + "\n"
+ "current count: " + curCnt + "\n");*/
if (currentDom.join(".") in domainCountDict){
/*console.log("currentDom2: " + currentDom.join("."));
console.log("increment existing");*/
domainCountDict[currentDom.join(".")] += parseInt(curCnt);
}
if (!(currentDom.join(".") in domainCountDict)){
/*console.log("currentDom3: " + currentDom.join("."));
console.log("increment new");*/
domainCountDict[currentDom.join(".")] = parseInt(curCnt);
//console.log(domainCountDict);
}
}
}
}
return domainCountDict;
}

Splice NOT removing certain characters

I'm working on some codewars problems and I came to this 'remove noise thing', I guess the point is to escape backslash \ and use replace method, which was easy. But I didn't want to use replace, instead I found myself in trouble trying to remove items with splice method.
Funny thing is, when I debug in Chrome dev tools, step by step I see items get removed, but console.log spits out certain characters($/·|ªl) problematic to remove, and at the end gets returned and join with those characters. Why is that?
function removeNoise(str) {
var base = "%$&/#·#|º\ª";
var arr = str.split('');
for(var i = 0; i < arr.length; i++) {
var item = arr[i];
var condition = base.indexOf(item);
if(condition + 1) {
//works like a charm
//arr[i] = '';
arr.splice(i,1);
//this thing wont work
//when debugging it removes the items from the array
//console log print no removing
}
}
return arr.join('');
}
removeNoise('he%$&/#·#|º\ª\llo'); //=> $/·|ªllo
You're using splice to remove entries from your array, but you're then incrementing i for the next loop. If you remove the entry at index 5 from a 10-entry array, what was the entry at index 6 is now at index 5 (of what's now a 9-entry array), so you don't want to increment your index.
The solution is to use a while loop and only update i if you don't splice:
function removeNoise(str) {
var base = "%$&/#·#|º\ª";
var arr = str.split('');
var i = 0;
while (i < arr.length) {
var item = arr[i];
var condition = base.indexOf(item);
if (condition + 1) {
// Remove this entry, reuse same value for 'i'
arr.splice(i,1);
} else {
// Don't remove this entry, move to next
++i;
}
}
return arr.join('');
}
var result = removeNoise('he%$&/#·#|º\ª\llo');
var pre = document.createElement('pre');
pre.appendChild(
document.createTextNode(result)
);
document.body.appendChild(pre);
You're removing characters from your array. This will throw your indexer variable i out of sync with the characters you want to test. Easy way to fix is to start at the end of the array working your way to the beginning.
Change your for loop to this.
for(var i = arr.length -; i <= 0; i--) {
function removeNoise(str) {
var base = "%$&/#·#|º\ª";
var arr = str.split('');
for(var i = arr.length - 1; i <= 0 ; i--) {
var item = arr[i];
if(base.indexOf(item) >= 0) {
//remove the offending character
arr.splice(i,1);
}
}
return arr.join('');
}
removeNoise('he%$&/#·#|º\ª\llo'); //=> $/·|ªllo

Using search method from string

I'm trying to count the number of times certain words appear in the strings. Every time I run it I get a
uncaught TypeErro: undefined is not a function
I just actually need to count the number of times each "major" appears.
Below is my code:
for(var i = 0; i < sortedarray.length; i++)
{
if(sortedarray.search("Multimedia") === true)
{
multimedia += 1;
}
}
console.log(multimedia);
Here is my csv file which is stored in a 1d array.
"NAME","MAJOR","CLASS STANDING","ENROLLMENT STATUS"
"Smith, John A","Computer Science","Senior","E"
"Johnson, Brenda B","Computer Science","Senior","E"
"Green, Daisy L","Information Technology","Senior","E"
"Wilson, Don A","Information Technology","Junior","W"
"Brown, Jack J","Multimedia","Senior","E"
"Schultz, Doug A","Network Administration","Junior","E"
"Webber, Justin","Business Administration","Senior","E"
"Alexander, Debbie B","Multimedia","Senior","E"
"St. John, Susan G","Information Technology","Junior","D"
"Finklestein, Harold W","Multimedia","Freshman","E"
You need to search inside each string not the array. To only search inside the "Major" column, you can start your loop at index 1 and increment by 4 :
var multimedia = 0;
for(var i = 1; i < sortedarray.length; i += 4)
{
if(sortedarray[i].indexOf("Multimedia") > -1)
{
multimedia += 1;
}
}
console.log(multimedia);
What you're probably trying to do is:
for(var i = 0; i < sortedarray.length; i++)
{
if(sortedarray[i].indexOf("Multimedia") !== -1)
{
multimedia++;
}
}
console.log(multimedia);
I use indexOf since search is a bit of overkill if you're not using regexes.
Also, I replaced the += 1 with ++. It's practically the same.
Here's a more straightforward solution. First you count all the words using reduce, then you can access them with dot notation (or bracket notation if you have a string or dynamic value):
var words = ["NAME","MAJOR","CLASS STANDING","ENROLLMENT STATUS"...]
var count = function(xs) {
return xs.reduce(function(acc, x) {
// If a word already appeared, increment count by one
// otherwise initialize count to one
acc[x] = ++acc[x] || 1
return acc
},{}) // an object to accumulate the results
}
var counted = count(words)
// dot notation
counted.Multimedia //=> 3
// bracket notation
counted['Information Technology'] //=> 3
I don't know exactly that you need this or not. But I think its better to count each word occurrences in single loop like this:
var occurencesOfWords = {};
for(var i = 0; i < sortedarray.length; i++)
{
var noOfOccurences = (occurencesOfWords[sortedarray[i]]==undefined?
1 : ++occurencesOfWords[sortedarray[i]]);
occurencesOfWords[sortedarray[i]] = noOfOccurences;
}
console.log(JSON.stringify(occurencesOfWords));
So you'll get something like this in the end:
{"Multimedia":3,"XYZ":2}
.search is undefined and isn't a function on the array.
But exists on the current string you want to check ! Just select the current string in the array with sortedarray[i].
Fix your code like that:
for(var i = 0; i < sortedarray.length; i++)
{
if(sortedarray[i].search("Multimedia") === true)
{
multimedia += 1;
}
}
console.log(multimedia);

Javascript: matching a dynamic string against an array

I'm attempting to teach myself javascript. I chose something I assumed was simple, but ran into problems relatively quickly.
I'm attempting to search a string for another string given by the user.
My code so far is:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = [];
var one = 0;
var two = 0;
var k = 0;
var sourceSearch = function(text) {
for(i = 0; i < source.length; i++) { //for each character in the source
if(source[i] === searchString[0]) { //if a character in source matches the first element in the users input
one = source.indexOf(i); //confused from here on
for(p = searchString.length; p > 0; p--) {
}
}
}
};
sourceSearch(searchString);
My idea was:
check to see if the first loop finds a character that matches the first character in the user input
if it matches, check to see if the next X characters after the first match the next X characters in the source string
if they all match, push them to the hits array
My problem: I have no idea how to iterate along the arrays without nesting quite a few if statements, and even then, that wouldn't be sufficient, considering I want the program to work with any input.
Any ideas would be helpful. Thanks very much in advance.
Note: There are a few un-used variables from ideas I was testing, but I couldn't make them work.
You can try:
if (source.indexOf(searchString) !== -1) {
// Match!
}
else
{
//No Match!
}
As the other answers so far point out, JavaScript strings have an indexOf function that does what you want. If you want to see how it's done "by hand", you can modify your function like this:
var sourceSearch = function(text) {
var i, j, ok; // always declare your local variables. globals are evil!
// for each start position
for(i = 0; i < source.length; i++) {
ok = true;
// check for a match
for (j = searchString.length - 1; ok && j >= 0; --j) {
ok = source[i + j] === searchString[j];
}
if (ok) {
// searchString found starting at index i in source
}
}
};
This function will find all positions in source at which searchString was found. (Of course, you could break out of the loop on the first success.) The logic is to use the outer loop to advance to each candidate start position in source and use the inner loop to test whether that position actually is the position of a match to searchString.
This is not the best algorithm for searching strings. The built-in algorithm is much faster (both because it is a better algorithm and because it is native code).
to follow your approach, you can just play with 2 indexes:
var sourceSearch = function(text) {
j = 0;
for(i = 0; i < source.length; i++) {
if(source[i] === text[j]) {
j++;
} else {
j = 0;
}
if (j == text.length) {
console.log(i - j); //this prints the starting index of the matching substring
}
}
};
These answers are all pretty good, but I'd probably opt for something like this:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = source.split(searchString);
var hitsCount = hits.length - 1;
This way you have all of the data you need to figure out where each hit occurred in he source, if that's important to you.

Categories