ID:162409
 
What I'm trying to do is creating rows of AIs. There are 10 rows and each row has 10 AIs. Out of the 100 AIs created 20 of them are Zombies, and the rest are Warriors. I've done this part, but the zombies are usually all closed together in one spot. How would I make it so the 20 zombies are scattered in the 10 rows of AI?

Like so:

o x x x x o x x x o
x x x o x x x x x x
x x x x x x x o x x
x o x x x x x x x o
x x x x o x x o x x
x o x x x x x x x o
x o x x x x x x x x
x x x x x o x x o x
x x o x x x x x x x
o x x x o x x o x o

o - Zombie
x - Warrior

Also when they are scattered I don't want them to be at the same spot all the time. I think the best way to do this is randomizing between (0-3) zombies to add to each row. I kind of achieved what I wanted when I let all the warriors be created, and then changed specific ones to zombies. But I found it too slow. So basically I'm looking for a way to scattering the zombies from into 10 rows, and it should be random, and it shouldn't have any type of delay or long delay time.
There are a few procs to do random things:
pick()
rand()
prob()

Those are my most used ones. Look them up in the DM Reference, and figure it out.
In response to Kaiochao2536
I already know how to use those procs. Like I said, I already know how to generate the 20 zombies randomly, but the thing is they are usually close together and not spread out in the 10 rows. I figure that using prob() can make it more spread out, but I wouldn't end up with 20 zombies.

The only thing that I can come up with is when the monsters are created, they are assigned a value for a variable. Then I would use rand() to check if the value of that variable is between certain numbers. But I'm sure it's not efficient at all.

If you can provide a small working and efficient way to do this that I can build upon, that would really help.
In response to Bobmcapple
How about you make a variable? For every monster, add 1. When a monster is created, nullify it. If it is 10(ten monsters in a row), make a warrior.

Of course, you'll be making warriors between 1 and 10.
The problem is you really don't want randomness; a true random distribution would have some clustering. The easiest method is probably to go with something weighted that adjusts each time you put a new zombie in. The algorithm would be something like this:

  • Create a list of 100 items, each set to 1. These are relative weights for picking a zombie in each spot. Create a parallel list of type paths saying what type of creature goes in each slot.
  • Loop 20 times. Each time through the loop:
  • Add up the total weight of the list. Multiply by rand() and that gives you a target. Now go through the list and subtract the weights, one by one, from your target until you're below 0; then you've hit the right position.
  • At your target position, change the type path for your monster list to a zombie; set the corresponding weight to 0.
  • For all other positions, multiply the weight by distance2/(distance2+9); this can be adjusted but in this case it means the relative weight of an adjacent position goes down to 10% of what it was before. 2 spaces away it's about 30%.

    Here's some code that effects that result:
var/list/weights = new
var/list/types = new
var/i,j
for(i=1, i<=100, ++i)
weights += 1
types += /mob/warrior
for(i=1, i<=20, ++i)
var/total = 0
for(j=weights.len, j>0, --j)
total += weights[j]
total *= rand()
// now find our target cell
for(j=weights.len, j>0, --j)
total -= weights[j]
if(total < 0) break
weights[j] = 0 // don't pick this again
types[j] = /mob/zombie
// adjust nearby weights
var/X=((j-1)%10), Y=round((j-1)/10)
for(j=1, j<=100, ++j)
if(weights[++j])
var/dsq = X*X + Y*Y
weights[j] *= dsq / (dsq + 9)

--X
if(!(j%10)) // end of a row
--Y
X+=10</dm>

There might be faster ways to do this or something like it, but it probably doesn't matter because this should run through fairly quickly.

Lummox JR
In response to Lummox JR
I really don't want any type of delay so I decided to take a different approach even if the randomness has some clustering. What I decided to do is the first 20 mobs created will be the zombies the rest will be warriors. After they're all created, a proc will be run that swaps zombie positions with warriors. The proc looks something like this:

proc/Scatter()
var/list/warriors = list()
var/list/zombies = list()
for(var/mob/AI/A in world)
if(A.monster == "warrior") warriors += A
if(A.monster == "zombie") zombies += A
for(var/mob/AI/Z in zombies)
var/mob/AI/A = pick(warriors)
warriors -= A
Z.icon = 'warrior.dmi'
Z.monster = "warrior"
A.icon = 'zombie.dmi'
A.monster = "zombie"


These monsters aren't being used to fight other mobs, so I don't think it's crucial that they should have their own specific type path. The proc works, but how would I:

1. Make it more efficient.
2. Make it less clustering but still with no type of delay
3. Since the first 20 mobs created are zombies, when the proc is called the first 2 rows will be warriors. The first two rows will always be one type. I want to avoid that and I think I can do this by selecting random mobs in the list to be switched, but I think there is a delay associated with this idea. I tried using prob() in the for() loop but that doesn't seem to work. If you have any ideas that fixes this issue and wouldn't involve a or much of a delay, that would really help.
In response to Bobmcapple
Bump
In response to Bobmcapple
Just follow Lummox's advice.
In response to Garthor
But there's delay?
In response to Bobmcapple
There's delay in everything. Sometimes really small, sometimes long.

If you see any sleeps or spawns, take them out. If not, your code is so large it's taking a while to process..