View unanswered posts | View active topics It is currently Fri Apr 19, 2024 2:39 pm



Reply to topic  [ 15 posts ] 
 Home Made GetDistance Routine... 
Author Message
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Home Made GetDistance Routine...
Wondering if anyone out there can help with this routine. Inspired by Elder Prophets breadth-first routine, I decided to try and write a GetDistance routine that would be faster than the built-in TWX GetDistance. After a few attempts with different concepts (don't try: SetArray SECTORS SECTORS, lol), this is the best I could come up with. for short distances it appears accurate and fast (haven't compared timing with the native TWX command), but for long plots there's usually a difference of one-hop. This is interesting to me, because I've often wondered at how TWX derives it's Course-plots, etc. ...thinking that my routine might be a tad more accurate.. hehe.

I'm playing around with this because of another script I'd like to rewrite that makes intensive GetDistance calculations, and really bogs down the CPU with large data-sets.

Code:
SetVar $Starting_Point 1
SetVar $Looking_For 100
SetArray $Checked SECTORS
SetVar $Warps 55000
SetArray $QUE $warps
SetVar $MAX_LENGTH 45
SetVar $QUE_BOTTOM 1
SetVar $QUE_TOP 1
SetVar $Distance 1
SetVar $Checked[$Starting_Point] TRUE
SetVar $Sector_Focus $Starting_Point
SetVar $Absolute_PTR 1
While ($Distance <= $MAX_LENGTH)
   While ($QUE_BOTTOM <= $QUE_TOP)
      SetVar $ADJ 1
      While (SECTOR.WARPS[$Sector_Focus][$ADJ] <> 0)
         If ($Checked[SECTOR.WARPS[$Sector_Focus][$ADJ]] = FALSE)
            If (SECTOR.WARPS[$Sector_Focus][$ADJ] = $Looking_For)
               Echo "***" & ANSI_7 & "Distance from "
               Echo ANSI_14 & $Starting_Point & ANSI_7 & " to "
               Echo ANSI_14 & $Looking_For & ANSI_7 & " is "
               Echo ANSI_14 & $Distance & ANSI_7 & " hops."
               GetDistance $Dist 1 $Looking_For
               Echo ANSI_7 & "*getDistance Result: " & ANSI_14 & $Dist "**"
               Halt
            End
            SetVar $QUE[$Absolute_PTR] SECTOR.WARPS[$Sector_Focus][$ADJ]
            SetVar $Checked[SECTOR.WARPS[$Sector_Focus][$ADJ]] TRUE
            Add $Absolute_PTR 1
         End
         Add $ADJ 1
      End
      Add $QUE_BOTTOM 1
      SetVar $Sector_Focus $QUE[$QUE_BOTTOM]
   End
   Subtract $QUE_BOTTOM 1
   SetVar $Sector_Focus $QUE[$QUE_BOTTOM]
   SetVar $QUE_TOP $Absolute_PTR
   Add $Distance 1
End


Feel free to ask any questions about the code.. including criticisms.

Thanks

[EDIT] Not intended for sectors > 20k (would require a larger $QUE.
[EDIT] Cleaned up the code a tad.


Attachments:
File comment: EDIT: Cleaned up the code a tad
getdistance.ts [1.22 KiB]
Downloaded 622 times

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)
Sun Nov 30, 2014 10:31 am
Profile ICQ YIM
Ambassador
User avatar

Joined: Fri Feb 23, 2001 3:00 am
Posts: 4016
Location: USA
Unread post Re: Home Made GetDistance Routine...
You know I don't write scripts but I can make out a little bit.

Why hard code in Max Length? Shouldn't you be pulling that value from the * menu since it's sysop configurable?

_________________

BOTE 1998 Champs: Team Fament
HHT 2015 Champs: Cloud09
Big Game 2016 Champs: Draft team
HHT 2018 Champs: Rock Stars
Big Game 2019 Champs: Draft Team


Classic Style Games Here:
telnet://crunchers-twgs.com:2002

Web page from 1990's: https://web.archive.org/web/20170103155645/http://tradewars.fament.com/Cruncher/tradewar.htm
Blog with current server info: http://cruncherstw.blogspot.com
Discord: https://discord.gg/4dja5Z8
E-mail: Cruncherstw@gmail.com
FaceBook: http://www.facebook.com/CrunchersTW


Sun Nov 30, 2014 6:55 pm
Profile ICQ WWW
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Re: Home Made GetDistance Routine...
Cruncher wrote:
Why hard code in Max Length? Shouldn't you be pulling that value from the * menu since it's sysop configurable?


If I'm not mistaken, the value you're alluding too is used with respect to Course Plots.

The value of '45' is arbitrary; I don't believe I've ever come across a course length greater. In practice the value could be anything but should not be infinite. The routine could be used, for example, to give you all sectors within/further-than x-hops, or give you all sectors x number of hops out. There are probably a few more possibilities but for now I'm curious about making it faster than the native GetDistance.

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)


Sun Nov 30, 2014 7:49 pm
Profile ICQ YIM
Boo! inc.
User avatar

Joined: Tue Jun 18, 2002 2:00 am
Posts: 30
Location: earth
Unread post Re: Home Made GetDistance Routine...
GetDistance execution time does vary with course length, so it would seem unlikely that any scripted version could improve on it. The breadth-first search clearly outperforms GetNearestWarps for finding nearby targets however, since it stops when a target is found rather than doing entire universe.

Since you use array $Checked to skip sectors already processed, it looks like SECTORS is the maximum possible number of elements in $QUE. The routine should terminate when all reachable sectors have been checked, whether $MAX_LENGTH is imposed or not.

$Distance seems to get out of synch with actual depth level somewhere; I am still looking it over. Have you tried implementing the routine with a stack instead of a queue?






LoneStar wrote:
Wondering if anyone out there can help with this routine. Inspired by Elder Prophets breadth-first routine, I decided to try and write a GetDistance routine that would be faster than the built-in TWX GetDistance. After a few attempts with different concepts (don't try: SetArray SECTORS SECTORS, lol), this is the best I could come up with. for short distances it appears accurate and fast (haven't compared timing with the native TWX command), but for long plots there's usually a difference of one-hop. This is interesting to me, because I've often wondered at how TWX derives it's Course-plots, etc. ...thinking that my routine might be a tad more accurate.. hehe.

I'm playing around with this because of another script I'd like to rewrite that makes intensive GetDistance calculations, and really bogs down the CPU with large data-sets.



Sun Nov 30, 2014 10:14 pm
Profile ICQ
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Re: Home Made GetDistance Routine...
Xanos wrote:
GetDistance execution time does vary with course length, so it would seem unlikely that any scripted version could improve on it. The breadth-first search clearly outperforms GetNearestWarps for finding nearby targets however, since it stops when a target is found rather than doing entire universe.

Since you use array $Checked to skip sectors already processed, it looks like SECTORS is the maximum possible number of elements in $QUE. The routine should terminate when all reachable sectors have been checked, whether $MAX_LENGTH is imposed or not.

$Distance seems to get out of synch with actual depth level somewhere; I am still looking it over. Have you tried implementing the routine with a stack instead of a queue?


$que is really a Stack (named QUE as a tip of the hat at EP). And it does need to be at least equal to the number of Warps in the game because of how it is used to reference previous results from the previous iterations. If you change the destination sector to one that is adjacent sector 10 for example (ie 3hops out), reduce the $que size to about 50, pause execution and look at the variables, you'll get an idea of how I'm using the QUE as a stack. Note that $absolute_ptr moves up through the Stack and the Que_Bottom and Que_top are relative.

Also, $Checked prevents an infinite Loop as sector 2 is adj sector 1; when scanning sector 2's adjacents we don't want to consider sector 1 again, otherwise the loop will run forever scanning and rescanning sector 1 and 2's adjacents.
I can post a screen cap if convenient.

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)


Sun Nov 30, 2014 10:58 pm
Profile ICQ YIM
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Re: Home Made GetDistance Routine...
…wanted to mention that this routine might I fact be ideal for the same reason you've pointed out; I can break out of the GetDistance if a Target is too far. Something I hadn't considered.

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)


Sun Nov 30, 2014 11:45 pm
Profile ICQ YIM
Boo! inc.
User avatar

Joined: Tue Jun 18, 2002 2:00 am
Posts: 30
Location: earth
Unread post Re: Home Made GetDistance Routine...
In that case it should be possible to keep $distance updated by incrementing it each time you "push" onto the stack and decrementing for each "pull".

If no sector ever gets stored in $Que more than once (because of $Checked), how is the universe warp count relevant?


LoneStar wrote:
$que is really a Stack (named QUE as a tip of the hat at EP). And it does need to be at least equal to the number of Warps in the game because of how it is used to reference previous results from the previous iterations. If you change the destination sector to one that is adjacent sector 10 for example (ie 3hops out), reduce the $que size to about 50, pause execution and look at the variables, you'll get an idea of how I'm using the QUE as a stack. Note that $absolute_ptr moves up through the Stack and the Que_Bottom and Que_top are relative.

Also, $Checked prevents an infinite Loop as sector 2 is adj sector 1; when scanning sector 2's adjacents we don't want to consider sector 1 again, otherwise the loop will run forever scanning and rescanning sector 1 and 2's adjacents.
I can post a screen cap if convenient.

_________________
Are you suggesting coconuts migrate?!


Mon Dec 01, 2014 12:14 am
Profile ICQ
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Re: Home Made GetDistance Routine...
Xanos wrote:
In that case it should be possible to keep $distance updated by incrementing it each time you "push" onto the stack and decrementing for each "pull".

If no sector ever gets stored in $Que more than once (because of $Checked), how is the universe warp count relevant?


Yeah. I see what you mean now. Makes sense. Thanks for the input, I really appreciate the outside perspective.

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)


Mon Dec 01, 2014 12:28 am
Profile ICQ YIM
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Re: Home Made GetDistance Routine...
After much debugging and testing I figured out why $Distance returned was incorrect --some of the time. Let's just say that Stack-Pointers, Base-Pointers, and relative 'addressing' can be your friend or your nemesis :D


Example caller routine for testing purposes
Code:
SetVar $MAX_LENGTH 45
SetVar $I 100
While ($I <= 150)
   SetVar $Starting_Point ($I + 10)
   SetVar $Looking_For $I
   Gosub :GETDISTANCE
   Echo "*" & $Starting_Point & " to " & $Looking_For & " = " & $Distance & " : "
   GetDistance $DIST $Starting_Point $Looking_For
   Echo $DIST & " (TWX GetDistance)"
   Add $i 1
End
Halt

Actual GetDistance routine, with minimal bounds checking.
Code:
:GETDISTANCE
SetArray $Checked SECTORS
If ($RUNONCE = 0)
   SetArray $QUE sectors
   SetVar $RUNONCE 1
end
SetVar $QUE_BOTTOM 1
SetVar $QUE_TOP 1
SetVar $Distance 1
SetVar $Checked[$Starting_Point] TRUE
SetVar $Sector_Focus $Starting_Point
SetVar $Absolute_PTR 1

If ($MAX_LENGTH = 0) OR ($MAX_LENGTH > 45)
   SetVar $MAX_LENGTH 45
End

If ($Starting_Point < 1) OR ($Starting_Point > SECTORS) OR ($Looking_For < 1) OR ($Looking_For > SECTORS)
   Setvar $Distance "-1"
   Return
End

If ($Starting_Point = $Looking_For)
   Setvar $Distance 0
   Return
End

While ($Distance <= $MAX_LENGTH)
   While ($QUE_BOTTOM <= $QUE_TOP)
      SetVar $ADJ 1
      While (SECTOR.WARPS[$Sector_Focus][$ADJ] <> 0)
         If ($Checked[SECTOR.WARPS[$Sector_Focus][$ADJ]] = FALSE)
            If (SECTOR.WARPS[$Sector_Focus][$ADJ] = $Looking_For)
                Return
            End
            SetVar $QUE[$Absolute_PTR] SECTOR.WARPS[$Sector_Focus][$ADJ]
            SetVar $Checked[SECTOR.WARPS[$Sector_Focus][$ADJ]] TRUE
            Add $Absolute_PTR 1
         End
         Add $ADJ 1
      End
      Add $QUE_BOTTOM 1
      SetVar $Sector_Focus $QUE[$QUE_BOTTOM]
   End
   Subtract $QUE_BOTTOM 1
   SetVar $Sector_Focus $QUE[$QUE_BOTTOM]
   SetVar $QUE_TOP ($Absolute_PTR - 1)
   Add $Distance 1
End

SetVar $Distance "-1"
Return


Attachments:
File comment: Working Version
GetDistance.ts [1.55 KiB]
Downloaded 648 times

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)
Thu Dec 04, 2014 7:30 am
Profile ICQ YIM
Commander
User avatar

Joined: Tue Oct 07, 2003 2:00 am
Posts: 1131
Location: Augusta, GA
Unread post Re: Home Made GetDistance Routine...
I've written such routines many many times, and would be willing to share mine, if you'd like. There's no beating the native calls for getDistance and getCourse, but there are always cases where having your own is advantageous. I once wrote a getCourse search that worked both sides simultaneously (sorta) which was significantly faster than the typical approach (and might beat getCourse in speed), but was very hard to make it match the exact same path as the conventional method. That isn't necessarily important though. Fun times.

I implemented the getNearestWarps to serve the majority of breadth-first search needs (nearfig, nearest Sxx port, etc.), and it sure saves me a lot of time and lines of code. But rolling your own and creating your own exit criteria will sometimes be preferable for adept scripters - so kudos for pursuing it.

+EP+

_________________
Claim to Fame: only guy to ever crack the TW haggle algorithm, and fig/shield/hold price formula, twice.


Tue Dec 16, 2014 7:53 pm
Profile WWW
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Re: Home Made GetDistance Routine...
ElderProphet wrote:
I've written such routines many many times, and would be willing to share mine, if you'd like.


Yes I would like to see how this could be faster. I learned a lot from studying your routines. I find that there's a certain level of intrinsic Awesome-azing qualities when stepping away from Brute force methods.

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)


Tue Dec 16, 2014 11:27 pm
Profile ICQ YIM
Commander
User avatar

Joined: Tue Oct 07, 2003 2:00 am
Posts: 1131
Location: Augusta, GA
Unread post Re: Home Made GetDistance Routine...
The following :getDistance subroutine isn't necessarily faster, but rather as simple as possible. It can be made a bit shorter, but that results in horrible looking nested variables which are hard to understand.

Let me point out that the $que array (which you'll see in much of my code) is not a stack, but is a queue. Let me explain for posterity. With a queue, you add new items that you want to investigate to the top of the queue, but you pull the next item to investigate from the bottom. So the earliest or oldest item is processed for each iteration. This is how breadth-first searches are normally performed, meaning that all sectors that are 1-hop away will be processed before all sectors that are 2-hops, and so on. This is a natural product of using a queue.

Conversely, with a stack, you add new items to the top as before, but you also pull the next item to process from the top. Or in common stack terms, you push items onto the stack (onto the top), and pop them off the stack (again, from the top). Stacks are commonly used in depth-first searches, where a course is pursued linearly to it's end, and then back-tracked to the last branch. Think of this approach as akin to entering a maze and always taking the left-most unexplored corridor (and leaving a mark so you'll know you've taken it already.) Eventually you'll reach a dead end, and backtrack to the last unexplored branch. This backtracking is hard to do in TWX scripting, so you don't see depth-first searches often. I could probably be persuaded to write and share one, though it's been years...

In the :getDistance code below, we create the $que array, the $checked array to ensure we don't re-process a sector, and an array to track distance. I use "pointers" to track where I'm at in processing the items in the queue. Specifically, I track the next sector that will be processed with $bottom, and I track where new items will be added with $top. I add the starting sector to the $que array, in position 1. Then I iterate from $bottom to $top, and the result is a breadth-first search. Pay special attention to the 2 returns -- one when the object of our search is found, and one when the search is exhausted (and failed.)

Let me know if there are any aspects that I can help clarify,
+EP+

P.S. Turning this into a getCourse routine only requires a few additional lines of code.
Code:
:getInput
getInput $from "*What is the starting sector?"
getInput $to "*What is the destination sector?"
gosub :getDistance
echo "*The distance is " $distance "*"
goto :getInput

:getDistance
# Variables that must be set before calling:
# $from - the starting sector
# $to - the destination sector
# Once complete, the $distance variable will be set, or will be -1 if no path is found
setArray $que SECTORS
setArray $checked SECTORS
setArray $distance SECTORS
setVar $top 1
setVar $bottom 1
setVar $distance[$from] 0 // this isn't strictly necessary, but clearer
setVar $que[1] $from
setVar $checked[$from] TRUE
while ($bottom <= $top)
   setVar $focus $que[$bottom]
   setVar $i 1
   while ($i <= SECTOR.WARPCOUNT[$focus])
      setVar $adjacent SECTOR.WARPS[$focus][$i]      
      if ($checked[$adjacent] = FALSE)
         setVar $distance[$adjacent] ($distance[$focus] + 1)
         if ($adjacent = $to)
            # Path has been found
            setVar $distance $distance[$adjacent]
            return
         end
         add $top 1
         setVar $que[$top] $adjacent
         setVar $checked[$adjacent] TRUE
      end
      add $i 1
   end
   add $bottom 1
end
# No path was found
setVar $distance "-1"
return

_________________
Claim to Fame: only guy to ever crack the TW haggle algorithm, and fig/shield/hold price formula, twice.


Sat Dec 20, 2014 12:38 pm
Profile WWW
Commander
User avatar

Joined: Fri Jun 09, 2006 2:00 am
Posts: 1396
Location: Canada
Unread post Re: Home Made GetDistance Routine...
Thanks for sharing. I think I 'get' everything in the Code. I haven't worked with Stacks for a very long time, but I seem to remeber two different types of Stack: FIFO & LIFO, the QUE being the latter. However the native POP nemonic would be strictly be FIFO; and direct manipulating of Pointers would give LIFO. Anyway. I'm looking forward to testing the performance differences --my nested while-loops versus (your) single nested while-loop.

_________________
----------------------------
-= QUANTUM Computing 101: 15 = 3 x 5 ... 48% of the time.
-= There are 10 types of people in the world: Those that understand Binary and those who do not
-= If Oil is made from Dinosaurs, and Plastic is made from Oil... are plastic Dinosaurs made from real Dinosaurs?
-= I like to keep my friends and my enemies rich, and wait to see which is which - Tony Stark (R.I.P.)


Sun Dec 21, 2014 11:36 am
Profile ICQ YIM
Commander
User avatar

Joined: Tue Oct 07, 2003 2:00 am
Posts: 1131
Location: Augusta, GA
Unread post Re: Home Made GetDistance Routine...
Great, I'd be interested to hear your results.

Regarding push and pop, I've only seen that turn-of-phrase applied to stacks, specifically LIFO stacks.

_________________
Claim to Fame: only guy to ever crack the TW haggle algorithm, and fig/shield/hold price formula, twice.


Tue Dec 23, 2014 11:10 pm
Profile WWW
Commander
User avatar

Joined: Tue Oct 07, 2003 2:00 am
Posts: 1131
Location: Augusta, GA
Unread post Re: Home Made GetDistance Routine...
So I did some testing for a 5K sector map...

My un-optimized split-getDistance routine (that works from both directions simultaneously) is over 3.5 times faster on average than the normal getDistance routine I posted earlier. Theoritically, it could be about 4x faster, but remember that the course will not be the same that getCourse returns - same distance though.

However, the built-in TWX getDistance routine is 180 times faster than my split routine, and 640 times faster than the normal routine I posted. I expect these variances would increase as sector count increases.

This doesn't mean that there aren't times when you want to roll your own BFS though, but custom getDistance and getCourse routines will always be abysmal compared to the built-in versions.

+EP+

_________________
Claim to Fame: only guy to ever crack the TW haggle algorithm, and fig/shield/hold price formula, twice.


Sat Dec 27, 2014 4:03 pm
Profile WWW
Display posts from previous:  Sort by  
Reply to topic   [ 15 posts ] 

Who is online

Users browsing this forum: No registered users and 12 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by STSoftware.