// $fn=3;

// randomize = true;
// setseed = 123456;
// seed = randomize ? floor(rands(0, 1000000, 1)[0]) : setseed;
// echo(Seed = seed);

{
  // Functions
  
  {
    // Main noise generator
    //
    // b = base random array, don't set this
    // a = recursion array, don't set this!
    // no = number of octaves, you can set this, number of elements is no^2
    // o = current octave iteration, don't set this
    // seed = rands seed, you can set this
    //
    // Returns: Perlin noise array, length(no ^ 2)
    function perlin_noise(b=[], a=[], no=4, o=0, seed=0) = 
      (o > no)
      ? scalevec(2, a) // Done, return the array
      : (len(b) == 0)
        ? perlin_noise(rands(0, 1, no ^ 2, seed), a=[], no=no, o=o, seed=seed)
        : (len(a) == 0)
          ? perlin_noise(b=b, a=octave(o=0, b=b), no=no, o=o + 1, seed=seed)
          : perlin_noise(b=b, a=addvec(a, octave(o=o, b=b)), no=no, o=o + 1, seed=seed);
  }
  // ^ Main noise generator
  
  {
    // Octave generator
    //
    // o = octave
    // b = base random array
    //
    // Returns: array of values from a single noise octave
    function octave(o=0, b=[]) = 
      expand(c=len(b), a=[
        for(i=[0 : len(b) / (2 ^ o) : len(b) - 1]) b[i]
      ]);
  }
  // ^ Octave generator
  
  {
    // Expand octave
    //
    // c = base array length
    // a = octave array
    //
    // Returns: array of length=length(base) with interpolated octave values
    function expand(c=0, a=[]) = [
      for(i=[0 : c - 1]) 
        (len(a) == 1)
        ? a[0]
        : (len(a) == c)
          ? a[i] * (c / len(a) / c)
          : (interp(v=[
                        a[floor(i / (c / len(a)))],
                        (floor(i / (c / len(a))) + 1 == len(a))
                          ? a[0]
                          : a[floor(i / (c / len(a))) + 1]],
                    s=c / len(a))
                    * (i % (c / len(a)))
                    + a[floor(i / (c / len(a)))])
                  * ((c / len(a)) / c)
      ];
  }
  // ^ Expand octave
  
  {
    // Helper functions
    function interp(v=[], s=0) = (v[1] - v[0]) / s;
    
    function addvec(a=[], b=[]) = [
      for(i=[0 : len(a) - 1])
        a[i] + b[i]
      ];
      
    function scalevec(d=2, v=[]) = [
    for(i=[0 : len(v) - 1])
      v[i] / d
    ];

  }
  // ^ Helper functions
}
// ^ Functions

// // Example:
// //
// // no = 8 means we will get a noise array with 8 ^ 2 = 64 values (range 0-1)
// // seed = seed, this is set up with the variables above, you could set it manually. Defaults to 0 if not set
// a = noise(no=8, seed=seed);

// // This displays the values.
// repeat = 1;
// for(i=[0 : len(a) - 1], x=[0 : repeat]) {
//   translate([i + len(a) * x, 0, 0]) cylinder(a[i] * 100, d=1);
// }

