flocc 0.5.18 → 0.5.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/flocc.js CHANGED
@@ -378,10 +378,19 @@
378
378
  }
379
379
 
380
380
  /**
381
- * Linearly interpolate between two values.
382
- * @param x {number} - The first value.
383
- * @param y {number} - The second value.
384
- * @param t {number} - The amount by which to interpolate (0 returns x, 1 returns y).
381
+ * Linearly interpolates between `x` and `y`. The third parameter `t` (usually
382
+ * a value between `0` and `1`) is the amount by which to interpolate — a value of `0`
383
+ * returns the `x` value and `1` returns the `y` value.
384
+ *
385
+ * ```js
386
+ * lerp(5, 10, 0.5); // returns 7.5
387
+ * lerp(0, 100, 0.1); // returns 10
388
+ * lerp(22, 79, 1); // returns 79
389
+ * ```
390
+ *
391
+ * @param x The first value.
392
+ * @param y The second value.
393
+ * @param t The amount by which to interpolate (0 returns x, 1 returns y).
385
394
  * @since 0.2.4
386
395
  */
387
396
  function lerp(x, y, t) {
@@ -392,7 +401,7 @@
392
401
  * Copies the values of `source` to `arr`
393
402
  * or to a new Array.
394
403
  *
395
- * @private
404
+ * @hidden
396
405
  * @param {Array} source The Array to copy values from.
397
406
  * @param {Array} [arr=[]] The Array to copy values to.
398
407
  * @returns {Array}
@@ -409,6 +418,8 @@
409
418
  }
410
419
 
411
420
  /**
421
+ * A `Vector` contains multi-dimensional numeric data.
422
+ *
412
423
  * @since 0.1.0
413
424
  */
414
425
  var Vector = /** @class */ (function () {
@@ -421,20 +432,40 @@
421
432
  this.dimension = data ? data.length : 0;
422
433
  }
423
434
  /**
435
+ * Retrieve a value from a `Vector` by its index. If the given index is greater than the
436
+ * `Vector`'s dimension, this returns `0` by default.
437
+ *
438
+ * ```js
439
+ * const v = new Vector(1, 2, 4);
440
+ *
441
+ * v.index(0); // returns 1
442
+ * v.index(2); // returns 4
443
+ * v.index(5); // returns 0
444
+ * ```
424
445
  * @since 0.1.0
425
446
  */
426
- Vector.prototype.index = function (n) {
427
- if (this.dimension > n) {
428
- return this.data[n];
447
+ Vector.prototype.index = function (i) {
448
+ if (this.dimension > i) {
449
+ return this.data[i];
429
450
  }
430
451
  // Attempting to access index ${n} on a vector greater than the vector's dimension returns 0 by default
431
452
  return 0;
432
453
  };
433
454
  /**
434
- * Overwrite the value at a given index or position. If the index is beyond the dimension of this vector,
435
- * the dimension will be increased to the dimensionality implied by the index.
436
- * @param i {number | string} - The numerical index (0-based) or lowercase string value ('x') to set.
437
- * @param value {number} - The value to set at this index/position.
455
+ * Set the value at a given index. If the index is greater than the {@linkcode dimension}
456
+ * of this `Vector`, the dimension will be increased to the dimensionality implied by the index.
457
+ * @param i The numerical index (0-based) or lowercase string value (e.g. `"x"`) to set.
458
+ * @param value The value to set at this index/position.
459
+ *
460
+ * ```js
461
+ * const vector = new Vector();
462
+ * vector.set(0, 10);
463
+ * vector.set('y', 2);
464
+ * vector.set(2, 4);
465
+ *
466
+ * vector.xyz; // [10, 2, 4]
467
+ * ```
468
+ *
438
469
  * @since 0.1.0
439
470
  */
440
471
  Vector.prototype.set = function (i, value) {
@@ -462,128 +493,175 @@
462
493
  return this;
463
494
  };
464
495
  Object.defineProperty(Vector.prototype, "x", {
496
+ /** @since 0.1.0 */
465
497
  get: function () {
466
498
  return this.index(0);
467
499
  },
500
+ /** @since 0.1.0 */
468
501
  set: function (n) {
469
502
  this.set(0, n);
470
503
  },
471
- enumerable: true,
504
+ enumerable: false,
472
505
  configurable: true
473
506
  });
474
507
  Object.defineProperty(Vector.prototype, "y", {
508
+ /** @since 0.1.0 */
475
509
  get: function () {
476
510
  return this.index(1);
477
511
  },
512
+ /** @since 0.1.0 */
478
513
  set: function (n) {
479
514
  this.set(1, n);
480
515
  },
481
- enumerable: true,
516
+ enumerable: false,
482
517
  configurable: true
483
518
  });
484
519
  Object.defineProperty(Vector.prototype, "z", {
520
+ /** @since 0.1.0 */
485
521
  get: function () {
486
522
  return this.index(2);
487
523
  },
524
+ /** @since 0.1.0 */
488
525
  set: function (n) {
489
526
  this.set(2, n);
490
527
  },
491
- enumerable: true,
528
+ enumerable: false,
492
529
  configurable: true
493
530
  });
494
531
  Object.defineProperty(Vector.prototype, "w", {
532
+ /** @since 0.1.0 */
495
533
  get: function () {
496
534
  return this.index(3);
497
535
  },
536
+ /** @since 0.1.0 */
498
537
  set: function (n) {
499
538
  this.set(3, n);
500
539
  },
501
- enumerable: true,
540
+ enumerable: false,
502
541
  configurable: true
503
542
  });
504
543
  Object.defineProperty(Vector.prototype, "xy", {
544
+ /** @since 0.2.4 */
505
545
  get: function () {
506
546
  return [this.index(0), this.index(1)];
507
547
  },
508
- enumerable: true,
548
+ enumerable: false,
509
549
  configurable: true
510
550
  });
511
551
  Object.defineProperty(Vector.prototype, "xz", {
552
+ /** @since 0.2.4 */
512
553
  get: function () {
513
554
  return [this.index(0), this.index(2)];
514
555
  },
515
- enumerable: true,
556
+ enumerable: false,
516
557
  configurable: true
517
558
  });
518
559
  Object.defineProperty(Vector.prototype, "yz", {
560
+ /** @since 0.2.4 */
519
561
  get: function () {
520
562
  return [this.index(1), this.index(2)];
521
563
  },
522
- enumerable: true,
564
+ enumerable: false,
523
565
  configurable: true
524
566
  });
525
567
  Object.defineProperty(Vector.prototype, "xyz", {
568
+ /** @since 0.2.4 */
526
569
  get: function () {
527
570
  return [this.index(0), this.index(1), this.index(2)];
528
571
  },
529
- enumerable: true,
572
+ enumerable: false,
530
573
  configurable: true
531
574
  });
532
575
  Object.defineProperty(Vector.prototype, "r", {
576
+ /**
577
+ * `r` for 'red' (the 1st value)
578
+ * @since 0.1.0
579
+ */
533
580
  get: function () {
534
581
  return this.index(0);
535
582
  },
583
+ /**
584
+ * `r` for 'red' (the 1st value)
585
+ * @since 0.1.0
586
+ */
536
587
  set: function (n) {
537
588
  this.set(0, n);
538
589
  },
539
- enumerable: true,
590
+ enumerable: false,
540
591
  configurable: true
541
592
  });
542
593
  Object.defineProperty(Vector.prototype, "g", {
594
+ /**
595
+ * `g` for 'green' (the 2nd value)
596
+ * @since 0.1.0
597
+ */
543
598
  get: function () {
544
599
  return this.index(1);
545
600
  },
601
+ /**
602
+ * `g` for 'green' (the 2nd value)
603
+ * @since 0.1.0
604
+ */
546
605
  set: function (n) {
547
606
  this.set(1, n);
548
607
  },
549
- enumerable: true,
608
+ enumerable: false,
550
609
  configurable: true
551
610
  });
552
611
  Object.defineProperty(Vector.prototype, "b", {
612
+ /**
613
+ * `b` for 'blue' (the 3rd value)
614
+ * @since 0.1.0
615
+ */
553
616
  get: function () {
554
617
  return this.index(2);
555
618
  },
619
+ /**
620
+ * `b` for 'blue' (the 3rd value)
621
+ * @since 0.1.0
622
+ */
556
623
  set: function (n) {
557
624
  this.set(2, n);
558
625
  },
559
- enumerable: true,
626
+ enumerable: false,
560
627
  configurable: true
561
628
  });
562
629
  Object.defineProperty(Vector.prototype, "a", {
630
+ /**
631
+ * `a` for 'alpha' (the 4th value)
632
+ * @since 0.1.0
633
+ */
563
634
  get: function () {
564
635
  return this.index(3);
565
636
  },
637
+ /**
638
+ * `a` for 'alpha' (the 4th value)
639
+ * @since 0.1.0
640
+ */
566
641
  set: function (n) {
567
642
  this.set(3, n);
568
643
  },
569
- enumerable: true,
644
+ enumerable: false,
570
645
  configurable: true
571
646
  });
572
647
  Object.defineProperty(Vector.prototype, "rgb", {
648
+ /** @since 0.2.4 */
573
649
  get: function () {
574
650
  return [this.index(0), this.index(1), this.index(2)];
575
651
  },
576
- enumerable: true,
652
+ enumerable: false,
577
653
  configurable: true
578
654
  });
579
655
  Object.defineProperty(Vector.prototype, "rgba", {
656
+ /** @since 0.2.4 */
580
657
  get: function () {
581
658
  return [this.index(0), this.index(1), this.index(2), this.index(3)];
582
659
  },
583
- enumerable: true,
660
+ enumerable: false,
584
661
  configurable: true
585
662
  });
586
663
  /**
664
+ * Add another `Vector` to this `Vector`. This *does* mutate the `Vector` that calls this method.
587
665
  * @since 0.1.0
588
666
  */
589
667
  Vector.prototype.add = function (v) {
@@ -598,6 +676,17 @@
598
676
  return this;
599
677
  };
600
678
  /**
679
+ * Multiply this `Vector` by a scalar number. This *does* mutate the `Vector` that calls this method.
680
+ *
681
+ * ```js
682
+ * const v = new Vector(1, 2);
683
+ * v.multiplyScalar(5);
684
+ * v.xy; // returns [5, 10]
685
+ *
686
+ * v.multiplyScalar(-0.5);
687
+ * v.xy; // returns [-2.5, -5]
688
+ * ```
689
+ *
601
690
  * @since 0.1.0
602
691
  */
603
692
  Vector.prototype.multiplyScalar = function (n) {
@@ -605,6 +694,7 @@
605
694
  return this;
606
695
  };
607
696
  /**
697
+ * Add a scalar number to all of this `Vector`'s values'. This *does* mutate the `Vector` that calls this method.
608
698
  * @since 0.1.0
609
699
  */
610
700
  Vector.prototype.addScalar = function (n) {
@@ -619,8 +709,14 @@
619
709
  return Math.sqrt(sum(this.data.map(function (x) { return Math.pow(x, 2); })));
620
710
  };
621
711
  /**
622
- * Normalize the vector (turn it into a vector with length = 1).
623
- * Has no effect on the 0 vector.
712
+ * Normalize the `Vector` (turn it into a `Vector` with length = `1`). Has no effect on the 0 `Vector`. This *does* mutate the `Vector` that calls this method.
713
+ *
714
+ * ```js
715
+ * const v = new Vector(5, 3, -1);
716
+ * v.normalize();
717
+ * v.length(); // returns 1
718
+ * ```
719
+ *
624
720
  * @since 0.1.0
625
721
  */
626
722
  Vector.prototype.normalize = function () {
@@ -631,6 +727,7 @@
631
727
  return this;
632
728
  };
633
729
  /**
730
+ * Create a copy of this `Vector`.
634
731
  * @since 0.1.0
635
732
  */
636
733
  Vector.prototype.clone = function () {
@@ -638,8 +735,15 @@
638
735
  return new (Vector.bind.apply(Vector, __spreadArrays([void 0], data)))();
639
736
  };
640
737
  /**
641
- * Rotate a vector about the Z axis.
642
- * @param angle {number} - The angle by which to rotate the vector, in radians
738
+ * Rotate the `Vector` about the z-axis by `angle` radians (updating its `x` and `y` values). This *does* mutate the `Vector` that calls this method.
739
+ *
740
+ * ```js
741
+ * const v = new Vector(1, 0);
742
+ * v.rotateZ(Math.PI / 2); // rotate by PI / 2 radians = 90 degrees
743
+ *
744
+ * v.xy; // returns [0, 1]
745
+ * ```
746
+ *
643
747
  * @since 0.2.2
644
748
  */
645
749
  Vector.prototype.rotateZ = function (angle) {
@@ -652,8 +756,8 @@
652
756
  return this;
653
757
  };
654
758
  /**
655
- * Get the dot product of this vector with another.
656
- * @param {Vector} v - The other vector.
759
+ * Get the {@link https://en.wikipedia.org/wiki/Dot_product | dot product} of this `Vector` with another.
760
+ * @since 0.2.4
657
761
  */
658
762
  Vector.prototype.dot = function (v) {
659
763
  var dimension = Math.max(this.dimension, v.dimension);
@@ -663,11 +767,23 @@
663
767
  return sum;
664
768
  };
665
769
  /**
666
- * Linearly interpolate between this vector and another vector.
667
- * Note that this method returns a new vector and does not mutate the vector on which it is called!
668
- * @param {Vector} v - The other vector.
669
- * @param {number} t - The amount by which to interpolate.
770
+ * Linearly interpolate between this `Vector` and another `Vector`. This *does not* mutate the original `Vector` that calls this method, but returns a new `Vector`.
771
+ *
772
+ * ```js
773
+ * const a = new Vector(1, 3, -5);
774
+ * const b = new Vector(4, -2);
775
+ *
776
+ * a.lerp(b, 0); // returns a clone of Vector a
777
+ * a.lerp(b, 1); // returns a clone of Vector b
778
+ *
779
+ * const mid = a.lerp(b, 0.5); // returns a Vector halfway between a and b
780
+ * mid.xyz; // returns [2.5, 0.5, -2.5]
781
+ * ```
782
+ *
783
+ * @param v - The other vector.
784
+ * @param t - The amount by which to interpolate (usually between `0` and `1`, although it can be any number).
670
785
  * @returns {Vector} - The new, interpolated vector.
786
+ * @since 0.2.4
671
787
  */
672
788
  Vector.prototype.lerp = function (v, t) {
673
789
  var longerVector = this.dimension > v.dimension ? this : v;
@@ -732,16 +848,70 @@
732
848
  return obj[name].apply(obj, args);
733
849
  };
734
850
  /**
851
+ * The `Rule` class is an experimental interface for adding behavior to {@linkcode Agent}s. A `Rule` object may be used in place of a `tick` function to be added as `Agent` behavior using `agent.set('tick', tickRule)`. As a trivial example, consider the following `Rule`, which increments the `Agent`'s `x` value with every time step:
852
+ *
853
+ * ```js
854
+ * const rule = new Rule(environment, [
855
+ * "set", "x", [
856
+ * "add", 1, [
857
+ * "get", "x"
858
+ * ]
859
+ * ]
860
+ * ]);
861
+ * agent.set("tick", rule);
862
+ * ```
863
+ *
864
+ * Reading from the outer arrays inward, the steps of this `Rule` instructs the `Agent` to:
865
+ * - `set` the `Agent`'s `"x"` value to...
866
+ * - The result of `add`ing `1` and...
867
+ * - The `Agent`'s current `"x"` value
868
+ *
869
+ * Generally, `Rule` steps are a deeply nested array, where the first value of any given array is always an instruction or operator (e.g. `"set"`, `"add"`, `"filter"`). See the {@linkcode constructor} function for more information about steps.
735
870
  * @since 0.3.0
736
871
  */
737
872
  var Rule = /** @class */ (function () {
873
+ /**
874
+ * A single step may be as simple as `["get", "x"]`. This returns the `Agent`'s `"x"` value to the outer step that contains it. So, for example, the step `["add", 1, ["get", "x"]]`, working from the inside out, retrieves the `"x"` value and then adds `1` to it. More complex steps function similarly, always traversing to the deepest nested step, evaluating it, and 'unwrapping' until all steps have been executed.
875
+ *
876
+ * A step's first element should be a string that is one of the allowed operators, followed by a certain number of arguments.
877
+ *
878
+ * |Operator|Arguments|Notes|
879
+ * |---|---|---|
880
+ * |`"add"`|`2`|Pass 2 numbers, or two steps that evaluate to numbers|
881
+ * |`"subtract"`|`2`|""|
882
+ * |`"multiply"`|`2`|""|
883
+ * |`"divide"`|`2`|""|
884
+ * |`"mod"`|`2`|""|
885
+ * |`"power"`|`2`|""|
886
+ * |`"get"`|`1`|Pass the key of `Agent` data to retrieve|
887
+ * |`"set"`|`2`|Pass the key and value to set|
888
+ * |`"enqueue"`|`2`|Pass the key and value to enqueue|
889
+ * |`"local"`|`2`|Pass the key and value to set as local variables|
890
+ * |`"if"`|`3`|Pass the conditional (usually a step that evaluates to a boolean), the step to run when `true`, and the step to run when `false|
891
+ * |`"and"`|`2`|Pass the two steps to logically evaluate|
892
+ * |`"or"`|`2`|""|
893
+ * |`"gt"`|`2`|""|
894
+ * |`"gte"`|`2`|""|
895
+ * |`"lt"`|`2`|""|
896
+ * |`"lte"`|`2`|""|
897
+ * |`"eq"`|`2`|""|
898
+ * |`"map"`|`2`|Pass an array (or step that evaluates to an array) and a lambda to invoke for each element|
899
+ * |`"filter"`|`2`|""|
900
+ * |`"key"`|`2`|Pass an object (or step that evaluates to an object) and the key to retrieve from that object|
901
+ * |`"agent"`|`0`|No arguments; returns the `Agent`|
902
+ * |`"environment"`|`0`|No arguments, returns the `Environment`|
903
+ * |`"vector"`|`any`|Creates an n-dimensional {@linkcode Vector} from the supplied arguments|
904
+ */
738
905
  function Rule(environment, steps) {
739
906
  var _this = this;
907
+ /** @hidden */
740
908
  this.steps = [];
909
+ /** @hidden */
741
910
  this.locals = {};
742
911
  /**
743
912
  * interpret single array step
744
913
  * @since 0.3.0
914
+ * @hidden
745
915
  */
746
916
  this.evaluate = function (agent, step) {
747
917
  var first = step && step.length > 0 ? step[0] : null;
@@ -866,6 +1036,7 @@
866
1036
  }
867
1037
  /**
868
1038
  * @since 0.3.0
1039
+ * @hidden
869
1040
  */
870
1041
  Rule.prototype.call = function (agent) {
871
1042
  return this.evaluate(agent, this.steps);
@@ -921,40 +1092,85 @@
921
1092
  var warnOnce1 = once(console.warn.bind(console));
922
1093
  var warnOnce2 = once(console.warn.bind(console));
923
1094
  /**
1095
+ * This class puts the `Agent` in 'agent-based modeling.' More specifically,
1096
+ * an `Agent` represents an individual unit of data and its associated
1097
+ * behaviors.
924
1098
  * @since 0.0.5
925
1099
  */
926
1100
  var Agent = /** @class */ (function () {
1101
+ /**
1102
+ * `Agent`s can be instantiated with or without data. Instantiating
1103
+ * with data is equivalent to creating an `Agent` and immediately
1104
+ * calling {@linkcode Agent.set} to add data.
1105
+ *
1106
+ * ```js
1107
+ * // instantiates an Agent without data
1108
+ * const a = new Agent();
1109
+ *
1110
+ * // instantiates an Agent with data
1111
+ * const b = new Agent({
1112
+ * x: 50,
1113
+ * y: 100
1114
+ * });
1115
+ * ```
1116
+ * @param data
1117
+ */
927
1118
  function Agent(data) {
928
1119
  if (data === void 0) { data = {}; }
929
1120
  /**
930
- * @member {Environment|null} environment
931
- * @member {RuleObj[]} rules
932
- * @member {RuleObj[]} queue
933
- * @member {Object} data
1121
+ * An `Agent` can only belong to a single {@linkcode Environment}. When
1122
+ * `environment.addAgent(agent);` is called, this is value is updated
1123
+ * to point to that `Environment`.
1124
+ *
1125
+ * ```js
1126
+ * const environment = new Environment();
1127
+ * const agent = new Agent();
1128
+ * agent.environment; // returns `null`
1129
+ *
1130
+ * environment.addAgent(agent);
1131
+ * agent.environment === environment; // returns `true`
934
1132
  */
935
1133
  this.environment = null;
1134
+ /** @hidden */
936
1135
  this.rules = [];
1136
+ /** @hidden */
937
1137
  this.queue = [];
1138
+ /** @hidden */
938
1139
  this.data = {};
1140
+ /**
1141
+ * `Agent`s are automatically assigned a unique ID when they are created.
1142
+ * This can be useful when you need to refer to a specific `Agent`, and
1143
+ * they can be retrieved using their ID from their `Environment` by calling
1144
+ * {@link Environment.getAgentById | `environment.getAgentById(id);`}
1145
+ * ```js
1146
+ * const agent = new Agent();
1147
+ * const id = agent.id; // returns "59B4F928-46C8-..." (for example)
1148
+ * ```
1149
+ */
939
1150
  this.id = uuid$1();
940
- // This is used as a temporary store for data that
941
- // gets returned from rules. When enqueued rules are executed,
942
- // even if there aren't any enqueued rules, .set gets called
943
- // on any data that was placed here.
1151
+ /**
1152
+ * This is used as a temporary store for data that
1153
+ * gets returned from rules. When enqueued rules are executed,
1154
+ * even if there aren't any enqueued rules, .set gets called
1155
+ * on any data that was placed here.
1156
+ * @hidden
1157
+ */
944
1158
  this.__newData = {};
945
- // When agent.get('key') is called, this pseudo-private member is set to 'key'.
946
- // Once it is retrieved, it is reset to null. If agent.get('key') is called before
947
- // this has been reset, that means that there is an infinite loop, and the call
948
- // will throw an error.
1159
+ /** When agent.get('key') is called, this pseudo-private member is set to 'key'.
1160
+ * Once it is retrieved, it is reset to null. If agent.get('key') is called before
1161
+ * this has been reset, that means that there is an infinite loop, and the call
1162
+ * will throw an error.
1163
+ * @hidden
1164
+ */
949
1165
  this.__retrievingData = null;
1166
+ /** @hidden */
950
1167
  this.__subtree = null;
951
1168
  this.set(data);
952
1169
  }
953
1170
  /**
954
1171
  * Set a function value. `tick` and `queue` are not automatically called,
955
1172
  * but any other named value will automatically be called when referenced.
956
- * @param {string} name
957
- * @param {Function} fn
1173
+ * @hidden
958
1174
  */
959
1175
  Agent.prototype._setFunctionValue = function (name, fn) {
960
1176
  var _this = this;
@@ -970,9 +1186,8 @@
970
1186
  }
971
1187
  };
972
1188
  /**
973
- * Retrieve an arbitrary piece of data associated
974
- * with this agent by name.
975
- * @param {string} name
1189
+ * Retrieve an arbitrary piece of data associated by name.
1190
+ * If the data has not been {@linkcode set}, returns `null`.
976
1191
  * @since 0.0.5
977
1192
  */
978
1193
  Agent.prototype.get = function (name) {
@@ -990,8 +1205,20 @@
990
1205
  return data;
991
1206
  };
992
1207
  /**
993
- * Retrieve all the data associated with this agent
994
- * (useful for destructuring properties).
1208
+ * Retrieve all the data associated with this `Agent` at once.
1209
+ *
1210
+ * ```js
1211
+ * agent.set('x', 3);
1212
+ * agent.set('color', 'blue');
1213
+ * agent.set('active', false);
1214
+ *
1215
+ * agent.getData();
1216
+ * // returns {
1217
+ * // x: 3,
1218
+ * // color: 'blue',
1219
+ * // active: false
1220
+ * // }
1221
+ * ```
995
1222
  * @since 0.1.0
996
1223
  */
997
1224
  Agent.prototype.getData = function () {
@@ -1025,6 +1252,7 @@
1025
1252
  /**
1026
1253
  * Helper function to set key-value pair depending on whether value
1027
1254
  * is a function (callable) or not
1255
+ * @hidden
1028
1256
  */
1029
1257
  Agent.prototype._setKeyValue = function (key, value) {
1030
1258
  if (typeof value === "function") {
@@ -1063,25 +1291,57 @@
1063
1291
  }
1064
1292
  };
1065
1293
  /**
1066
- * Increment a numeric (assume integer) piece of data
1067
- * associated with this agent. If `n` is included, increments by
1068
- * `n`. If the value has not yet been set, initializes it to 1.
1069
- * @param {string} name
1070
- * @param {number} n
1294
+ * increment a numeric piece of data associated with this `Agent`
1295
+ * (increasing its value by 1). This method is *synchronous* —
1296
+ * it immediately increases the value (to *asynchronously* increase it,
1297
+ * the rule function should instead return a new value.
1298
+ *
1299
+ * ```js
1300
+ * agent.set('x', 50);
1301
+ * agent.increment('x');
1302
+ * agent.get('x'); // returns 51
1303
+ * ```
1304
+ *
1305
+ * If the second parameter `n` is included, decrements by that amount.
1306
+ *
1307
+ * ```js
1308
+ * agent.set('x', 50);
1309
+ * agent.increment('x', 10);
1310
+ * agent.get('x'); // returns 60
1311
+ * ```
1312
+ *
1313
+ * If the value has not yet been set, calling this method sets it to `1`
1314
+ * (or to `n`).
1071
1315
  * @since 0.0.8
1072
1316
  */
1073
1317
  Agent.prototype.increment = function (name, n) {
1074
1318
  if (n === void 0) { n = 1; }
1075
- if (!this.get(name))
1319
+ if (this.get(name) === null)
1076
1320
  this.set(name, 0);
1077
1321
  this.set(name, this.get(name) + n);
1078
1322
  };
1079
1323
  /**
1080
- * Decrement a numeric (assume integer) piece of data
1081
- * associated with this agent. If `n` is included, decrements by
1082
- * `n`. If the value has not yet been set,
1083
- * initializes it to -1.
1084
- * @param {string} name
1324
+ * Decrement a numeric piece of data associated with this `Agent`
1325
+ * (decreasing its value by 1). This method is *synchronous* —
1326
+ * it immediately decreases the value (to *asynchronously* decrease it,
1327
+ * the rule function should instead return a new value.
1328
+ *
1329
+ * ```js
1330
+ * agent.set('x', 50);
1331
+ * agent.decrement('x');
1332
+ * agent.get('x'); // returns 49
1333
+ * ```
1334
+ *
1335
+ * If the second parameter `n` is included, decrements by that amount.
1336
+ *
1337
+ * ```js
1338
+ * agent.set('x', 50);
1339
+ * agent.decrement('x', 10);
1340
+ * agent.get('x'); // returns 40
1341
+ * ```
1342
+ *
1343
+ * If the value has not yet been set, calling this method sets it to `-1`
1344
+ * (or to `-n`).
1085
1345
  * @since 0.0.8
1086
1346
  */
1087
1347
  Agent.prototype.decrement = function (name, n) {
@@ -1089,9 +1349,29 @@
1089
1349
  this.increment(name, -n);
1090
1350
  };
1091
1351
  /**
1092
- * Add a rule to be executed during the agent's
1093
- * environment's tick cycle. When executed, the
1094
- * @param {Function | Rule} rule
1352
+ * Until v0.5.14, this was the preferred way to add behavior to `Agent`s.
1353
+ * Now, the preferred method is by setting the `Agent`'s `"tick"` value (i.e. `agent.set({ tick: function(agt) { ... }})`).
1354
+ * This method will still be allowed until v0.7.0.
1355
+ *
1356
+ * Adds a rule (a function taking an `Agent` as a callback or a {@linkcode Rule} object) that may be run with every {@linkcode Environment.tick}.
1357
+ * It is possible to add *more than one rule* to an `Agent`, although it
1358
+ * is generally easier to write a longer function or to break it apart
1359
+ * into multiple functions.
1360
+ *
1361
+ * ```js
1362
+ * // adds a rule that *synchronously* increments the Agent's "x" value
1363
+ * agent.addRule(function(agt) {
1364
+ * agent.increment('x');
1365
+ * });
1366
+ *
1367
+ * // adds a rule that *asynchronously* increments the Agent's "x" value
1368
+ * agent.addRule(function(agt) {
1369
+ * return {
1370
+ * x: agt.get('x') + 1
1371
+ * };
1372
+ * });
1373
+ * ```
1374
+ *
1095
1375
  * @deprecated since version 0.5.14
1096
1376
  * @since 0.0.5
1097
1377
  */
@@ -1107,16 +1387,34 @@
1107
1387
  });
1108
1388
  };
1109
1389
  /**
1110
- * Enqueue a function to be executed at the end of
1111
- * the agent's environment's tick cycle (for example,
1112
- * if agents in an environment should perform their
1113
- * calculations and updates separately). Additional/external
1114
- * data passed in as arguments to the enqueued function will
1390
+ * Like {@linkcode Agent.addRule}, this method is deprecated and the
1391
+ * recommended way is to now call
1392
+ * `agent.set('queue', function(agt) { ... });`
1393
+ *
1394
+ * Calling this method enqueues a function to be executed
1395
+ * *asynchronously* (at the end of the {@linkcode Environment}'s tick cycle).
1396
+ * This is useful if a 'cleanup pass' should be performed between
1397
+ * time steps to adjust `Agent` data.
1398
+ *
1399
+ * Below, the `Agent` sets its `"x"` value to `30` whenever it is
1400
+ * activated during the `Environment`'s tick cycle. After all of that
1401
+ * cycle's `Agent`s have been activated, this `Agent` sets its `"x"`
1402
+ * value to `20`. So if any other `Agent` references its `"x"` value
1403
+ * during a tick cycle after it has been activated, it will return `30`,
1404
+ * but in between tick cycles it will return `20`.
1405
+ *
1406
+ * ```js
1407
+ * agent.addRule(agt => {
1408
+ * agt.set("x", 30);
1409
+ * agt.enqueue(a => {
1410
+ * a.set("x", 20);
1411
+ * });
1412
+ * });
1413
+ * ```
1414
+ *
1415
+ * Any additional parameters passed to the enqueued function will
1115
1416
  * be remembered and passed through when the function is executed.
1116
1417
  *
1117
- * The `queue` array is cleared at the very end of
1118
- * the environment's tick cycle.
1119
- * @param {Function} enqueuedRule
1120
1418
  * @deprecated since version 0.5.14
1121
1419
  * @since 0.0.5
1122
1420
  */
@@ -1133,7 +1431,7 @@
1133
1431
  };
1134
1432
  /**
1135
1433
  * From a RuleObj, execute a single rule (function or structured Rule).
1136
- * @param {RuleObj} ruleObj
1434
+ * @hidden
1137
1435
  */
1138
1436
  Agent.prototype.executeRule = function (ruleObj) {
1139
1437
  var rule = ruleObj.rule, args = ruleObj.args;
@@ -1148,6 +1446,7 @@
1148
1446
  };
1149
1447
  /**
1150
1448
  * Execute all rules.
1449
+ * @hidden
1151
1450
  */
1152
1451
  Agent.prototype.executeRules = function () {
1153
1452
  var _this = this;
@@ -1164,6 +1463,7 @@
1164
1463
  };
1165
1464
  /**
1166
1465
  * Execute all enqueued rules.
1466
+ * @hidden
1167
1467
  */
1168
1468
  Agent.prototype.executeEnqueuedRules = function () {
1169
1469
  // if new data from the rules
@@ -1193,9 +1493,15 @@
1193
1493
  }());
1194
1494
 
1195
1495
  /**
1196
- * Find the mean value of an Array of numbers.
1197
- * @param {Array<number>} arr
1198
- * @returns {number}
1496
+ * Return the mean value from an array of numbers.
1497
+ *
1498
+ * ```js
1499
+ * mean([1, 2, 3]); // returns 2
1500
+ * mean([10]); // returns 10
1501
+ *
1502
+ * mean([]); // returns null for empty arrays
1503
+ * ```
1504
+ *
1199
1505
  * @since 0.0.16
1200
1506
  */
1201
1507
  function mean(arr) {
@@ -1230,6 +1536,7 @@
1230
1536
  }
1231
1537
 
1232
1538
  /**
1539
+ * @hidden
1233
1540
  * @since 0.3.11
1234
1541
  */
1235
1542
  var NumArray = /** @class */ (function () {
@@ -1241,7 +1548,7 @@
1241
1548
  get: function () {
1242
1549
  return this._index;
1243
1550
  },
1244
- enumerable: true,
1551
+ enumerable: false,
1245
1552
  configurable: true
1246
1553
  });
1247
1554
  NumArray.prototype.set = function (i, n) {
@@ -1292,24 +1599,33 @@
1292
1599
  }());
1293
1600
 
1294
1601
  /**
1602
+ * A `Network` allows {@linkcode Agent}s to be connected to each other.
1295
1603
  * @since 0.1.3
1296
1604
  */
1297
1605
  var Network = /** @class */ (function () {
1298
1606
  function Network() {
1607
+ /** @hidden */
1299
1608
  this.adjacencyList = new Map();
1300
- // instantiated and updated in _resetAdjacencyMatrix
1609
+ /**
1610
+ * instantiated and updated in _resetAdjacencyMatrix
1611
+ * @hidden
1612
+ */
1301
1613
  this.adjacencyMatrix = null;
1302
1614
  /**
1303
- * list (JS array) of all the agents
1304
- * in the order they were added to the graph
1615
+ * An array of the {@linkcode Agent}s in this `Network`
1616
+ * (in the order they were added).
1305
1617
  */
1306
1618
  this.agents = [];
1307
1619
  }
1308
1620
  /**
1309
1621
  * Add an agent to the network.
1310
- * Returns `true` if the agent was successfully added.
1311
- * Returns `false` if the agent was already in the network.
1312
- * @param {Agent} agent
1622
+ * @returns Returns `true` if the `Agent` was successfully added, `false` otherwise.
1623
+ *
1624
+ * ```js
1625
+ * const a = new Agent();
1626
+ * network.addAgent(a); // returns true
1627
+ * network.addAgent(a); // returns false since `a` was already in the `Network`
1628
+ * ```
1313
1629
  * @since 0.1.3
1314
1630
  */
1315
1631
  Network.prototype.addAgent = function (agent) {
@@ -1322,8 +1638,8 @@
1322
1638
  return false;
1323
1639
  };
1324
1640
  /**
1325
- * Add all agents in an environment to this network.
1326
- * @param {Environment} environment
1641
+ * Given an {@linkcode Environment}, add all the {@linkcode Agent}s in that `Environment`
1642
+ * to this `Network`. (This is a shortcut for calling `environment.getAgents().forEach(a => network.addAgent(a)));`)
1327
1643
  * @since 0.2.1
1328
1644
  */
1329
1645
  Network.prototype.addFromEnvironment = function (environment) {
@@ -1331,10 +1647,20 @@
1331
1647
  environment.getAgents().forEach(function (agent) { return _this.addAgent(agent); });
1332
1648
  };
1333
1649
  /**
1334
- * Remove an agent from the network.
1335
- * Returns `true` if the agent was successfully removed.
1650
+ * Removes an {@linkcode Agent} from the `Network`.
1651
+ *
1652
+ * ```js
1653
+ * const a = new Agent();
1654
+ * network.addAgent(a);
1655
+ *
1656
+ * network.removeAgent(a); // returns true
1657
+ *
1658
+ * network.removeAgent(a); // returns false since `a` was no longer in the `Network`
1659
+ * ```
1660
+ *
1661
+ * @returns Returns `true` if the agent was successfully removed.
1662
+ *
1336
1663
  * Returns `false` if the agent was not in the network to begin with.
1337
- * @param {Agent} agent
1338
1664
  * @since 0.1.3
1339
1665
  */
1340
1666
  Network.prototype.removeAgent = function (agent) {
@@ -1354,7 +1680,17 @@
1354
1680
  return true;
1355
1681
  };
1356
1682
  /**
1357
- * Removes all agents from the network.
1683
+ * Removes all {@linkcode Agent}s from the `Network`.
1684
+ *
1685
+ * ```js
1686
+ * const network = new Network();
1687
+ * network.addAgent(new Agent());
1688
+ * network.size(); // returns 1
1689
+ *
1690
+ * network.clear();
1691
+ * network.size(); // returns 0
1692
+ * ```
1693
+ *
1358
1694
  * @since 0.2.1
1359
1695
  */
1360
1696
  Network.prototype.clear = function () {
@@ -1364,23 +1700,36 @@
1364
1700
  }
1365
1701
  };
1366
1702
  /**
1367
- * Returns true if successfully connected the two agents, false otherwise
1368
- * (for example, if tried to add an edge between an agent + itself
1369
- * or if the connection already exists).
1370
- * @param {*} a1
1371
- * @param {*} a2
1703
+ * Attempts to create a connection between {@linkcode Agent}s `a` and `b`.
1704
+ * @returns Returns `true` if the connection was successfully created (i.e. if `a` and `b` were previously not connected and now are).
1705
+ *
1706
+ * ```js
1707
+ * const a = new Agent();
1708
+ * const b = new Agent();
1709
+ * network.addAgent(a);
1710
+ * network.addAgent(b);
1711
+ *
1712
+ * network.connect(a, b); // returns true
1713
+ *
1714
+ * network.connect(a, b); // returns false since they are now already connected
1715
+ *
1716
+ * const c = new Agent();
1717
+ * network.connect(a, c); // returns false since `c` is not in the `Network`
1718
+ * ```
1719
+ *
1720
+ * Returns `false` otherwise, for example if `a` and `b` are the same `Agent`, or if either is not in the `Network`.
1372
1721
  * @since 0.1.3
1373
1722
  */
1374
- Network.prototype.connect = function (a1, a2) {
1375
- if (a1 === a2)
1723
+ Network.prototype.connect = function (a, b) {
1724
+ if (a === b)
1376
1725
  return false;
1377
- if (!this.isInNetwork(a1) || !this.isInNetwork(a2))
1726
+ if (!this.isInNetwork(a) || !this.isInNetwork(b))
1378
1727
  return false;
1379
- if (!this.areConnected(a1, a2)) {
1380
- this.adjacencyList.get(a1).push(a2);
1381
- this.adjacencyList.get(a2).push(a1);
1382
- var i1 = this.indexOf(a1);
1383
- var i2 = this.indexOf(a2);
1728
+ if (!this.areConnected(a, b)) {
1729
+ this.adjacencyList.get(a).push(b);
1730
+ this.adjacencyList.get(b).push(a);
1731
+ var i1 = this.indexOf(a);
1732
+ var i2 = this.indexOf(b);
1384
1733
  this.adjacencyMatrix.set(i1, i2, 1);
1385
1734
  this.adjacencyMatrix.set(i2, i1, 1);
1386
1735
  return true;
@@ -1388,24 +1737,42 @@
1388
1737
  return false;
1389
1738
  };
1390
1739
  /**
1391
- * Returns `true` if the given agents are connected in the network.
1392
- * @param {Agent} a1
1393
- * @param {Agent} a2
1740
+ * @returns Returns `true` if {@linkcode Agent}s `a` and `b` are connected, `false` if they are not.
1741
+ *
1742
+ * ```js
1743
+ * network.connect(a, b);
1744
+ * network.areConnected(a, b); // returns true since they have been connected
1745
+ *
1746
+ * network.disconnect(a, b);
1747
+ * network.areConnected(a, b); // returns false since they have been disconnected
1748
+ * ```
1749
+ *
1394
1750
  * @since 0.1.3
1395
1751
  */
1396
- Network.prototype.areConnected = function (a1, a2) {
1397
- if (!this.isInNetwork(a1) || !this.isInNetwork(a2))
1752
+ Network.prototype.areConnected = function (a, b) {
1753
+ if (!this.isInNetwork(a) || !this.isInNetwork(b))
1398
1754
  return false;
1399
- var i1 = this.indexOf(a1);
1400
- var i2 = this.indexOf(a2);
1755
+ var i1 = this.indexOf(a);
1756
+ var i2 = this.indexOf(b);
1401
1757
  return (this.adjacencyMatrix.get(i1, i2) === 1 &&
1402
1758
  this.adjacencyMatrix.get(i2, i1) === 1);
1403
1759
  };
1404
1760
  /**
1405
- * Like with connect, returns `true` if the edge was successfully
1406
- * removed, false if otherwise (if edge did not exist in the first place).
1407
- * @param {agent} a1
1408
- * @param {agent} a2
1761
+ * Attempts to sever the connection between {@linkcode Agent}s `a` and `b`.
1762
+ * @returns Returns `true` if the `Agent`s were successfully disconnected, `false` otherwise.
1763
+ *
1764
+ * ```js
1765
+ * const a = new Agent();
1766
+ * const b = new Agent();
1767
+ * network.addAgent(a);
1768
+ * network.addAgent(b);
1769
+ *
1770
+ * network.connect(a, b);
1771
+ * network.disconnect(a, b); // returns true since they were connected and are no longer
1772
+ *
1773
+ * network.disconnect(a, b); // returns false since they were already not connected
1774
+ * ```
1775
+ *
1409
1776
  * @since 0.1.3
1410
1777
  */
1411
1778
  Network.prototype.disconnect = function (a1, a2) {
@@ -1425,40 +1792,50 @@
1425
1792
  return false;
1426
1793
  };
1427
1794
  /**
1428
- * Number of agents in the network.
1795
+ * @returns Returns the number of {@linkcode Agent}s in the `Network`.
1796
+ *
1797
+ * ```js
1798
+ * const a = new Agent();
1799
+ * const b = new Agent();
1800
+ * const c = new Agent();
1801
+ * [a, b, c].forEach(agt => network.addAgent(agt));
1802
+ *
1803
+ * network.size(); // returns 3
1804
+ * ```
1805
+ *
1429
1806
  * @since 0.1.3
1430
1807
  */
1431
1808
  Network.prototype.size = function () {
1432
1809
  return this.agents.length;
1433
1810
  };
1434
1811
  /**
1435
- * Given a callback function, loop over all the agents in the network
1436
- * and invoke the callback, passing the agent + its index as parameters.
1437
- * @param {Function} cb
1812
+ * Loop over all the {@linkcode Agent}s in the `Network` (in the order they were added),
1813
+ * and invoke the `callback` function with the `Agent` and an index passed as parameters.
1438
1814
  * @since 0.1.3
1439
1815
  */
1440
- Network.prototype.forEach = function (cb) {
1441
- this.agents.forEach(cb);
1816
+ Network.prototype.forEach = function (callback) {
1817
+ this.agents.forEach(callback);
1442
1818
  };
1443
1819
  /**
1444
- * Same as forEach, but in random order.
1445
- * @param {Function} cb
1820
+ * The same method as {@linkcode forEach}, but executes in random order.
1446
1821
  * @since 0.1.3
1447
1822
  */
1448
- Network.prototype.forEachRand = function (cb) {
1449
- shuffle(this.agents).forEach(cb);
1823
+ Network.prototype.forEachRand = function (callback) {
1824
+ shuffle(this.agents).forEach(callback);
1450
1825
  };
1451
1826
  /**
1452
- * Returns true if the agent is in the network, false if it is not.
1453
- * @param {Agent} agent
1827
+ * Returns `true` if the given {@linkcode Agent} is in the `Network`, `false` if it is not.
1454
1828
  * @since 0.1.3
1455
1829
  */
1456
1830
  Network.prototype.isInNetwork = function (agent) {
1457
1831
  return this.adjacencyList.has(agent);
1458
1832
  };
1459
1833
  /**
1460
- * Get the agent at index i.
1461
- * @param {number} i
1834
+ * Returns the {@linkcode Agent} at index `i`, where `i = 0` is the first `Agent`
1835
+ * added to the `Network`, `i = 1` the second, etc.
1836
+ *
1837
+ * Negative indices are allowed, so `network.get(-1)` returns the `Agent` that was most recently
1838
+ * added to the `Network`, `-2` the second-most recent, etc.
1462
1839
  * @since 0.1.3
1463
1840
  */
1464
1841
  Network.prototype.get = function (i) {
@@ -1469,17 +1846,26 @@
1469
1846
  return this.agents[i];
1470
1847
  };
1471
1848
  /**
1472
- * Get the index of a given agent.
1473
- * @param {Agent} agent
1849
+ * Returns the index of the given {@linkcode Agent} in the {@linkcode agents} array.
1474
1850
  * @since 0.1.3
1475
1851
  */
1476
1852
  Network.prototype.indexOf = function (agent) {
1477
1853
  return this.agents.indexOf(agent);
1478
1854
  };
1479
1855
  /**
1480
- * Return the agents that are neighbors of a given agent
1481
- * (in a JS array). If the agent is not in the network, returns `null`.
1482
- * @param {Agent} agent
1856
+ * Returns an array of {@linkcode Agent}s that are connected to the given `Agent` (in no guaranteed order).
1857
+ *
1858
+ * Returns `null` if the given `Agent` is not in the `Network`.
1859
+ *
1860
+ * ```js
1861
+ * // suppose a, b, and c are connected
1862
+ * network.neighbors(a); // returns [b, c] (or [c, b])
1863
+ *
1864
+ * network.disconnect(a, c);
1865
+ * network.neighbors(a); // returns [b]
1866
+ * network.neighbors(c); // returns [b]
1867
+ * ```
1868
+ *
1483
1869
  * @since 0.1.3
1484
1870
  */
1485
1871
  Network.prototype.neighbors = function (agent) {
@@ -1488,7 +1874,7 @@
1488
1874
  return this.adjacencyList.get(agent);
1489
1875
  };
1490
1876
  /**
1491
- * Connect every agent in the network to every other agent.
1877
+ * Draw a connection between every pair of {@linkcode Agent}s in the `Network`.
1492
1878
  * @since 0.1.3
1493
1879
  */
1494
1880
  Network.prototype.complete = function () {
@@ -1501,6 +1887,7 @@
1501
1887
  /**
1502
1888
  * Internal helper function to reset the adjacencyMatrix.
1503
1889
  * This gets called when agents are added to or removed from the network.
1890
+ * @hidden
1504
1891
  */
1505
1892
  Network.prototype._resetAdjacencyMatrix = function () {
1506
1893
  var size = this.size();
@@ -1517,11 +1904,7 @@
1517
1904
  this.adjacencyMatrix = newMatrix;
1518
1905
  };
1519
1906
  /**
1520
- * Returns `true` if a, b, and c are a 'triplet' of agents --
1521
- * if (at least) one of the three is connected to the other two.
1522
- * @param {Agent} a
1523
- * @param {Agent} b
1524
- * @param {Agent} c
1907
+ * Returns `true` if `Agent`s a, b, and c form a 'triplet' &mdash; if (at least) one of the three is connected to the other two. Returns `false` otherwise.
1525
1908
  * @since 0.5.17
1526
1909
  */
1527
1910
  Network.prototype.isTriplet = function (a, b, c) {
@@ -1535,11 +1918,7 @@
1535
1918
  return connections >= 2;
1536
1919
  };
1537
1920
  /**
1538
- * Returns `true` if a, b, and c are a 'closed triplet' of agents --
1539
- * each connected to the other two.
1540
- * @param {Agent} a
1541
- * @param {Agent} b
1542
- * @param {Agent} c
1921
+ * Returns `true` if `Agent`s a, b, and c form a 'closed triplet' &mdash; if each of the three are connected to the other two. Returns `false` otherwise.
1543
1922
  * @since 0.5.17
1544
1923
  */
1545
1924
  Network.prototype.isClosedTriplet = function (a, b, c) {
@@ -1552,6 +1931,7 @@
1552
1931
  ].filter(function (v) { return v; }).length;
1553
1932
  return connections === 3;
1554
1933
  };
1934
+ /** @hidden */
1555
1935
  Network.prototype._globalClusteringCoefficient = function () {
1556
1936
  var _this = this;
1557
1937
  var triplets = 0;
@@ -1573,12 +1953,15 @@
1573
1953
  return closedTriplets / triplets;
1574
1954
  };
1575
1955
  /**
1576
- * If an agent is passed as the single parameter, returns the local
1577
- * clustering coefficient for that agent (a measure of how connected that
1578
- * agent's neighbors are to each other).
1579
- * If no parameter is passed, returns the global clustering coefficient
1580
- * of the network (an aggregate measure of how connected are the agents).
1581
- * @param {Agent} [agent]
1956
+ * The {@link https://en.wikipedia.org/wiki/Clustering_coefficient | clustering coefficient} is a measure of how
1957
+ * closely connected either an individual {@linkcode Agent}'s connections are or the `Network` as a whole is.
1958
+ *
1959
+ * If an `Agent` is passed as the single parameter, returns the {@link https://en.wikipedia.org/wiki/Clustering_coefficient#Local_clustering_coefficient | local
1960
+ * clustering coefficient} for that `Agent`.
1961
+ *
1962
+ * If no parameter is passed, returns the {@link https://en.wikipedia.org/wiki/Clustering_coefficient#Global_clustering_coefficient | global clustering coefficient}
1963
+ * of the `Network` (an aggregate measure of how connected the `Agent`s are).
1964
+ *
1582
1965
  * @since 0.5.17
1583
1966
  */
1584
1967
  Network.prototype.clusteringCoefficient = function (agent) {
@@ -1602,9 +1985,11 @@
1602
1985
  return (2 * clusterConnections) / (k * (k - 1));
1603
1986
  };
1604
1987
  /**
1605
- * Returns the average clustering coefficient for the network (the average
1606
- * of the local clustering coefficient across all agents). Note that
1607
- * this is a different measurement from the _global_ clustering coefficient.
1988
+ * Returns the {@link https://en.wikipedia.org/wiki/Clustering_coefficient#Network_average_clustering_coefficient | average clustering coefficient} for the `Network` (the average
1989
+ * of the {@link Network.clusteringCoefficient | local clustering coefficient} across all `Agent`s).
1990
+ *
1991
+ * Note that this is a different measurement from the _global_ clustering coefficient
1992
+ * (i.e. calling {@linkcode clusteringCoefficient} without any parameters).
1608
1993
  * @since 0.5.17
1609
1994
  */
1610
1995
  Network.prototype.averageClusteringCoefficient = function () {
@@ -1660,6 +2045,14 @@
1660
2045
  }());
1661
2046
 
1662
2047
  /**
2048
+ * Return the minimum value from an array of numbers.
2049
+ *
2050
+ * ```js
2051
+ * min([1, 2, 3]); // returns 1
2052
+ * min([10]); // returns 10
2053
+ *
2054
+ * min([]); // returns null for empty arrays
2055
+ * ```
1663
2056
  * @since 0.2.0
1664
2057
  */
1665
2058
  function min(arr) {
@@ -1669,6 +2062,15 @@
1669
2062
  }
1670
2063
 
1671
2064
  /**
2065
+ * Return the maximum value from an array of numbers.
2066
+ *
2067
+ * ```js
2068
+ * max([1, 2, 3]); // returns 3
2069
+ * max([10]); // returns 10
2070
+ *
2071
+ * max([]); // returns null for empty arrays
2072
+ * ```
2073
+ *
1672
2074
  * @since 0.2.0
1673
2075
  */
1674
2076
  function max(arr) {
@@ -1710,8 +2112,16 @@
1710
2112
  }
1711
2113
 
1712
2114
  /**
1713
- * Find the median value of an array of numbers. If there are an even number
1714
- * of elements in the array, takes the mean of the two values closest to the median.
2115
+ * Return the mean value from an array of numbers.
2116
+ *
2117
+ * ```js
2118
+ * median([1, 2, 3]); // returns 2
2119
+ * median([10]); // returns 10
2120
+ * median([1, 2, 3, 4]); // returns 2.5 (the mean of the two median values)
2121
+ *
2122
+ * median([]); // returns null for empty arrays
2123
+ * ```
2124
+ *
1715
2125
  * @param {number[]} arr
1716
2126
  * @since 0.2.0
1717
2127
  */
@@ -1719,6 +2129,9 @@
1719
2129
  return percentile(arr, 0.5);
1720
2130
  }
1721
2131
 
2132
+ function isMultipleSampleFunc(f) {
2133
+ return f([1]).length > 0;
2134
+ }
1722
2135
  var sample;
1723
2136
  /**
1724
2137
  * Gets a random element from `array`.
@@ -1808,12 +2221,21 @@
1808
2221
 
1809
2222
  /// <reference path="../types/Point.d.ts" />
1810
2223
  /**
1811
- * Finds the distance between `p1` and `p2`. The inputs may be plain objects
1812
- * with `x`, `y`, and/or `z` keys, or Agent-like objects who have
1813
- * `x`, `y`, and/or `z` data.
1814
- * @param {Point|Agent} p1
1815
- * @param {Point|Agent} p2
1816
- * @return {number} The distance between p1 and p2.
2224
+ * Finds the distance between `p1` and `p2`.
2225
+ *
2226
+ * The inputs may be plain objects with `x`, `y`, and/or `z` keys, {@linkcode Vector}s,
2227
+ * or {@linkcode Agent}s with `x`, `y`, and/or `z` data.
2228
+ *
2229
+ * ```js
2230
+ * const a1 = new Agent();
2231
+ * const a2 = new Agent({ x: 3, y: 4 });
2232
+ * distance(a1, a2); // returns 5 (defaults to x = 0 and y = 0 for a1)
2233
+ *
2234
+ * const p1 = { x: 0, y: 2 };
2235
+ * const p2 = { x: 0, y: 4 };
2236
+ * distance(p1, p2); // returns 2
2237
+ * ```
2238
+ *
1817
2239
  * @since 0.0.10
1818
2240
  */
1819
2241
  function distance(p1, p2) {
@@ -2111,6 +2533,14 @@
2111
2533
  }());
2112
2534
 
2113
2535
  /**
2536
+ * Finds the {@link https://en.wikipedia.org/wiki/Greatest_common_divisor | greatest common divisor} of `a` and `b`.
2537
+ *
2538
+ * ```js
2539
+ * gcd(7, 13); // returns 1
2540
+ * gcd(9, 15); // returns 3
2541
+ * gcd(12, 24); // returns 12
2542
+ * ```
2543
+ *
2114
2544
  * @since 0.4.5
2115
2545
  */
2116
2546
  function gcd(a, b) {
@@ -2179,32 +2609,80 @@
2179
2609
  grayscale: false,
2180
2610
  scale: 1
2181
2611
  };
2612
+ var BLACK = { r: 0, g: 0, b: 0, a: 255 };
2613
+ var WHITE = { r: 255, g: 255, b: 255, a: 255 };
2614
+ var RED = { r: 255, g: 0, b: 0, a: 255 };
2615
+ var MAROON = { r: 127, g: 0, b: 0, a: 255 };
2616
+ var YELLOW = { r: 255, g: 255, b: 0, a: 255 };
2617
+ var BLUE = { r: 0, g: 0, b: 255, a: 255 };
2618
+ var GREEN = { r: 0, g: 127, b: 0, a: 255 };
2619
+ var LIME = { r: 0, g: 255, b: 0, a: 255 };
2620
+ var AQUA = { r: 0, g: 255, b: 255, a: 255 };
2621
+ var ORANGE = { r: 255, g: 165, b: 0, a: 255 };
2622
+ var FUCHSIA = { r: 255, g: 0, b: 255, a: 255 };
2623
+ var PURPLE = { r: 127, g: 0, b: 127, a: 255 };
2182
2624
  /**
2625
+ * Each static member of the `Colors` class (e.g. `Colors.GREEN`, `Colors.RED`) is a pixel-like object with `r`, `g`, `b`, and `a` values that range from `0` to `255`.
2183
2626
  * @since 0.4.0
2184
2627
  */
2185
- var Colors = {
2186
- BLACK: { r: 0, g: 0, b: 0, a: 255 },
2187
- WHITE: { r: 255, g: 255, b: 255, a: 255 },
2188
- RED: { r: 255, g: 0, b: 0, a: 255 },
2189
- MAROON: { r: 127, g: 0, b: 0, a: 255 },
2190
- YELLOW: { r: 255, g: 255, b: 0, a: 255 },
2191
- BLUE: { r: 0, g: 0, b: 255, a: 255 },
2192
- GREEN: { r: 0, g: 127, b: 0, a: 255 },
2193
- LIME: { r: 0, g: 255, b: 0, a: 255 },
2194
- AQUA: { r: 0, g: 255, b: 255, a: 255 },
2195
- ORANGE: { r: 255, g: 165, b: 0, a: 255 },
2196
- FUCHSIA: { r: 255, g: 0, b: 255, a: 255 },
2197
- PURPLE: { r: 127, g: 0, b: 127, a: 255 }
2198
- };
2628
+ var Colors = /** @class */ (function () {
2629
+ function Colors() {
2630
+ }
2631
+ /** <div style="width: 100%; height: 20px; background-color: rgb(0, 0, 0);"></div> */
2632
+ Colors.BLACK = BLACK;
2633
+ /** <div style="width: 100%; height: 20px; background-color: rgb(255, 255, 255); border: 1px solid #eee;"></div> */
2634
+ Colors.WHITE = WHITE;
2635
+ /** <div style="width: 100%; height: 20px; background-color: rgb(255, 0, 0);"></div> */
2636
+ Colors.RED = RED;
2637
+ /** <div style="width: 100%; height: 20px; background-color: rgb(127, 0, 0);"></div> */
2638
+ Colors.MAROON = MAROON;
2639
+ /** <div style="width: 100%; height: 20px; background-color: rgb(255,255, 0);"></div> */
2640
+ Colors.YELLOW = YELLOW;
2641
+ /** <div style="width: 100%; height: 20px; background-color: rgb(0, 0, 255);"></div> */
2642
+ Colors.BLUE = BLUE;
2643
+ /** <div style="width: 100%; height: 20px; background-color: rgb(0, 127, 0);"></div> */
2644
+ Colors.GREEN = GREEN;
2645
+ /** <div style="width: 100%; height: 20px; background-color: rgb(0, 255, 0);"></div> */
2646
+ Colors.LIME = LIME;
2647
+ /** <div style="width: 100%; height: 20px; background-color: rgb(0, 255, 255);"></div> */
2648
+ Colors.AQUA = AQUA;
2649
+ /** <div style="width: 100%; height: 20px; background-color: rgb(255, 165, 0);"></div> */
2650
+ Colors.ORANGE = ORANGE;
2651
+ /** <div style="width: 100%; height: 20px; background-color: rgb(255, 0, 255);"></div> */
2652
+ Colors.FUCHSIA = FUCHSIA;
2653
+ /** <div style="width: 100%; height: 20px; background-color: rgb(127, 0, 127);"></div> */
2654
+ Colors.PURPLE = PURPLE;
2655
+ return Colors;
2656
+ }());
2199
2657
  /**
2658
+ * The `Terrain` class lets {@linkcode Environment}s function as lattices upon which {@link https://en.wikipedia.org/wiki/Cellular_automaton | cellular automata} can grow. With a `Terrain`, {@linkcode Agent}s may not be necessary, since all the cells of a `Terrain` can follow update rules (similar to but simplified from `Agent`s).
2659
+ *
2660
+ * ### Usage
2661
+ *
2662
+ * ```js
2663
+ * const environment = new Environment();
2664
+ * const terrain = new Terrain(30, 30); // create a 30 x 30 Terrain
2665
+ * environment.use(terrain); // tell the Environment to 'use' this Terrain as a helper
2666
+ * ```
2667
+ *
2200
2668
  * @since 0.4.0
2201
2669
  */
2202
2670
  var Terrain = /** @class */ (function () {
2203
2671
  /**
2672
+ * Instantiate a new `Terrain` by passing its `width` and `height` as the first two parameters, and an optional configuration object as the third.
2673
+ *
2674
+ * ### Options
2675
+ *
2676
+ * - `async` (*boolean* = `false`) &mdash; Whether to run the `Terrain` in synchronous (`true`) or asynchronous (`mode`). Defaults to synchronous. Depending on the timing mode, {@link addRule | Terrain update rules} should be written differently.
2677
+ * - `grayscale` (*boolean* = `false`)
2678
+ * - In **color mode** (the default), each cell of a `Terrain` is represented by a {@link Colors | pixel-like object} (an object with numeric keys `r`, `g`, `b`, and `a` ranging from 0-255).
2679
+ * - In **grayscale mode**, each cell of a `Terrain` is represented by a single number ranging from 0 (black) to 255 (white).
2680
+ * - `scale` (*number* = `1`) &mdash; The size, in pixels, of each cell's width and height when the `Terrain` is rendered using a {@linkcode CanvasRenderer}. In the below screenshots, the `Terrain` on the left uses a scale of `1` while the one on the right uses a scale of `5`:
2204
2681
  *
2205
- * @param {number} width - The width of the terrain
2206
- * @param {number} height - The height of the terrain
2207
- * @param options
2682
+ * <img alt="Terrain with scale = 1" style="width: 49%;" src="https://cms.flocc.network/wp-content/uploads/2020/04/terrain-1.png">
2683
+ * <img alt="Terrain with scale = 5" style="width: 49%;" src="https://cms.flocc.network/wp-content/uploads/2020/04/terrain-5.png">
2684
+ *
2685
+ * In addition to the above setup, you will need to {@link init | initialize} the `Terrain` and {@link addRule | add an update rule}.
2208
2686
  */
2209
2687
  function Terrain(width, height, options) {
2210
2688
  if (options === void 0) { options = defaultTerrainOptions; }
@@ -2224,9 +2702,16 @@
2224
2702
  this.nextData = new Uint8ClampedArray(this.data);
2225
2703
  }
2226
2704
  /**
2227
- * Initialize (or overwrite) the terrain data by passing a function with parameters (x, y)
2228
- * and returning a pixel value.
2229
- * @param {Function} rule - The rule to follow to instantiate pixel values
2705
+ * Initialize (or overwrite) all cell values. The rule you pass has the same signature
2706
+ * as {@linkcode addRule}, but should always return a value (either a number or {@linkcode Colors | pixel-like object}).
2707
+ *
2708
+ * ```js
2709
+ * // initializes cells randomly to either blue or red
2710
+ * terrain.init((x, y) => {
2711
+ * return utils.uniform() > 0.5 ? Colors.BLUE : Colors.RED;
2712
+ * });
2713
+ * ```
2714
+ *
2230
2715
  * @since 0.4.0
2231
2716
  */
2232
2717
  Terrain.prototype.init = function (rule) {
@@ -2249,12 +2734,41 @@
2249
2734
  }
2250
2735
  }
2251
2736
  }
2737
+ this.nextData = new Uint8ClampedArray(this.data);
2252
2738
  };
2253
2739
  /**
2254
- * Like with agents, this adds an update rule for the terrain. The function
2255
- * passed as the rule should be called with the parameters (x, y), and should return
2256
- * a pixel-like object { r: number, g: number, b: number, a: number } or number.
2257
- * @param {Function} rule - The update rule to be called on environment.tick()
2740
+ * Similar to adding behavior to {@linkcode Agent}s, this adds an update rule for the `Terrain`.
2741
+ * The function passed as the rule should be called with the parameters (`x`, `y`). In synchronous mode,
2742
+ * it should return a value that is the color of that cell on the next time step.
2743
+ *
2744
+ * ```js
2745
+ * // turns a cell red if the x-value is greater than 200,
2746
+ * // blue if the x-value is less than 100,
2747
+ * // and leaves it unchanged in between
2748
+ * terrain.addRule((x, y) => {
2749
+ * if (x > 200) {
2750
+ * return Colors.RED;
2751
+ * } else if (x < 100) {
2752
+ * return Colors.BLUE;
2753
+ * }
2754
+ * });
2755
+ * ```
2756
+ *
2757
+ * For grayscale mode, functions passed to `addRule` should return a number instead of a {@linkcode Colors | pixel-like object}.
2758
+ *
2759
+ * In asynchronous mode, functions should use the {@linkcode set} method to update either this cell
2760
+ * or a different cell.
2761
+ *
2762
+ * ```js
2763
+ * // swaps the colors of this cell and the one five cells to the right
2764
+ * terrain.addRule((x, y) => {
2765
+ * const here = terrain.sample(x, y);
2766
+ * const there = terrain.sample(x + 5, y);
2767
+ * terrain.set(x, y, there);
2768
+ * terrain.set(x + 5, y, here);
2769
+ * });
2770
+ * ```
2771
+ *
2258
2772
  * @since 0.4.0
2259
2773
  */
2260
2774
  Terrain.prototype.addRule = function (rule) {
@@ -2262,14 +2776,23 @@
2262
2776
  };
2263
2777
  /**
2264
2778
  * Given a local path or remote URL to an image, load that image and set
2265
- * terrain pixel data accordingly. This will scale the image to match the
2266
- * dimensionss of the terrain.
2779
+ * `Terrain` data accordingly. This will scale the image to match the
2780
+ * dimensions of the terrain.
2781
+ *
2267
2782
  * A 2nd callback parameter fires once the image has been successfully loaded.
2268
- * @param {string} path - The path or URL to the image
2269
- * @param {Function} cb - The function to call once the image loads
2783
+ *
2784
+ * ```js
2785
+ * const terrain = new Terrain(400, 400);
2786
+ * terrain.load("/path/to/local/image.jpg", function() {
2787
+ * console.log("Image loaded successfully!");
2788
+ * });
2789
+ * ```
2790
+ *
2791
+ * @param {string} path - The path to or URL of the image
2792
+ * @param {Function} cb - The function to call once the image loads (takes no parameters)
2270
2793
  * @since 0.4.0
2271
2794
  */
2272
- Terrain.prototype.load = function (path, cb) {
2795
+ Terrain.prototype.load = function (path, callback) {
2273
2796
  var _this = this;
2274
2797
  var img = document.createElement("img");
2275
2798
  img.src = path;
@@ -2283,8 +2806,8 @@
2283
2806
  .getContext("2d")
2284
2807
  .getImageData(0, 0, _this.width, _this.height).data;
2285
2808
  _this.data = data;
2286
- if (cb)
2287
- cb();
2809
+ if (callback)
2810
+ callback();
2288
2811
  };
2289
2812
  img.onerror = function () {
2290
2813
  console.error("There was an error loading the image for the terrain. Check the path to the URL to make sure that it exists, \n or consider saving a local copy to pull from the same origin: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors");
@@ -2325,16 +2848,21 @@
2325
2848
  }
2326
2849
  };
2327
2850
  /**
2328
- * Get the neighbors of a coordinate within a certain radius.
2329
- * Depending on the fourth parameter, retrieves either the von Neumann neighborhood
2330
- * (https://en.wikipedia.org/wiki/Von_Neumann_neighborhood) or the Moore neighborhood
2331
- * (https://en.wikipedia.org/wiki/Moore_neighborhood).
2851
+ * Get the values of the neighbors of a cell within a certain radius.
2852
+ * Depending on the fourth parameter, retrieves either the {@link https://en.wikipedia.org/wiki/Von_Neumann_neighborhood | von Neumann neighborhood}
2853
+ * or the {@link https://en.wikipedia.org/wiki/Moore_neighborhood | Moore neighborhood}.
2332
2854
  *
2333
- * @param {number} x - The x coordinate
2334
- * @param {number} y - The y coordinate
2335
- * @param {number} radius - how far to look for neighbors
2336
- * @param {boolean} moore - whether to use the Moore neighborhood or von Neumann (defaults to von Neumann)
2337
- * @returns {Pixel[] | number[]} - An array of numbers (grayscale only) or pixel-like objects
2855
+ * ```js
2856
+ * // in grayscale mode:
2857
+ * terrain.neighbors(5, 5, 1); // returns [127, 100, 255, 255] (4 values)
2858
+ *
2859
+ * // in color mode:
2860
+ * terrain.neighbors(5, 5, 1, true);
2861
+ * // returns [{ r: 255, g: 0, b: 0, a: 255 }, { r: 127, ... }, ...] (8 values)
2862
+ * ```
2863
+ *
2864
+ * @param moore - Defaults to using the von Neumann neighborhood.
2865
+ * @returns Either an array of numbers (grayscale mode) or {@link Colors | pixel-like objects} (color mode).
2338
2866
  * @since 0.4.0
2339
2867
  */
2340
2868
  Terrain.prototype.neighbors = function (x, y, radius, moore) {
@@ -2356,6 +2884,7 @@
2356
2884
  }
2357
2885
  return neighbors;
2358
2886
  };
2887
+ /** @hidden */
2359
2888
  Terrain.prototype._setAbstract = function (data, x, y, r, g, b, a) {
2360
2889
  var _a = this, width = _a.width, height = _a.height, opts = _a.opts;
2361
2890
  var grayscale = opts.grayscale, scale = opts.scale;
@@ -2408,9 +2937,11 @@
2408
2937
  Terrain.prototype.set = function (x, y, r, g, b, a) {
2409
2938
  this._setAbstract(this.data, x, y, r, g, b, a);
2410
2939
  };
2940
+ /** @hidden */
2411
2941
  Terrain.prototype._setNext = function (x, y, r, g, b, a) {
2412
2942
  this._setAbstract(this.nextData, x, y, r, g, b, a);
2413
2943
  };
2944
+ /** @hidden */
2414
2945
  Terrain.prototype._execute = function (x, y) {
2415
2946
  var _a = this, rule = _a.rule, opts = _a.opts;
2416
2947
  var async = opts.async;
@@ -2423,6 +2954,7 @@
2423
2954
  // update on nextData
2424
2955
  this._setNext(x, y, result);
2425
2956
  };
2957
+ /** @hidden */
2426
2958
  Terrain.prototype._loop = function (_a) {
2427
2959
  var _b = _a.randomizeOrder, randomizeOrder = _b === void 0 ? false : _b;
2428
2960
  var _c = this, rule = _c.rule, width = _c.width, height = _c.height, opts = _c.opts;
@@ -2452,52 +2984,272 @@
2452
2984
  return Terrain;
2453
2985
  }());
2454
2986
 
2455
- var defaultTickOptions = {
2456
- activation: "uniform",
2457
- count: 1,
2458
- randomizeOrder: false
2459
- };
2460
- var defaultEnvironmentOptions = {
2461
- torus: true,
2462
- height: 0,
2463
- width: 0
2464
- };
2465
- var warnOnce = once(console.warn.bind(console));
2466
2987
  /**
2467
- * An environment provides the space and time in which agents interact.
2468
- * Environments, like agents, can store data in key-value pairs
2469
- * that can be updated over time.
2988
+ * Given a `number` and `min` and `max` values, restrict the number
2989
+ * to the range specified.
2990
+ *
2991
+ * ```js
2992
+ * clamp(5, 1, 10); // returns 5
2993
+ * clamp(5, 2, 4); // returns 4
2994
+ * clamp(0, -4, -3); // returns -3
2995
+ * ```
2996
+ *
2470
2997
  * @since 0.0.5
2471
2998
  */
2472
- var Environment = /** @class */ (function (_super) {
2473
- __extends(Environment, _super);
2474
- function Environment(opts) {
2475
- if (opts === void 0) { opts = defaultEnvironmentOptions; }
2476
- var _this = _super.call(this) || this;
2477
- /** @member {Agent[]} */
2478
- _this.agents = [];
2479
- _this.agentsById = new Map();
2480
- _this.cache = new Map();
2481
- _this.helpers = {
2482
- kdtree: null,
2483
- network: null,
2484
- terrain: null
2485
- };
2486
- /** @member {AbstractRenderer[]} */
2487
- _this.renderers = [];
2488
- /** @since 0.1.4 */
2489
- _this.time = 0;
2490
- _this.opts = Object.assign({}, defaultEnvironmentOptions);
2491
- _this.opts = Object.assign(_this.opts, opts);
2492
- _this.width = _this.opts.width;
2493
- _this.height = _this.opts.height;
2494
- return _this;
2999
+ function clamp(x, min, max) {
3000
+ if (x < min)
3001
+ return min;
3002
+ if (x > max)
3003
+ return max;
3004
+ return x;
3005
+ }
3006
+
3007
+ /**
3008
+ * Given a mean and standard deviation,
3009
+ * returns a value from a normal/Gaussian distribution.
3010
+ *
3011
+ * ```js
3012
+ * // returns values mostly between 5 and 15 (but sometimes lower or higher)
3013
+ * gaussian(10, 5);
3014
+ *
3015
+ * // no parameters defaults to mean = 0, std. dev. = 1
3016
+ * gaussian(); // mostly values between -1 and 1
3017
+ * ```
3018
+ *
3019
+ * @since 0.0.8
3020
+ */
3021
+ function gaussian(mean, sd) {
3022
+ if (mean === void 0) { mean = 0; }
3023
+ if (sd === void 0) { sd = 1; }
3024
+ var y, x1, x2, w;
3025
+ do {
3026
+ x1 = 2 * uniform() - 1;
3027
+ x2 = 2 * uniform() - 1;
3028
+ w = x1 * x1 + x2 * x2;
3029
+ } while (w >= 1);
3030
+ w = Math.sqrt((-2 * Math.log(w)) / w);
3031
+ y = x1 * w;
3032
+ return y * sd + mean;
3033
+ }
3034
+
3035
+ /// <reference path="../types/Point.d.ts" />
3036
+ /**
3037
+ * Finds the {@link https://en.wikipedia.org/wiki/Taxicab_geometry | Manhattan distance} between `p1` and `p2`.
3038
+ *
3039
+ * The inputs may be plain objects with `x`, `y`, and/or `z` keys, {@linkcode Vector}s,
3040
+ * or {@linkcode Agent}s with `x`, `y`, and/or `z` data.
3041
+ *
3042
+ * ```js
3043
+ * const a1 = new Agent();
3044
+ * const a2 = new Agent({ x: 3, y: 4 });
3045
+ * manhattanDistance(a1, a2); // returns 7 (defaults to x = 0 and y = 0 for a1)
3046
+ *
3047
+ * const p1 = { x: 3, y: 2 };
3048
+ * const p2 = { x: 0, y: 4 };
3049
+ * manhattanDistance(p1, p2); // returns 5
3050
+ * ```
3051
+ *
3052
+ * @since 0.0.12
3053
+ */
3054
+ function manhattanDistance(p1, p2) {
3055
+ var x1 = (p1 instanceof Agent ? p1.get("x") : p1.x) || 0;
3056
+ var y1 = (p1 instanceof Agent ? p1.get("y") : p1.y) || 0;
3057
+ var z1 = (p1 instanceof Agent ? p1.get("z") : p1.z) || 0;
3058
+ var x2 = (p2 instanceof Agent ? p2.get("x") : p2.x) || 0;
3059
+ var y2 = (p2 instanceof Agent ? p2.get("y") : p2.y) || 0;
3060
+ var z2 = (p2 instanceof Agent ? p2.get("z") : p2.z) || 0;
3061
+ var dx = Math.abs(x2 - x1);
3062
+ var dy = Math.abs(y2 - y1);
3063
+ var dz = Math.abs(z2 - z1);
3064
+ // distance for toroidal environments
3065
+ if (p1 instanceof Agent &&
3066
+ p2 instanceof Agent &&
3067
+ p1.environment &&
3068
+ p2.environment &&
3069
+ p1.environment === p2.environment &&
3070
+ p1.environment.width &&
3071
+ p1.environment.height &&
3072
+ p1.environment.opts.torus) {
3073
+ var environment = p1.environment;
3074
+ var width = environment.width, height = environment.height;
3075
+ if (dx > width / 2)
3076
+ dx = width - dx;
3077
+ if (dy > height / 2)
3078
+ dy = height - dy;
2495
3079
  }
3080
+ return dx + dy + dz;
3081
+ }
3082
+
3083
+ /**
3084
+ * Maps a number x, from the given domain aMin --> aMax,
3085
+ * onto the given range bMin --> bMax.
3086
+ * Ex: remap(5, 0, 10, 0, 100) => 50.
3087
+ * @param {number} x
3088
+ * @param {number} aMin
3089
+ * @param {number} aMax
3090
+ * @param {number} bMin
3091
+ * @param {number} bMax
3092
+ * @returns {number} The remapped value.
3093
+ * @since 0.0.5
3094
+ */
3095
+ function remap(x, aMin, aMax, bMin, bMax) {
3096
+ return bMin + ((bMax - bMin) * (x - aMin)) / (aMax - aMin);
3097
+ }
3098
+
3099
+ /**
3100
+ * Seed a pseudo-random number generator with a value.
3101
+ * This can be used to produce predictable pseudo-random numbers.
3102
+ * When calling `utils.random`, `utils.sample`, or other functions
3103
+ * relying on randomness with the same initial seed, the values
3104
+ * generated will always be the same.
3105
+ *
3106
+ * Predictable randomness can be turned off by calling `seed(null)`, or reset
3107
+ * by calling `seed(value)` again with the initial value you used.
3108
+ * @param value
3109
+ * @since 0.5.0
3110
+ */
3111
+ var seed = function (value) { return PRNG.seed(value); };
3112
+
3113
+ /**
3114
+ * Find the standard deviation of an Array of numbers.
3115
+ * @param {Array<number>} arr
3116
+ * @returns {number}
3117
+ * @since 0.0.16
3118
+ */
3119
+ function stdDev(arr) {
3120
+ if (arr.length === 0)
3121
+ return null;
3122
+ var ave = mean(arr);
3123
+ return Math.sqrt(mean(arr.map(function (x) { return (x - ave) * (x - ave); })));
3124
+ }
3125
+
3126
+ /**
3127
+ * @since 0.1.4
3128
+ */
3129
+ function zfill(str, width) {
3130
+ if (width === void 0) { width = 0; }
3131
+ var output = str;
3132
+ while (output.length < width)
3133
+ output = "0" + output;
3134
+ return output;
3135
+ }
3136
+
3137
+
3138
+
3139
+ var utils = /*#__PURE__*/Object.freeze({
3140
+ __proto__: null,
3141
+ clamp: clamp,
3142
+ distance: distance,
3143
+ gaussian: gaussian,
3144
+ gcd: gcd,
3145
+ manhattanDistance: manhattanDistance,
3146
+ lerp: lerp,
3147
+ remap: remap,
3148
+ random: random,
3149
+ sample: sample$1,
3150
+ sampler: sampler,
3151
+ seed: seed,
3152
+ series: series,
3153
+ shuffle: shuffle,
3154
+ sum: sum,
3155
+ max: max,
3156
+ mean: mean,
3157
+ median: median,
3158
+ min: min,
3159
+ percentile: percentile,
3160
+ stdDev: stdDev,
3161
+ uniform: uniform,
3162
+ uuid: uuid$1,
3163
+ zfill: zfill
3164
+ });
3165
+
3166
+ var defaultTickOptions = {
3167
+ activation: "uniform",
3168
+ activationCount: 1,
3169
+ count: 1,
3170
+ randomizeOrder: false
3171
+ };
3172
+ var defaultEnvironmentOptions = {
3173
+ torus: true,
3174
+ height: 0,
3175
+ width: 0
3176
+ };
3177
+ var warnOnce = once(console.warn.bind(console));
3178
+ /**
3179
+ * An environment provides the space and time in which Agents interact.
3180
+ * Environments are themselves Agents, and can store data in key-value
3181
+ * pairs that can be manipulated just like Agent data.
3182
+ * @since 0.0.5
3183
+ */
3184
+ var Environment = /** @class */ (function (_super) {
3185
+ __extends(Environment, _super);
2496
3186
  /**
2497
- * Add an agent to the environment. Automatically sets the
2498
- * agent's environment to be this environment.
2499
- * @param {Agent} agent
2500
- * @param {boolean} rebalance - Whether to rebalance if there is a KDTree (defaults to true)
3187
+ * Although `Environment`s inherit {@linkcode Agent} methods
3188
+ * like {@linkcode Agent.set}, {@linkcode Agent.get}, etc. they have
3189
+ * a different `constructor` signature.
3190
+ *
3191
+ * Pass in predefined `Environment` options for:
3192
+ * - `torus` &mdash; Whether the `Environment` should wrap around in 2d space (with `Agent`s that move off the right reappearing on the left, off the top reappearing on the bottom, etc.)
3193
+ * - `width` &mdash; The width of the `Environment` (used when `torus = true`)
3194
+ * - `height` &mdash; The height of the `Environment` (used when `torus = true`)
3195
+ * @override
3196
+ */
3197
+ function Environment(opts) {
3198
+ if (opts === void 0) { opts = defaultEnvironmentOptions; }
3199
+ var _this = _super.call(this) || this;
3200
+ /** @hidden */
3201
+ _this.agents = [];
3202
+ /** @hidden */
3203
+ _this.agentsById = new Map();
3204
+ /** @hidden */
3205
+ _this.environment = null;
3206
+ /** @hidden */
3207
+ _this.cache = new Map();
3208
+ /** @hidden */
3209
+ _this.helpers = {
3210
+ kdtree: null,
3211
+ network: null,
3212
+ terrain: null
3213
+ };
3214
+ /**
3215
+ * An array of the renderers associated with this `Environment`.
3216
+ * An `Environment` can have multiple renderers, usually one to render
3217
+ * the {@linkcode Agent}s spatially and others for data visualization,
3218
+ * such as a {@linkcode LineChartRenderer}, {@linkcode Histogram}, etc.
3219
+ */
3220
+ _this.renderers = [];
3221
+ /**
3222
+ * This property will always equal the number of tick cycles that
3223
+ * have passed since the `Environment` was created. If you call
3224
+ * {@linkcode tick} so that it goes forward multiple time steps, it will
3225
+ * increase the `time` by that value (not by just `1`, even though
3226
+ * you only called `tick` once).
3227
+ *
3228
+ * ```js
3229
+ * const environment = new Environment();
3230
+ * environment.time; // returns 0
3231
+ *
3232
+ * environment.tick();
3233
+ * environment.time; // returns 1
3234
+ *
3235
+ * environment.tick(3);
3236
+ * environment.time; // returns 4
3237
+ * ```
3238
+ *
3239
+ * @since 0.1.4
3240
+ * */
3241
+ _this.time = 0;
3242
+ _this.opts = Object.assign({}, defaultEnvironmentOptions);
3243
+ _this.opts = Object.assign(_this.opts, opts);
3244
+ _this.width = _this.opts.width;
3245
+ _this.height = _this.opts.height;
3246
+ return _this;
3247
+ }
3248
+ /**
3249
+ * Add an {@linkcode Agent} to this `Environment`. Once this is called,
3250
+ * the `Agent`'s {@link Agent.environment | `environment`} property
3251
+ * will automatically be set to this `Environment`.
3252
+ * @param rebalance - Whether to rebalance if there is a `KDTree` (defaults to true)
2501
3253
  * @since 0.0.5
2502
3254
  */
2503
3255
  Environment.prototype.addAgent = function (agent, rebalance) {
@@ -2559,7 +3311,7 @@
2559
3311
  return this.agentsById.get(id) || null;
2560
3312
  };
2561
3313
  /**
2562
- * Removes all agents from the environment.
3314
+ * Remove all agents from the environment.
2563
3315
  * @since 0.1.3
2564
3316
  */
2565
3317
  Environment.prototype.clear = function () {
@@ -2569,64 +3321,132 @@
2569
3321
  }
2570
3322
  };
2571
3323
  /**
2572
- * From the parameter passed to .tick, get a structured TickOptions object.
2573
- * @param {number | TickOptions} opts
3324
+ * From the parameter passed to {@linkcode Environment.tick}, get a structured TickOptions object.
3325
+ * @hidden
2574
3326
  */
2575
3327
  Environment.prototype._getTickOptions = function (opts) {
2576
- var count = defaultTickOptions.count, randomizeOrder = defaultTickOptions.randomizeOrder;
3328
+ var baseOpts = Object.assign({}, defaultTickOptions);
2577
3329
  if (typeof opts === "number") {
2578
- count = opts;
3330
+ baseOpts.count = opts;
2579
3331
  }
2580
3332
  else if (!!opts) {
2581
- count = opts.count || 1;
2582
- }
2583
- if (opts &&
2584
- typeof opts !== "number" &&
2585
- opts.hasOwnProperty("randomizeOrder")) {
2586
- randomizeOrder = opts.randomizeOrder;
3333
+ Object.assign(baseOpts, opts);
2587
3334
  }
2588
- else if (opts === undefined ||
3335
+ if (opts === undefined ||
2589
3336
  (typeof opts !== "number" && !opts.hasOwnProperty("randomizeOrder"))) {
2590
3337
  warnOnce("You called `environment.tick` without specifying a `randomizeOrder` option. Currently this defaults to `false` (i.e. each agent ticks in the order it was added to the environment). However, in **Flocc 0.6.0 this will default to `true`** — agent activation order will default to being randomized.");
2591
3338
  }
2592
- return { count: count, randomizeOrder: randomizeOrder };
3339
+ return baseOpts;
2593
3340
  };
2594
3341
  /**
2595
- * Execute all agent rules.
2596
- * @param { boolean } randomizeOrder
3342
+ * For all agents passed, execute agent rules
3343
+ * @hidden
2597
3344
  */
2598
- Environment.prototype._executeAgentRules = function (randomizeOrder) {
2599
- (randomizeOrder ? shuffle(this.agents) : this.agents).forEach(function (agent) {
2600
- return agent.executeRules();
2601
- });
3345
+ Environment.prototype._executeAgentRules = function (agents) {
3346
+ agents.forEach(function (agent) { return agent === null || agent === void 0 ? void 0 : agent.executeRules(); });
2602
3347
  };
2603
3348
  /**
2604
- * Execute all enqueued agent rules.
2605
- * @param { boolean } randomizeOrder
3349
+ * For all agents passed, execute enqueued agent rules
3350
+ * @hidden
2606
3351
  */
2607
- Environment.prototype._executeEnqueuedAgentRules = function (randomizeOrder) {
2608
- (randomizeOrder ? shuffle(this.agents) : this.agents).forEach(function (agent) {
2609
- return agent.executeEnqueuedRules();
2610
- });
3352
+ Environment.prototype._executeEnqueuedAgentRules = function (agents) {
3353
+ agents.forEach(function (agent) { return agent === null || agent === void 0 ? void 0 : agent.executeEnqueuedRules(); });
2611
3354
  };
2612
3355
  /**
2613
- * Moves the environment forward in time,
2614
- * executing all agent's rules sequentially, followed by
2615
- * any enqueued rules (which are removed with every tick).
2616
- * Can take either a number or a configuration object as a parameter.
2617
- * If a number, the environment will tick forward that many times.
2618
- * @param {number | TickOptions} opts
3356
+ * Runs the `Environment`s tick cycle. Depending on the parameters, one,
3357
+ * some, or all of the {@linkcode Agent}s in the `Environment`
3358
+ * might be activated, and all renderers associated with the
3359
+ * `Environment` will update. After the tick cycle finishes, any rules that were enqueued will be run and the `Environment`'s {@linkcode time} property will have incremented.
3360
+ *
3361
+ * ```js
3362
+ * environment.tick(); // ticks once
3363
+ *
3364
+ * // To run multiple tick cycles, you can pass a number
3365
+ * environment.tick(5); // ticks 5 times
3366
+ * ```
3367
+ *
3368
+ * Passing a configuration object (instead of a number) allows
3369
+ * you to have finer control over the tick cycle. The object can
3370
+ * have the following keys:
3371
+ * - `activation`: Either `"uniform"` or `"random"` (defaults to `"uniform"`).
3372
+ * - `activation = "uniform"` &mdash; All `Agent`s in the `Environment` are activated with every tick cycle.
3373
+ * - `activation = "random"` &mdash; One or more `Agent`s are randomly selected to be activated every tick cycle (see `activationCount` below).
3374
+ * - `activationCount`: For `"random"` activation, this many `Agent`s will be activated with each tick cycle. Defaults to `1`. If `activationCount` is greater than the number of `Agent`s in the `Environment`, then all the `Agent`s will be activated exactly once in random order.
3375
+ * - `count`: The number of tick cycles to run.
3376
+ * - `randomizeOrder`: When `activation = "uniform"`, if `randomizeOrder = true`, `Agent`s will be activated in random order, otherwise in the order they were added to the `Environment`. **This currently defaults to `false` but will default to `true` in v0.6.0.**
3377
+ *
3378
+ * ```js
3379
+ * // Ticks three times, activating 10 random agents with each tick cycle.
3380
+ * environment.tick({
3381
+ * activation: "random",
3382
+ * activationCount: 10,
3383
+ * count: 3
3384
+ * });
3385
+ * ```
3386
+ *
2619
3387
  * @since 0.0.5
2620
3388
  */
2621
3389
  Environment.prototype.tick = function (opts) {
2622
- var _a = this._getTickOptions(opts), count = _a.count, randomizeOrder = _a.randomizeOrder;
2623
- this._executeAgentRules(randomizeOrder);
2624
- this._executeEnqueuedAgentRules(randomizeOrder);
3390
+ var _a = this._getTickOptions(opts), activation = _a.activation, activationCount = _a.activationCount, count = _a.count, randomizeOrder = _a.randomizeOrder;
3391
+ // for uniform activation, every agent is always activated
3392
+ if (activation === "uniform") {
3393
+ var agentsInOrder = randomizeOrder ? shuffle(this.agents) : this.agents;
3394
+ this._executeAgentRules(agentsInOrder);
3395
+ this._executeEnqueuedAgentRules(agentsInOrder);
3396
+ }
3397
+ // for random activation, the number of agents activated
3398
+ // per tick is determined by the `activationCount` option
3399
+ else if (activation === "random") {
3400
+ if (activationCount === 1) {
3401
+ var agent = sample$1(this.agents);
3402
+ if (agent !== null) {
3403
+ agent.executeRules();
3404
+ agent.executeEnqueuedRules();
3405
+ }
3406
+ }
3407
+ else if (activationCount > 1) {
3408
+ var sampleCount = sampler(activationCount);
3409
+ // this safety check should always return `true`
3410
+ if (isMultipleSampleFunc(sampleCount)) {
3411
+ var agents = sampleCount(this.getAgents());
3412
+ this._executeAgentRules(agents);
3413
+ this._executeEnqueuedAgentRules(agents);
3414
+ }
3415
+ }
3416
+ else {
3417
+ warnOnce("You passed a zero or negative `activationCount` to the Environment's tick options. No agents will be activated.");
3418
+ }
3419
+ }
2625
3420
  if (this.helpers.kdtree)
2626
3421
  this.helpers.kdtree.rebalance();
2627
3422
  var terrain = this.helpers.terrain;
2628
- if (terrain && terrain.rule)
2629
- terrain._loop({ randomizeOrder: randomizeOrder });
3423
+ if (terrain && terrain.rule) {
3424
+ if (activation === "uniform") {
3425
+ terrain._loop({ randomizeOrder: randomizeOrder });
3426
+ }
3427
+ else if (activation === "random") {
3428
+ if (activationCount === 1) {
3429
+ var x = random(0, terrain.width);
3430
+ var y = random(0, terrain.height);
3431
+ terrain._execute(x, y);
3432
+ }
3433
+ else if (activationCount > 1) {
3434
+ var generator = series(terrain.width * terrain.height);
3435
+ var indices = [];
3436
+ while (indices.length < activationCount) {
3437
+ var index = generator.next().value;
3438
+ var x = index % terrain.width;
3439
+ var y = (index / terrain.width) | 0;
3440
+ terrain._execute(x, y);
3441
+ indices.push(index);
3442
+ }
3443
+ }
3444
+ // in synchronous mode, write the buffer to the data
3445
+ if (!terrain.opts.async) {
3446
+ terrain.data = new Uint8ClampedArray(terrain.nextData);
3447
+ }
3448
+ }
3449
+ }
2630
3450
  this.time++;
2631
3451
  if (count > 1) {
2632
3452
  this.tick(count - 1);
@@ -2635,26 +3455,41 @@
2635
3455
  this.renderers.forEach(function (r) { return r.render(); });
2636
3456
  };
2637
3457
  /**
2638
- * Use a helper with this environment.
2639
- * @param {EnvironmentHelper} e
3458
+ * Use a helper with this environment. A helper can be one of:
3459
+ * - {@linkcode KDTree}
3460
+ * - {@linkcode Network}
3461
+ * - {@linkcode Terrain}
2640
3462
  * @since 0.1.3
2641
3463
  */
2642
- Environment.prototype.use = function (e) {
2643
- if (e instanceof KDTree)
2644
- this.helpers.kdtree = e;
2645
- if (e instanceof Network)
2646
- this.helpers.network = e;
2647
- if (e instanceof Terrain)
2648
- this.helpers.terrain = e;
3464
+ Environment.prototype.use = function (helper) {
3465
+ if (helper instanceof KDTree)
3466
+ this.helpers.kdtree = helper;
3467
+ if (helper instanceof Network)
3468
+ this.helpers.network = helper;
3469
+ if (helper instanceof Terrain)
3470
+ this.helpers.terrain = helper;
2649
3471
  };
2650
3472
  /**
2651
3473
  * Get an array of data associated with agents in the environment by key.
2652
- * Equivalent to calling `environment.getAgents().map(agent => agent.get(key));`
2653
- * Defaults to calculating and storing the result within the same environment tick.
2654
- * If the 2nd parameter is set to `false`, will recalculate and return the result every time.
2655
- * @param {string} key - The key for which to retrieve data.
2656
- * @param {boolean} useCache - Whether or not to cache the result (defaults to true).
2657
- * @return {any[]} Array of data associated with `agent.get(key)` across all agents.
3474
+ * Calling `environment.stat('name')` is equivalent to calling
3475
+ * `environment.getAgents().map(agent => agent.get('name'));`
3476
+ *
3477
+ * By default, calling this will calculate the result at most once
3478
+ * per time cycle, and return the cached value on subsequent calls (until
3479
+ * the next time cycle, when it will recalculate).
3480
+ *
3481
+ * @param key - The key for which to retrieve data.
3482
+ * @param useCache - Whether or not to cache the result.
3483
+ * @returns Array of data associated with `agent.get(key)` across all agents.
3484
+ *
3485
+ * ```js
3486
+ * environment.addAgent(new Agent({ name: "Alice" }));
3487
+ * environment.addAgent(new Agent({ name: "Bob" }));
3488
+ * environment.addAgent(new Agent({ name: "Chaz" }));
3489
+ *
3490
+ * environment.stat('name'); // returns ['Alice', 'Bob', 'Chaz']
3491
+ * ```
3492
+ *
2658
3493
  * @since 0.3.14
2659
3494
  */
2660
3495
  Environment.prototype.stat = function (key, useCache) {
@@ -2675,9 +3510,17 @@
2675
3510
  };
2676
3511
  /**
2677
3512
  * Pass a function to cache and use the return value within the same environment tick.
2678
- * @param {Function} fn - The function to memoize.
2679
- * @return {any} The return value of the function that was passed.
3513
+ * @param fn - The function to memoize.
3514
+ * @return The return value of the function that was passed.
2680
3515
  * @since 0.3.14
3516
+ *
3517
+ * ```js
3518
+ * // Within the same time cycle, this function will only be called once.
3519
+ * // The cached value will be used on subsequent calls.
3520
+ * const blueAgents = environment.memo(() => {
3521
+ * return environment.getAgents().filter(a => a.get('color') === 'blue');
3522
+ * });
3523
+ * ```
2681
3524
  */
2682
3525
  Environment.prototype.memo = function (fn, key) {
2683
3526
  var serialized = (key ? key + "-" : "") + fn.toString();
@@ -2718,10 +3561,21 @@
2718
3561
  };
2719
3562
  var warnOnce$1 = once(console.warn.bind(console));
2720
3563
  /**
2721
- * @since 0.0.5
3564
+ * A `GridEnvironment` is the **deprecated** version of a cellular automata.
3565
+ * It's now recommended that you use a standard {@linkcode Environment} with a
3566
+ * {@linkcode Terrain}. This class will be removed entirely in v0.6.0.
3567
+ *
3568
+ * In a `GridEnvironment` with an {@linkcode ASCIIRenderer}, {@linkcode Agent}s are rendered
3569
+ * using their `"value"` data (a single character).
3570
+ *
3571
+ * @deprecated since 0.4.0
3572
+ * @since 0.0.10
2722
3573
  */
2723
3574
  var GridEnvironment = /** @class */ (function (_super) {
2724
3575
  __extends(GridEnvironment, _super);
3576
+ /**
3577
+ * Create a `GridEnvironment` with the given `width` and `height`.
3578
+ */
2725
3579
  function GridEnvironment(width, height) {
2726
3580
  if (width === void 0) { width = 2; }
2727
3581
  if (height === void 0) { height = 2; }
@@ -2756,6 +3610,7 @@
2756
3610
  }
2757
3611
  };
2758
3612
  /**
3613
+ * @hidden
2759
3614
  * @since 0.1.0
2760
3615
  */
2761
3616
  GridEnvironment.prototype.normalize = function (x, y) {
@@ -2770,7 +3625,7 @@
2770
3625
  return { x: x, y: y };
2771
3626
  };
2772
3627
  /**
2773
- * For GridEnvironments, `addAgent` takes `x` and `y` values
3628
+ * For `GridEnvironment`s, `addAgent` takes `x` and `y` values
2774
3629
  * and automatically adds a Agent to that cell coordinate.
2775
3630
  * @param {number} x_
2776
3631
  * @param {number} y_
@@ -2799,8 +3654,8 @@
2799
3654
  return agent;
2800
3655
  };
2801
3656
  /**
2802
- * For GridEnvironments, `removeAgent` takes `x` and `y` values
2803
- * and removes the Agent (if there is one) at that cell coordinate.
3657
+ * For GridEnvironments, `removeAgentAt` takes `x` and `y` values
3658
+ * and removes the `Agent` (if there is one) at that cell coordinate.
2804
3659
  * @param {number} x_
2805
3660
  * @param {number} y_
2806
3661
  * @since 0.1.0
@@ -2963,6 +3818,7 @@
2963
3818
  };
2964
3819
  /**
2965
3820
  * Execute all cell rules.
3821
+ * @hidden
2966
3822
  * @param { boolean } randomizeOrder
2967
3823
  */
2968
3824
  GridEnvironment.prototype._executeCellRules = function (randomizeOrder) {
@@ -2989,6 +3845,7 @@
2989
3845
  };
2990
3846
  /**
2991
3847
  * Execute all enqueued cell rules.
3848
+ * @hidden
2992
3849
  * @param { boolean } randomizeOrder
2993
3850
  */
2994
3851
  GridEnvironment.prototype._executeEnqueuedCellRules = function (randomizeOrder) {
@@ -3014,8 +3871,8 @@
3014
3871
  }
3015
3872
  };
3016
3873
  /**
3017
- * Override/extend Environment.tick to include the
3018
- * GridEnvironment's cells.
3874
+ * Override/extend {@linkcode Environment.tick} to include the
3875
+ * `GridEnvironment`'s cells.
3019
3876
  * @override
3020
3877
  * @param {number} opts
3021
3878
  */
@@ -3024,11 +3881,11 @@
3024
3881
  // execute all cell rules
3025
3882
  this._executeCellRules(randomizeOrder);
3026
3883
  // execute all agent rules
3027
- this._executeAgentRules(randomizeOrder);
3884
+ this._executeAgentRules(randomizeOrder ? shuffle(this.agents) : this.agents);
3028
3885
  // execute all enqueued cell rules
3029
3886
  this._executeEnqueuedCellRules(randomizeOrder);
3030
3887
  // execute all enqueued agent rules
3031
- this._executeEnqueuedAgentRules(randomizeOrder);
3888
+ this._executeEnqueuedAgentRules(randomizeOrder ? shuffle(this.agents) : this.agents);
3032
3889
  this.time++;
3033
3890
  if (count > 1) {
3034
3891
  this.tick(count - 1);
@@ -3041,13 +3898,24 @@
3041
3898
 
3042
3899
  var AbstractRenderer = /** @class */ (function () {
3043
3900
  function AbstractRenderer() {
3901
+ /** @hidden */
3044
3902
  this.canvas = document.createElement("canvas");
3903
+ /** @hidden */
3045
3904
  this.context = this.canvas.getContext("2d");
3046
3905
  }
3047
3906
  AbstractRenderer.prototype.render = function () { };
3048
3907
  /**
3049
3908
  * Mount this renderer to a DOM element. Pass either a string representing a
3050
- * CSS selector matching the element (i.e. `"#element-id") or the element itself.
3909
+ * CSS selector matching the element or the element itself.
3910
+ *
3911
+ * ```js
3912
+ * // mounts the renderer to the element with the ID `container`
3913
+ * renderer.mount('#container');
3914
+ *
3915
+ * // mounts the renderer to the element itself
3916
+ * const container = document.getElementById('container');
3917
+ * renderer.mount(container);
3918
+ * ```
3051
3919
  * @param {string | HTMLElement} el
3052
3920
  */
3053
3921
  AbstractRenderer.prototype.mount = function (el) {
@@ -3062,11 +3930,25 @@
3062
3930
 
3063
3931
  var warnOnce$2 = once(console.warn.bind(console));
3064
3932
  /**
3933
+ * An `ASCIIRenderer` renders the {@link Agent | `Agent`}s in
3934
+ * a {@linkcode GridEnvironment}. `Agent`s are rendered
3935
+ * using their `"value"` data (a single character).
3936
+ * Since v0.4.0, this class has been **deprecated**, and it will be removed
3937
+ * entirely in v0.6.0.
3938
+ * ```js
3939
+ * const renderer = new ASCIIRenderer(grid);
3940
+ * renderer.mount("#container-id");
3941
+ * ```
3942
+ * @deprecated since 0.4.0
3065
3943
  * @since 0.0.10
3066
3944
  */
3067
3945
  var ASCIIRenderer = /** @class */ (function (_super) {
3068
3946
  __extends(ASCIIRenderer, _super);
3069
- function ASCIIRenderer(environment, opts) {
3947
+ /**
3948
+ * Create a new `ASCIIRenderer` by passing in the
3949
+ * {@linkcode GridEnvironment} you want to be rendered.
3950
+ */
3951
+ function ASCIIRenderer(environment) {
3070
3952
  var _this = _super.call(this) || this;
3071
3953
  warnOnce$2("As of Flocc v0.5.0, ASCIIEnvironment is **DEPRECATED**. It will be **REMOVED** in v0.6.0. The Terrain helper should be used for 2-dimensional grid-like data, with CanvasRenderer to visualize. Read more about Terrains here: https://flocc.network/docs/terrain");
3072
3954
  _this.environment = environment;
@@ -3075,6 +3957,7 @@
3075
3957
  return _this;
3076
3958
  }
3077
3959
  /**
3960
+ * Renders the contents of the `ASCIIRenderer`'s {@linkcode GridEnvironment}.
3078
3961
  * @since 0.0.10
3079
3962
  */
3080
3963
  ASCIIRenderer.prototype.render = function () {
@@ -3110,12 +3993,46 @@
3110
3993
  trace: false
3111
3994
  };
3112
3995
  /**
3996
+ * A `CanvasRenderer` renders an {@linkcode Environment} spatially in two dimensions.
3997
+ * Importantly, it expects that all {@linkcode Agent}s in the `Environment`
3998
+ * have numeric `"x"` and `"y"` values associated with them.
3999
+ *
4000
+ * `CanvasRenderer`s will render all `Agent`s that are visible in the rendered `Environment` space,
4001
+ * with the color of their `"color"` value (defaulting to black).
4002
+ * Depending on the `"shape"` of the `Agent`, additional data might be needed. `Agent` `"shape"`s can be:
4003
+ * - `"circle"` (default) &mdash; Draws a circle centered at the `Agent`'s `"x"` / `"y"` values.
4004
+ * - If the `Agent` has a `"size"` value, uses that for the circle radius (defaults to 1px).
4005
+ * - `"arrow"` &mdash; Draws an arrow centered at the `Agent`'s `"x"` / `"y"` values.
4006
+ * - The arrow will point in the direction of the `Agent`s `"vx"` / `"vy"` values. For example, an `Agent` with `"vx" = 1` and `"vy" = 0` will be rendered as an arrow pointing to the right.
4007
+ * - Also uses the `"size" value.
4008
+ * - `"rect"` &mdash; Draws a rectangle with the upper-left corner at `"x"` / `"y"`.
4009
+ * - Uses the `Agent`'s `"width"` and `"height"` values for the dimensions of the rectangle.
4010
+ * - `"triangle"` &mdash; Draws a triangle centered at the `Agent`'s `"x"` / `"y"` values.
4011
+ * - Also uses the `"size"` value.
4012
+ *
3113
4013
  * @since 0.0.11
3114
4014
  */
3115
4015
  var CanvasRenderer = /** @class */ (function (_super) {
3116
4016
  __extends(CanvasRenderer, _super);
4017
+ /**
4018
+ * The first parameter must be the {@linkcode Environment} that this
4019
+ * `CanvasRenderer` will render.
4020
+ *
4021
+ * The second parameter specifies options, which can include:
4022
+ * - `autoPosition` (*boolean* = `false`) &mdash; For `Environment`s using a {@linkcode Network}, whether to automatically position the `Agent`s.
4023
+ * - `background` (*string* = `"transparent"`) &mdash; The background color to draw before rendering any `Agent`s.
4024
+ * - `connectionColor` (*string* = `"black"`) &mdash; For `Environment`s using a `Network`, the color of lines
4025
+ * - `connectionOpacity` (*number* = `1`) &mdash; For `Environment`s using a `Network`, the opacity of lines
4026
+ * - `connectionWidth` (*number* = `1`) &mdash; For `Environment`s using a `Network`, the width of lines
4027
+ * - `height` (*number* = `500`) &mdash; The height, in pixels, of the canvas on which to render
4028
+ * - `origin` (*{ x: number; y: number }* = `{ x: 0, y: 0 }`) &mdash; The coordinate of the upper-left point of the space to be rendered
4029
+ * - `scale` (*number* = `1`) &mdash; The scale at which to render (the larger the scale, the smaller the size of the space that is actually rendered)
4030
+ * - `trace` (*boolean* = `false`) &mdash; If `true`, the renderer will not clear old drawings, causing the `Agent`s to appear to *trace* their paths across space
4031
+ * - `width` (*number* = `500`) &mdash; The width, in pixels, of the canvas on which to render
4032
+ */
3117
4033
  function CanvasRenderer(environment, opts) {
3118
4034
  var _this = _super.call(this) || this;
4035
+ /** @hidden */
3119
4036
  _this.terrainBuffer = document.createElement("canvas");
3120
4037
  _this.environment = environment;
3121
4038
  environment.renderers.push(_this);
@@ -3136,14 +4053,17 @@
3136
4053
  _this.context.fillRect(0, 0, width, height);
3137
4054
  return _this;
3138
4055
  }
4056
+ /** @hidden */
3139
4057
  CanvasRenderer.prototype.x = function (v) {
3140
4058
  var _a = this.opts, origin = _a.origin, scale = _a.scale;
3141
4059
  return window.devicePixelRatio * scale * (v - origin.x);
3142
4060
  };
4061
+ /** @hidden */
3143
4062
  CanvasRenderer.prototype.y = function (v) {
3144
4063
  var _a = this.opts, origin = _a.origin, scale = _a.scale;
3145
4064
  return window.devicePixelRatio * scale * (v - origin.y);
3146
4065
  };
4066
+ /** @hidden */
3147
4067
  CanvasRenderer.prototype.createCanvas = function () {
3148
4068
  var dpr = window.devicePixelRatio;
3149
4069
  var _a = this.opts, width = _a.width, height = _a.height;
@@ -3152,6 +4072,117 @@
3152
4072
  canvas.height = height * dpr;
3153
4073
  return canvas;
3154
4074
  };
4075
+ /** @hidden */
4076
+ CanvasRenderer.prototype.drawPath = function (points, dx, dy) {
4077
+ if (dx === void 0) { dx = 0; }
4078
+ if (dy === void 0) { dy = 0; }
4079
+ var bufferContext = this.buffer.getContext("2d");
4080
+ points.forEach(function (_a, i) {
4081
+ var px = _a[0], py = _a[1];
4082
+ if (i === 0) {
4083
+ bufferContext.moveTo(px + dx, py + dy);
4084
+ }
4085
+ else {
4086
+ bufferContext.lineTo(px + dx, py + dy);
4087
+ }
4088
+ });
4089
+ };
4090
+ /** @hidden */
4091
+ CanvasRenderer.prototype.drawPathWrap = function (points) {
4092
+ var _this = this;
4093
+ var _a = this, width = _a.width, height = _a.height;
4094
+ var right = false;
4095
+ var left = false;
4096
+ var lower = false;
4097
+ var upper = false;
4098
+ points.forEach(function (_a) {
4099
+ var px = _a[0], py = _a[1];
4100
+ if (_this.x(px) >= width)
4101
+ right = true;
4102
+ if (_this.x(px) < 0)
4103
+ left = true;
4104
+ if (_this.y(py) >= height)
4105
+ lower = true;
4106
+ if (_this.y(py) < 0)
4107
+ upper = true;
4108
+ });
4109
+ if (right)
4110
+ this.drawPath(points, -width, 0);
4111
+ if (left)
4112
+ this.drawPath(points, width, 0);
4113
+ if (lower && right)
4114
+ this.drawPath(points, -width, -height);
4115
+ if (upper && right)
4116
+ this.drawPath(points, -width, height);
4117
+ if (lower && left)
4118
+ this.drawPath(points, width, -height);
4119
+ if (upper && left)
4120
+ this.drawPath(points, width, height);
4121
+ if (lower)
4122
+ this.drawPath(points, 0, -height);
4123
+ if (upper)
4124
+ this.drawPath(points, 0, height);
4125
+ };
4126
+ /** @hidden */
4127
+ CanvasRenderer.prototype.drawCircle = function (x, y, r) {
4128
+ var bufferContext = this.buffer.getContext("2d");
4129
+ bufferContext.moveTo(this.x(x), this.y(y));
4130
+ bufferContext.arc(this.x(x), this.y(y), r, 0, 2 * Math.PI);
4131
+ };
4132
+ /** @hidden */
4133
+ CanvasRenderer.prototype.drawCircleWrap = function (x, y, size) {
4134
+ var _a = this, width = _a.width, height = _a.height;
4135
+ if (this.x(x + size) >= width) {
4136
+ this.drawCircle(x - width, y, size);
4137
+ if (this.y(y + size) >= height)
4138
+ this.drawCircle(x - width, y - height, size);
4139
+ if (this.y(y - size) < 0)
4140
+ this.drawCircle(x - width, y + height, size);
4141
+ }
4142
+ if (this.x(x - size) < 0) {
4143
+ this.drawCircle(x + width, y, size);
4144
+ if (this.y(y + size) >= height)
4145
+ this.drawCircle(x + width, y - height, size);
4146
+ if (this.y(y - size) < 0)
4147
+ this.drawCircle(x + width, y + height, size);
4148
+ }
4149
+ if (this.y(y + size) > height)
4150
+ this.drawCircle(x, y - height, size);
4151
+ if (this.y(y - size) < 0)
4152
+ this.drawCircle(x, y + height, size);
4153
+ };
4154
+ /**
4155
+ * Draw a rectangle centered at (x, y). Automatically calculates the offset
4156
+ * for both width and height.
4157
+ * @hidden
4158
+ */
4159
+ CanvasRenderer.prototype.drawRect = function (x, y, width, height) {
4160
+ var bufferContext = this.buffer.getContext("2d");
4161
+ var dpr = window.devicePixelRatio;
4162
+ bufferContext.fillRect(this.x(x) - (width * dpr) / 2, this.y(y) - (height * dpr) / 2, width * dpr, height * dpr);
4163
+ };
4164
+ /** @hidden */
4165
+ CanvasRenderer.prototype.drawRectWrap = function (x, y, w, h) {
4166
+ var _a = this.opts, width = _a.width, height = _a.height;
4167
+ if (this.x(x + w / 2) >= width) {
4168
+ this.drawRect(x - width, y, w, h);
4169
+ if (this.y(y + h / 2) >= height)
4170
+ this.drawRect(x - width, y - height, w, h);
4171
+ if (this.y(y - height / 2) < 0)
4172
+ this.drawRect(x - width, y + height, w, h);
4173
+ }
4174
+ if (this.x(x - w / 2) < 0) {
4175
+ this.drawRect(x + width, y, w, h);
4176
+ if (this.y(y + h / 2) >= height)
4177
+ this.drawRect(x + width, y - height, w, h);
4178
+ if (this.y(y - height / 2) < 0)
4179
+ this.drawRect(x + width, y + height, w, h);
4180
+ }
4181
+ if (this.y(y + h / 2) > height)
4182
+ this.drawRect(x, y - height, w, h);
4183
+ if (this.y(y - height / 2) < 0)
4184
+ this.drawRect(x, y + height, w, h);
4185
+ };
3155
4186
  CanvasRenderer.prototype.render = function () {
3156
4187
  var _this = this;
3157
4188
  var _a = this, buffer = _a.buffer, context = _a.context, environment = _a.environment, width = _a.width, height = _a.height, opts = _a.opts, terrainBuffer = _a.terrainBuffer;
@@ -3239,28 +4270,36 @@
3239
4270
  var _vx = 3 * size * (vx / norm) * dpr;
3240
4271
  var _vy = 3 * size * (vy / norm) * dpr;
3241
4272
  bufferContext.beginPath();
3242
- bufferContext.save();
3243
- bufferContext.translate(_this.x(x), _this.y(y));
3244
- bufferContext.moveTo(1.5 * _vx, 1.5 * _vy);
3245
- bufferContext.lineTo(_vy / 2, -_vx / 2);
3246
- bufferContext.lineTo(-_vy / 2, _vx / 2);
3247
- bufferContext.restore();
4273
+ var points = [
4274
+ [_this.x(x) + 1.5 * _vx, _this.y(y) + 1.5 * _vy],
4275
+ [_this.x(x) + _vy / 2, _this.y(y) - _vx / 2],
4276
+ [_this.x(x) - _vy / 2, _this.y(y) + _vx / 2]
4277
+ ];
4278
+ _this.drawPath(points);
4279
+ if (environment.opts.torus)
4280
+ _this.drawPathWrap(points);
3248
4281
  }
3249
4282
  else if (shape === "rect") {
3250
4283
  var _h = agent.getData(), _j = _h.width, width_1 = _j === void 0 ? 1 : _j, _k = _h.height, height_1 = _k === void 0 ? 1 : _k;
3251
- bufferContext.fillRect(_this.x(x) - (width_1 * dpr) / 2, _this.y(y) - (height_1 * dpr) / 2, width_1 * dpr, height_1 * dpr);
4284
+ _this.drawRect(x, y, width_1, height_1);
4285
+ if (environment.opts.torus)
4286
+ _this.drawRectWrap(x, y, width_1, height_1);
3252
4287
  }
3253
4288
  else if (shape === "triangle") {
3254
4289
  bufferContext.beginPath();
3255
- bufferContext.save();
3256
- bufferContext.translate(_this.x(x), _this.y(y));
3257
- bufferContext.moveTo(0, -size / 2);
3258
- bufferContext.lineTo(size / 2, size / 2);
3259
- bufferContext.lineTo(-size / 2, size / 2);
3260
- bufferContext.restore();
4290
+ var points = [
4291
+ [_this.x(x), _this.y(y) - size / 2],
4292
+ [_this.x(x) + size / 2, _this.y(y) + size / 2],
4293
+ [_this.x(x) - size / 2, _this.y(y) + size / 2]
4294
+ ];
4295
+ _this.drawPath(points);
4296
+ if (environment.opts.torus)
4297
+ _this.drawPathWrap(points);
3261
4298
  }
3262
4299
  else if (shape === "circle" || shape === undefined) {
3263
- bufferContext.arc(_this.x(x), _this.y(y), size * dpr, 0, 2 * Math.PI);
4300
+ _this.drawCircle(x, y, size * dpr);
4301
+ if (environment.opts.torus)
4302
+ _this.drawCircleWrap(x, y, size);
3264
4303
  }
3265
4304
  bufferContext.fill();
3266
4305
  if (text) {
@@ -3282,22 +4321,6 @@
3282
4321
  return CanvasRenderer;
3283
4322
  }(AbstractRenderer));
3284
4323
 
3285
- /**
3286
- * Maps a number x, from the given domain aMin --> aMax,
3287
- * onto the given range bMin --> bMax.
3288
- * Ex: remap(5, 0, 10, 0, 100) => 50.
3289
- * @param {number} x
3290
- * @param {number} aMin
3291
- * @param {number} aMax
3292
- * @param {number} bMin
3293
- * @param {number} bMax
3294
- * @returns {number} The remapped value.
3295
- * @since 0.0.5
3296
- */
3297
- function remap(x, aMin, aMax, bMin, bMax) {
3298
- return bMin + ((bMax - bMin) * (x - aMin)) / (aMax - aMin);
3299
- }
3300
-
3301
4324
  /// <reference path="../types/NRange.d.ts" />
3302
4325
  function extractRoundNumbers(range) {
3303
4326
  var min = range.min, max = range.max;
@@ -3609,7 +4632,7 @@
3609
4632
  if (opts.autoScroll && t >= width) {
3610
4633
  x -= t - width;
3611
4634
  }
3612
- else if (opts.autoScale && t >= width) {
4635
+ else if (opts.autoScale) {
3613
4636
  x *= width / t;
3614
4637
  }
3615
4638
  return x | 0;
@@ -3657,7 +4680,7 @@
3657
4680
  context.restore();
3658
4681
  // draw time values for horizontal axis
3659
4682
  var min = opts.autoScroll && t >= width ? t - width : 0;
3660
- var max = opts.autoScale && t >= width ? t : width;
4683
+ var max = opts.autoScale ? Math.max(t, 5) : width;
3661
4684
  var timeRange = { min: min, max: max };
3662
4685
  var timeMarkers = extractRoundNumbers(timeRange);
3663
4686
  context.save();
@@ -3737,14 +4760,61 @@
3737
4760
  };
3738
4761
  var escapeStringQuotes = function (s) { return "\"" + s.replace(/"/g, '\\"') + "\""; };
3739
4762
  /**
4763
+ * A `TableRenderer` renders an HTML table (for browsers only) or CSV (comma-separated value)
4764
+ * representation of {@linkcode Agent} data.
4765
+ *
4766
+ * ```js
4767
+ * for (let i = 0; i < 3; i++) {
4768
+ * environment.addAgent(new Agent({
4769
+ * x: i * 10,
4770
+ * y: i - 2
4771
+ * }));
4772
+ * }
4773
+ *
4774
+ * const renderer = new TableRenderer(environment);
4775
+ * renderer.columns = ['x', 'y'];
4776
+ * renderer.mount('#container');
4777
+ * environment.tick();
4778
+ * ```
4779
+ *
4780
+ * The `TableRenderer` renders:
4781
+ *
4782
+ * |x |y |
4783
+ * |----|----|
4784
+ * |0 |-2 |
4785
+ * |10 |-1 |
4786
+ * |20 |0 |
4787
+ *
3740
4788
  * @since 0.5.0
3741
4789
  */
3742
4790
  var TableRenderer = /** @class */ (function (_super) {
3743
4791
  __extends(TableRenderer, _super);
4792
+ /**
4793
+ * The first parameter must be the {@linkcode Environment} that this
4794
+ * `TableRenderer` will render.
4795
+ *
4796
+ * The second parameter specifies options, which can include:
4797
+ * - `"type"` (`"csv"` | `"table"` = `"table"`) &mdash; Whether to render output in CSV or HTML `<table>` format
4798
+ * - `"filter"` &mdash; Include a function (`Agent` => `boolean`) to specify which rows to include in the output. For example, if you only want to include `Agent`s with an x value greater than 100:
4799
+ * ```js
4800
+ * const renderer = new TableRenderer(environment, {
4801
+ * filter: agent => {
4802
+ * return agent.get('x') > 100;
4803
+ * }
4804
+ * });
4805
+ * ```
4806
+ * - `"limit"` (*number* = `Infinity`) &mdash; The maximum number of rows (`Agent`s) to render. If using a `filter` function, applies the `limit` *after* filtering.
4807
+ * - `"sortKey"` (*string* = `null`) &mdash; Sort the `Agent` data by this key of data
4808
+ * - `"order"` (`"asc"` | `"desc"` = `"desc"`) &mdash; When using a `"sortKey"`, specify whether `Agent`s should be listed in *asc*ending or *desc*ending order
4809
+ * - `"precision"` (*number* = `3`) &mdash; For floating point values, the number of decimal places to display
4810
+ * - `"refresh"` (*number* = `500`) &mdash; The number of milliseconds that should elapse between re-rendering (if this happens too quickly the effect can be visually jarring)
4811
+ */
3744
4812
  function TableRenderer(environment, options) {
3745
4813
  if (options === void 0) { options = {}; }
3746
4814
  var _this = _super.call(this) || this;
4815
+ /** @hidden */
3747
4816
  _this.lastRendered = +new Date();
4817
+ /** @hidden */
3748
4818
  _this.opts = Object.assign({}, defaultTableRendererOptions);
3749
4819
  _this.environment = environment;
3750
4820
  environment.renderers.push(_this);
@@ -3754,7 +4824,16 @@
3754
4824
  }
3755
4825
  /**
3756
4826
  * Mount this renderer to a DOM element. Pass either a string representing a
3757
- * CSS selector matching the element (i.e. `"#element-id") or the element itself.
4827
+ * CSS selector matching the element or the element itself.
4828
+ *
4829
+ * ```js
4830
+ * // mounts the renderer to the element with the ID `container`
4831
+ * renderer.mount('#container');
4832
+ *
4833
+ * // mounts the renderer to the element itself
4834
+ * const container = document.getElementById('container');
4835
+ * renderer.mount(container);
4836
+ * ```
3758
4837
  * @override
3759
4838
  * @param {string | HTMLElement} el
3760
4839
  */
@@ -3767,6 +4846,7 @@
3767
4846
  }
3768
4847
  this.table = container;
3769
4848
  };
4849
+ /** @hidden */
3770
4850
  TableRenderer.prototype.serializeColumns = function (joiner, start, end, escape) {
3771
4851
  if (start === void 0) { start = ""; }
3772
4852
  if (end === void 0) { end = ""; }
@@ -3778,6 +4858,7 @@
3778
4858
  return "";
3779
4859
  return start + columns.join(joiner) + end;
3780
4860
  };
4861
+ /** @hidden */
3781
4862
  TableRenderer.prototype.serializeRows = function (cellJoiner, rowJoiner, start, end, rowStart, rowEnd, escape) {
3782
4863
  var _this = this;
3783
4864
  if (start === void 0) { start = ""; }
@@ -3826,6 +4907,7 @@
3826
4907
  .join(rowJoiner) +
3827
4908
  end);
3828
4909
  };
4910
+ /** @hidden */
3829
4911
  TableRenderer.prototype.renderCSV = function () {
3830
4912
  var columns = this.serializeColumns(",", "", "", true);
3831
4913
  if (columns === "")
@@ -3835,12 +4917,28 @@
3835
4917
  return columns;
3836
4918
  return columns + "\n" + rows;
3837
4919
  };
4920
+ /** @hidden */
3838
4921
  TableRenderer.prototype.renderHTMLTable = function () {
3839
4922
  var thead = this.serializeColumns("</td><td>", "<thead><tr><td>", "</td></tr></thead>");
3840
4923
  var tbody = this.serializeRows("</td><td>", "", "<tbody>", "</tbody>", "<tr><td>", "</td></tr>");
3841
4924
  return "<table>" + thead + tbody + "</table>";
3842
4925
  };
3843
4926
  /**
4927
+ * Returns the outer HTML of the table or the CSV data as a string. This can be useful for exporting data, particularly in a Node.js environment as opposed to in a browser. For instance, in a Node.js script, you could write the CSV data to a file as follows:
4928
+ *
4929
+ * ```js
4930
+ * const fs = require('fs'); // import the file system module
4931
+ *
4932
+ * const environment = new Environment();
4933
+ * for (let i = 0; i < 3; i++) environment.addAgent(new Agent({ i }));
4934
+ *
4935
+ * const renderer = new TableRenderer(environment, { type: 'csv' });
4936
+ * renderer.columns = ['i'];
4937
+ *
4938
+ * // write the TableRenderer's output to a CSV file named data.csv
4939
+ * fs.writeFileSync('./data.csv', renderer.output());
4940
+ * ```
4941
+ *
3844
4942
  * @since 0.5.0
3845
4943
  */
3846
4944
  TableRenderer.prototype.output = function () {
@@ -3866,22 +4964,6 @@
3866
4964
  return TableRenderer;
3867
4965
  }(AbstractRenderer));
3868
4966
 
3869
- /**
3870
- * Restricts a number x to the range min --> max.
3871
- * @param {number} x
3872
- * @param {number} min
3873
- * @param {number} max
3874
- * @return {number} The clamped value.
3875
- * @since 0.0.5
3876
- */
3877
- function clamp(x, min, max) {
3878
- if (x < min)
3879
- return min;
3880
- if (x > max)
3881
- return max;
3882
- return x;
3883
- }
3884
-
3885
4967
  var PADDING_AT_BOTTOM$1 = 60;
3886
4968
  var PADDING_AT_LEFT$1 = 60;
3887
4969
  var isAxisObject = function (obj) {
@@ -3898,12 +4980,48 @@
3898
4980
  };
3899
4981
  var warnOnce$3 = once(console.warn.bind(console));
3900
4982
  /**
4983
+ * A `Heatmap` can be used to visualize the distribution of {@linkcode Agent}s across two metrics.
4984
+ * While {@linkcode Histogram}s are useful for showing the distribution of `Agent`s along a single metric
4985
+ * (or on multiple metrics using the same scale), a `Heatmap` can show how two metrics relate to one another &mdash;
4986
+ * correlation, inverse correlation, in a nonlinear manner, randomly (no correlation), etc.
4987
+ *
4988
+ * <img src="https://cms.flocc.network/wp-content/uploads/2020/11/heatmap-basic.png" />
4989
+ *
4990
+ * Note above that, although the output appears similar to what a {@linkcode CanvasRenderer} might output, the `y` axis is reversed here &mdash; low values are at the bottom and high at the top, whereas on a `CanvasRenderer` high values are at the bottom and low at the top.
4991
+ *
3901
4992
  * @since 0.5.8
3902
4993
  */
3903
4994
  var Heatmap = /** @class */ (function (_super) {
3904
4995
  __extends(Heatmap, _super);
4996
+ /**
4997
+ * The first parameter must be the {@linkcode Environment} that this
4998
+ * `Heatmap` will render.
4999
+ *
5000
+ * The second parameter specifies options, which can include:
5001
+ * - `from` (*string* = `"white"`) &mdash; The color (name, hex value, or RGB) to draw when a cell contains `0` {@linkcode Agent}s
5002
+ * - `to` (*string* = `"black"`) &mdash; The color (name, hex value, or RGB) to draw when a cell contains the highest number of `Agent`s
5003
+ * - `x` and `y` can be either:
5004
+ * - *string* = `"x"`/`"y"` respectively &mdash; The name of `Agent` data to measure along the `x`/`y` axis
5005
+ * - *{ buckets: number; key: string; min: number; max: number }* = `{ buckets: 10, key: 'x' | 'y', min: 0, max: 1 }` &mdash; Include the number of buckets to divide the range `min → max` into, along with the name of `Agent` data
5006
+ * - `width` (*number* = `500`) &mdash; The width, in pixels, of the canvas on which to render
5007
+ * - `height` (*number* = `500`) &mdash; The height, in pixels, of the canvas on which to render
5008
+ * - `scale` (either `"relative"` or `"fixed"`, defaults to `"relative"`)
5009
+ * - `"relative"` &mdash; The maximum number of `Agent`s in any single cell is automatically used as the highest value in the scale. This updates over time based on `Agent` distribution.
5010
+ * - `"fixed"` &mdash; You supply the number to use as the maximum value (see `max` below).
5011
+ * - `max` (optional, *number*) &mdash; If you use `scale = "fixed"`, then setting a `max` will cause cells with that number (or higher) of `Agent`s to be drawn using the `to` color.
5012
+ *
5013
+ * ```js
5014
+ * // plots the correlation between age of agents (on the x-axis)
5015
+ * // vs. their wealth (on the y-axis)
5016
+ * const heatmap = new Heatmap(environment, {
5017
+ * x: 'age',
5018
+ * y: 'wealth'
5019
+ * });
5020
+ * ```
5021
+ */
3905
5022
  function Heatmap(environment, opts) {
3906
5023
  var _this = _super.call(this) || this;
5024
+ /** @hidden */
3907
5025
  _this.opts = defaultHeatmapOptions;
3908
5026
  _this.environment = environment;
3909
5027
  _this.opts = Object.assign({}, _this.opts, opts);
@@ -3922,7 +5040,7 @@
3922
5040
  }
3923
5041
  /**
3924
5042
  * Map a value (on the range x-min to x-max) onto canvas space to draw it along the x-axis.
3925
- * @param value
5043
+ * @hidden
3926
5044
  */
3927
5045
  Heatmap.prototype.x = function (value) {
3928
5046
  var width = this.width;
@@ -3930,12 +5048,13 @@
3930
5048
  };
3931
5049
  /**
3932
5050
  * Map a value (on the range y-min to y-max) onto canvas space to draw it along the y-axis.
3933
- * @param value
5051
+ * @hidden
3934
5052
  */
3935
5053
  Heatmap.prototype.y = function (value) {
3936
5054
  var height = this.height;
3937
5055
  return remap(value, this.getMin("y"), this.getMax("y"), height - PADDING_AT_BOTTOM$1, 0);
3938
5056
  };
5057
+ /** @hidden */
3939
5058
  Heatmap.prototype.getKey = function (axis) {
3940
5059
  var a = this.opts[axis];
3941
5060
  if (isAxisObject(a)) {
@@ -3945,12 +5064,14 @@
3945
5064
  return a;
3946
5065
  }
3947
5066
  };
5067
+ /** @hidden */
3948
5068
  Heatmap.prototype.getBuckets = function (axis) {
3949
5069
  var a = this.opts[axis];
3950
5070
  if (isAxisObject(a) && a.hasOwnProperty("buckets"))
3951
5071
  return a.buckets;
3952
5072
  return 10;
3953
5073
  };
5074
+ /** @hidden */
3954
5075
  Heatmap.prototype.getMin = function (axis) {
3955
5076
  var a = this.opts[axis];
3956
5077
  if (isAxisObject(a) && a.hasOwnProperty("min")) {
@@ -3960,6 +5081,7 @@
3960
5081
  return 0;
3961
5082
  }
3962
5083
  };
5084
+ /** @hidden */
3963
5085
  Heatmap.prototype.getMax = function (axis) {
3964
5086
  var a = this.opts[axis];
3965
5087
  if (isAxisObject(a) && a.hasOwnProperty("max")) {
@@ -3969,6 +5091,7 @@
3969
5091
  return 1;
3970
5092
  }
3971
5093
  };
5094
+ /** @hidden */
3972
5095
  Heatmap.prototype.drawMarkers = function () {
3973
5096
  var _a = this, context = _a.context, width = _a.width, height = _a.height;
3974
5097
  var _b = this.opts, from = _b.from, to = _b.to;
@@ -4021,6 +5144,7 @@
4021
5144
  }
4022
5145
  }
4023
5146
  };
5147
+ /** @hidden */
4024
5148
  Heatmap.prototype.updateScale = function () {
4025
5149
  var _a = this, context = _a.context, environment = _a.environment, height = _a.height;
4026
5150
  var scale = this.opts.scale;
@@ -4042,6 +5166,7 @@
4042
5166
  this.lastUpdatedScale = new Date();
4043
5167
  }
4044
5168
  };
5169
+ /** @hidden */
4045
5170
  Heatmap.prototype.drawRectangles = function () {
4046
5171
  var _a = this, canvas = _a.canvas, environment = _a.environment, width = _a.width, height = _a.height;
4047
5172
  var _b = this.opts, scale = _b.scale, from = _b.from, to = _b.to;
@@ -4068,11 +5193,13 @@
4068
5193
  }
4069
5194
  context.globalAlpha = 1;
4070
5195
  };
5196
+ /** @hidden */
4071
5197
  Heatmap.prototype.resetBuckets = function () {
4072
5198
  for (var i = 0; i < this.getBuckets("x") * this.getBuckets("y"); i++) {
4073
5199
  this.buckets[i] = 0;
4074
5200
  }
4075
5201
  };
5202
+ /** @hidden */
4076
5203
  Heatmap.prototype.updateBuckets = function () {
4077
5204
  var _this = this;
4078
5205
  var environment = this.environment;
@@ -4115,135 +5242,9 @@
4115
5242
  }(AbstractRenderer));
4116
5243
 
4117
5244
  /**
4118
- * Given a mean and standard deviation,
4119
- * returns a value from a normal/Gaussian distribution.
4120
- * @param {number} mean
4121
- * @param {number} sd
4122
- * @returns {number}
4123
- * @since 0.0.8
4124
- */
4125
- function gaussian(mean, sd) {
4126
- if (mean === void 0) { mean = 0; }
4127
- if (sd === void 0) { sd = 1; }
4128
- var y, x1, x2, w;
4129
- do {
4130
- x1 = 2 * uniform() - 1;
4131
- x2 = 2 * uniform() - 1;
4132
- w = x1 * x1 + x2 * x2;
4133
- } while (w >= 1);
4134
- w = Math.sqrt((-2 * Math.log(w)) / w);
4135
- y = x1 * w;
4136
- return y * sd + mean;
4137
- }
4138
-
4139
- /// <reference path="../types/Point.d.ts" />
4140
- /**
4141
- * Finds the Manhattan distance between `p1` and `p2`.
4142
- * The inputs may be plain objects
4143
- * with `x`, `y`, and/or `z` keys, or Agent-like objects who have
4144
- * `x`, `y`, and/or `z` data.
4145
- * @param {Point|Agent} p1
4146
- * @param {Point|Agent} p2
4147
- * @return {number} The Manhattan distance between p1 and p2.
4148
- * @since 0.0.12
4149
- */
4150
- function manhattanDistance(p1, p2) {
4151
- var x1 = (p1 instanceof Agent ? p1.get("x") : p1.x) || 0;
4152
- var y1 = (p1 instanceof Agent ? p1.get("y") : p1.y) || 0;
4153
- var z1 = (p1 instanceof Agent ? p1.get("z") : p1.z) || 0;
4154
- var x2 = (p2 instanceof Agent ? p2.get("x") : p2.x) || 0;
4155
- var y2 = (p2 instanceof Agent ? p2.get("y") : p2.y) || 0;
4156
- var z2 = (p2 instanceof Agent ? p2.get("z") : p2.z) || 0;
4157
- var dx = Math.abs(x2 - x1);
4158
- var dy = Math.abs(y2 - y1);
4159
- var dz = Math.abs(z2 - z1);
4160
- // distance for toroidal environments
4161
- if (p1 instanceof Agent &&
4162
- p2 instanceof Agent &&
4163
- p1.environment &&
4164
- p2.environment &&
4165
- p1.environment === p2.environment &&
4166
- p1.environment.width &&
4167
- p1.environment.height &&
4168
- p1.environment.opts.torus) {
4169
- var environment = p1.environment;
4170
- var width = environment.width, height = environment.height;
4171
- if (dx > width / 2)
4172
- dx = width - dx;
4173
- if (dy > height / 2)
4174
- dy = height - dy;
4175
- }
4176
- return dx + dy + dz;
4177
- }
4178
-
4179
- /**
4180
- * Seed a pseudo-random number generator with a value.
4181
- * This can be used to produce predictable pseudo-random numbers.
4182
- * When calling `utils.random`, `utils.sample`, or other functions
4183
- * relying on randomness with the same initial seed, the values
4184
- * generated will always be the same.
4185
- *
4186
- * Predictable randomness can be turned off by calling `seed(null)`, or reset
4187
- * by calling `seed(value)` again with the initial value you used.
4188
- * @param value
4189
- * @since 0.5.0
4190
- */
4191
- var seed = function (value) { return PRNG.seed(value); };
4192
-
4193
- /**
4194
- * Find the standard deviation of an Array of numbers.
4195
- * @param {Array<number>} arr
4196
- * @returns {number}
4197
- * @since 0.0.16
4198
- */
4199
- function stdDev(arr) {
4200
- if (arr.length === 0)
4201
- return null;
4202
- var ave = mean(arr);
4203
- return Math.sqrt(mean(arr.map(function (x) { return (x - ave) * (x - ave); })));
4204
- }
4205
-
4206
- /**
4207
- * @since 0.1.4
5245
+ * The current version of the Flocc library.
4208
5246
  */
4209
- function zfill(str, width) {
4210
- if (width === void 0) { width = 0; }
4211
- var output = str;
4212
- while (output.length < width)
4213
- output = "0" + output;
4214
- return output;
4215
- }
4216
-
4217
-
4218
-
4219
- var utils = /*#__PURE__*/Object.freeze({
4220
- __proto__: null,
4221
- clamp: clamp,
4222
- distance: distance,
4223
- gaussian: gaussian,
4224
- gcd: gcd,
4225
- manhattanDistance: manhattanDistance,
4226
- lerp: lerp,
4227
- remap: remap,
4228
- random: random,
4229
- sample: sample$1,
4230
- sampler: sampler,
4231
- seed: seed,
4232
- series: series,
4233
- shuffle: shuffle,
4234
- sum: sum,
4235
- max: max,
4236
- mean: mean,
4237
- median: median,
4238
- min: min,
4239
- percentile: percentile,
4240
- stdDev: stdDev,
4241
- uniform: uniform,
4242
- uuid: uuid$1,
4243
- zfill: zfill
4244
- });
4245
-
4246
- var version = "0.5.18";
5247
+ var version = "0.5.21";
4247
5248
 
4248
5249
  exports.ASCIIRenderer = ASCIIRenderer;
4249
5250
  exports.Agent = Agent;