BonusBalancer is deterministic

Joined
Dec 5, 2005
Messages
3,663
Note: I discovered this in BTS 3.13, but it appears to be present in all versions, and has been for some time. Moderator, please move this report if it is more appropriate to another forum.

The BonusBalancer.normalizeAddExtras method in CvMapGeneratorUtil.py places the strategic resources by scanning the plots in a predictable order.

As a result, players who are familiar with the order that the plots are scanned can anticipate the precise location of those resources before they are revealed.

The most straight forward method for eliminating the problem is to random.shuffle(plots) after the array of plots is constructed, but before iterating through them.

Code:
plots = [] # build a list of the plots near the starting plot
for dx in range(-5,6):
	for dy in range(-5,6):
		x,y = startx+dx, starty+dy
		pLoopPlot = self.map.plot(x,y)
		if not pLoopPlot.isNone():
			plots.append(pLoopPlot)

resources_placed = []
for pass_num in range(4):
	bIgnoreUniqueRange  = pass_num >= 1
	bIgnoreOneArea 		= pass_num >= 2
	bIgnoreAdjacent 	= pass_num >= 3
	
	for bonus in range(self.gc.getNumBonusInfos()):
		type_string = self.gc.getBonusInfo(bonus).getType()
		if (type_string not in resources_placed) and (type_string in self.resourcesToBalance):
			for (pLoopPlot) in plots:
 
Hi all,
So I know everyone is aware of this since 2007... still I thought the fix would as easy as described above,
But when I do the simple addition of " random.shuffle(plots)"
Code:
    def normalizeAddExtras(self):
 
        for i in range(self.gc.getMAX_CIV_PLAYERS()):
            #if (self.gc.getPlayer(i).isAlive()):
            if (self.gc.getPlayer(i).isEverAlive()):#2.22 Wow this solves a lot of things - otherwise you'll get bronze etc each time of spectator on bottom left tile(s)
                start_plot = self.gc.getPlayer(i).getStartingPlot() # returns a CyPlot
                startx, starty = start_plot.getX(), start_plot.getY()
             
                plots = [] # build a list of the plots near the starting plot
                for dx in range(-5,6):
                    for dy in range(-5,6):
                        x,y = startx+dx, starty+dy
                        pLoopPlot = self.map.plot(x,y)
                        if not pLoopPlot.isNone():
                            plots.append(pLoopPlot)
             
                resources_placed = []
             
                random.shuffle(plots)#2.34 - A miss by Firaxis
             
                for pass_num in range(4):
                    bIgnoreUniqueRange  = pass_num >= 1
                    bIgnoreOneArea         = pass_num >= 2
                    bIgnoreAdjacent     = pass_num >= 3
                 
                    for bonus in range(self.gc.getNumBonusInfos()):
                        type_string = self.gc.getBonusInfo(bonus).getType()
                        if (type_string not in resources_placed) and (type_string in self.resourcesToBalance):
                            for (pLoopPlot) in plots:
                                if (pLoopPlot.canHaveBonus(bonus, True)):
                                    if self.isBonusValid(bonus, pLoopPlot, bIgnoreUniqueRange, bIgnoreOneArea, bIgnoreAdjacent):
                                        pLoopPlot.setBonusType(bonus)
                                        resources_placed.append(type_string)
                                        #print "placed", type_string, "on pass", pass_num
                                        break # go to the next bonus

To my surprised it doesn't fix the "left-bias" of resource appearance.

I'm missing something ? How are others fixing this ?
 
Looks like it should work; are you sure your code is getting executed? I've looked up my own fix:
Git commit | amendment - prefer placing Oil on land
I'm picking a separate random offset into plots for each resource type, but I don't think this actually makes a difference. (The "DLL integration" part is just so that the DLL can tell which resources have been affected by the BonusBalancer.) On a related note, the "normalization" code in the DLL also has several noticeable biases, e.g. these two addressed by K-Mod:
K-Mod 1.21 changelog said:
Randomized the position of extra rivers and lakes added by the start-position normalizer, so that we don't always get a river on the south-east corner, and a lake on the north.
 
Thanks as always f1rpo,

You're always so fast and am always so slow ;)
I took the time to try properly...
Yes, first thing to establish was I 100% it was running : well I've commented out now and saw nothing got placed, so yeah it does run (am testing on Wheel, InlandSea anyways).
Running my logic I still found example I could not believe ran well
Running your logic am much more convinced it's good now ! I'm still baffled by some example that looks still very "left-biased", but I guess once you run all the condition (no river...no adjacent) there is only like 2-5 tiles left for Bronze/Horse/Iron to be placed!

I will use your logic going forward :)
Added bonus it's so much cleaner to handle the non-sea oil there than in the map each time

Thanks again !
 
Top Bottom