Bizarre array problems- changing length, predefined first element - arrays

This is a basic piece of code I've created that generates a random two-coloured level:
var map:Array = new Array();
var mLength:int = 28;
var mHeight:int = 16;
var mArea:int = mLength * mHeight;
var tileWidth:int = 20;
var tileHeight:int = 20;
var tileX:int = 0 - tileWidth;
var tileY:int = 0;
var genTile:int;
var genDone:Boolean = false;
var waterChance:int = 10;
var grassChance:int = 33;
var tile:Sprite = new Sprite();
var waterTile:Sprite = new Sprite();
var waterHolder:Sprite = new Sprite();
var genericTileHolder:Sprite = new Sprite();
var hitting:Boolean = false;
var i:int = 0;
for (i = 0; i < mArea; i++) {
if (map[i - 27] == 1) {
waterChance * 8;
grassChance / 2;
}
if (map[i - 28] == 1) {
waterChance * 8;
grassChance / 2;
}
if (map[i - 29] == 1) {
waterChance * 8;
grassChance / 2;
}
if (map[i - 1] == 1) {
waterChance * 8;
grassChance / 2;
}
tileX += tileWidth;
if (tileX >= mLength * tileWidth) {
tileX = 0;
tileY += tileHeight;
}
genTile = (Math.round((Math.random()*(waterChance+grassChance))));
if (0 < genTile < waterChance) {
waterTile.graphics.beginFill(0x0033CC);
waterTile.graphics.drawRect(tileX,tileY,tileWidth,tileHeight);
waterHolder.addChildAt(waterTile, 0);
map.push("1");
}
if ((waterChance + 1) < genTile && genTile < (waterChance + grassChance)) {
tile.graphics.beginFill(0x216B18);
tile.graphics.drawRect(tileX,tileY,tileWidth,tileHeight);
genericTileHolder.addChildAt(tile, 0);
map.push("2");
}
grassChance = 33;
waterChance = 10;
}
stage.addChildAt(waterHolder, 0);
stage.addChildAt(genericTileHolder, 1);
The problem is two-fold. One, whenever the array generates, the length seems to have a random bit of variation- using trace(map.length) I get a lot of different lengths, from 750 to 780, when it should only be 400 at most.
Secondly, whenever I trace the level itself, using trace(map) I find that the first element seems to be set by default to 1. I can't figure out why it's doing this, as it should be 2 at least once after 20 tries.

You cant compare more than 2 items in actionscript:
if (0 < genTile < waterChance) {...
It will always return true (i think). Instead:
if ((0 < genTile) && (genTile < waterChance)) {...
Also, looks like each loop can do map.push("1") and map.push("2") - hence map is larger than mArea - i assume it should do one or the other?

Problem 2: first element of map is 1 by default
if (0 < genTile < waterChance)
{
waterTile.graphics.beginFill (0x0033CC); // Blue
waterTile.graphics.drawRect (tileX,tileY,tileWidth,tileHeight);
waterHolder.addChildAt (waterTile, 0);
map.push ("1");
}
Since < operator is left-associative, the expression will be evaluated as (0 < genTile) < waterChance.
Since genTile is never less than 0, (0 < genTile) is always false.
And since waterChance is also never less than 0, (false < waterChance)
which translates to (0 < waterChance) is always true.
That makes (0 < genTile) < waterChance always true.
Therefore the first element of map is always "1".
Problem 1: map.length varies
if ((waterChance + 1) < genTile && genTile < (waterChance + grassChance))
{
tile.graphics.beginFill (0x216B18); // Green
tile.graphics.drawRect (tileX,tileY,tileWidth,tileHeight);
genericTileHolder.addChildAt (tile, 0);
map.push ("2");
}
Since mArea equals 448, the water tiles will always total to 448 .
And since genTile is a random number, the grass tiles will always total to a random number.
Therefore map.length varies.
I hope that helps.

Related

How to distribute 'n' items in an 'M' sized array such that the elements get distributed evenly?

Suppose I have an array of size 100.
Initially, let's assume that all the elements have a value of 0.
Now, let's say I want to insert 60 elements such that the elements get filled evenly.
I don't want all the elements to be filled from arr[0] to arr[59]. Rather, I want the whole array to be filled in such a way that the array looks filled. What algorithm can I use to achieve this?
For eg-
I have 5 elements to be filled (let's say with 1) in an array of size 10. Then the array should look like this:
[1,0,1,0,1,0,1,0,1,0]
In the case of 3 elements,
[1,0,0,0,1,0,0,0,1,0]
Is there any smart way to do this dynamically?
You would need to find the right gap length to evenly fill it. For this, we binary search the correct gap which most evenly fills the gap such that the no. of 1's to be supposedly filled doesn't go out of the array bounds.
In the case where no. of ones to be filled is greater than half of the array size, we fill it with as even gaps of length 2 as much as possible and fill the remaining ones adjacent to each other.
function solve(arraySize, oneCount) {
let newArray = Array(arraySize).fill(0);
let low = 0,
high = arraySize;
let gap = 0;
while (low <= high) {
let mid = (low + high) >> 1;
if (mid * (oneCount - 1) < arraySize) {
gap = mid;
low = mid + 1;
} else {
high = mid - 1;
}
}
let needsEvenDivision = oneCount > (arraySize >> 1) && gap === 1;
gap = needsEvenDivision ? 2 : gap;
let idx = 0;
while (idx < arraySize && oneCount > 0) {
newArray[idx] = 1;
oneCount--;
if (needsEvenDivision && arraySize - idx - 2 < oneCount) gap = 1;
idx += gap;
}
return newArray;
}
console.log(solve(4, 2));
console.log(solve(10, 4));
console.log(solve(10, 7));
The problem is like:
There is a 60mm long rubber with a scale every 1mm.
Where is the position of each scale when this rubber is stretched to a length of 100 mm?
int main(void)
{
constexpr int M= 10;
constexpr int n = 5;
//initially all 0
int Array[M] = { 0 };
//Calclate where the ith element of the n elements should go in the result array
for( int i=0; i<n; ++i )
{
int idx = (int)std::round( (double)i * M / n);
Array[idx] = 1;
}
//Show Result
for( auto a : Array ){ std::cout << a << " "; }
std::cout << std::endl;
return 0;
}
Here is something you can do
function populateArray(arraySize, arrayElements) {
const newArray = [];
if (arraySize >= arrayElements) {
const parts = Math.ceil(arraySize / arrayElements);
for (let i = 0; i < arraySize; i++) {
if (i % parts == 0) {
newArray.push(1);
} else {
newArray.push(0);
}
}
return newArray;
}
return "Invalid array Size";
}
console.log(populateArray(10, 3));

Coin Change Leetcode

Problem: https://leetcode.com/problems/coin-change/
Solution:
https://repl.it/#Stylebender/HatefulAliceblueTransversal#index.js
var coinChange = function(coins, amount) {
let dp = Array(amount + 1).fill(Infinity); //Fill dp array with dummy values
dp[0] = 0;
for (let i = 1; i <= amount; i++) {
for (let j = 0; j < coins.length; j++) { //Iterate through coin denominations
if (coins[j] <= i) { //Is current coin denomination less than amount?
dp[i] = Math.min(dp[i], 1 + dp[i - coins[j]]);
//dp array[current amount - coin denomination]
}
}
}
return dp[amount] === Infinity ? -1 : dp[amount];
};
I understand the general conceptual flow of the solution of building the dp array from button up but I was just wondering with respect to Line 10:
dp[i] = Math.min(dp[i], 1 + dp[i - coins[j]]);
Why is there a 1 + when you select the current j'th coin denomination for consideration?
Is it because since there is a valid coin denomination, we have unlocked a new method to make up the i'th amount?
Yes, that's right. We'd be approaching the target amount by that one increment.
If for instance 0.5 would be somehow the min increment, then that would have become 0.5 + the rest.
const coinChange = function(coins, amount) {
const inf = Math.pow(2, 31)
const dp = []
dp[0] = 0
while (dp.length <= amount) {
let curr = inf - 1
for (let index = 0; index < coins.length; index++) {
if (dp.length - coins[index] < 0) {
continue
}
curr = Math.min(curr, 1 + dp[dp.length - coins[index]])
}
dp.push(curr)
}
return dp[amount] == inf - 1 ? -1 : dp[amount]
};
Maybe it would be easier to grasp in Python:
class Solution:
def coinChange(self, coins, amount):
dp = [0] + [float('inf')] * amount
for index in range(1, amount + 1):
for coin in coins:
if index - coin > -1:
dp[index] = min(dp[index], dp[index - coin] + 1)
return -1 if dp[-1] == float('inf') else dp[-1]

Why am I pulling an error? array.push course work

Book has page with the ff code to convert Centigrade to Fahrenheit, we've been asked to rewrite/simplify it.
function convertToCentigrade(degFahren)
{
var degCent;
degCent = 5/9 * (degFahren - 32);
return degCent;
}
var degFahren = new Array(212, 32, -459.15);
var degCent = new Array();
var loopCounter;
for (loopCounter = 0; loopCounter <= 2; loopCounter++)
{
degCent[loopCounter] = convertToCentigrade(degFahren[loopCounter]);
}
for (loopCounter = 2; loopCounter >= 0; loopCounter-- )
{
document.write(“Value “ + loopCounter + “ was “ +
degFahren[loopCounter] + “ degrees Fahrenheit”);
document.write(“ which is “ + degCent[loopCounter] +
“ degrees centigrade<br />”);
}
My version:
var degFar = [212, 32, -459.15];
var degCent = [];
function convert(input) {
result = (5/9 * (input - 32));
return result;
}
for (i = 0; j = degFar.length; i <= j; i++) {
degCent.push(convert(degFar[i]));
document.write(degCent[i]);
}
I pulling an error (obviously), but I don't understand what I'm doing wrong.
degFar has 3 elements but its index starts at 0.
Your array is like this:
[0] 212
[1] 32
[2] -459.15
You're trying to push an index [3] that doesn't exists. So modify your loop with this, notice I replaced i<=j for i<j:
for (i = 0; j = degFar.length; i < j; i++) {
degCent.push(convert(degFar[i]));
document.write(degCent[i]);
}
Your for loop is causing the error. You try to use two variables, 'j' and 'i'. I'm not sure what you are trying to accomplish by using 'j' (on top of that you never declared 'j' before trying to initialize it to degFar.length).
Keeping with your logic, I would get rid of 'j'-- you don't need it. After removing 'j' and using 'i' it should look something like this:
for (i = 0; i < degFar.length; i++) {
degCent.push(convert(degFar[i]));
document.write(degCent[i] + "<br>");
}
Hope this helps.

generating random numbers without repeating with an exception AS3

I have seen this question for other languages but not for AS3... and I'm having a hard time understanding it...
I need to generate 3 numbers, randomly, from 0 to 2, but they cannot repeat (as in 000, 001, 222, 212 etc) and they cannot be in the correct order (0,1,2)...
Im using
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
mcCor.gotoAndStop((Math.random() * (2 - u + 1) + u) | 0); // random w/ repeats
//mcCor.gotoAndStop(Math.floor(Math.random() * (2 - u + 1) + u)); // random w/ repeats
//mcCor.gotoAndStop((Math.random() * 3) | 0); // crap....
//mcCor.gotoAndStop(Math.round(Math.random()*u)); // 1,1,1
//mcCor.gotoAndStop(u + 1); // 1,2,3
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
those are the codes i've been trying.... best one so far is the active one (without the //), but it still gives me duplicates (as 1,1,1) and still has a small chance to come 0,1,2....
BTW, what I want is to mcCor to gotoAndStop on frames 1, 2 or 3....without repeating, so THE USER can put it on the right order (1,2,3 or (u= 0,1,2), thats why I add + 1 sometimes there)
any thoughts?? =)
I've found that one way to ensure random, unique numbers is to store the possible numbers in an array, and then sort them using a "random" sort:
// store the numbers 0, 1, 2 in an array
var sortedNumbers:Array = [];
for(var i:int = 0; i < 3; i++)
{
sortedNumbers.push(i);
}
var unsortedNumbers:Array = sortedNumbers.slice(); // make a copy of the sorted numbers
trace(sortedNumbers); // 0,1,2
trace(unsortedNumbers); // 0,1,2
// randomly sort array until it no longer matches the sorted array
while(sortedNumbers.join() == unsortedNumbers.join())
{
unsortedNumbers.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
trace(unsortedNumbers); // [1,0,2], [2,1,0], [0,1,2], etc
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
// grab the corresponding value from the unsorted array
mcCor.gotoAndStop(unsortedNumbers[u] + 1);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
Marcela is right. Approach with an Array is widely used for such task. Of course, you will need to check 0, 1, 2 sequence and this will be ugly, but in common code to get the random sequence of integers can look like this:
function getRandomSequence(min:int, max:int):Array
{
if (min > max) throw new Error("Max value should be greater than Min value!");
if (min == max) return [min];
var values:Array = [];
for (var i:int = min; i <= max; i++) values.push(i);
var result:Array = [];
while (values.length > 0) result = result.concat(values.splice(Math.floor(Math.random() * values.length), 1));
return result;
}
for (var i:uint = 0; i < 10; i++)
{
trace(getRandomSequence(1, 10));
}
You will get something like that:
2,9,3,8,10,6,5,1,4,7
6,1,2,4,8,9,5,10,7,3
3,9,10,6,8,2,5,4,1,7
7,6,1,4,3,8,9,2,10,5
4,6,7,1,3,2,9,10,8,5
3,10,5,9,1,7,2,4,8,6
1,7,9,6,10,3,4,5,2,8
4,10,8,9,3,2,6,1,7,5
1,7,8,9,10,6,4,3,2,5
7,5,4,2,8,6,10,3,9,1
I created this for you. It is working but it can be optimized...
Hope is good for you.
var arr : Array = [];
var r : int;
for (var i: int = 0; i < 3; i++){
r=rand(0,2);
if(i == 1){
if(arr[0] == r){
i--;
continue;
}
if(arr[0] == 0){
if(r==1){
i--;
continue;
}
}
}else if(i==2){
if(arr[0] == r || arr[1] == r){
i--;
continue;
}
}
arr[i] = r;
}
trace(arr);
for(var i=0;i<3;i++){
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (i % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(i / 3));
mcCor.gotoAndStop(arr[i]);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
function rand(min:int, max:int):int {
return Math.round(Math.random() * (max - min) + min);
}
try this...

Action Script 3. Randomly moving items UP and DOWN from array

So I'm creating game similar like this: example
I have an array of items already added to 4 holes. I need to make that these items randomly moved up (+100px) and down(-100px).
I have added to all holes for 6 items:
for(var i:uint = 0; i < 6; i++)
{
holeArr[0].inside.addChild(itemsArr[4][i]);
holeArr[1].inside.addChild(itemsArr[5][i]);
holeArr[2].inside.addChild(itemsArr[6][i]);
holeArr[3].inside.addChild(itemsArr[7][i]);
}
How can I make them randomly move up (+100px) and down(-100px)? I started, but I don't know what to do next... Could you help me, please?
function randomSpawn() {
for(var i:uint = 0; i < 6; i++)
{
itemsArr[4][i].x += 100;
itemsArr[5][i].x += 100;
itemsArr[6][i].x += 100;
itemsArr[7][i].x += 100;
}
}
To move an item randomly up/down +-100 pixels:
var distance = Math.round(Math.random() * 2 - 1) * 100;
mySprite.y += distance;
To animate it with Tweenlite
var newPosY = mySprite.y;
newPosY += Math.round(Math.random() * 2 - 1) * 100;
TweenLite.to(mySprite,1,{y:newPosY});
The simplest way to select a random item from an array
var index = Math.round(Math.random * (myArray.length - 1));
var myRandomItem = myArray[index];

Resources