Results 1 to 13 of 13

Thread: TReflectNPC.FindSpiral

  1. #1
    Join Date
    Feb 2007
    Location
    Access Violation at 0x00000000
    Posts
    2,865
    Mentioned
    3 Post(s)
    Quoted
    18 Post(s)

    Lightbulb TReflectNPC.FindSpiral

    Simba Code:
    //Look for NPC with Name in spiral pattern around player, within an RxR square
    function TReflectNPC.FindSpiral(Name: String; R: Integer; checkInteracting: Boolean): Boolean;
    var
      currTile: TTile;
      i, j, n, k, di, dj, seg, segLen, buf, m, l: Integer;
      tNPC: TReflectNPC;
      tNPCA, tRNPCA: TReflectNPCArray;
      condition: Boolean;
    begin
      if not isLoggedIn then
        Exit;

      //Get all NPCs and select only those with the right Name
      Self.Null;
      tNPCA.GetAll;
      j := 0;
      k := High(tNPCA);
      SetLength(tRNPCA, k + 1);
      for i := 0 to k do
        if tNPCA[i].Name = Name then
        begin
          tRNPCA[j] := tNPCA[i];
          Inc(j);
        end;
      l := j;

      currTile := cP.GetTile; //cP is a global TReflectLocalPlayer
      k := R * R;
      i := 0;
      j := 0;
      di := 1;
      dj := 0;
      seg := 0;
      segLen := 1;

      //Spiral around the player, looking for matches between found NPCs' location and the current spiral location
      for n := 0 to k do
      begin
        IncEx(currTile.X, di);
        IncEx(currTile.Y, dj);
        Inc(seg);

        for m := 0 to l do
        begin
          if checkInteracting then
            condition := (tRNPCA[m].Tile.X = currTile.X) and (tRNPCA[m].Tile.Y = currTile.Y) and (tRNPCA[m].InteractingIndex = -1)
          else
            condition := (tRNPCA[m].Tile.X = currTile.X) and (tRNPCA[m].Tile.Y = currTile.Y);

          if condition then
          begin
            Self := tRNPCA[m];
            Result := True;
            Exit;
          end;
        end;

        if seg = segLen then
        begin
          seg := 0;
          buf := di;
          di := -dj;
          dj := buf;

          if dj = 0 then
            Inc(segLen);
        end;
      end;

      Result := False;
    end;

    For a script I've created.
    It will search the tiles around the player in a spiraling pattern for an NPC named 'Name' (todo: add ID support), in a R^2 square as max range.
    The spiraling logic I've adapted from a StackOverflow answer that was in Python. The checkInteracting bit is because I'll mainly be looking for NPCs to fight, to make sure they're not already engaged.

    This is my first thing since like 2009 so I'm quite rusty. Tell me what you think

    EDIT:

    Shortened it a bit, removed that first loop. Will test out when hooks are back up.
    Simba Code:
    //Look for NPC with Name in spiral pattern around player, within an RxR square
    function TReflectNPC.FindSpiral(Name: String; R: Integer; checkInteracting: Boolean): Boolean;
    var
      currTile: TTile;
      x, y, n, k, dx, dy, seg, segLen, buf, i, npcCount: Integer;
      tNPCA: TReflectNPCArray;
      condition: Boolean;
    begin
      if not isLoggedIn then
        Exit;

      Self.Null;
      tNPCA.GetAll;
      npcCount := High(tNPCA);
      currTile := cP.GetTile;
      k := R * R;
      x := 0;
      y := 0;
      dx := 1;
      dy := 0;
      seg := 0;
      segLen := 1;

      //Spiral around the player, looking for matches between found NPCs' location and the current spiral location
      for n := 0 to k do
      begin
        IncEx(currTile.X, dx);
        IncEx(currTile.Y, dy);
        Inc(seg);

        for i := 0 to npcCount do
        begin
          if checkInteracting then
            condition := (tNPCA[i].Name = Name) and (tNPCA[i].Tile.X = currTile.X) and (tNPCA[i].Tile.Y = currTile.Y) and (tNPCA[i].InteractingIndex = -1)
          else
            condition := (tNPCA[i].Name = Name) and (tNPCA[i].Tile.X = currTile.X) and (tNPCA[i].Tile.Y = currTile.Y);

          if condition then
          begin
            Self := tNPCA[i];
            Result := True;
            Exit;
          end;
        end;

        if seg = segLen then
        begin
          seg := 0;
          buf := dx;
          dx := -dy;
          dy := buf;

          if dy = 0 then
            Inc(segLen);
        end;
      end;

      Result := False;
    end;
    Last edited by Floor66; 02-12-2015 at 01:56 PM.
    Ce ne sont que des gueux


  2. #2
    Join Date
    Oct 2006
    Posts
    6,752
    Mentioned
    95 Post(s)
    Quoted
    532 Post(s)

    Default

    Looks good man! Though, I'm sure it can be simplified and sped up by using Reflect.Tiles.DistanceFromTile(Tile: TTile);
    It won't technically be 'spiraling,' but since it just simply uses the distance formula, and you could loop through them that way, I'd assume it'd be faster.
    “The long-lived and those who will die soonest lose the same thing. The present is all that they can give up, since that is all you have, and what you do not have, you cannot lose.” - Marcus Aurelius

  3. #3
    Join Date
    Feb 2007
    Location
    Access Violation at 0x00000000
    Posts
    2,865
    Mentioned
    3 Post(s)
    Quoted
    18 Post(s)

    Default

    Yeah I'd thought about that, I'll compare and see what is fastest (and get an excuse to teach myself that spiraling algorithm ). Using this and some other tricks I can get my bot to match the speed and sometimes even beat humans.
    I just wasn't quite satisfied with the speed I was getting using a different method ^^ I've got a few more of these snippets (TileOnMS, WaitUpText) if you're interested.
    Last edited by Floor66; 02-12-2015 at 01:58 PM.
    Ce ne sont que des gueux


  4. #4
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Step 1:
    Find all NPCs of that ID and store their tiles in an array

    Step 2:
    Sort the array from closest to furthest from the player tile

    Step 3:
    Iterate this list checking each result in a spiral search pattern; this step would be made easier by using a Map or HashMap pascal variation

    Step 4:
    Profit!

  5. #5
    Join Date
    Feb 2007
    Location
    Access Violation at 0x00000000
    Posts
    2,865
    Mentioned
    3 Post(s)
    Quoted
    18 Post(s)

    Default

    Thing is, I'm thinking of performance here. I was targeting chickens, which move quite fast so I didn't want to waste time. Also, I don't like using more loops than I have to.

    Step 1) is a loop, checking for the NPCs' names
    Step 2) is sorting, which is a bunch of nested loops
    Step 3) is kind of what I have going on --> could you expand on the use of Maps/HashMaps?
    Last edited by Floor66; 02-12-2015 at 03:22 PM.
    Ce ne sont que des gueux


  6. #6
    Join Date
    Oct 2006
    Posts
    6,752
    Mentioned
    95 Post(s)
    Quoted
    532 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    Step 1:
    Find all NPCs of that ID and store their tiles in an array

    Step 2:
    Sort the array from closest to furthest from the player tile

    Step 3:
    Iterate this list checking each result in a spiral search pattern; this step would be made easier by using a Map or HashMap pascal variation

    Step 4:
    Profit!
    That's how the current TReflectNpcArray.Sort works minus the spiral at the end
    “The long-lived and those who will die soonest lose the same thing. The present is all that they can give up, since that is all you have, and what you do not have, you cannot lose.” - Marcus Aurelius

  7. #7
    Join Date
    Sep 2012
    Location
    Netherlands
    Posts
    2,752
    Mentioned
    193 Post(s)
    Quoted
    1468 Post(s)

    Default

    Quote Originally Posted by elfyyy View Post
    That's how the current TReflectNpcArray.Sort works minus the spiral at the end
    spiral is not even necessary imo

  8. #8
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Quote Originally Posted by hoodz View Post
    spiral is not even necessary imo
    My thoughts exactly however the OP requested spiral sorting.

  9. #9
    Join Date
    Oct 2006
    Posts
    6,752
    Mentioned
    95 Post(s)
    Quoted
    532 Post(s)

    Default

    Quote Originally Posted by hoodz View Post
    spiral is not even necessary imo
    Hense why .Sort doesn't use it
    “The long-lived and those who will die soonest lose the same thing. The present is all that they can give up, since that is all you have, and what you do not have, you cannot lose.” - Marcus Aurelius

  10. #10
    Join Date
    Nov 2011
    Location
    England
    Posts
    3,072
    Mentioned
    296 Post(s)
    Quoted
    1094 Post(s)

    Default

    Sprial has it's benefits, as the spiral paths are (should?) be created randomly.

    Who clicks the pixel perfect nearest npc each time?

    + you're all crazy talking about hashmaps and stuff, you're going to have like 20 npc's max on your screen.

  11. #11
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Referencing my post above, you can avoid using a Map by using a 2D array, its just not as pretty.

    Java:

    Code:
    public class Blah {
     
      public static void main(String[] args) {
        print2dArray(getSpiralArray(5));
      }
     
      public static int[][] getSpiralArray(int dimension) {
        int[][] spiralArray = new int[dimension][dimension];
     
        int numConcentricSquares = (int) Math.ceil((dimension) / 2.0);
     
        int j;
        int sideLen = dimension;
        int currNum = 0;
     
        for (int i = 0; i < numConcentricSquares; i++) {
          // do top side
          for (j = 0; j < sideLen; j++) {
            spiralArray[i][i + j] = currNum++;
          }
     
          // do right side
          for (j = 1; j < sideLen; j++) {
            spiralArray[i + j][dimension - 1 - i] = currNum++;
          }
     
          // do bottom side
          for (j = sideLen - 2; j > -1; j--) {
            spiralArray[dimension - 1 - i][i + j] = currNum++;
          }
     
          // do left side
          for (j = sideLen - 2; j > 0; j--) {
            spiralArray[i + j][i] = currNum++;
          }
     
          sideLen -= 2;
        }
     
        return spiralArray;
      }
     
      public static void print2dArray(int[][] array) {
        for (int[] row : array) {
          for (int elem : row) {
            System.out.printf("%3d", elem);
          }
          System.out.println();
        }
      }
    }
    Pascal:

    Simba Code:
    program Spiralmat;
    type
      tDir = (left,down,right,up);
      tdxy = record
               dx,dy: longint;
             end;
      tdeltaDir = array[tDir] of tdxy;
    const
      Nextdir : array[tDir] of tDir = (down,right,up,left);
      cDir : tDeltaDir = ((dx:1;dy:0),(dx:0;dy:1),(dx:-1;dy:0),(dx:0;dy:-1));
      cMaxN = 32;
    type
      tSpiral =  array[0..cMaxN,0..cMaxN] of LongInt;
     
    function FillSpiral(n:longint):tSpiral;
    var
      b,i,k, dn,x,y : longInt;
      dir : tDir;
      tmpSp : tSpiral;
    BEGIN
      b := 0;
      x := 0;
      y := 0;
      //only for the first line
      k := -1;
      dn := n-1;
      tmpSp[x,y] := b;
      dir :=  left;
      repeat
        i := 0;
        while i < dn do
        begin
          inc(b);
          tmpSp[x,y] := b;
          inc(x,cDir[dir].dx);
          inc(y,cDir[dir].dy);
          inc(i);
        end;
        Dir:= NextDir[dir];
        inc(k);
        IF k > 1 then
        begin
          k := 0;
          //shorten the line every second direction change
          dn := dn-1;
          if dn <= 0 then
            BREAK;
        end;
      until false;
      //the last
      tmpSp[x,y] := b+1;
      FillSpiral := tmpSp;
    end;
     
    var
      a : tSpiral;
      x,y,n : LongInt;
    BEGIN
      For n := 1 to 5{cMaxN} do
      begin
        A:=FillSpiral(n);
        For y := 0 to n-1 do
        begin
          For x := 0 to n-1 do
            write(A[x,y]:4);
          writeln;
        end;
        writeln;
      end;
    END.

    Edit:

    Above solutions will sort a "mat" of objects (in your case the mat is onscreen tiles). It will sort from outside inwards, but is fairly easy to reverse.

    Both examples will run and generate + spiral sort a matrix.

  12. #12
    Join Date
    Feb 2007
    Location
    Access Violation at 0x00000000
    Posts
    2,865
    Mentioned
    3 Post(s)
    Quoted
    18 Post(s)

    Default

    Quote Originally Posted by Olly View Post
    Sprial has it's benefits, as the spiral paths are (should?) be created randomly.

    Who clicks the pixel perfect nearest npc each time?

    + you're all crazy talking about hashmaps and stuff, you're going to have like 20 npc's max on your screen.
    This is also what I was considering -> simply grabbing the nearest in a straight line vs. nearest by spiral pattern.
    These are my other snippets btw:
    Simba Code:
    function TReflectionText.WaitUpTextMulti(S: TStringArray; time: Integer): Boolean;
    var
      t: Timer;
    begin
      Result := False;
      t.start;

      while t.timeElapsed < time do
      begin
        if Reflect.Text.IsUpTextMulti(S) then
          Exit(True);
        Wait(20 + Random(20));
      end;
    end

    function TReflectionText.WaitUpText(S: String; time: Integer): Boolean;
    var
      t: Timer;
    begin
      Result := TReflectionText.WaitUpTextMulti([S], time);
    end
    Ce ne sont que des gueux


  13. #13
    Join Date
    Sep 2012
    Location
    Netherlands
    Posts
    2,752
    Mentioned
    193 Post(s)
    Quoted
    1468 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    My thoughts exactly however the OP requested spiral sorting.
    however, its still nice he contributed.
    rep+

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •