I'm working on a mod that will simulate the spread of a contagious plague. It's starting to work pretty well, but I'm having a strange problem with the list that contains all the infected plots and the level of infection.
See, it's supposed to increase the level of infection when the (already infected) plot gets re-infected by a neighboring plot, and decrease it if it happens to get better on its own. Each of these is controlled by a random number and works well.
The problem arises when the plot's infection level (stored in the second element of the list representing that plot, which is, in turn, an element in the nested list InfectedPlots) drops to zero or lower. After checking for changes in the levels of existing infections and adding new ones, the code runs a loop to remove any plots that have dropped to zero or lower from the list.
The list element representing the no-longer-infected plot is successfully removed, but then the strange thing happens: a neighboring plot gets duplicated on the list instead. So I will have the same plot appearing twice on the list (which isn't supposed to be possible--the code checks before adding to make sure it's not already there).
To remove the no-longer-infected, I am using the list.pop(i) function. I would use "remove," but it refers to the contents of the list element rather than the index, so it's less useful to me.
So, here's my code. I'm starting to get stumped here, so if anybody sees my error, please point it out.
Note: this code won't run on its own; it needs some changes to xml and native python files to do anything. However, if you want to test it, you can change the initialization of InfectedPlots to some random coordinates, and it should run okay (I haven't tried this, but I don't see why it wouldn't).
See, it's supposed to increase the level of infection when the (already infected) plot gets re-infected by a neighboring plot, and decrease it if it happens to get better on its own. Each of these is controlled by a random number and works well.
The problem arises when the plot's infection level (stored in the second element of the list representing that plot, which is, in turn, an element in the nested list InfectedPlots) drops to zero or lower. After checking for changes in the levels of existing infections and adding new ones, the code runs a loop to remove any plots that have dropped to zero or lower from the list.
The list element representing the no-longer-infected plot is successfully removed, but then the strange thing happens: a neighboring plot gets duplicated on the list instead. So I will have the same plot appearing twice on the list (which isn't supposed to be possible--the code checks before adding to make sure it's not already there).
To remove the no-longer-infected, I am using the list.pop(i) function. I would use "remove," but it refers to the contents of the list element rather than the index, so it's less useful to me.
So, here's my code. I'm starting to get stumped here, so if anybody sees my error, please point it out.
Code:
from CvPythonExtensions import *
from Popup import PyPopup
import random
gc = CyGlobalContext ()
cyGame = CyGame()
cyMap = CyMap()
cyInterface = CyInterface()
iSpreadByPlotChance = 5
iInfectUnitChance = 40
iSpreadByUnitChance = 40
iSpreadUnitToUnitChance = 30
iGetBetterChance = 15
InfectedPlots = []
InfectedUnits = []
#InfectedPlots is a list of smaller lists.
def PlagueListAdd(NewPlot):
global InfectedPlots
InfectedPlots.append([NewPlot,1])
def Plagueturn():
global InfectedPlots
global InfectedUnits
NewInfectedPlots = []
NewInfectedUnits = []
if InfectedPlots:
###Begin test thing###
bloop = ''
for blarg in InfectedPlots:
warg = blarg[0]
yikes = blarg[1]
bloop = bloop + str(warg.getX())+', '+str(warg.getY())+', level: '+str(yikes)+'\n'
tpop = PyPopup()
tpop.setHeaderString('Infected Plot List:')
tpop.setBodyString(bloop)
tpop.launch()
###end test thing###
for PlotSet in InfectedPlots: #For each of the infected plots...
ThisPlot = PlotSet[0]
Level = PlotSet[1]
Neighbors = []
x = ThisPlot.getX()
y = ThisPlot.getY()
x_range = range(x-1, x+2)
y_range = range(y-1, y+2)
for i in x_range: #Create a list of all its neighbors
for j in y_range:
if i != x or j != y:
Neighbors.append(cyMap.plot(i,j))
for ThisNeighbor in Neighbors: #For each neighbor...
if random.randint(1,100) <= iSpreadByPlotChance + ThisNeighbor.isRoute() * 5: #See if infection is spread
if InfectedPlotFind(ThisNeighbor,InfectedPlots)==-1: #If it's not already infected,
if InfectedPlotFind(ThisNeighbor,NewInfectedPlots)==-1: #And it's not already on the list about to be infected,
NewInfectedPlots.append([ThisNeighbor,1]) #add it to the list about to be infected.
else: #If it's already about to be infected,
NewInfectedPlots[InfectedPlotFind(ThisNeighbor,NewInfectedPlots)][1] += 1 #The new infection gets worse
else: #If it is already infected,
InfectedPlots[InfectedPlotFind(ThisNeighbor, InfectedPlots)][1] += 1 #The infection gets worse.
if ThisNeighbor.isCity() and InfectedPlotFind(ThisNeighbor,InfectedPlots)==-1: #Notify the first time a city is infected
ThisCity = ThisNeighbor.getPlotCity()
Owner = gc.getPlayer(ThisCity.getOwner())
tCity = (Owner.getCivilizationAdjectiveKey(), ThisCity.getName())
cyInterface.addImmediateMessage(CyTranslator().getText('Plague has spread to the %s1 city of %s2.', tCity), '')
iUnits = ThisPlot.getNumUnits()
UnitsHereIndex = range(1, iUnits) #Create a list of all units on this plot
for unit_iter in UnitsHereIndex:
ThisUnit = ThisPlot.getUnit(unit_iter)
if random.randint(1,100)<=iInfectUnitChance: #See if the units are infected
NewInfectedUnits.append(ThisUnit) #If infected, add to a new list to be appended later.
bpop = PyPopup()
bpop.setHeaderString('Infected Unit')
bpop.setBodyString(ThisUnit.getName())
bpop.launch()
if random.randint(1,100)<= iGetBetterChance:
PlotSet[1] = PlotSet[1]-1
bpop = PyPopup()
bpop.setHeaderString('Slight Improvement')
bpop.setBodyString('It is not so bad in '+str(PlotSet[0].getX())+', '+str(PlotSet[0].getY()))
bpop.launch()
trashlist = []
for PlotSet in InfectedPlots:
PlotSet[0] = ThisPlot
if PlotSet[1] >=3 and ThisPlot.isCity():
ThisCity = ThisNeighbor.getPlotCity()
Owner = gc.getPlayer(ThisCity.getOwner())
ThisCity.changePopulation(-1)
PlotSet[1] = PlotSet[1]-2
tCity = (Owner.getCivilizationAdjectiveKey(), ThisCity.getName())
cyInterface.addImmediateMessage(CyTranslator().getText('The plague is causing widespread deaths in the %s1 city of %s2.', tCity), '')
if PlotSet[1] <= 0:
trashlist.append(InfectedPlotFind(PlotSet[0],InfectedPlots))
for index in trashlist:
InfectedPlots.pop(index)
if len(InfectedPlots) ==0:
cyInterface.addImmediateMessage('Physicians believe the plague may have been eradicated.','')
for Infected in InfectedUnits: #For each unit presently infected
x = Infected.getX()
y = Infected.getY()
Here = cyMap.plot(x,y)
if random.randint(1,100)<= iSpreadByUnitChance: #If infection is spread to the unit's new location...
NewInfectedPlots.append(Here) #Add it to the new infections list
iUnits = Here.getNumUnits()
UnitsHereIndex = range(1, iUnits) #Create a list of all units on this plot
for unit_iter in UnitsHereIndex: #For each unit on the same plot...
ThisUnit = Here.getUnit(unit_iter)
if random.randint(1,100)<=iSpreadUnitToUnitChance: #See if the units are infected
NewInfectedUnits.append(ThisUnit) #If infected, add to a new list to be appended later.
#Now that we're done iterating through infected things, append the lists with the new infections.
###Begin test thing###
bloop = ''
for blarg in NewInfectedPlots:
warg = blarg[0]
yikes = blarg[1]
bloop = bloop + str(warg.getX())+', '+str(warg.getY())+', level: '+str(yikes)+'\n'
tpop = PyPopup()
tpop.setHeaderString('Newly Infected Plot List:')
tpop.setBodyString(bloop)
if NewInfectedPlots:
tpop.launch()
###end test thing###
InfectedPlots.extend(NewInfectedPlots)
InfectedUnits.extend(NewInfectedUnits)
def InfectedPlotFind(MyPlot,PlotList):
count = 0
for Entry in PlotList:
ThisPlot = Entry[0]
if ThisPlot.getX() == MyPlot.getX() and ThisPlot.getY() == MyPlot.getY():
return count
count += 1
return -1
Note: this code won't run on its own; it needs some changes to xml and native python files to do anything. However, if you want to test it, you can change the initialization of InfectedPlots to some random coordinates, and it should run okay (I haven't tried this, but I don't see why it wouldn't).