1

I am trying to create a small program where all degrees in a triangle will add up to 180 degrees. So far what I have is that when I use the Math.Random method, I get a random number but somethings the degrees do not add up to 180°. I have tried using the if condition statement but no luck so far.

Here is my code:

https://jsfiddle.net/14p880p9/

    var a = Math.round((Math.random() * 100) + 1);
    var b = Math.round((Math.random() * 100) + 1);
    var c = Math.round((Math.random() * 100) + 1);

    var d = a + b + c;



    ctx.beginPath();
    ctx.moveTo(50, 10);
    ctx.lineTo(50, 450);
    ctx.lineTo(650, 400);
    ctx.closePath();
    ctx.lineWidth = 10;
    ctx.strokeStyle = '#666666';
    ctx.stroke();
    ctx.fillStyle = "#FFCC00";
    ctx.fill();

    ctx.font = "30px Comic Sans MS";
    ctx.fillStyle = "black";
    ctx.fillText(a + "°",52,60);


    //width distance, and then altitude
    ctx.font = "30px Comic Sans MS";
    ctx.fillStyle = "black";
    ctx.fillText(b+ "°",60,420);



    //width distance, and then altitude
    ctx.font = "30px Comic Sans MS";
    ctx.fillStyle = "black";
    ctx.fillText(c + "°",570,400);
Cœur
  • 37,241
  • 25
  • 195
  • 267
user2984143
  • 85
  • 1
  • 11

3 Answers3

3

Use this, it can generate ANY combination, unlike the limited above option where one of the sides must be 1-100.

var a = Math.round((Math.random() * 90) + 1);
var b = Math.round((Math.random() * 90) + 1);
var c = 180 - a - b;
Assafi Cohen-Arazi
  • 837
  • 10
  • 30
1

Your logic for the generation of the randomness is a little off. At the minute you're asking it to generate 3 random numbers between 1-100. The downside to this approach is the numbers have no bearing on having to add to 180;

You should update this logic to know that the total must equal 180. Something like this:

var a = Math.round((Math.random() * 100) + 1); // generates a random number between 1-100
var b = Math.round((Math.random() * (179-a)) + 1); // generates a random number between 1-179 (minus a)
var c = 180 - a - b; // is the remaining value of 180 - a - b

var d = a + b + c;

JSFIDDLE

haxxxton
  • 6,422
  • 3
  • 27
  • 57
1

a) either use a stick...

An easy way to tackle this is to visualize your 180 as a stick. You want to break that stick into 3 pieces. So all you need to do is generate two non-equal rounded random values from 1 to 179 (the cutting points: one & two). And your random values will be:

  • a: from zero to smallest value cutting point
  • b: from smallest to largest value cutting points
  • c: from largest value cutting point to 180

var Triangle = function() {
    this.getRandom = function() {
        // 1 - 179 random integer generator
        return Math.round(Math.random() * (179 - 1) + 1);
    }

    this.one = this.getRandom();
    this.two = this.getRandom();

    while (this.one == this.two) {
        // if equal, regenerate second - we don't want any segment to have 0 length
        this.two = this.getRandom();
    }

    return {
        'a': Math.min(this.one, this.two),
        'b': Math.max(this.one, this.two) - Math.min(this.one, this.two),
        'c': 180 - Math.max(this.one, this.two)
    }
}

// Now let's make a few tests... how about 180 tests?
for (var i = 0; i < 180; i++) {

    var t = new Triangle;

    var div = document.createElement('div');
    div.innerHTML = t.a + ' + ' + t.b + ' + ' + t.c + ' = ' +
        (t.a + t.b + t.c);

    document.getElementsByTagName('body')[0].appendChild(div);
}
div {
  width: 33.3333%;
  float: left;
  padding: .5rem 0;
  text-align: center;
}

b) ... or maths

While the above method is easy to visualize, and ensures each segment value has equal chances at being anywhere between 1 and 178 (total - (parts - 1 )), it's not particularly efficient from a programming point of view.

Each time one of the cutting points overlaps an existing one, it needs to be recalculated. In our case that would be quite rare but, given variable values for total and parts, the odds of it happening might differ.
Besides, we can totally avoid having to regenerate any value, thus saving computing power and, ultimately, the planet, or at least delaying its doom by an insignificant amount of time.

If we look at this from a mathematical point of view, we'll notice

  • at least 1 part will be smaller than 61 ((180 / (3 - 0)) + 1)
  • at least 2 parts will be smaller than 91 ((180 / (3 - 1)) + 1)

So, as a general rule, at least n parts will be smaller than (total / (parts - (n - 1)) + 1). Now let's rewrite our method, generating the minimal amount or random numbers, in the correct range of possible values.
We also need to add as a last value the difference between total and the sum of all previous values.
To make it more useful, I also considered total and parts as variables, so the method could be used to segment any total number into any number of parts.

var Segmentation = function (total, parts) {
    this.random = function (min, max) {
        return Math.round(Math.random() * (max - min) + min);
    }

    this.segments = [];
    for (var i = 0; i < parts - 1; i++) {
        this.segments.push(this.random(parts - i, total / parts + 1));
    }

    this.segments.push(total - this.segments.reduce((a, b) => a + b, 0));
    return this.segments;

}
// let's test it

var h1 = document.createElement('h2');
h1.innerHTML = 'Triangles';
document.getElementsByTagName('body')[0].appendChild(h1);

for (var i = 0; i < 21; i++) {

    var t = new Segmentation(180, 3),
        div = document.createElement('div');

    div.innerHTML = '';
    for (var j = 0; j < t.length; j++) {
        div.innerHTML += t[j] + (t.length - j > 1 ? ' + ' : ' = ');
    }
    div.innerHTML += t.reduce((a, b) => a + b, 0);

    document.getElementsByTagName('body')[0].appendChild(div);
}

var h1 = document.createElement('h2');
h1.innerHTML = '<hr />Rectangles';
document.getElementsByTagName('body')[0].appendChild(h1);

for (var i = 0; i < 21; i++) {

    var t = new Segmentation(360, 4),
        div = document.createElement('div');

    div.innerHTML = '';
    for (var j = 0; j < t.length; j++) {
        div.innerHTML += t[j] + (t.length - j > 1 ? ' + ' : ' = ');
    }
    div.innerHTML += t.reduce((a, b) => a + b, 0);

    document.getElementsByTagName('body')[0].appendChild(div);
}

var h1 = document.createElement('h2');
h1.innerHTML = '<hr />Random segments';
document.getElementsByTagName('body')[0].appendChild(h1);

for (var i = 0; i < 21; i++) {
    var total = Math.round(Math.random() * (2000 - 200) + 200),
        parts = Math.round(Math.random() * (8 - 3) + 3),
        t = new Segmentation(total, parts);

    var div = document.createElement('div');
    div.className = ('full');
    div.innerHTML = '';
    for (var j = 0; j < t.length; j++) {
        div.innerHTML += t[j] + (t.length - j > 1 ? ' + ' : ' = ');
    }
    div.innerHTML += t.reduce((a, b) => a + b, 0);

    document.getElementsByTagName('body')[0].appendChild(div);
}
div {
  width: 33.3333%;
  float: left;
  padding: .5rem 0;
  text-align: center;
}

div.full {
  width: 100%;
  text-align: initial;
}

Using this method, the first entry in the array has the biggest chances of having the smallest value while the last part has the biggest chances of having the highest value.

Note: Using this in a production environment is not recommended without sanitizing the input values.

Another note: To calculate the sum of all existing values in an array I used this awesome answer's method.

Community
  • 1
  • 1
tao
  • 82,996
  • 16
  • 114
  • 150