From dc8e3b6766b84deb2c609ad9488a7ea67180aa1b Mon Sep 17 00:00:00 2001
From: kopareigns <kopareigns@gmail.com>
Date: Sun, 7 Oct 2018 00:16:49 -0400
Subject: [PATCH] Normal distribution for intelligence

---
 src/js/utilJS.tw | 97 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 90 insertions(+), 7 deletions(-)

diff --git a/src/js/utilJS.tw b/src/js/utilJS.tw
index 18549d4aa77..7fe7ed1251c 100644
--- a/src/js/utilJS.tw
+++ b/src/js/utilJS.tw
@@ -144,13 +144,6 @@ window.Height = (function(){
 		return table[nationality + "." + race] || table[nationality] || table["." + race] || table[""] || def;
 	};
 
-	// Helper method - generate two independent Gaussian numbers using Box-Muller transform
-	const gaussianPair = function() {
-		let r = Math.sqrt(-2.0 * Math.log(1 - Math.random()));
-		let sigma = 2.0 * Math.PI * (1 - Math.random());
-		return [r * Math.cos(sigma), r * Math.sin(sigma)];
-	};
-
 	// Helper method: Generate a skewed normal random variable with the skew s
 	// Reference: http://azzalini.stat.unipd.it/SN/faq-r.html
 	const skewedGaussian = function(s) {
@@ -290,6 +283,96 @@ window.Height = (function(){
 	};
 })();
 
+window.Intelligence = (function(){
+	'use strict';
+
+	// Global configuration (for different game modes/options/types)
+	var mean = 0;
+	var minMult = -3.0;
+	var maxMult = 3.0;
+	var skew = 0.0;
+	var spread = 45;
+	var minIntelligence = -101;
+	var maxIntelligence = 100;
+
+	// Configuration method for the above values
+	const _config = function(conf) {
+		if(_.isUndefined(conf)) {
+			return {mean: mean, limitMult: [minMult, maxMult], limitIntelligence: [minIntelligence, maxIntelligence], skew: skew, spread: spread};
+		}
+		if(_.isFinite(conf.mean)) { mean = Math.clamp(conf.mean, -100, 100); }
+		if(_.isFinite(conf.skew)) { skew = Math.clamp(conf.skew, -1000, 1000); }
+		if(_.isFinite(conf.spread)) { spread = Math.clamp(conf.spread, 0.1, 100); }
+		if(_.isArray(conf.limitMult) && conf.limitMult.length === 2 && conf.limitMult[0] !== conf.limitMult[1] &&
+			_.isFinite(conf.limitMult[0]) && _.isFinite(conf.limitMult[1])) {
+			minMult = Math.min(conf.limitMult[0], conf.limitMult[1]);
+			maxMult = Math.max(conf.limitMult[0], conf.limitMult[1]);
+		}
+		if(_.isArray(conf.limitIntelligence) && conf.limitIntelligence.length === 2 && conf.limitIntelligence[0] !== conf.limitIntelligence[1] &&
+			_.isFinite(conf.limitIntelligence[0]) && _.isFinite(conf.limitIntelligence[1])) {
+			minIntelligence = Math.min(conf.limitIntelligence[0], conf.limitIntelligence[1]);
+			maxIntelligence = Math.max(conf.limitIntelligence[0], conf.limitIntelligence[1]);
+		}
+		return {limitMult: [minMult, maxMult], limitIntelligence: [minIntelligence, maxIntelligence], skew: skew, spread: spread};
+	};
+
+	// Helper method: Generate a skewed normal random variable with the skew s
+	// Reference: http://azzalini.stat.unipd.it/SN/faq-r.html
+	const skewedGaussian = function(s) {
+		let randoms = gaussianPair();
+		if(s === 0) {
+			// Don't bother, return an unskewed normal distribution
+			return randoms[0];
+		}
+		let delta = s / Math.sqrt(1 + s * s);
+		let result = delta * randoms[0] + Math.sqrt(1 - delta * delta) * randoms[1];
+		return randoms[0] >= 0 ? result : -result;
+	};
+
+	// Height multiplier generator; skewed gaussian according to global parameters
+	const multGenerator = function() {
+		let result = skewedGaussian(skew);
+		while(result < minMult || result > maxMult) {
+			result = skewedGaussian(skew);
+		}
+		return result;
+	};
+
+	// Helper method: Generate an intelligence based on the mean one and limited according to config.
+	const intelligenceGenerator = function() {
+		let result = multGenerator() * spread + mean;
+
+		while(result < minIntelligence || result > maxIntelligence) {
+			result = multGenerator() * spread + mean;
+		}
+		
+		return Math.ceil(result);
+	};
+
+	const _randomIntelligence = function(settings) {
+	if (settings) {
+		const currentConfig = _config();
+		_config(settings);
+		const result = intelligenceGenerator();
+		_config(currentConfig);
+		return result;
+	}
+	return intelligenceGenerator();
+	};
+
+	return {
+		random: _randomIntelligence,
+		config: _config,
+	};
+})();
+
+// Helper method - generate two independent Gaussian numbers using Box-Muller transform
+window.gaussianPair = function() {
+	let r = Math.sqrt(-2.0 * Math.log(1 - Math.random()));
+	let sigma = 2.0 * Math.PI * (1 - Math.random());
+	return [r * Math.cos(sigma), r * Math.sin(sigma)];
+};
+
 if(!Array.prototype.findIndex) {
 	Array.prototype.findIndex = function(predicate) {
 		if (this == null) {
-- 
GitLab