Control the randomness?

So i have a basic function which uses Random.Range which selects between 0 - 12 and depending on what it chooses will change how many resources a tile has. I want to be able to do is adjust the rng so it’s not completely random but I have control over how rare a certain amount of resources is.

So for example there might be 80% chance a gold tile drops with 3 gold on it and another 80% chance that a food tile with 2 spawns there. The problem I’m having is that if i than set the random.range to choose between 0 and 100 to get the random chance. Surely its always going to pick the if statement thats above the other. I want to verify that btw but I’m sure code will always read line by line till it finds code to execute or break out of the loop. Or if i have a 79% and 80% chance than surely there’s only a 1% chance certainty that tile will spawn depending if its less than or more than if statement.

Current Tile Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Tile : MonoBehaviour 
{
	public int goldValue;
	public int foodValue;
	public int ironValue;

	public Vector3 screenPos;
	public Transform textTag;

	//Who owns the tile
	public string playerName;
	public Color tileColor;
	public bool owned = false;
	public int ownersPlayerID;

	[Header("Color values")]
	public Color goldValue1Color;
	public Color goldValue2Color;
	public Color goldValue3Color;
	public Color goldValue4Color;

	public Color foodValue1Color;
	public Color foodValue2Color;
	public Color foodValue3Color;
	public Color foodValue4Color;

	public Color ironValue1Color;
	public Color ironValue2Color;
	public Color ironValue3Color;
	public Color ironValue4Color;

	void Start()
	{
		textTag = gameObject.transform; 
		RandomiseValue();
	}

	void Update()
	{
		screenPos = Camera.main.WorldToScreenPoint (textTag.position);
		if (owned == true)
		{
			gameObject.GetComponent<MeshRenderer> ().material.color = tileColor;
		}
	}

	private void RandomiseValue()
	{
		int rng = Random.Range (0, 12);

		if (rng == 0) 
		{
			goldValue = 0;
			foodValue = 0;
			ironValue = 0;
			gameObject.GetComponent<MeshRenderer> ().material.color = Color.gray;
		}

		if (rng == 1) 
		{
			goldValue = 1;
			gameObject.GetComponent<MeshRenderer> ().material.color = goldValue1Color;
		}

		if (rng == 2) 
		{
			goldValue = 2;
			gameObject.GetComponent<MeshRenderer> ().material.color = goldValue2Color;
		}

		if (rng == 3) 
		{
			goldValue = 3;
			gameObject.GetComponent<MeshRenderer> ().material.color = goldValue3Color;
		}

		if (rng == 4) 
		{
			goldValue = 4;
			gameObject.GetComponent<MeshRenderer> ().material.color = goldValue4Color;
		}

		if (rng == 5) 
		{
			foodValue = 1;
			gameObject.GetComponent<MeshRenderer> ().material.color = foodValue1Color;
		}

		if (rng == 6) 
		{
			foodValue = 2;
			gameObject.GetComponent<MeshRenderer> ().material.color = foodValue2Color;
		}

		if (rng == 7) 
		{
			foodValue = 3;
			gameObject.GetComponent<MeshRenderer> ().material.color = foodValue3Color;
		}

		if (rng == 8) 
		{
			foodValue = 4;
			gameObject.GetComponent<MeshRenderer> ().material.color = foodValue4Color;
		}

		if (rng == 9) 
		{
			ironValue = 1;
			gameObject.GetComponent<MeshRenderer> ().material.color = ironValue1Color;
		}

		if (rng == 10) 
		{
			ironValue = 2;
			gameObject.GetComponent<MeshRenderer> ().material.color = ironValue2Color;
		}

		if (rng == 11) 
		{
			ironValue = 3;
			gameObject.GetComponent<MeshRenderer> ().material.color = ironValue3Color;
		}

		if (rng == 12) 
		{
			ironValue = 4;
			gameObject.GetComponent<MeshRenderer> ().material.color = ironValue4Color;
		}
	}

	public void TileOwnedBy(string name, Color color, int ID)
	{
		playerName = name;
		tileColor = color;
		ownersPlayerID = ID;
		owned = true;
		Debug.Log ("Owners Name " + playerName);
	}

Im sorry if i worded that funny but basically Im looking for is to control how random something is? Added in the code to show what I mean.

It would likely be better to decouple tile generation and tile resources. This will make it MUCH easier to design for because now your probabilities are all straightforward.

To use your example, you have an 80% chance of spawning gold and an 80% chance of spawning food. (I’m ignoring the quantities for now, I’ll get to those later). Now, what you’ve TOLD it to do is have an 80% chance of spawning gold and an 80% chance of spawning food, but, that’s not actually what ends up happening. The probability actually depends on which spawn you check first. From your code, it doesn’t look like you ever have a tile that has multiple kinds of resource on it at the same time. Meaning, if the tile has gold, it doesn’t have food.

So, let’s say, you check gold first, then food. So you calculate gold, which has an 80% chance to be gold, and therefore 20% chance to be anything else. If it is something else, it’s got an 80% chance to be food, but this only happens 20% of the time, so the tile really has a 16% chance of happening. That’s not a lot of food.

Forgive me if this is not the case, and you can have multiple types of resources on one tile. Regardless, it’ll still make it easier because you can work with the actual probabilities.

The solution:

  1. Use a random chance to determine if there IS a tile to begin with. Not sure how you generate your worlds so I won’t get into detail on this one.
  2. Assuming you DO HAVE a tile:
    have an array of the different things the tile can be and the probability (or rather, the weight) of these things that the tile can be.
  3. Add up all of these weights, and generate a random float between 0 and that sum.
  4. Loop through the different possibilities, regenerating this random float, and check if the random number is less than the weight on that possibility. If it is, then make the tile that type and break out of the loop.
  5. If you go through the entire loop and still don’t have anything generated, the most technically accurate thing to do would be to repeat the loop, but eventually that just takes too much time. If, after a few tries (or even one, depending on the fidelity to probability you want), you can just choose one at random by picking an int between 0 and the number of possibilities, and use that. This is the same as what you’re doing basically at this point.
  6. You have your tile.

But what about the quantities?

You could in theory create a separate possibility for each quantity of each item, but that’s tedious and not easy to extend. So, one way to improve this is to let each possibility have its own array of quantities with their own weights. Then:

  1. Assuming you have a tile, and you have decided on what resource goes on it as per the above:
  2. Sum up the weights in the array of quantities
  3. Loop through again, like above, regenerating a random float between 0 and this sum, and determine what quantity to assign

Now, you have a tile with a percent to exist, a percent to be a certain resource, and a percent to be a certain quantity of said resource.

You have gold food and iron. Now let’s say you want 80% chance getting food, 50% getting iron and 30% getting gold (considering rarity I’d say):

bool GetItem(int percent)
{
     int rand = Random.Range(0,100); // 100 is excluded 
     return rand <  percent;      // is rand between 0 and percent 
}

and you can now check for each:

void SetResource()
{
     bool food = GetItem(80);
     if(food){  AddFood(); }

     bool iron = GetItem(50);
     if(iron) {  AddIron(); }

     bool gold = GetItem(30);
     if(gold) {  AddGold(); }
}

You can extend the concept to have no gold as well

   void SetGoldResource()
   {
         int rand = Random.Range(0,10);

         if(rand < 2)  {  return; }     // 20% chancefor no gold
         else if(rand >=2 && rand < 6) { AddGold(1); } // 40% for 1
         else if(rand >=6 && rand < 9) { AddGold(2); } // 30% for 2
         else { AddGold(3); } // 10% for 3 
   }

You could look into an introduction to probability to see how to extend with more precision but this should be enough to begin with.