Acyclic Graph 3D Javascript

Viewed 91

I'm looking for a JS DAG algorithm to draw lines passing through all the points of a set of stacked cubes from the center without ever going through the same one twice. Imagine something like a 4x4 Rubik's Cube made of 64 cubes: you start from center point and turn around increasing by one cube width at a time in x,y or z direction, until the 125 corners are linked (25 corners on each face).

I have tried and tried to draw a lot of diagrams on paper but I can't reach all the points without going through the same one twice . I don't know if it's possible or not. I guess it is, but how?

diagrams on paper

On a flat graph made of adjacent squares you just start from center and turn clockwise till all corners are linked, bu how to achieve it in a 3D set of cubes?

The reason I need this is that I have objects - each one getting its own ID - arranged in a virtual cube and I need to explore them one by one until a certain value is reached: the result of a calculation defines the starting point in x,y,z and the algorithm runs in 3d around this point looking for this value.

Another possibility is to start from one of the outer corners and reach the opposite one but in this case we're only going in one direction, e.g. from the starting point to the north-west.

I know a number of DAG algorithms to go from one point to another or from one value to another by the shortest path, but not in a circular 3d way. Any help is welcome :-)


EDIT: quick and weird solution but it works :

<style>
  body { font: 100%/1.3 Arial; }
  section { width: 160px; margin-left: calc(50% - 80px); }
  div { position: relative; width: 160px; height: 160px; border:1px solid #aaa; margin: 10px 0; transform: skewY(-15deg) rotate(40deg) scaleY(0.7); }
  span { display: inline-block; width: 38px; height: 38px; border:1px solid #ccc; margin: 0; }
  ins { display: block; position: absolute; margin: -5px 0 0 -5px; width: 10px; height: 10px; background-color: #ccc; border-radius: 50%; }
</style>


<button onclick="start()">START</button>
<section id="cubes"></section>

Create objets and array

   $id=function(id){ return document.getElementById(id); }

   // create a 120 objects array
   let ref = [];
   for(i=0; i<120; i++){
       ref[i] = [];
   }

   // draw 5 faces (4 bottom + 1 last top) + 16 squares on each face
   for(i=0; i<5; i++){
       let cube = '<div id="cube'+i+'">';
        for(j=0; j<16; j++){
            cube += '<span>&nbsp;</span>';
        }
        cube += '</div>';
        $id("cubes").innerHTML += cube;
    }

    // randomize a spot number to get value=1
    let rand = Math.floor((Math.random() * 120)+1);

    // create spots in divs
    for(i=0; i<5; i++){
        let spots ='';
        for(j=0; j<25; j++){
            let left = (j*40) % 200; 
            let top = Math.floor(j/5) * 40;
            spots += '<ins id="s-'+left+'-'+top+'-'+i+'" style="left:'+left+'px;top:'+top+'px;"></ins>';
            if( (i*24)+j == rand ) { ref[(i*24)+j]=[ i,left,top,1 ]; } // only ONE spot with value=1
            else  { ref[(i*24)+j]=[ i,left,top,0 ]; } // default value=0
         }
         $id("cube"+i).innerHTML += spots;
    }

    // verify that one of them got value=1
    console.table(ref);

Let's go

function start(){

    // 1st spot id="s-80-80-2" = 2nd face in the middle
    $id("s-80-80-2").style.backgroundColor = "red";

    /*  rules for switching between spots from first to 120th
    *   we first explore spots around the first one (central)

            +-----+-----+-----+-----+
            |     |     |     |     |
            |     |     |     |     |
            +-----•-----•-----•-----+
            |     |     |     |     |
            |     |     |     |     |
            +-----•-----c-----•-----+
        Y   |     |     |     |     |
        ^   |     |     |     |     |
        |   +-----•-----•-----•-----+
        |   |     |     |     |     |
        |   |     |     |     |     |
        |   +-----+-----+-----+-----+

            ----------> X

    *   1. get current spot by ID
    *   2. we select the next one depending its left/top 
    *   3. when current spot on 3rd face is the 8th we jump to 2nd/4th face
    *   4. when thses 3 faces centers are explored we explore the outer spots of these 3 faces
    *   5. then switch to 1st and 5th central spots
    *   6. then to outer spots of  1st and 5th faces
    */

    next("s-80-80-2",1,1); // starting spot ID
}

Then loop in defined order

function next(id,num,cycle){ 

    let o = id.split('-')
    let pos_x   = parseInt(o[1]); // 80
    let pos_y   = parseInt(o[2]); // 80
    let pos_z   = parseInt(o[3]); // face 2
    let goto;

    /*  num = how many spots explored on this face?
    *   num is 1 on start because the 1st one (central) is explored
    *   cycle = exploration: 1->around central [• on graph], 2->outer spots [+ on graph]
    *   cycle=1 : num value from 1 to 8 (central+7 •)
    *   cycle=2 : num value from 1 to 16 (16 +)
    */

    // looking for value 0/1
    let val;
    for(i=0; i<120; i++){
        if(ref[i][3] == 1) {
            val = 's-'+ref[i][1]+'-'+ref[i][2]+'-'+ref[i][0]; break;
        }
    }
    // stop when founded
    if(id==val) { $id(id).style.backgroundColor = "red"; }

    else {

    setTimeout(function(){  

        // turning around central spot on same face
        if (cycle == 1) { 
            let matrix = [ [],[1,0],[0,1],[-1,0],[-1,0],[0,-1],[0,-1],[1,0],[1,0] ];    
            if (num <= 8) { 
                goto = 's-'+( pos_x + (matrix[num][0]*40) )+'-'+( pos_y + (matrix[num][1]*40) )+'-'+pos_z;
                num++;
            }
            else { // explore other faces (up and down) 
                if( pos_z == 0 ) { goto = 's-'+80+'-'+80+'-'+4; }
                if( pos_z == 1 ) { cycle = 2; goto = 's-'+160+'-'+160+'-'+2; }      
                if( pos_z == 2 ) { goto = 's-'+80+'-'+80+'-'+3; }
                if( pos_z == 3 ) { goto = 's-'+80+'-'+80+'-'+1; }
                if( pos_z == 4 ) { cycle = 2; goto = 's-'+160+'-'+160+'-'+0; }
                num = 1;
            }
        }   

        // turning around face's outer spots
        else if (cycle == 2) {  
            if (num < 17){
                if (num <= 4) goto = 's-'+( pos_x - 40 )+'-'+pos_y+'-'+pos_z;
                if (num >4 && num <= 8) goto = 's-'+pos_x+'-'+( pos_y - 40 )+'-'+pos_z;
                if (num >8 && num <= 12) goto = 's-'+( pos_x + 40 )+'-'+pos_y+'-'+pos_z;
                if (num >12 && num <= 15) goto = 's-'+pos_x+'-'+( pos_y + 40 )+'-'+pos_z;
                num++;
            }
            if (num == 17){
                if( pos_z == 0 ) { goto = 's-'+160+'-'+160+'-'+4; }
                if( pos_z == 1 ) { cycle = 1; goto = 's-'+80+'-'+80+'-'+0; }
                if( pos_z == 2 ) { goto = 's-'+160+'-'+160+'-'+3; }
                if( pos_z == 3 ) { goto = 's-'+160+'-'+160+'-'+1; }
                num = 1;
            }
        }

        $id(id).style.backgroundColor = "#000";
        if($id(goto)) { 
            $id(goto).style.backgroundColor = "#999";
            next(goto,num,cycle);
        }

    },1); // 500 to quietly see how it works

    }
}

When the spot getting "1" as value is reached the script stops and the spot turns red.

enter image description here

2 Answers

Let's consider the faces as horizontal planes

Bottom is face 0, up is face 4

  x-------x
 / face4 /
x-------x
x
x x-------x
x/ face0 /
x-------x 

We start (by problem statement) at the center of the cube: face2 and center of face2 (C_2)

First: Go to the center of face4: C_4 via C_2->C_3->C_4

Then fill the roof (anticlockwise fashion)

Face4


   |   |   |   |   |
---v---<---<---<---<---
   |   |   |   |   |
---v---v---<---<---^---
   |   |   |   |   |
---v---v--C_4-->---^---
   |   |   |   |   |
---v--->--->--->---^---
   |   |   |   |   |
--->--->--->--->--O_4--
   |   |   |   |   |

From O_4 go down to O_3 and fill Face3. We stop at P_3 because C_3 has already been visited.


   |   |   |   |   |
---v---<---<---<---<---
   |   |   |   |   |
---v---v---<---<---^---
   |   |   |   |   |
---v---v--C_3--^---^---
   |   |   |   |   |
---v--->--P_3--^---^---
   |   |   |   |   |
--->--->--->---^--O_3--
   |   |   |   |   |

From P_3 go down to P_2 and fill Face2 until Q_2


   |   |   |   |   |
---v---<---<---<---<---
   |   |   |   |   |
---v---v---<---<---^---
   |   |   |   |   |
---v---v--C_2--^---^---
   |   |   |   |   |
---v---v--P_2--^---^---
   |   |   |   |   |
--Q_2-->--->--->---^---
   |   |   |   |   |

And so forth

easy: manage a 8 cubes (4+4) volume. We always are at 1 length of center, turning around.

     6----5----4
    /         /
   7    2----3
  /     |   /
 8----9----10
        |  \
        |
    14---13----12
    /   |    \ /
  15    1    11
  /         
16---17----18
          \

    22---21----20
    /       \ /
  23    27    19
  /       \  
24---25----26

I'm now trying the same way to manage a 4x4x4 version, turning around center with +1 length, then with +2... Something like:

          -------------------------
         /     /     /     /      /     
        -----73----72----71------
       /     /     /     /     / 
      -----74----69----70------
     /     /     /     /     / 
    -----75----76----77------
   /     /     /     /     / 
  -------------------------


          -------------------------
         /     /     /     /     /     
        -----23----22----21------
       /     /     /     /     / 
      -----24----19----20------
     /     /     /     /     / 
    -----25----26----27------
   /     /     /     /     / 
  -------------------------


         35----34----33----32-----31
         /     /     /     /     /     
       36-----5-----4-----3-----30
       /     /     /     /     / 
     37-----6-----1-----2-----29
     /     /     /     /     / 
   38-----7-----8-----9-----28
   /     /     /     /     / 
 39----40----41----42-----43


         52----51----50----49-----48
         /     /     /     /     /     
       53----14----13----12-----47
       /     /     /     /     / 
     54----15----10----11-----46
     /     /     /     /     / 
   55----16----17----18-----45
   /     /     /     /     / 
 56----57----58----59-----44

          -------------------------
         /     /     /     /     /     
        -----64----63----62------
       /     /     /     /     / 
      -----65----60----61------
     /     /     /     /     / 
    -----66----67----68------
   /     /     /     /     / 
  -------------------------
Related