• Welcome to the new COTI server. We've moved the Citizens to a new server. Please let us know in the COTI Website issue forum if you find any problems.

Modeling the communications delay

Originally posted by Anthony:
As I've mentione before: if you can parse C code, I've handled most of these in my own trade route software. You can download the code from http://maps.travellercentral.com/nr.c ; it won't run from that (mostly due to lack of required data files and blankmap.ps) but the logic should be sound.
Hi Anthony!
In a Nutshell - what is the logic behind what you did? I am overly fond of algorithms for some odd reason ;)

Hal
 
For which problem?

For path finding, it's a simple tree structure:

We start at one world, which we'll call the destination. From there, every other world is given a trace-back path: if you follow that trace-back path, you'll eventually reach the destination. In addition, each world is marked with a distance (along it's trace-back path) to the destination world.

Now, the way the trace-back path is built is as follows:

For X starting at zero and going upwards, find all worlds at X parsecs from the destination. Then, for each such world, find all worlds within jump range of the first world.

If the second world either has no trace-back path, or its current trace-back path is _longer_ than the route which goes through the first world, change its trace-back path to point to the first world, and set its computed distance from the homeworld as equal to the distance through the first world. By the time X reaches a value equal to that required to reach the second world, you're guaranteed that the current trace-back path will be as short as it can be, though there's no guarantee you've found a unique solution.
 
Here is some commented PHP.... I don't claim it is the fastest possible implementation, just one I considered elegant by not having to check distances or to discard false results.

</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">

/* This function validates the input values
* It checks to see if the hex address is 4 chars long and an is an integer.
* It checks to see if the range is 1-6.
* If the criteria are all true, the function returns true, otherwise it returns false.
* It should have no side effects.
*/
function validate_input($hexAddr, $rng)
{
if((intval($hexAddr) == 0) || (strlen($hexAddr) != 4))
{
echo '<br>address incorrect<br>' . strlen($hexAddr) . " : " . intval($hexAddr);
return false;
}
if (($rng > 6) || ($rng < 1))
{
echo '<br>range incorrect<br>';
return false;
}
return true;
}

if($nucleusHex) // if you have a hex to work with
{
// validate user input
if(validate_input($nucleusHex, $range)) // validate the input
{
// determine the x and y components of the 4 digit hex address (from 0101 to 3240)
$xCoord = substr($nucleusHex, 0, 2);
$yCoord = substr($nucleusHex, 2, 2);

// realize that the maximum range in y is in the row of the specified nucleus (origin) hex
// and at that point, it is equal to twice the range entered by the user plus one
$maxRangeY = $range * 2 + 1;

echo '<br>Center System:<b> ' . $xCoord . $yCoord . '</b> Range: <b>' . $range . '</b><hr>';

// now, step through all the possible columns (called xRow, but it is really a column)
// from nucleus hex x value minus range to x value plus range
for ($xRow = ($xCoord - $range); $xRow <= ($xCoord + $range); $xRow++)
{
// calculate the distance from the nucleus row
$xD = abs(($xRow-$xCoord)); // xD is distance from our nucleus hex row

// the range of y values that is appropriate at any location is
// the maxiumum range in Y minus the displacement in x
$rangeY = $maxRangeY - $xD;

/*******************************************************************
There are eight cases of interest.... the three degrees of freedom
which apply are: The original coordinates (odd or even hex column),
the current column coordinate, and whether the maximum range in Y is
an even or odd value.

With these three degrees of freedom, eight cases are generated:

Even Max Range in Y - Start xCoord Odd - Current Row Odd
Even Max Range in Y - Start xCoord Odd - Current Row Even
Even Max Range in Y - Start xCoord Even - Current Row Odd
Even Max Range in Y - Start xCoord Even - Current Row Even
Odd Max Range in Y - Start xCoord Odd - Current Row Odd
Odd Max Range in Y - Start xCoord Odd - Current Row Even
Odd Max Range in Y - Start xCoord Even - Current Row Odd
Odd Max Range in Y - Start xCoord Even - Current Row Even


In each case, a slightly different value for the upper and lower valid
Y coordinates is required. So, go calculate them. :)
*********************************************************************/

if($maxRangeY % 2) // Max Range is Odd
{
if($xCoord % 2) // Starting Coord is Odd
{
if($xRow % 2) // Current Row is Odd
{
$yUpperLim = $yCoord - (0.5 * $rangeY) + 0.5;
$yLowerLim = $yCoord + (0.5 * $rangeY) - 0.5;
}
else // Current Row is Even
{
$yUpperLim = $yCoord - (0.5 * $rangeY);
$yLowerLim = $yCoord + (0.5 * $rangeY) - 1.0;
}
}
else // Starting Coord is Even
{
if($xRow % 2) // Current Row is Odd
{
$yUpperLim = $yCoord - (0.5 * $rangeY) + 1.0;
$yLowerLim = $yCoord + (0.5 * $rangeY);
}
else // Current Row is Even
{
$yUpperLim = $yCoord - (0.5 * $rangeY) + 0.5;
$yLowerLim = $yCoord + (0.5 * $rangeY) - 0.5;
}
}
}
else // Max Range is Even
{
if($xCoord % 2) // Starting Coord is Odd
{
if($xRow % 2) // Current Row is Odd
{
$yUpperLim = $yCoord - (0.5 * $rangeY) + 0.5;
$yLowerLim = $yCoord + (0.5 * $rangeY) - 0.5;
}
else // Current Row is Even
{
$yUpperLim = $yCoord - (0.5 * $rangeY);
$yLowerLim = $yCoord + (0.5 * $rangeY);
}
}
else // Starting Coord is Even
{
if($xRow % 2) // Current Row is Odd
{
$yUpperLim = $yCoord - (0.5 * $rangeY);
$yLowerLim = $yCoord + (0.5 * $rangeY);
}
else // Current Row is Even
{
$yUpperLim = $yCoord - (0.5 * $rangeY) + 0.5;
$yLowerLim = $yCoord + (0.5 * $rangeY) - 0.5;
}
}
}

// Having calculated the y coordinates upper and lower that are
// appropriate, step through the available range
for ($yRow = $yUpperLim; $yRow <= $yLowerLim; $yRow++)
{
$xResult = $xRow;
$yResult = $yRow;

// compensate for shifts that have pushed us into the negatives (happens in top hexrows of sector or
// the lowermost columns)

if ($xResult < 0)
{
$xResult += 32;
}
if ($yResult < 0)
{
$yResult += 40;
}

// compensate for lapping over into the sector below (or to the right)

$xResult = $xResult % 32;
$yResult = $yResult % 40;

if (($xResult % 32) == 0)
{
$xResult = 32;
}
if (($yResult % 40) == 0)
{
$yResult = 40;
}

// print out the coordinates

printf("<br><b>%02.0f</b>", $xResult);
printf("<b>%02.0f</b>", $yResult);
}
echo '<hr>';
}
}
}

?></pre>[/QUOTE]
 
Nice job, I ported it to perl and it runs faster (x2) than the LUT implementation I posted earlier. The only disadvantage is that it returns all hexes within JN, as opposed to all hexes at JN. I'm sure it could be tweaked to handle that too...
 
Some people are never happy....
file_21.gif


I'll take a look and see if I can think of an elegant algorithm for doing hexes at JN. I can think of a quick and dirt solution right off the bat, but I'll look and see if I can't do a bit better than that.
 
I think there is an elegant way to do 'hex rings' if all you want is the JN-only hexes using an entirely different algorithm based off vertices or sides. However, for the moment, I have other fish to fry.

So, a quick hack at the prior php produces

PHP solution to all hexes at range N only (hex ring)

And, so you have the code: (changed bit only)

</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">

// Having calculated the y coordinates upper and lower that are
// appropriate, step through the available range
for ($yRow = $yUpperLim; $yRow <= $yLowerLim; $yRow++)
{
$xResult = $xRow;
$yResult = $yRow;

// ignore hexes that are not of interest for the JN ONLY problem set
// which actually makes for two cases:
// case 1: we want all hexes located at the x columns of max
// and min values
// case 2: we want only the topmost and bottommost hexes located
// in columns of other hex values

// Case 1:
if(($xResult == ($xCoord-$range)) || ($xResult == ($xCoord+$range)))
{

// compensate for shifts that have pushed us into the negatives (happens in top hexrows of sector or
// the lowermost columns)

if ($xResult < 0)
{
$xResult += 32;
}
if ($yResult < 0)
{
$yResult += 40;
}

// compensate for lapping over into the sector below (or to the right)

$xResult = $xResult % 32;
$yResult = $yResult % 40;

if (($xResult % 32) == 0)
{
$xResult = 32;
}
if (($yResult % 40) == 0)
{
$yResult = 40;
}

// print out the coordinates

printf("<br><b>%02.0f</b>", $xResult);
printf("<b>%02.0f</b>", $yResult);
}
// Case 2:
else if((($xResult > ($xCoord-$range)) && ($xResult < ($xCoord+$range))) &&
(($yResult == $yUpperLim) || ($yResult == $yLowerLim)))
{

// compensate for shifts that have pushed us into the negatives (happens in top hexrows of sector or
// the lowermost columns)

if ($xResult < 0)
{
$xResult += 32;
}
if ($yResult < 0)
{
$yResult += 40;
}

// compensate for lapping over into the sector below (or to the right)

$xResult = $xResult % 32;
$yResult = $yResult % 40;

if (($xResult % 32) == 0)
{
$xResult = 32;
}
if (($yResult % 40) == 0)
{
$yResult = 40;
}

// print out the coordinates

printf("<br><b>%02.0f</b>", $xResult);
printf("<b>%02.0f</b>", $yResult);
}

}</pre>[/QUOTE]It's a bit dirty, as all I do is fall through the loop for the uninteresting hexes in the larger hex (the ones 'inside'). But it works, and should be at least as fast as the unmodified code. So, you can translate it to Perl, or whatever...
file_28.gif

file_23.gif

:rolleyes:
:cool:

Fill yer Boots. All rights granted except the right to claim it as your own (and I only restrict that so no one can come back later and say 'hey, you, you're using our algorithm'), yadda yadda. If you do use the approach for something, a brief mention in the source code or a thanks somewhere is always wonderful. And encourage people to write and share code, free as in beer!
 
...and I've already found a bug in it. Interesting how publishing one's code makes one suddenly take a serious look at it.
 
And, since the Perl YAML package is just a YAML version of Data::Dumper, it's trivial to serialize instances of UWP (or any Perl thingy, really) to and from text files. For example, here's the first three worlds from Zarushagar sector. Be aware that this data is as easy to read back into Perl (via YAML) as it was to dump (via YAML).

Source Code:
</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">use UWP;

open IN, "zarushagar.sec";
my @dat = <IN>;
close IN;

for( 1..3 )
{
my $uwp = new UWP;
$uwp->decode( shift @dat );
push @list, $uwp;
}

print Dump( \@list );</pre>[/QUOTE]Output:
</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">--- #YAML:1.0
- !perl/UWP
_permitted: &1
allegiance: ~
atmosphere: ~
bases: ~
belts: ~
codes: ~
gas_giants: ~
government: ~
hydrosphere: ~
law_level: ~
location: ~
name: ~
ok: ~
pop_mult: ~
population: ~
size: ~
starport: ~
stellar: ~
tl: ~
tradeIndex: ~
xboat: ~
zone: ~
allegiance: Im
atmosphere: 0
bases: S
belts: 0
codes: 'Ni Va '
gas_giants: 3
government: 3
hydrosphere: 0
law_level: 4
location: 0101
name: 'Kiseti '
ok: 1
pop_index: 4
pop_mult: 6
population: 60000
size: 1000
starport: C
stellar: K0 V
tl: 8
tradeIndex: 0
xboat: ''
zone: ' '
- !perl/UWP
_permitted: *1
allegiance: Im
atmosphere: 0
bases: ' '
belts: 0
codes: 'Ni Va '
gas_giants: 3
government: 3
hydrosphere: 0
law_level: 3
location: 0106
name: 'Yalta '
ok: 1
pop_index: 4
pop_mult: 3
population: 30000
size: 1000
starport: B
stellar: M3 V M5 D
tl: 10
tradeIndex: 0
xboat: ''
zone: ' '
- !perl/UWP
_permitted: *1
allegiance: Im
atmosphere: 2
bases: ' '
belts: 0
codes: 'Ni '
gas_giants: 2
government: 7
hydrosphere: 50
law_level: 7
location: 0108
name: 'Hetty '
ok: 1
pop_index: 6
pop_mult: 2
population: 2000000
size: 5000
starport: B
stellar: A2 V
tl: 14
tradeIndex: 0
xboat: ''
zone: ' '</pre>[/QUOTE]
 
Pardon me for barging in again, but it's also trivial to read a YAML document into Perl, then turn around and write it back out as XML. Or vice versa.
 
Perl is undoubtedly the buzzsaw of modern programming.

It just gives me nightmares (yes, I am a disciple of the design and design some more school of thinking and also a fan of strongly typed languages that don't let you hacksaw object models....or lack them entirely....). :eek:

But we don't discuss religion on CotI, so that's a topic for another place.

I'm glad we're seeing activity in multiple formats. Perl is ... more portable. I'm going to do Java implmentations of whatever I decide to finally do with this, PHP was just a quick and net-able solution. JSP would be my real preference (ease of tying to Java), but most ISPs refuse to run Servlet containers because they are afraid (which is funny, given they run CGI and PHP).
 
My (current) preference: JNLP. And MVC of course.

Oh yeah, baby. WebStart. Oh yeah!

Call me a crossover. I wish.

To everything, turn, turn, turn
There is a season, turn, turn, turn
And a time to every purpose under heaven.

A time to UML,
A time to hack,
A time for Java,
A time for Perl,
A time for SQL,
A time for configuration files,
A time for structure and a time for chaos...
 
robject,

Thanks for posting this.


I think the following would be a fair extrapolation of your pseudocode into Java:

</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">public int calculateDistance(int col1, int row1, int col2, int row2) {

int a1 = row1 + Math.floor(col1/2);
int a2 = row2 + Math.floor(col2/2);

int d1 = Math.abs( a1 - a2 );
int d2 = Math.abs( col1 - col2 );
int d3 = Math.abs( (a1 - col1) - (a2 - col2) );

if (( d1 >= d2 )&&( d1 >= d3 )) {
return d1;
};
if (( d2 >= d1 )&&( d2 >= d3 )) {
return d2;
};
return d3;

};</pre>[/QUOTE]Would you agree?

-Flynn
 
Back
Top