@@ -11,20 +11,20 @@ const shortestPath = (nodes) => {
1111 for ( let i = 0 ; i < nodes . length - 1 ; i ++ ) {
1212 const node1 = nodes [ i ]
1313 const node2 = nodes [ i + 1 ]
14- let node1Key = node1 . toString ( )
15- let edge12Key = edgeKey ( node1 , node2 )
14+ const node1Key = node1 . toString ( )
15+ const edge12Key = edgeKey ( node1 , node2 )
1616
1717 if ( visited [ edge12Key ] ) {
18- const unvisitedNode = nearestUnvisitedNode ( i + 1 , nodes , visited , graph )
18+ const result = nearestUnvisitedNode ( i + 1 , nodes , visited , graph )
1919
20- if ( unvisitedNode != null ) {
20+ if ( result ) {
2121 const shortestSubPath = graph . dijkstraShortestPath (
2222 node1Key ,
23- unvisitedNode . toString ( ) ,
23+ result . node . toString ( ) ,
2424 )
2525
2626 path . push ( ...cloneVertices ( shortestSubPath . slice ( 1 ) ) )
27- i = nodes . indexOf ( unvisitedNode ) - 1
27+ i = result . index - 1
2828 }
2929 } else {
3030 path . push ( node2 )
@@ -41,7 +41,7 @@ const nearestUnvisitedNode = (nodeIndex, nodes, visited, graph) => {
4141 const node2 = nodes [ i + 1 ]
4242
4343 if ( ! visited [ edgeKey ( node1 , node2 ) ] ) {
44- return node2
44+ return { node : node2 , index : i + 1 }
4545 }
4646 }
4747
@@ -98,6 +98,7 @@ export const lsystem = (config) => {
9898 }
9999 input = output
100100 }
101+
101102 return output
102103}
103104
@@ -111,10 +112,26 @@ const lsystemDraw = (vertex, angle, config) => {
111112 )
112113}
113114
115+ // Skip to matching closing bracket, accounting for nesting
116+ const skipBranch = ( instructions , startIndex ) => {
117+ let depth = 1
118+ let i = startIndex + 1
119+
120+ while ( i < instructions . length && depth > 0 ) {
121+ if ( instructions [ i ] === "[" ) depth ++
122+ else if ( instructions [ i ] === "]" ) depth --
123+ i ++
124+ }
125+
126+ return i - 1 // return index of matching ]
127+ }
128+
114129export const lsystemPath = ( instructions , config ) => {
115130 let vertex = new Victor ( 0 , 0 )
116131 let currVertices = [ vertex ]
117132 let angle = - Math . PI / 2
133+ const rng = config . rng || Math . random
134+ const branchProb = config . branchProbability ?? 1
118135
119136 if ( config . startingAngle ) {
120137 angle =
@@ -125,6 +142,7 @@ export const lsystemPath = (instructions, config) => {
125142
126143 // This will store the previous return paths we are not working on.
127144 let returnPaths = [ ]
145+
128146 for ( let i = 0 ; i < instructions . length ; i ++ ) {
129147 let char = instructions [ i ]
130148
@@ -145,11 +163,19 @@ export const lsystemPath = (instructions, config) => {
145163 returnPaths . slice ( - 1 ) [ 0 ] . push ( "B" )
146164 }
147165 } else if ( char === "[" ) {
148- // open a branch
149- returnPaths . push ( [ ] )
166+ // Randomly skip branch based on probability
167+ if ( branchProb < 1 && rng ( ) > branchProb ) {
168+ i = skipBranch ( instructions , i )
169+ } else {
170+ // open a branch
171+ returnPaths . push ( [ ] )
172+ }
150173 } else if ( char === "]" ) {
151174 // Return to the beginning of the branch
152- let returnPath = returnPaths . pop ( ) . reverse ( )
175+ let returnPath = returnPaths . pop ( )
176+
177+ if ( ! returnPath ) continue
178+ returnPath . reverse ( )
153179
154180 for ( let j = 0 ; j < returnPath . length ; j ++ ) {
155181 let revChar = returnPath [ j ]
0 commit comments