Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Arrays and if macros

How do I make sure that an array does not have more than a set amount of a variable? I've already looked at the Sugarcube 2 library and the count and includes macros don't seem to work with if macros.
<<if $mapArray.count("3") gt 7>>
<<set $mapArray.("3") to 7>>
<</if>>

Please let me know what I'm doing wrong.

Comments

  • edited December 2016
    note: You don't supply an example of your array so I will assume it is something like the following:
    <<set $array to ["A", "B", "C", "B"]>>
    


    I believe you are confusing two things:

    1. Counting the number of times a particular value appears within an array.
    This is what the Array count() function does, as demonstrated by the following:
    Number of B's in array is: <<= $array.count("B") >>
    Is there more than one B?: \
    <<if $array.count("B") gt 1>>Yes<<else>>No<</if>>
    


    2. Accessing and assigning the value of a particular element of an array.
    note: SugarCube and Javascript arrays are zero based which means that the first array element has an index of 0 not 1.
    What value is contained in the third array element: $array[2]
    Is the third array element a C: \
    <<if $array[2] is "C">>Yes<<else>>No<</if>>
    
    
    <<set $array[2] to "D">>\
    Is the third array element now a D: \
    <<if $array[2] is "D">>es<<else>>No<</if>>
    
  • My map array is as follows;
    <<for _i = 0; _i < 30; _i++>>
    <<run $line1map.push(0)>>
    <<run $line2map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line3map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line4map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line5map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line6map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line7map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line8map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line9map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line10map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line11map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line12map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line13map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line14map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line15map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line16map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line17map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line18map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line19map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line20map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line21map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line22map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line23map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line24map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line25map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line26map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line27map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line28map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line29map.push(either(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6))>>
    <<run $line30map.push(either(0))>>
    <</for>>
    
    <<set $mapArray to [$line1map, $line2map, $line3map, $line4map, $line5map, $line6map, $line7map, $line8map, $line9map, $line10map, $line11map, $line12map, $line13map, $line14map, $line15map, $line16map, $line17map, $line18map, $line19map, $line20map, $line21map, $line22map, $line23map, $line24map, $line25map, $line26map, $line27map, $line28map, $line29map, $line30map]>>
    

    I'm trying to ensure that "3" doesn't appear more than 7 times in the randomly generated array.
  • The Array.count method won't do what you want because it only looks at the value of the elements belonging to the Array it is call on, it will not search the elements belonging to each of the child arrays in your structure.

    Before I suggest a solution I need to know if you actually need the $lineXmap ($line1map to $line30map) variables or can I get rid of them?
  • Yes, I do believe I need them. However, I would still like to hear whatever you had in mind should you remove them. Thank you by the way.
  • Couldn't you generate the array without any '3's and then add 3 of them later?
  • Not necessarily, as the main purpose of my long drawn out mess of code is to ensure that my array is randomly generated each time.
  • @Strangedog you don't state what you want to happen after the 7th 3 is assigned, and there are a number of possible outcomes so the following example is going to assume you want the 3 removed from the list of possible values.

    The following Javascript is one way to achieve your desired result and it needs to be placed within your story's Story Javascript area. It generates an array named $mapArray which has 30 elements and each of those elements contains a child 30 element array full of random numbers.
    var _i, _j, _value, _threeCount = 0;
    
    /* list of possible values */
    var _options = [1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6];
    
    /* create the parent array. */
    var _size = 30;
    var _array = new Array(_size);
    
    for (_i = 0; _i < _size; _i++) {
    
    	/* create the child array for the current parent element. */
    	_array[_i] = new Array(_size);
    
    	for (_j = 0; _j < _size; _j++) {
    
    		/* default value used in first and last elements of parent array. */
    		_value = 0;
    
    		/* determine random value of other parent elements. */
    		if (_i > 0 && _i < (_size - 1)) {
    			_value = _options.random();
    			
    			/* track the number of 3's */
    			if (_value == 3) {
    				_threeCount++;
    				
    				if (_threeCount > 7) {
    					/* remove 3 from option list. */
    					_options.splice(9, 1);
    					_value = _options.random();
    				}
    			}
    		}
    
    		_array[_i][_j] = _value;
    	}
    
    }
    /* create story variable to contain parent array. */
    State.variables["mapArray"] = _array;
    
    note: there are a number of ways the above code can be condensed and improved, I wrote it long-hand so you can see the steps involved. The above could also be written using TwineScript but because of the inherent overhead involved I felt Javascript would be a better choice.
  • Strangedog wrote: »
    Not necessarily, as the main purpose of my long drawn out mess of code is to ensure that my array is randomly generated each time.

    Generating a random array of 1's, 2's, 4's, 5s and 6's and then picking 7 random cells to overwrite with 3's is going to give you a better distribution of 3's than your current method.

    Unless you've been very careful to tune your probabilities, the 3's will tend to appear in the first few lines of your array. The chance of any cell containing a 3 is 1 in 15. You've got 30 cells in each line, so that would give you an average of 2 3's in each line. On average you should expect to have 7 threes on the map by the end of your 4th row. Exceptional cases might get as far as the 8th row. Highly unlikely to find any 3's in the bottom 22 rows.

    Might save yourself some typing if you look into whether or not your either takes an array as an argument. I think the later ones do.
  • I believe either macros accept arrays as their argument, however the javascript that greyelf provided is much more stream lined, and I will be using the line of code they provided. However, mykael brought up a very good point, and I'm trying to figure out how to do what they suggested. Thank you, both of you.
  • Instead of overwriting all 3's after the seventh one, you could use an array to track the location of all the 3's in the main array. You could then randomly choose which 3's to replace.
    var _i, _j, _value, _ind, _threes = [];
    
    /* list of possible values */
    var _options = [1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6];
    
    /* create the parent array. */
    var _size = 30;
    var _array = new Array(_size);
    
    for (_i = 0; _i < _size; _i++) {
    
    	/* create the child array for the current parent element. */
    	_array[_i] = new Array(_size);
    
    	for (_j = 0; _j < _size; _j++) {
    
    		/* default value used in first and last elements of parent array. */
    		_value = 0;
    
    		/* determine random value of other parent elements. */
    		if (_i > 0 && _i < (_size - 1)) {
    			_value = _options.random();
    			
    			/* track the location of the 3's */
    			if (_value == 3) {
    				_threes.push([_i, _j])
    			}
    		}
    
    		_array[_i][_j] = _value;
    	}
    }
    
    /* remove 3 from option list. */
    _options.splice(9, 1);
    
    /* randomly remove unwanted 3's */
    while (_threes.length > 7) {
    	_ind = _threes.pluck();
    	_i = _ind[0];
    	_j = _ind[1];
    	_array[_i][_j] = _options.random();
    }
    
    /* create story variable to contain parent array. */
    State.variables["mapArray"] = _array;
    
    note: again there are a number of ways the above code can be condensed and improved.
Sign In or Register to comment.