Modulo introduction, Array wrapping. Sketch


#1

Hello there,

I’d like to be able to create a level on my own, but I never done that before. So I’d like to post here the idea I worked on before wasting time in fighting the level editor. If the idea seems ok enough to be crafted as a new level, I’d like some tips from experienced users to limit the time I’ll take to implement it.

The level I’m working on is themed on remainder operator, and its specific use in array wrapping. I worked in game, in the CragTag level, with a PotionMaster and the Golden Rod and BossStar 1 in order to create a situation where I have few units walking around in circle. Of course, I ignore Pender totally. The movement of the units would be part of the level (whereas here, I’m stuck with making them move myself, as the player), and no other action would be asked from the player than “this.say” clever sentences. Illustration :

The idea is to cache the array of units in the initialization, and make the units walk in circle. Every time a unit comes close, your hero perform an interaction (say ?) with this unit. As they walk several times around the circle, the player will be introduced to the use of the remainder to circle through the array, wrapping around indexes. The whole level is based on the new concept :

kSoldier=( kSoldier + 1 ) % nSoldiers

The plot would be “We’ll celebrate soon the [XXX] festival ! Your troups need to rehearse their Parade walk ! Tell your soldiers wether they’re too slow or too quick ! We need them to be equally distributed around the circle during the Parade”.

Your units aren’t evenly distributed around the circle, because of the arrFakRnd parameter. The random number (I suggest within -0.2 and +0.2) messes up the positionning of every soldier by a tiny bit. Every time a soldier passes by your hero, your hero will react to tell him/her to adapt their position, based on

closeSolder.pos.y>this.pos.y

I couldn’t make the hero react as “say” in the code below, because it locks my hero and he can’t command the troups in the mean time, and that messes up the whole timing. So I made him moveXY a tinybit left of right depending on the result of the test. In a real level, the player’s hero would “say” instead of moveXY of course. (again limited with ingame engine)

If the reaction of the hero is correct, the level should react by making the arrFakRnd numbers lower and lower in order to be closer and closer to the even distribution :

arrFakRnd [kSoldier] /= - 3 ;

Below is a copy-pastable code you can use in CragTag with a Wizard that can cast GoldStorm and command soldiers.
I hope you will see that your hero goes [left, right , right, right, left, right] during the first round because the arrFakRnd number I chose are : [negative , positive , positive , positive , negative , positive];

I think this concept of circular arrays illustrated with units walking in circle is a good start to create similar levels like this. Two quick examples : What happens if the units walk the other way ? How to check the distance between two units in a circular array ? I think modulo / remainder is tricky stuff for young people, and needs a lot of levels about it in order to even get familiar to it.

Disclaimer, this is a sketch. Don’t pick too much on me ^^. Make it run before anything else. I hope my syntax is somewhat understandable, and my comments are clear enough.

// Initializing variables
var soldierTarget=origPos; 
var Pi=3.14159;

// Circle parameters
    var origPos={x:39,y:36};
    var r=10; // radius 
    var timeBlock= 2;// number of sec a soldier takes to reach the position of the soldier before him.

// Setting up the level    
this.cast("goldstorm");
this.say("Waiting for gold to fall down");
this.wait(10);
   
loop { // Collecting coins to summon soldiers.
    var coins=this.findByType("coin");
    if(coins[0]){
        this.move(this.findNearest(coins).pos);
    }
    else {
        break;
    }
}

this.moveXY(origPos.x+5,origPos.y); // Going near the 0th soldier at start.
this.moveXY(origPos.x+5,origPos.y); // no ice skating when arrived.

while (this.gold>=20) { // Summoning soldiers
    this.summon("soldier");
}

var mySoldiers=this.findByType("soldier");
var nSoldiers=mySoldiers.length;
var arrFakRnd=[-0.1,0.2,0.05,0.1,-0.2,0.1]; // This array should be random seeded by the Send button. Numbers within [-0.2 , 0.2 ]

for(var k=0;k<nSoldiers;k++){ // Soldiers walking to their starting positions.
    soldierTarget={
        x:origPos.x + r*Math.cos(2*Pi*(k+arrFakRnd[k])/nSoldiers),
        y:origPos.y + r*Math.sin(2*Pi*(k+arrFakRnd[k])/nSoldiers)
    };
    this.command(mySoldiers[k], "move",soldierTarget );
}

this.wait(5);
this.say("This setup is the starting setup");
this.say("Starting level now !");



// End of setup


kSoldier=0;
var t0=this.now();

loop {
    var t=this.now();
    if( (t-t0) % timeBlock<0.01){ // every timeBlock seconds, a new soldier passes by.
        // This if statement would be what the player will write to solve the level.
    
        var closeSolder=mySoldiers[kSoldier];
        if(closeSolder.pos.y>this.pos.y){
            this.moveXY(origPos.x+6, origPos.y); // arrFakRnd[kSoldier]>0
            this.moveXY(origPos.x+6, origPos.y); // No ice skating.
            //this.say(mySoldiers[kSoldier].id+", Slow down !");
            arrFakRnd[kSoldier] /= -3 ; // This would be the level reacting to the "say"
        }else{
            this.moveXY(origPos.x+7, origPos.y);// arrFakRnd[kSoldier]<0
            this.moveXY(origPos.x+7, origPos.y); // No ice skating
            //this.say(mySoldiers[kSoldier].id+", Hurry up ! !");
            arrFakRnd[kSoldier] /= - 3; // This would be the level reacting to the "say"
        }
        
        kSoldier=(kSoldier+1) % nSoldiers; // New concept line. Most important line.
        
    }

    
    for(k=0;k<6;k++){ // This for loop will be taken care of by the level itself.
        // This is just making the soldiers walking around in circle at known positions.
        soldierTarget={
            x:origPos.x+r*Math.cos(2*Pi*((k+arrFakRnd[k])-(t-t0)/timeBlock)/nSoldiers),
            y:origPos.y+r*Math.sin(2*Pi*((k+arrFakRnd[k])-(t-t0)/timeBlock)/nSoldiers)
        };
        this.command(mySoldiers[k], "move",soldierTarget);
    }
    
}

#2

While I like the idea, I fear the players can simply bypass this by a distanceTo(findNearest(findFriends())) check.

Maybe we can combine it with the following approach:


Another idea would be to count stacks of soldiers, and whenever a stack is not a multiple of (let’s say) the first stack, command as many soldiers as needed to join or command them to go back to a pool, depending on which multiple is closer. Finding if something is a multiple of something else is a usual task I use modulo for (normally x%2 for even-checks, when I don’t know how to check the least significant bit).

The level could be like this (fancy ASCII-Art incoming):

random generated  |  off by 1  |  correct  |  off by 1
      stack       |            |           |
                  |            |     s     |
                  |     s      |     s     |
                  |     s      |     s     |     s
        s         |     s      |     s     |     s
        s         |     s      |     s     |     s
        s         |     s      |     s     |     s

Pool:
s   s s    s   ss  s  ss
 s s s   s     s    s
   s  ss  s s s   s ss  s

So the second stack would be filled to 6, the third stack would be left as is and the fourth stack would be reduced to 3.


After thoroughly thinking through this lacks Array wrapping… Maybe limit vision so only the current stack can ever be seen at any time… Wouldn’t really work…
This could be called Drill Training


#3

Originally, I checked the distance between two soldiers to trigger the interaction.

currSoldier = soldiers[ kSoldier % nSoldiers ] ; 
nextSoldier = soldiers[ ( kSoldier + 1 ) % nSoldiers];
distToNextSoldier = currSoldier.distanceTo(nextSoldier) ; 
if (distToNextSoldier  > radius ) {
     // In an Hexagon, the distance between vertexes is equal to the radius.
     this.say( currSoldier .id+" ! Hurry up !")
}

In that case, player couldn’t get away with “findNearest” because of the need to find the nextSoldier. But I thought it was too tough for an introduction to modulo, and wanted to keep it very simple for the first level of array wrapping. This example above would be the level just after the one in the original post.

I’ll answer tomorrow (it’s 10:30 pm here) to your Drill training idea. I’ll sleep on it tonight.


#4

I like the “Parade” idea, kind of like Dance-Off, but with the hero calling the steps (see below for a little running with that idea).

I can see using your “array wrapping” example, to introduce how the operator works. (But, conceptually array wrapping isn’t a remainder operation, it is simply an “if over, set to 0.”) Lost Viking comes to mind, and like array wrapping it is really just concerned with the lack of a remainder.

# Functionally      (meaning: "in what it does")
kSoldier = (kSoldier + 1) % nSoldiers
# is the same as 
kSoldier = (kSoldier + 1) if kSoldier < (nSoldiersLessOne) else 0
# but much prettier :-) 

“Count Off” (as used to assign teams) seems more conceptual. (for example: Defending X towers with a growing array of Y soldiers.)

"Calling the Steps"
In your “Parade March” idea, you have count the X soldiers (via array index) as they pass by the review point (your y-line in the above code) telling them to slow down or speed up depending on their relationship to the line at time T. Instead of looping the counter itself, keep a running count (you still have “arrayindex = count mod numSoldiers”). Then add in, as every Mth soldier passes by (M not related to X) say “expand” and for the Mth+N soldier (“mod M = N”) you say “contract” (causing the soldiers to correspondingly change the radius of their circle. Of course, they have to go slower with small circles and faster with large circles but still fits with your check y-line at time T idea (and the base radius-slower/faster is in your code not the players, they still only have to tweak them when off).

I originally, thought of shrinking and flaring the circle as a way to make the soldiers parade walk not be just a boring circle. (You could even reverse the flow every Rth (of course) soldier.)

(Drill stacking: I take two guys from the pool, send them to stack 0, take one gal from stack 2 and send her to stack 3. Muh-hahahahaha)


#5

That would be 3 operations instead of the best possible 2.


#6

Maybe not optimal for you but that guy in the pool needed the exercise, to pass his next physical exam.
(I didn’t see where the instructions specified minimal/optimum troop movement…) :wink:


#7

@Catsync interesting level idea here! Maybe we can work this in?