Adding Percentage to My RNG

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By CameronTheNinja

I’m trying to make my dungeon auto-generate randomly and such, which includes the floor. I have a few floor tiles I want to use, but I want one to appear more often than the others, I want my first one to have like a 70% or 80% chance to be the tile spawned and then my other ones to have like 5% or 10% chance to be the one that spawns. What way would I go about this other than adding a bunch of duplicates to my tilemap and using a normal random number generator?

:bust_in_silhouette: Reply From: timothybrentwood

Adding a bunch of tiles would be imo the most elegant solution but not for that disparate of percentages. Otherwise, you could create a tuple of [tile_type, percent_chance] and select one randomly. The only stipulations for this implementation is that the integer percent chances are in descending order as demonstrated AND that none of the chances are the same integer. This implementation assumes higher roll = better or more rare.

var tile_rarities = [[0, 80], [1, 10], [2, 5], [3,4]]
# list = [[tile_type, integer_percent_chance], [tile_type, integer_percent_chance],...]
func get_random_tile_type(list):
	var total = 0
	for pair in list:
		total += pair[1]
	
	randomize()
	var roll = randi() % int(total) + 1
	# default value just in case
    var chosen_tile = list[0][0]
	
	for pair in list:
		if roll <= pair[1]:
			chosen_tile = pair[0]
			break
		else:
			roll -= pair[1]
		
	return chosen_tile

Hmm, I don’t think I could fit all of that where I’m trying to put it. I mean, I was just trying to ass this into my auto-generated floor. Which is already in a function, and if I’m not mistaken, I can’t throw a function within a function. I guess I’ll do it the dumb way I said before, I could always use what you typed for loot drops or something.

CameronTheNinja | 2021-05-05 17:49

You can call a function from within a function though…

extends TileMap

func generate_map():
    var tile_rarities = [[0, 80], [1, 10], [2, 5], [3,4]]
    for row in range(_max_rows):
        for col in range(_max_cols):
            var selected_tile_type = get_random_tile_type(tile_rarities)
            self.set_cell(row, col, selected_tile_type)

func get_random_tile_type(list):
    var total = 0
    for pair in list:
        total += pair[1]

    randomize()
    var roll = randi() % int(total) + 1
    # default value just in case
    var chosen_tile = list[0][0]

    for pair in list:
        if roll <= pair[1]:
            chosen_tile = pair[0]
            break
        else:
            roll -= pair[1]

    return chosen_tile

That’s in fact how you should write code, it makes it more modular, maintainable and readable.

timothybrentwood | 2021-05-05 18:07