Official Everybody Edits Forums

Do you think I could just leave this part blank and it'd be okay? We're just going to replace the whole thing with a header image anyway, right?

You are not logged in.

#1 Before February 2015

Tako
Member
From: Memphis, Tennessee, USA
Joined: 2015-08-10
Posts: 6,663
Website

[Guide] Fill algorithm

Hey. I made a fill algorithm. I hope a couple of you will find it interesting. I know I did. It's kind of interesting to watch.

It works by randomly spreading out from one point and then stopping when it reaches a boundary, or rather, anything that is not the replaceId. If you want to remove the cool growing effect, you can just add them all to a list, shuffle, and build them all afterward instead of building them as it goes.

Specifically, it...
• selects start block
and then...
• adds blocks on all sides that aren't already filled or outside of bounds
• adds the blocks to a list
• selects a random point
• removes it from list
• repeats until the list is empty

It might seem like it's slowing down, but it's actually running at the same speed the entire time. It just has a larger border to fill and can't do it as fast as when it was small.

You can also fill over extra blocks by replacing `map[x, y, 0].Id == replaceId` with `replaceIds.Contains(map[x, y, z].Id)`, where replaceIds is a List<int> of the ids you want to ignore.

Pastebin if you like the syntax highlighting: http://pastebin.com/htSeAXtQ (not updated)

        // Start x, start y, the ID that it will be filled with, the ID that it will replace.         // The layer is automatically detected, but if you set it then it won't change it.         private static void Fill(int x, int y, int fillId, int replaceId, int layer = 0)         {             List<Point> points = new List<Point>(); // Point is from System.Drawing & lets you remember x's/y's.             Block[, ,] map = r.Map;                 // replace with whatever method you use to read the map.                                                     //   It needs to contain all the blocks in the room.                                                     //   I use a three-dimensional array of Block objects.                                                     //   Blocks are found by typing Map[x,y,layer].              // If the layer has been set, use it. Otherwise, automatically detect. (Only set             layer = layer != 0 ? layer : replaceId >= 500 ? 1 : 0;              do // using a do-while instead of a while because the list starts at 0 and it wouldn't execute.             {                 // if you're on the replace id, replace it and remove it from the list.                 if (map[x, y, layer].Id == replaceId)                 {                     Build(fillId, x, y);                      map[x, y, layer] = new Block(fillId, x, y);                      points.RemoveAll(s => s.X == x && s.Y == y);                 }                 else // If you're not on the replace id, you're on the border. Select a random point and remove it from the list.                 {                     var RanPoint = points[Tools.Ran.Next(points.Count)]; // Do not use `new Random` here. Do it outside the loop.                      x = RanPoint.X;                      y = RanPoint.Y;                      for (int ind = 0; ind < points.Count; ind++)                         if (points[ind].X == x && points[ind].Y == y)                             points.RemoveAt(ind);                 }                  // Where there is replaceId, draw and add a point. Update the map and it becomes exponentially faster.                 UpdatePoint(x + 1, y, fillId, replaceId, ref map, ref points);                 UpdatePoint(x - 1, y, fillId, replaceId, ref map, ref points);                 UpdatePoint(x, y + 1, fillId, replaceId, ref map, ref points);                 UpdatePoint(x, y - 1, fillId, replaceId, ref map, ref points);                  // You just added a few points to the list, generally 2-3.                 // Return, select a random one, delete it, and repeat until there are none left.                 // What you end up with in the List<Point> points is all the points that have not been checked, aka the ones on the front line.             } while (points.Count > 0); // Once the list is empty, it is done.         } // end Fill function          private static void UpdatePoint(int x, int y, int fillId, int replaceId, ref Block[, ,] map, ref List<Point> points)         {             if (map[x, y, layer].Id == replaceId)             {                 b.Push.Build(fillId, x, y);                  map[x, y, layer] = new Block(fillId, x, y);                  points.Add(new Point(x, y));             }         }

[Edit] Changed `out` to `ref`, fixed id mismatch (used `id` instead of `fillId`)
[Edit2] Used LINQ instead of for loop.
[Edit3] Added layer support.

Last edited by Tako (Jul 30 2014 10:59:59 am)


Yeah, well, you know that's just like, uh, your opinion, man.

Offline

#2 Before February 2015

hummerz5
Member
From: wait I'm not a secret mod huh
Joined: 2015-08-10
Posts: 5,852

Re: [Guide] Fill algorithm

props for the cupid shuffle references.

I did this once. It worked... then it stopped working. yay bugs!

Though, this looks slightly more sophisticated.

Offline

#3 Before February 2015

TiKen
Member
Joined: 2015-02-24
Posts: 298

Re: [Guide] Fill algorithm

Pseudo-recursive algorithm. Ahhhh, dream of my childhood!

But I don't get why you did this like this... points contains points that have already been replaced (see UpdatePoint). So why bother checking every time?

Offline

#4 Before February 2015

ugotpwned
Member
Joined: 2015-02-16
Posts: 376

Re: [Guide] Fill algorithm

Well, I've noticed a bug while looking through your code, if it even matters to you.

for (int ind = 0; ind < points.Count; ind++) if (points[ind].X == x && points[ind].Y == y)     points.RemoveAt(ind);

This doesn't work because if it were to remove a point from the list all the objects's indicies get moved - 1. An easy fix is just to enumerate backwards through the list.

Last edited by UgotPwned (Jul 30 2014 1:18:58 am)

Offline

#5 Before February 2015

Tako
Member
From: Memphis, Tennessee, USA
Joined: 2015-08-10
Posts: 6,663
Website

Re: [Guide] Fill algorithm

UgotPwned wrote:

Well, I've noticed a bug while looking through your code, if it even matters to you.

for (int ind = 0; ind < points.Count; ind++) if (points[ind].X == x && points[ind].Y == y)     points.RemoveAt(ind);

This doesn't work because if it were to remove a point from the list all the objects's indicies get moved - 1. An easy fix is just to enumerate backwards through the list.

Not quite. For loops check the boolean after every iteration. When it checks, it gets a fresh value of points.Count.

I use this exact code in my own program, and have tested it several times. If it threw an exception I would've fixed it by now.


Yeah, well, you know that's just like, uh, your opinion, man.

Offline

#6 Before February 2015

ugotpwned
Member
Joined: 2015-02-16
Posts: 376

Re: [Guide] Fill algorithm

Tako wrote:

For loops check the boolean after every iteration. When it checks, it gets a fresh value of points.Count.

No, the problem is not the for loop condition, it's when an array or list has two or three elements in a a row that would be removed with RemoveAt, this causes the failure becuase after shifting all the elements to the left, it essentially skips an element. And I can prove it.

List<int> myInts = new List<int>(); myInts.Add(2); myInts.Add(1); myInts.Add(2); myInts.Add(3); myInts.Add(2); myInts.Add(2); myInts.Add(2); myInts.Add(4); myInts.Add(2);  for (int i = 0; i < myInts.Count; i++) {       if (myInts[i] == 2)       {            myInts.RemoveAt(i);       } }

Go ahead and unit test that. It's not going to throw an exception, but at the end of the loop, myInts contains a two.

Last edited by UgotPwned (Jul 30 2014 10:39:48 am)

Offline

#7 Before February 2015

Tako
Member
From: Memphis, Tennessee, USA
Joined: 2015-08-10
Posts: 6,663
Website

Re: [Guide] Fill algorithm

So you could also solve the problem by doing `i--;` after you remove, correct? That seems more intuitive than going backwards, even though they both fix the problem.


Yeah, well, you know that's just like, uh, your opinion, man.

Offline

#8 Before February 2015

ugotpwned
Member
Joined: 2015-02-16
Posts: 376

Re: [Guide] Fill algorithm

Tako wrote:

So you could also solve the problem by doing `i--;` after you remove, correct? That seems more intuitive than going backwards, even though they both fix the problem.

Yeah that's another way you could fix it.

Last edited by UgotPwned (Jul 30 2014 11:31:29 am)

Offline

#9 Before February 2015

Processor
Member
Joined: 2015-02-15
Posts: 2,246

Re: [Guide] Fill algorithm

Wtf? Why not LINQ?

points.RemoveAll(s => s.X == x && s.Y == y);


I have never thought of programming for reputation and honor. What I have in my heart must come out. That is the reason why I code.

Offline

#10 Before February 2015

Anch
Member
Joined: 2015-02-16
Posts: 5,447

Re: [Guide] Fill algorithm

Is this code to put into your bot? Because I wanted to make a bot that fills stuff...
I bet I sound stupid. Right?

Offline

#11 Before February 2015

Tako
Member
From: Memphis, Tennessee, USA
Joined: 2015-08-10
Posts: 6,663
Website

Re: [Guide] Fill algorithm

anch159 wrote:

Is this code to put into your bot? Because I wanted to make a bot that fills stuff...

Yes.

I bet I sound stupid. Right?

Kinda. You're in Bots and Programming.


Yeah, well, you know that's just like, uh, your opinion, man.

Offline

Tako1423758073203359

Board footer

Powered by FluxBB

[ Started around 1713609037.811 - Generated in 0.189 seconds, 12 queries executed - Memory usage: 1.53 MiB (Peak: 1.69 MiB) ]