For those of you determined enough to get the Programmaticon V the array library may still be a puzzle:
How to use them and what are their advantages?
Simple answer: it allows you to generate some very light and fast code.
Good if your level code keeps crashing or if you are running into HEL (hard execution limit, currently 3 million)
I will explain how to use the most important functions in the library: map, filter and reduce
An appendix will list all the array methods grouped by categories
This document assumes you have already read the methods description. I will not copy that information.
Advantage of array methods:
They allow you to provide a callback function which will be called for every single element of the array.
The transpiled code will be much simpler than when creating your own loop over the array
Severe limitation:
You cannot call any other function inside the callback function. The method’s documentation implies that you can, but even calling
function forwardValue(e){return e;}
will stop your code from working.
(Issue 1/3 @nick)
1. Use Map to generate new information.
Map allows you to construct another array by processing the initial array arguments
enemies=this.findEnemies();
distances=enemies.map(this.distanceTo);
We have just computed the distances to every single enemy with one function call!
That’s extremely light. But we cannot do much with the distance array by itself, because you do not know what each element represents. We must link the info to original enemy list:
2. Define your callback functions to process the array
//Must define this before using
function distanceIndex(distance,index){return {d:distance,i:index};}
enemy_info=distances.map(distanceIndex);
Now enemy_info links the distance value to the enemies index in the original array.
In this example we just use the distance. But in your program you can add as much information about the enemies: estimated DPS, range, speed or how much money he owns you.
Most of the callback functions will receive 3 parameters:
elem //the value of the element in list for which the callback is called
index //the position of the element in list
array //the name of the list
If you are writing Python code make sure you accepting all these paramters
##3. Use filter to select only part of the array elements.
Lets say we are playing agrippa-defence and we are really annoyed by “Palt”,“Smerk”,“Godel” (they didn’t tip at the dinner)
In a real level we’ll go for ogres, throwers, wiches and other stuff - it’s basically about selection
We’ll like to use:
selection=enemies.filter(names.indexOf);
but unfortunately indexOf cannot be used as callback function. My guess is that indexOf expects (elem,searchFromIndex) while a callback function receives (elem,elem_index).
(Issue 2/3 @nick)
The first 2 simple solutions:
- define your own indexOf function
- use indexOf but define your own filter function
are not efficient
Instead we define the values we search for as property names and we use the JavaScript’s automatic hashing of property names:
//instead of names we can have enemy types and
//instead of 'true' an index to the enemy type information object
var HashNames={"Palt":true,"Smerk":true,"Godel":true};
function inHash(elem){return (hash_list[enemies[elem.i].id]);}
//use can use globals to pass parameters to callback functions
hash_list=HashNames;
selection=enemy_info.filter(inHash);
##4. Use reduce to select a winning value from a list
Cosidering it is an enemy, what he wins is a good beating.
The reduce functions get two elements as arguments and they have to return the best of the two:
function nearestReduce(e1,e2){
if (e1.d<e2.d) return e1;
else return e2;
}
if(selection.length){
nearest=selection.reduce(nearestReduce);
//We could have used one line instead of array methods
//!!! What are you teaching ???
nearest2=this.findNearest(this.findByType("munchkin",this.findEnemies()));
this.say(enemies[nearest.i].id);
}
##5. Use a heavy iteration to determine how good is your code:
//https://codecombat.com/play/level/the-agrippa-defense
function distanceIndex(distance,index){return {d:distance,i:index};}
function inHash(elem){return (hash_list[enemies[elem.i].id]);}
function nearestReduce(e1,e2){
if (e1.d<e2.d) return e1;
else return e2;
}
var HashNames={"Palt":true,"Smerk":true,"Godel":true};
var enemies,distance,enemy_info,hash_list,selection,nearest;
var i,iterations=0;
loop{
enemies=this.findEnemies();
//test your code in a heavy iteration until HEL
if(!enemies.length) continue;
for(i=0;i<3000;i++,iterations++){
distances=enemies.map(this.distanceTo);
enemy_info=distances.map(distanceIndex);
//a real selection decision may use all distances
hash_list=HashNames; //pass callback parameter through global value
selection=enemy_info.filter(inHash);
if(selection.length){
nearest=selection.reduce(nearestReduce);
//We could have used one line instead of array methods !!!
//What are teaching ????
//nearest2=this.findNearest(this.findByType("munchkin",this.findEnemies()));
//this.say(enemies[nearest.i].id);
}
}
this.say(iterations);
}
##6. Array methods by cathegory:
// 1. Reduce functions:
every -> boolean AND
some -> boolean OR
reduce -> iterrative reduce operator from the left
reduceRight
// 2. Array transformation.
//Some modify the parent arey, some not. See the comments:
filter //elem selection) NOT MODIFIED
map //elem transformation by handle function) NOT MOTIFIED
slice (begin,end_not_included)
//returns slice of array, the original array is NOT MODIFIED
sort(callback) //sorts IN PLACE, also passes result. Callback returns true if 1st elem is greater
reverse //array is reversed IN PLACE!
splice(index,how_many_deleted, <list of params to be inserted>)
// IN PLACE, deletes & inserts in part of the array
// 3. Iterators:
entries // key,value tuple
keys
// 4. Search:
find,findIndex(callback)
// returns the first element for which the callback function is true
indexOf(elem,fromIndex)
// negValue - index position computed from the end of the array
// -1 is the last elem
//array is still searched front to back
lastIndexOf //indexOf, search backwards
//5. Multi array manipulations:
concat
//6. Processing:
forEach //runs the callback for each element. Like map but no array created
//7. Deletion & Insertion
//The delete functions also return the element deleted
pop //deletes last place
shift //deletes first place
push //inserts on last
unshift //inserts on first
//8. Print - join all elemens into a single string
toString //joins the elements together using the default separator ','
toLocaleString //uses each object's toString function to convert it into a string
join('separator') // joins all array elements in a string using the separator
Question:
Is there a planed level to teach the use of array methods within CombatCombat?
Issue 3/3 @nick