What I want - I want to have some magic function getEnemyType(currentLevel), which will return, for example, a number. Number is enemy type, let's say, there are ten (10) types. 1 - the easiest, 10 - the hardest. I can't even find the idea, where to dig, to get such algorythm: I give this magic function current level number and it calculate suitable enemy type with increasing and decreasing chanse of getting hard or easy enemy. Example:

  • Level 1: function will generate random type from array of one element: [1], okay
  • Level 2: generating random types from such set: [1,1,2], reason is to have more easy and less hard enemies.
  • Level 3: [1,1,1,2,2]
  • ...
  • Level 50: [1,7,7,9] (more 7s, less 9s for challenge, and little number of 1s for fun)
  • Level 10000: [1, 10, 10, 10, 10, 10, 10]

Ideally game must be infinite, so I can just add enemy types to suit increasing difficulty. Is this real? :)


One solution for solving this problem:

Python (pseudo) code:

def getEnemyTypesByLevel(Level):
   # max is maximal Difficulty
   Options = [
      {"Count":1, "Max":1, "Exponent":1.0},
      {"Count":3, "Max":2, "Exponent":1.2},
      {"Count":5, "Max":2, "Exponent":1.3},
      {"Count":8, "Max":10, "Exponent":42.0}

   DifficultyArray = []

   CurrentOption = Options[Level]

   Base = 1.5

   i = 0
   while i < CurrentOption["Count"]:
      Difficulty = (random.random() * Base) ** CurrentOption["Exponent"]
      Difficulty = max(CurrentOption["Max"], Difficulty)


      i += 1

   return DifficultyArray

instead of using the Exponent function you can use logarithmic functions or any arbitary function, depending on your wishes.

I hope this helps.

Edit 1: Added the Base constant/value, without it it doesn't really do what you want.

  • \$\begingroup\$ Thanks mate! Seems cool, will check it in the evening closer and write back. \$\endgroup\$ – user543229 Apr 8 '13 at 10:59
  • \$\begingroup\$ So, I've found some way, thanks to Quonux, he gave me idea about math distrubution. I think that this one is quite good for my purposes, and of course it can (must) be tweaked and polished to give better results. So, here it is: 1. we're counting total amount of enemies and take it as X 2. calculate depending varible with such equation: type = Math.round(Math.abs( (x/80) * Math.cos(x / 8) )) || 1; (javascript) 3. ... 4. Profit! Look at the graph to see distribution results.img267.imageshack.us/img267/1228/graphho.png \$\endgroup\$ – user543229 Apr 8 '13 at 13:52
  • \$\begingroup\$ less linear dependance may be implemeted, but I'm good with this one. \$\endgroup\$ – user543229 Apr 8 '13 at 13:54

It might not be exactly what you are looking for, but I'd suggest attaching the chance of appearance to the actual enemy type. That way you can fine tune it a bit more without needing to modify the actual algorithm, for example you seem to want enemy type 1 to appear at all levels, but not type 2, 3, 4 etc.


struct EnemyType
   unsigned int id; //Generic id number
   int baseLevel; //The player level where this enemy starts to appear but is rare.
   int commonLevel; //The player level where the enemy becomes common.
   int rareLevel; //The player level where the enemy stops being common again.
   int extinctLevel; //The player level where the enemy stops appearing.

Then maybe assign a weight to each enemy type based upon the player level:

float getWeight(EnemyType enemyType, int playerLevel)
   if(playerLevel < enemyType.baseLevel || 
      playerLevel >= enemyType.extinctLevel) return 0.0f;
   else if(playerLevel >= enemyType.rareLevel ||
           playerLevel < enemyType.commonLevel) return 0.5f;
   else return 1.0f;

Any weighted random selection algorithm should then finish the job, but the probability of getting any one enemy type returned from getEnemyType() should be:

 weight of type / total weights of all types

This is a bit rough, as there are many good ways of implementing such an algorithm. But the main point I'm trying to make is specify the probability changes on the enemy type instead of in the actual selection algorithm.

EDIT: Here's an example of the selection algorithm (psuedocode):

//Initialize these somewhere, maybe use a vector or whatever your language's equiv is.
const unsigned int numEnemyTypes;
EnemyType enemyTypeArray[];

EnemyType getEnemyType(int playerLevel)
   floatrandom = someRNG(); //Gives a number between 0 and 1.

   //Find total weights
   float totalWeight = 0.0;
   for(int i = 0; i < numEnemyTypes; i++)
       EnemyType enemyType = enemyTypeArray[i]
       totalWeight += getWeight(enemyType, playerLevel);

   //Find enemy type
   float range = 0.0;
   for(int i = 0; i < numEnemyTypes; i++)
       EnemyType enemyType = enemyTypeArray[i]
       range += getWeight(enemyType, playerLevel)/totalWeight;
       if(range >= random) return enemyType;

Essentially each enemy type gets a portion of the number range between 0 and 1, if the random number falls into that enemy type's range that is the enemy type selected. EG if you have 2 enemies, one with weight 0.5 and one with weight 1.0 then the first will have the range 0.0 to 3.33 while the second will have the range 3.33 to 1.0. If you add a third enemy with weight 1.0 then the ranges will look like:

0 to 0.2 (0.5 / 2.5 = 0.2) 0.2 to 0.6 (1.0 / 2.5 = 0.4) 0.6 to 1.0 (as above)

The code above isn't exactly optimal but hopefully it gives an idea of what I am talking about.

  • \$\begingroup\$ Looks cool. Didn't know about such thing as "weighted random selection algorithm", now I know, what to google! Thank you very much for the answer. \$\endgroup\$ – user543229 Apr 9 '13 at 10:01
  • \$\begingroup\$ I'm not sure if that is their technical name. If I can think of an example that is easy to fit into the end of my answer I will edit it in. \$\endgroup\$ – Lewis Wakeford Apr 9 '13 at 15:34
  • \$\begingroup\$ I got it. Wonderful. \$\endgroup\$ – user543229 Apr 10 '13 at 6:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.