Jump to content
sarogahtyp

[SOLVED] Array trouble

Recommended Posts

Hey guys,

I need some help please.

I wrote a sqf implementation of Dikstra's Shortest Path algorithm. The algorithm itself is working but my problem is that the manipulated input array (_allNodes) which I gave as parameter 3 does not contain the solution at the end.

I guess that somwhere during the script the pointer connection to the input array gets lost but I cant discover where.

 

situation the script is feeded with as picture:

 

https://imgur.com/UMT9v1B

 

I start the script from initServer.sqf with:

private _nodeThings = [3,1,0,2];
private _index = [0, 3, _nodeThings, [[10, 0, 1], [9,0,2], [15, 1, 3], [5, 2, 3]]] spawn saroSSSP_fnc_shortPathDijkstra;

waitUntil {scriptDone _index};

// DEBUG
_notext = " ";
_text = "Nodes after script";
diag_Log _text;
diag_log _nodeThings;
diag_log _notext;
// DEBUG

 

 

parameters are described here:

Spoiler

1.	number - ID of start node

2.  number - ID of end node

3.  array - nodes list - format: [ [ID1, positionASL], [ID2, positionASL], ..., [IDn, positionASL] ]
               ID1-IDn - numbers, ID of the specific node 
			   ID range has to be 0 to n and each ID between 0 and n has to have a node (no leaks)
			   ID may provided unsorted cause they get sorted anyways
		    positionASL - position above sea level

     format(alternative, faster): [ ID1, ID2, ..., IDn ]

4.  array - connections list - format: [[fromID, toID], [fromID, toID], ..., [fromID, toID]]
            fromID - number, connections start node ID
            toID - number, connections end node ID

         format (alternative, faster): [[distance, fromID, toID], [distance, fromID, toID], ..., [distance, fromID, toID]]
                                       distance can be any distance format you prefer (distance, distanceSqr, distance2D may be worse with multiple floors)


5.   boolean - Oneway - do we have Oneway connections? true means we have such. false means not.

   returned nodes array (3.) - array of nodeIDs in order to pass from first (start node) to last (end node) element or
					           boolean false - indicating that input data was not valid
                               boolean true - indicating that there is no possible solution

 

 

complete Script here:

Spoiler

/*  !!! WIP !!! - don't use, it's not ready...

	Author: Sarogahtyp
	Title: SSSP(D) - Sarogahtyps Simple Shortest Path - Dijkstra algorithm
                                                          https://en.wikipedia.org/wiki/Dijkstra

	Description: Dijkstra-algorithm - sqf implementation
                     This algorithm is much more time consuming than A* algorithm if only 1 floor is necessary
                     if multiple floors are needed then it has to be tested if A* (multiple floor solution) is faster or not

	Arguments:
        if you use alternative format at 3. then you have to use alternative format at 4 as well and vice versa
        if you have precalculated distances (maybe at mission start) for 4. then alternative format is faster
        if you would calculate
         
1.	number - ID of start node

2.  number - ID of end node

3.  array - nodes list - format: [ [ID1, positionASL], [ID2, positionASL], ..., [IDn, positionASL] ]
               ID1-IDn - numbers, ID of the specific node 
			   ID range has to be 0 to n and each ID between 0 and n has to have a node (no leaks)
			   ID may provided unsorted cause they get sorted anyways
		    positionASL - position above sea level

     format(alternative, faster): [ ID1, ID2, ..., IDn ]

4.  array - connections list - format: [[fromID, toID], [fromID, toID], ..., [fromID, toID]]
            fromID - number, connections start node ID
            toID - number, connections end node ID

         format (alternative, faster): [[distance, fromID, toID], [distance, fromID, toID], ..., [distance, fromID, toID]]
                                       distance can be any distance format you prefer (distance, distanceSqr, distance2D may be worse with multiple floors)

   returned nodes array (3.) - array of nodeIDs in order to pass from first (start node) to last (end node) element or
					           boolean false - indicating that input data was not valid
                               boolean true - indicating that there is no possible solution
*/


private _correctList = params [ ["_startNode", objNull, [0]],  // numbers allowed only
         ["_endNode", objNull, [0]],    // numbers allowed only
         ["_allNodes", objNull, [ [] ]], // arrays allowed only
         ["_allConnections", objNull, [ [] ]], // arrays allowed only
		  "_oneway" ];

// check for valid parameter data types
if (!_correctList) exitWith {_allNodes = false;};

//check if first element of _allNodes is number or array and if it is array then with exact 2 elements
private _correctNodes = _allNodes params [["_firstElementNodes", objNull, [0, []], [2]]];

//check if first element of _allConnections is an array and if it has 2 or 3 elements
private _correctConnections = _allConnections params [["_firstElementConnections", objNull, [[]], [2, 3]]];

// exit if at least one of both first elements has wrong format
if (!_correctNodes || !_correctConnections) exitWith {_allNodes = false;};

// determine arguments 3. and 4. format
private _alternativeFormat = count _firstElementConnections isEqualTo 3;

private _sqrt2 = 1.41421;

//set maximum possible distance
private _maxDist = worldSize * _sqrt2;

//ensures that ID is the same as the array index of each element 
_allNodes sort true;
 
if (!_alternativeFormat) then
{
 // calculate distances and insert as first element of each connection
 _allConnections = _allConnections apply 
 {
  _x params ["_fromID", "_toID"];
  _fromPos = (_allNodes select _fromID) param [1];
  _toPos = (_allNodes select _toID) param [1];
  _dist = _fromPos distanceSqr _toPos;
  [_dist, _fromID, _toID]
 };
};

// insert distance to start value, predecessor node ID and already viewed state for each node.
// delete positions as not needed anymore
_allNodes = _allNodes apply
{
 _nodeID = if(typeName _x isEqualTo "ARRAY") then {_x param [0]} else {_x};
 _dist = if(_nodeID isEqualTo _startNode) then {0} else {_maxDist};
 [_dist, _maxDist, false, _nodeID]
};

_unviewedAvailable = true;
_solutionFound = false;

// define a name for the script scope to be able to break all loops
scopeName "main";

while {_allNodes findIf {(_x param [2]) isEqualTo false} > -1} do
{
 //sort by distance
 _allNodes sort true;

 // select node with shortest distance value (_allNodes is sortet ascending by distance)

 private _index = _allNodes findIf {_x params ["", "", "_viewed"]; _viewed isEqualTo false};
 _currentNode = _allNodes param [_index];
 _currentNode params ["_currDist","","", "_currID"];

 // change viewed state of current node to true
 _currentNode set [2, true];

 //get all connections to all neighbors of current node
 _neighbConns = _allConnections select
 {
  _x params ["", "_fromID","_toID"];
  (_fromID isEqualTo _currID) || (_toID isEqualTo _currID)
 };

 //get all not viewed neighbors of current node
 _neighbNodes = _allNodes select
 {
  _x params ["","","_neighbView", "_neighbID"];
  _isNeighbor = _neighbConns findIf {_x params ["", "_fromID","_toID"]; (_fromID isEqualTo _neighbID) || (_toID isEqualTo _neighbID)} > -1;
  (!_neighbView && _isNeighbor)
 };
 
 //process all neighbor nodes of current node
 {
  _x params ["_neighbDist","","", "_neighbID"];
  
  // find the index of the connection between current node and this neighbor node
  private _index = _neighbConns findIf {_x params ["", "_fromID","_toID"]; _neighbID isEqualTo _fromID || _neighbID isEqualTo _toID};
  
  // get distance value of the that connection
  private _connDist = (_neighbConns select _index) param [0];
   
  private _thisDist = _currDist + _connDist;
  
  // if we found a shorter distance then set current node as predecessor of this neighbor node and update the found distance for it
  if ( _neighbDist > _thisDist ) then
  {
   _x set [0, _thisDist];
   _x set [1, _currID];
  
   //check if this neighbor is the end node
   if (_neighbID isEqualTo _endNode) then
   {
    _solutionFound = true;

	breakTo "main";    //breaks all scopes except main scope
   };
  };
 } count _neighbNodes;
};

if (!_solutionFound) exitWith {
 _allNodes = true;
 _text = "No Solution found:";
 diag_Log _text;
 diag_Log " ";
};

// rearrange _allNodes array to get it sorted by node ID again
// also get rid of not needed data
_allNodes = _allNodes apply
{
 _x params ["", "_predID", "", "_nodeID"];
 [_nodeID, _predID]
};

_allNodes sort true;

// build solution path array from end node to start node

private _solution = [];

private _currNode = _allNodes param [_endNode];

while {!((_currNode param [0]) isEqualTo _startNode)} do
{
 //current nodes ID is part of solution
 _solution pushBack (_currNode param [0]);
 
 //next current node is predecessor of actual current node
 _currNode = _allNodes param [(_currNode param [1])];
};

_solution pushBack _startNode;

// reverse it to get start point first and end point last
reverse _solution;

_allNodes resize (count _solution);

{
 _allNodes set [_forEachIndex, _x];
} forEach _solution;

// DEBUG
_notext = " ";
_text = "Solution Nodes:";
diag_Log _text;
diag_log _allNodes;
diag_log _notext;
// DEBUG

 

 

diag_log Output at end of script is:

7:03:17 "Solution Nodes:"
17:03:17 [0,2,3]

 

diag log of initserver.sqf after script is ran is this:

17:03:17 "Nodes after script"
17:03:17 [0,1,2,3]

As you can see, the "Nodes after script" are not the same as the "Solution Nodes" inside the script.

I looked at it nearly a day and I don't get it... please help 🙂   SOS...

  • Like 1

Share this post


Link to post
Share on other sites

In your script, you have the line

_allNodes = _allNodes apply...

Apply will create a new array which is then assigned to the local variable _allNodes.  After that, the caller's array is never touched again.

Instead, You have to modify the existing array.  So use a forEach on _allNodes and fiddle with the array contents.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

@JB47394 Thank you for your fast reply.

2 minutes ago, JB47394 said:

Apply will create a new array

 

Are you sure? I doubt that this is the case but I can't proof currently.

Share this post


Link to post
Share on other sites
1 minute ago, sarogahtyp said:

Are you sure?

Absolutely sure.

  • Thanks 1

Share this post


Link to post
Share on other sites
2 minutes ago, JB47394 said:

Absolutely sure.

yeah I tested it. You are right, sadly. Wasn't the answer I'd liked to get but better a bad news which is a solution than vice versa.

 

Thx a lot.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×