Narnius McDoodle Narnius McDoodle - 1 year ago 59
Python Question

How can I randomly populate a list of lists in Python?

I have been trying to produce an exploration game, so naturally I started with a world generator. I am stuck, however, on populating my list of biomes. The "biome_map" list is essentially an array that is equal in width and height to whatever size the user requested. Here is the code I have written:

EWbiome_map = [] #produces an empty row that is E_W_Size km wide
for chunk1 in range (1, (E_W_Size + 1)):
EWbiome_map = EWbiome_map + ["empty"]

biome_map = []

for chunk2 in range (1, (N_S_Size + 1)):
biome_map = biome_map + [EWbiome_map]
print ("Map Initialized")
print ("Assigning Biomes...") # produces an empty array
print (biome_map)

Seed1 = Seed
random.seed (Seed)
x = 0
for element in biome_map:
y = 0
for chunk3 in element:
(biome_map[x])[y] = random.choice (biome_list)
y = y + 1
x = x + 1
print ("Biomes Assigned")
print (biome_map)

The error shows up in the result, where each list is a copy of the last.

Modules Successfully Imported
Biomes Initialized
Map Initialized
Assigning Biomes...
[['empty', 'empty', 'empty'], ['empty', 'empty', 'empty'],['empty', 'empty', 'empty']]
Biomes Assigned
[['tundra', 'tundra', 'plateaus'], ['tundra', 'tundra', 'plateaus'], ['tundra', 'tundra', 'plateaus']]

Answer Source

Your problem is the line

biome_map = biome_map + [EWbiome_map]

You are making biome_map to be a list where each element is the list EWbiome_map. Note that each element is not a copy of the list, it is the list itself. To correct this you want a copy of the EWbiome_map list. One way to do this is

biome_map = biome_map + [list(EWbiome_map)]

Another way is

biome_map = biome_map + [EWbiome_map[:]]

There are also other ways, but these should be clear enough.

To clarify what is happening in your code, remember that everything in Python is an object, and an object is handled internally as a pointer to where the data in the object is stored. When you add EWbiome_map to your biome_map list, that list actually stores a pointer to EWbiome_map and not the data itself. So when you change one occurrence of that data it is changed for all references everywhere.

Doing copies by list(EWbiome_map) or EWbiome_map[:] makes a new list with its own data and pointer. Now you can change one of those without affecting the others.

TL;DR Variables are handled differently in Python than in many other languages, since everything is an object. Pointers are used more extensively than you think, but the implementation is (usually) hidden from you.