Javascript random array checker error - javascript

Working on a game and cant figure out why my functions aren't working right..
Uncaught RangeError: Maximum call stack size exceeded
By my knowledge one of my functions have a infinite loop(?)
I have a array witch needs to have 3 random speeds in it.
var randomSpeeds = new Array();
I have a function made witch generate a random speed:
function generateSpeed() {
var randomSpeed = Math.random().toFixed(1) * 5;
if(randomSpeed == 0){
randomSpeed = 1;
}
return randomSpeed;
}
The array is filled by this function:
function fillSpeedArray() {
for(var i = 0; i < 3; i++) {
var randomSpeed = generateSpeed();
if(speedArrayChecker(randomSpeed) != false) {
randomSpeeds.splice(i, 0, randomSpeed);
} else {
fillSpeedArray();
}
}
}
The function loops 3 times and each time it generates a random speed and goos through a if/else statement for checking if the array already has got the random generated number (speedArrayChecker).
The speedArrayChecker:
function speedArrayChecker(speed) {
for(speeds in randomSpeeds) {
if(speeds != speed) {
return true;
}
}
return false;
}
This last function goos through the array and if the array already go the random generated number, return true else false.
Function called and checked:
fillSpeedArray();
console.log(randomSpeeds);
By a reason I don't see the functions aren't working correctly.
Thanks and regards.

Solution:
var randomSpeeds = new Array();
function generateSpeed() {
var randomSpeed = Math.random().toFixed(1) * 5;
if(randomSpeed == 0){
randomSpeed = 1;
}
return randomSpeed;
}
function fillSpeedArray() {
while (randomSpeeds.length < 3) {
var randomSpeed = generateSpeed();
if (speedArrayChecker(randomSpeed) != false) {
randomSpeeds.splice(randomSpeeds.length, 0, randomSpeed);
}
}
}
function speedArrayChecker(speed) {
return randomSpeeds.indexOf(speed) === -1
}
fillSpeedArray();
console.log(randomSpeeds);
Explanation:
There were two problems with your code.
The implementation of the speedArrayChecker function was fundamentally flawed. It returned false only when the randomSpeeds was empty.
You had an infinite loop caused by infinite recursion.
The solution was to correct the speedArrayChecker implementation and to use a while loop instead of a for loop.

You have an infinite loop(by recursion) here:
function fillSpeedArray() {
for(var i = 0; i < 3; i++) {
var randomSpeed = generateSpeed();
if(speedArrayChecker(randomSpeed) != false) {
randomSpeeds.splice(i, 0, randomSpeed);
} else {
fillSpeedArray();
}
}
}
In the else if the speed exists already it will call the function it's currently in again and again. This function will never exit, unless you get 3 random speeds perfectly the first time. I would recommend changing fillSpeedArray() to maybe i--.
On a side note why don't you use randomSpeeds.push(randomSpeed) to add speeds to the array.

Related

JavaScript game starts fast and slows down over time

My simple JavaScript game is a Space Invaders clone.
I am using the p5.js client-side library.
I have tried many things to attempt at speeding up the game.
It start off fast, and then over time it get slower, and slower, it isn't as enjoyable.
I do not mean to show every bit of code I have. I am not showing every class, but I will show the main class where everything is happening.
Could someone eyeball this and tell me if you see anything major?
I am new to JS and new to making games, I know there is something called update()
that people use in scripting but I am not familiar with it.
Thank you.
var ship;
var flowers = []; // flowers === aliens
var drops = [];
var drops2 = [];
function setup() {
createCanvas(600, 600);
ship = new Ship();
for (var i = 0; i < 6; i ++) {
flowers[i] = new Flower(i * 80 + 80, 60);
}
flower = new Flower();
}
function draw() {
background(51);
ship.show();
ship.move();
shipDrops();
alienDrops();
dropsAndAliens();
dropDelete();
drop2Delete();
}
// if 0 drops, show and move none, if 5, etc..
function shipDrops() {
for (var i = 0; i < drops.length; i ++) {
drops[i].show();
drops[i].move();
for (var j = 0; j < flowers.length; j++) {
if(drops[i].hits(flowers[j]) ) {
flowers[j].shrink();
if (flowers[j].r === 0) {
flowers[j].destroy();
}
// get rid of drops after it encounters ship
drops[i].evaporate();
}
if(flowers[j].toDelete) {
// if this drop remove, use splice function to splice out of array
flowers.splice(j, 1); // splice out i, at 1
}
}
}
}
function alienDrops() {
// below is for alien/flower fire drops 2
for (var i = 0; i < drops2.length; i ++) {
drops2[i].show();
drops2[i].move();
if(drops2[i].hits(ship) ) {
ship.shrink();
drops2[i].evaporate(); // must evap after shrink
ship.destroy();
if (ship.toDelete) {
delete ship.x;
delete ship.y;
} // above is in progress, deletes after ten hits?
}
}
}
function dropsAndAliens() {
var randomNumber; // for aliens to shoot
var edge = false;
// loop to show multiple flowers
for (var i = 0; i < flowers.length; i ++) {
flowers[i].show();
flowers[i].move();
// ******************************************
randomNumber = Math.floor(Math.random() * (100) );
if(randomNumber === 5) {
var drop2 = new Drop2(flowers[i].x, flowers[i].y, flowers[i].r);
drops2.push(drop2);
}
//**************** above aliens shooting
// below could be method, this will ensure the flowers dont
//go offscreen and they move
//makes whtever flower hits this space become the farther most
//right flower,
if (flowers[i].x > width || flowers[i]. x < 0 ) {
edge = true;
}
}
// so if right is true, loop thru them all again and reset x
if (edge) {
for (var i = 0; i < flowers.length; i ++) {
// if any flower hits edge, all will shift down
// and start moving to the left
flowers[i].shiftDown();
}
}
}
function dropDelete() {
for (var i = drops.length - 1; i >= 0; i--) {
if(drops[i].toDelete) {
// if this drop remove, use splice function to splice out of array
drops.splice(i, 1); // splice out i, at 1
}
}
}
function drop2Delete() {
for (var i = drops2.length - 1; i >= 0; i--) {
if(drops2[i].toDelete) {
// if this drop remove, use splice function to splice out of array
drops2.splice(i, 1); // splice out i, at 1
}
}
}
function keyReleased() {
if (key != ' ') {
ship.setDir(0); // when i lift the key, stop moving
}
}
function keyPressed() {
// event triggered when user presses key, check keycode
if(key === ' ') {
var drop = new Drop(ship.x, height); // start ship x and bottom of screen
drops.push(drop); // when user hits space, add this event to array
}
if (keyCode === RIGHT_ARROW) {
// +1 move right
ship.setDir(1);
} else if (keyCode === LEFT_ARROW) {
// -1 move left
ship.setDir(-1);
} // setir only when pressing key, want continuous movement
}
Please post a MCVE instead of a disconnected snippet that we can't run. Note that this should not be your entire project. It should be a small example sketch that just shows the problem without any extra code.
But to figure out what's going on, you need to debug your program. You need to find out stuff like this:
What is the length of every array? Are they continuously growing over time?
What is the actual framerate? Is the framerate dropping, or does it just appear to be slower?
At what point does it become slower? Try hard-coding different values to see what's going on.
Please note that I'm not asking you to tell me the answers to these questions. These are the questions you need to be asking yourself. (In fact, you should have all of these answers before you post a question on Stack Overflow!)
If you still can't figure it out, then please post a MCVE in a new question post and we'll go from there. Good luck.

screeps: conditions won't work - clueless

So i have been trying this to automatically spawn Creeps in percentage to total living creeps.
however when i run this, it just keeps on spawning harvesters, completely ignoring the conditions even though console.log returns the expected results .
and now i'm clueless about what is going wrong
//creepManager.creations() == counts total creeps and spawns creeps in function of total
var spawnCreep = require('spawnCreep');
var counter = require('counter');
exports.creations=function(){
if( counter.guardCount()/counter.totalCount()<0.5 && counter.harvesterCount()>1){
spawnCreep.guard();
} else if (counter.harvesterCount()/counter.totalCount()<0.3){
spawnCreep.harvester();
} else if(counter.builderCount()/counter.totalCount()<0.2){
spawnCreep.builder();
} else {
spawnCreep.guard(); //default
}
}; // 5guards, 3harvesters, 2 builder per 10CREEPS`
(spawnCreep is another module which keeps track of how the creepers are build)
I was doing something similar in my old code:
function allocateResources() {
var counts = {guard : 0, healer : 0}
for (var name in Game.creeps) {
if (name.indexOf("guard") > -1) {
counts["guard"]++;
} else if (name.indexOf("builder") > -1) {
counts["builder"]++;
}
// ...
counts["total"]++;
}
if (counts["guard"] / (counts["total"] + 1) < 0.51) {
spawnCreep("guard");
} else if (counts["builder"] / (counts["total"] + 1) < 0.34) {
spawnCreep("builder");
}
// ...
}
You should make sure that you avoid division by zero, perhaps that's the bug for you.

Counting in binary

I'm only learning to program and was trying to make a program to count in binary.
I made a function that could convert the provided decimal to binary and it looks to be working just ok, but when I try to count upwards using a for loop my browser freezes and I can't understand why. Using a similar while loop produces the result I needed.
The problem is right at the bottom commented out. Please help figure out what I'm doing wrong here.
Here's my code:
function isOdd(num) {return num % 2};
var toBinary = function (number) {
ints = [];
binary = [];
ints.push(Math.floor(number));
while (number >= 1) {
number = (Math.floor(number))/2;
ints.push(Math.floor(number));
}
for (i=ints.length-1;i>=0;i--) {
if (isOdd(ints[i])) {
binary.push(1);
} else {
binary.push(0);
}
}
if (binary[0] === 0) {
binary.splice(0,1);
}
return binary;
};
var count = 0;
while (count <= 50) {
console.log(toBinary(count));
count++;
}
/*
for (i=1;i<=50;i++) {
console.log(toBinary(i));
}
*/
Use for (var i=ints.length-1;i>=0;i--) and for (var i=1;i<=50;i++), otherwise i will be a global variable and it will be overwritten inside toBinary.
You haven't declared i in the toBinary function, hence i is redefined on every call of toBinary in the last loop, and i will never reach 50.
Use var to declare variables like so:
var toBinary = function (number) {
var ints = [],
binary = [],
i;
:
}

Small Straight (Yahtzee) Algorithm

I have created a working javascript function to check an array of 5 numbers for a small straight, in a Yahtzee game I'm making. I've tested it to no end and I'm confident it works 100% of the time, but it is also probably the worst algorithm of all time in terms of being efficient. Here is what it looks like:
function calcSmstraight() {
var sum = 0;
var r = new Array();
var r2 = new Array();
var counter = 0;
var temp;
var bool = false;
var bool2 = false;
r[0] = document.getElementById('setKeep1').value;
r[1] = document.getElementById('setKeep2').value;
r[2] = document.getElementById('setKeep3').value;
r[3] = document.getElementById('setKeep4').value;
r[4] = document.getElementById('setKeep5').value;
// Move non-duplicates to new array
r2[0] = r[0];
for(var i=0; i<r.length; i++) {
for(var j=0; j<r2.length; j++) {
if(r[i] == r2[j]) {
bool2 = true; // Already in new list
}
}
// Add to new list if not already in it
if(!bool2) {
r2.push(r[i]);
}
bool2 = false;
}
// Make sure list has at least 4 different numbers
if(r2.length >= 4) {
// Sort dice from least to greatest
while(counter < r2.length) {
if(r2[counter] > r2[counter+1]) {
temp = r2[counter];
r2[counter] = r2[counter+1];
r2[counter+1] = temp;
counter = 0;
} else {
counter++;
}
}
// Check if the dice are in order
if(((r2[0] == (r2[1]-1)) && (r2[1] == (r2[2]-1)) && (r2[2] == (r2[3]-1)))
|| ((r2[1] == (r2[2]-1)) && (r2[2] == (r2[3]-1)) && (r2[3] == (r2[4]-1)))) {
bool = true;
}
}
if(bool) {
// If small straight give 30 points
sum = 30;
}
return sum;
}
My strategy is to:
1) Remove duplicates by adding numbers to a new array as they occur
2) Make sure the new array is at least 4 in length (4 different numbers)
3) Sort the array from least to greatest
4) Check if the first 4 OR last 4 (if 5 in length) numbers are in order
My question:
Does anyone know a way that I can improve this method? It seems ridiculously terrible to me but I can't think of a better way to do this and it at least works.
Given that you're implementing a Yahtzee game you presumably need to test for other patterns beyond just small straights, so it would be better to create the array of values before calling the function so that you can use them in all tests, rather than getting the values from the DOM elements inside the small straight test.
Anyway, here's the first way that came to my mind to test for a small straight within an array representing the values of five six-sided dice:
// assume r is an array with the values from the dice
r.sort();
if (/1234|2345|3456/.test(r.join("").replace(/(.)\1/,"$1") {
// is a small straight
}
Note that you can sort an array of numbers using this code:
r2.sort(function(a,b){return a-b;});
...but in your case the values in the array are strings because they came from the .value attribute of DOM elements, so a default string sort will work with r2.sort(). Either way you don't need your own sort routine, because JavaScript provides one.
EDIT: If you assume that you can just put the five values as a string as above you can implement tests for all possible combinations as a big if/else like this:
r.sort();
r = r.join("");
if (/(.)\1{4}/.test(r)) {
alert("Five of a Kind");
} else if (/(.)\1{3}/.test(r)) {
alert("Four of a Kind");
} else if (/(.)\1{2}(.)\2|(.)\3(.)\4{2}/.test(r)) {
alert("Full House");
} else if (/(.)\1{2}/.test(r)) {
alert("Three of a Kind");
} else if (/1234|2345|3456/.test( r.replace(/(.)\1/,"$1") ) {
alert("Small Straight");
} // etc.
Demo: http://jsfiddle.net/4Qzfw/
Why don't you just have a six-element array of booleans indicating whether a number is present, then check 1-4, 2-5, and 3-6 for being all true? In pseudocode:
numFlags = array(6);
foreach(dice)
numFlags[die.value-1] = true;
if(numFlags[0] && numFlags[1] && numFlags[2] && numFlags[3]) return true
//Repeat for 1-4 and 2-5
return false
This wouldn't be a useful algorithm if you were using million-sided dice, but for six-siders there are only three possible small straights to check for, so it's simple and straightforward.
I do not play Yahtzee, but I do play cards, and it would appear the algorithm might be similar. This routine, written in ActionScript (my JavaScript is a bit rusty) has been compiled but not tested. It should accept 5 cards for input, and return a message for either straights greater than 3 cards or pairs or higher.
private function checkCards(card1:int,card2:int,card3:int,card4:int,card5:int):String
{
// Assumes that the 5 cards have a value between 0-12 (Ace-King)
//The key to the routine is using the card values as pointers into an array of possible card values.
var aryCardValues:Array = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
var aryCardNames:Array = new Array("Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King");
var strOutMessage:String;
var intCardCount:int = 0;
var strSeperator:String;
var strHighCard:String;
for (var i:int = 0;i < aryCardValues.length;i++)
{
//Check for runs of three of a kind or greater.
if (aryCardValues[i] >= 2)
{
strOutMessage = strOutMessage + strSeperator + i + "-" + aryCardNames[i] + "s";
strSeperator = " & ";
}
//Check for values in a straight.
if (aryCardValues[i] > 0)
{
intCardCount++;
if (intCardCount > 3)strHighCard = aryCardNames[i];
}
else
{
if (intCardCount < 3)intCardCount = 0;
}
}
if (intCardCount > 3) strOutMessage = intCardCount + " run " + strHighCard + " High."
return strOutMessage;
}
It may not be as concise as the regular expressions used above, but it might be more readable and easily modified. One change that could be made is to pass in an array of cards rather than discrete variables for each card.

Unique number counter function?

This undoubtedly already exists but I can't find it anywhere after 20 min of looking.
All I want is a function that counts up so the first time you call uniqueNum() it returns 0, then 1, then 2 etc.
function uniqueNum(){
if (typeof x !== 'number') {
var x = 0;
} else {
x++;
}
return x
}
I don't want any globals or vars outside of the function hopefully.
What I've got always returns 0;
A closure can do that:
var uniqueNum = (function(){
var num = 0;
return function(){
return num++;
}
}());
uniqueNum(); // 0
uniqueNum(); // 1
A "static" variable works too, as suggested in other answers.
You can implement a "static" variable like this:
function uniqueNum() {
return uniqueNum.counter = (uniqueNum.counter || 0)+1;
}
The following will use the function itself for storing the counter:
function uniqueNum() {
if (uniqueNum.x == null) {
uniqueNum.x = 0;
} else {
uniqueNum.x++;
}
return uniqueNum.x;
}
console.log(uniqueNum()); // 0
console.log(uniqueNum()); // 1
console.log(uniqueNum.x); // 1

Categories

Resources