Verifying Adjacent Plot

OrionVeteran

Deity
Joined
Dec 25, 2003
Messages
2,443
Location
Newport News VA
I am having a problem with the following function:

Spoiler :

Code:
def isAdjacentCityPlot(pUnit):
	# Orion's Army Mod
	# Returns True if the unit is on a plot adjacent to a city
	# Returns False if the unit is Not on a plot adjacent to a city
	isAdjacentPlot = False
	iOwner = pUnit.getOwner()	
	iPlotX = pUnit.getX()
	iPlotY = pUnit.getY()
	pUnitPlot = CyMap().plot(iPlotX, iPlotY)	
	
	for iGamePlayer in range(gc.getMAX_PLAYERS()):
		GamePlayer = gc.getPlayer(iGamePlayer)
		if GamePlayer.isAlive():	
			for iCity in range(GamePlayer.getNumCities()):
				pCity = GamePlayer.getCity(iCity)
				iCityOwner = pCity.getOwner()		
				iX = pCity.getX()
				iY = pCity.getY()
				pCityPlot = CyMap().plot(iX, iY)
				if iCityOwner != iOwner:
					for iPlotLoop in range(CyMap().numPlots()):
						pLoopPlot = CyMap().plotByIndex(iPlotLoop)
						if pLoopPlot != pCityPlot:
							iDistanceFromCity = CyMap().calculatePathDistance(pCityPlot, pLoopPlot)	
							if iDistanceFromCity == 1:		
								if (pLoopPlot.getOwner() != -1):
									CyInterface().addImmediateMessage("B", "")
									[COLOR="Red"]if pUnitPlot == pLoopPlot:[/COLOR]						
										CyInterface().addImmediateMessage("Found Adjacent Plot", "")
										isAdjacentPlot = True
										break
										break
										break


The code fails to get beyond the red line. I don't know why.
 
I found a much better way to do it:

Spoiler :

Code:
def isAdjacentCityPlot(pUnit):
	# Orion's Army Mod
	# Returns True if the unit is on a plot adjacent to a city
	# Returns False if the unit is Not on a plot adjacent to a city
	isAdjacentPlot = False
	iOwner = pUnit.getOwner()
	pPlayer = gc.getPlayer(iOwner)	
	iPlotX = pUnit.getX()
	iPlotY = pUnit.getY()
	pUnitPlot = CyMap().plot(iPlotX, iPlotY)	
		
	for iPlotLoop in range(CyMap().numPlots()):
		pLoopPlot = CyMap().plotByIndex(iPlotLoop)
		iLoopPlotOwner = pLoopPlot.getOwner()
		
		if iLoopPlotOwner != -1:
			if iLoopPlotOwner != iOwner:
				if pLoopPlot != pUnitPlot:
					if pLoopPlot.isCity():
						iDistanceFromUnit = CyMap().calculatePathDistance(pUnitPlot, pLoopPlot)					
						if iDistanceFromUnit == 1:
							CyInterface().addImmediateMessage("Found Adjacent Plot", "")
							isAdjacentPlot = True
							break
	
	if isAdjacentPlot:
		return True
		
	else:
		return False


This code tested OK.
 
That still seems like the hard, or at least slow, way to do it.

You shouldn't need to check every plot on the map to see if it adjacent to the unit.

Get the unit's current position. Check the plots that are adjacent to that plot. If there is a city in one of those plots, then you are adjacent to a city. You can probably skip the check if there is a city in the plot that the unit is in...

There is even a function in Civ's Python called "plotDirection" that will get you the plot that is adjacent to a plot in a specific direction, using the DirectionTypes data. This uses a function of the CyGameCoreUtils part of the DLL (it's actually an inlined function defined in CvGameCoreUtils.h).

It should be used something like this:
Code:
adjacentPlot = plotDirection( iX, iY, iDirection)
The "iDirection" value can be any of the DirectionType.DIRECTION_NORTH etc. values, which range from 0 for north around clockwise to 7 for northwest, so you can loop over values from 0 to 7 (or, better, from 0 to DirectionTYpes.NUM_DIRECTIONS) - there is also a function for this "DirectionTypes(iI)" that returns the iI-th direction code. If you pass plotDirection a direction of -1 (DirectionType.NO_DIRECTION) it returns the plot at iX,iY.

This function takes care of map wrapping, returning nothing if the adjacent plot is off the edge of the map in a direction that doesn't wrap.

It is used in various map generators and a few other places.

So a much shorter and faster version would be:
Code:
def isAdjacentCityPlot(pUnit):
	# Orion's Army Mod
	# Returns True if the unit is on a plot adjacent to a city
	# Returns False if the unit is Not on a plot adjacent to a city
	isAdjacentPlot = False
	iOwner = pUnit.getOwner()
	pPlayer = gc.getPlayer(iOwner)	
	iPlotX = pUnit.getX()
	iPlotY = pUnit.getY()

	for iDirection in range(DirectionTypes.NUM_DIRECTION_TYPES):
		pLoopPlot = plotDirection( iPlotX, iPlotY, DirectionTypes(iDirection))
		
		if not pLoopPlot.isNone(): #make sure it is not None
			if pLoopPlot.isCity():
				CyInterface().addImmediateMessage("Found Adjacent Plot", "")
				isAdjacentPlot = True
				break

	if isAdjacentPlot:
		return True
		
	return False
I have not tested this, but it should be about right.

Note that I left out some stuff from your function. You were checking to see if the plot was owned by someone other than the unit's owner too - I did not.
 
I have not tested this, but it should be about right. Note that I left out some stuff from your function. You were checking to see if the plot was owned by someone other than the unit's owner too - I did not.

Thanks for the efficiency improvement. It worked perfectly with my additional checks! I have two mods that will benefit from this function.

:thanx:
 
Where is the plotDirection() function defined? Because its not in the API!
 
Yes, I know it isn't. Seems like an oversight. The API pages appears to define the objects you have access to and their associated methods. It doesn't seem to mention the functions that are not part of an object that you have access too.

You can see a list of functions made accessible to Python in CyGameCoreUtilsInterface.cpp. Note that in this file there is no line like "python::class_<CyGame>("CyGame")" which you'd find in the other *Interface.cpp files (this example taken from CyGameInterface.cpp). These are all available directly - you just say "pPlot = plotDirection(...)" rather than the more typical "x = pCyThingy.somethingOrOther(...)".

I expect the definitions are actually loaded into the Python code via the "from CvPythonExtensions import *" line you find all over the place.

The actual definitions of the functions on the C++ end is in the various ".h" files listed at the start of CyGameCoreUtilsInterface.cpp or their associated .cpp files, but I expect that most of them come from CvGameCoreUtils.* (for example, plotDirection() is actually defined in CvGameCoreUtils.h, not .cpp). It looks like all of the functions set up in CyGameCoreUtilsInterface.cpp that start "cy" are defined in CyGameCoreUtils.h/.cpp as wrappers to call functions defined in the various other .cpp files, and the functions that don't start with "cy" are defined directly in the various .h files that are included at the beginning of CyGameCoreUtilsInterface.cpp.
 
I'll have to look into this, some day. Too bad these functions aren't properly documented... :p
 
Top Bottom