How to detect an island?

Infixo

Deity
Joined
Jan 9, 2016
Messages
4,034
Location
Warsaw
I am looking for a simple algorithm on how to detect that we are on the island. Or generally in a place with “sea” bias. It should be based only on tiles revealed. So, basically a scout is exploring and revealing a map - when and how could he determine that this is an “island” type of land?
 
It is already in the game: GlobalParameters AI_ISLAND_COAST_PERCENTAGE
I am not sure how is that related to my question? I want to write my own function for that.
On a separate note, my tests show that this parameter does not affect how the AI detects “being on an island”. Not at all. I noticed only that size of the spawn Area has something to do with that. Smaller areas generate that info faster, i.e. minors detect that fact faste than majors. But the problem is not with speed, rather with accuracy.
So, any ideas for an algorithm?
 
lua or DB methods ?
Lua. My goal is to determine, based on revealed tiles only, in what situation I am:
- small island
- bigger island
- land, but with lots of coast (like peninsulas, etc.)
- mostly land, straight line coast
- pangea, so big land, but barely any seas around
 
Are you allowed to read parameters known at map creation time (eg. map size) or is that considered cheating in this context?

I think you are looking for 2 distinct things, which will need significantly different numbers of revealed tiles to appoint:
- differentiate "lacerated/convoluted" or "smooth/straight" coast line will probably need comparably few revealed tiles.
- small island, bigger island, pangaea ... depend on the ratio of coast-tiles in a closed line to the number of land-tiles in between (area/perimeter) as well as the world size (a 1 tile island has 6 surrounding coast-tiles, ratio = ~0.167 --- --- a "standard city" island with 3 rings has 37 land-tiles and 24 surrounding coast-tiles, ratio = ~1.542) I suppose, you need a lot of revealed tiles and the world size to determine.
 
Last edited:
@cvb Map size yes, known. Human player knows much more, anyway. Just by selecting a map :)
Anyway, my thinking goes along similar lines, i.e. ratios between coast / land / sea.
Also, I am thinking about "biggest continous land". That would be e.g. all land tiles that ar at least N tiles away from the sea, The bigger the N (2..4 is enough), the more smooth this part becomes. Comparing this part to the remains should tell about the shape of the coast line.
 
  • Like
Reactions: cvb
I believe these are all valid in a GameplayScript

From the cold war scenario
Code:
		-- Reveal the map to all players.
		local pCurPlayerVisibility = PlayersVisibility[pPlayer:GetID()];
		if(pCurPlayerVisibility ~= nil) then
			pCurPlayerVisibility:RevealAllPlots();
		end
From the Alexander Scenario (tho it is also for setting visibility of a plot rather than checking for visibility)
Code:
local function SetInitialVisibility()

	print ("SetInitialVisibility");

	-- Apply updates to all majors
	local aPlayers = PlayerManager.GetAliveMajors();
	for loop, pPlayer in ipairs(aPlayers) do
		if(pPlayer:IsHuman() == true) then
			local iPlayer = pPlayer:GetID();
	
			local pCurPlayerVisibility = PlayersVisibility[pPlayer:GetID()];
			if(pCurPlayerVisibility ~= nil) then
		
				-- Reveal Balkans and Turkey
				for iX = 0, 17, 1 do
					for iY = 25, 36, 1 do
						local iPlotIndex = Map.GetPlot(iX, iY):GetIndex();
						pCurPlayerVisibility:ChangeVisibilityCount(iPlotIndex, 1);
					end
				end
            .................and a bunch more stuff.......

This is from WorldViewIconsManager.lua (ie, UI context) so may not be usable in a GameplayScript
Code:
	local eObserverID = Game.GetLocalObserver();
	local pLocalPlayerVis = PlayerVisibilityManager.GetPlayerVisibility(eObserverID);

	if (pLocalPlayerVis ~= nil) then
		local iCount = Map.GetPlotCount();
		for plotIndex = 0, iCount-1, 1 do

			local visibilityType = pLocalPlayerVis:GetState(plotIndex);
			if (visibilityType == RevealedState.HIDDEN) then
				RemoveAll(plotIndex);
			else		
				if (visibilityType == RevealedState.REVEALED) then
					ChangeToMidFog(plotIndex);
				else
					if (visibilityType == RevealedState.VISIBLE) then
						ChangeToVisible(plotIndex);
					end
				end
			end
		end
	end
end




From Civ6Common.lua (so "IsVisible" may only be valid in UI context)
Code:
		local results:table;
		if (PlayersVisibility[eAttackingPlayer]:IsVisible(plotX, plotY)) then
			results = CombatManager.IsAttackChangeWarState(eUnitComponentID, plotX, plotY);
			if (results ~= nil and #results > 0) then
				bWillStartWar = true;
			end
		end
We can find how many plots belong to the same "Area" of a plot via Plot:GetArea():GetPlotCount() but this does not tell us if a land area is detached or is part of a series of small continents all jammed together, I don't think. In Civ5 each individual landmass was its own "Area" with an assigned Area ID #, but with the way Civ6 jams multiple continents into the same landmass I am not sure this is true for Civ6 and I have not tested in any way to determine if it is or is not like Civ5.
 
LeeS, this excursion to PlayersVisibility is great! Exactly what I'm going to need when I'll port some 'Initial views' from civ4 to civ6:

"""Reveal All up to distance 2, Forests & Rivers up to distance 3, Hills & Lakes up to distance 4, Mountains & Oases up to distance 5 and Boni up to distance 6"""

The reasoning was along the intro "since generations your tribe is wandering around and now finally settles down" ... I always thought: Whow, they wandered around for generations and don't know important resources or Oases behind the next hills or forests?!

Spoiler :

civ4, Python
Code:
def revealPlots(iUnitX, iUnitY):
   """Reveal All up to distance 2, Forests & Rivers up to distance 3, Hills & Lakes up to distance 4, Mountains & Oases up to distance 5 and Boni up to distance 6"""

   for iX in range(iUnitX - 6, iUnitX + 7):
      for iY in range(iUnitY - 6, iUnitY + 7):
         cyPlot = cyMap.plot(iX, iY)
         iabsX, iabsY = abs(iX-iUnitX), abs(iY-iUnitY)

         if cyPlot.isRevealed(iTeam, False) or (iabsX==6 and iabsY==6):           # skip corners and already revealed plots
            continue

         eBT = cyPlot.getBonusType(iTeam)

         if (   (max(iabsX, iabsY) < 3)                                                                        # All
                or ( (cyPlot.isRiver() or (cyPlot.getFeatureType() == eForest)) and (max(iabsX, iabsY) < 4) )  # Forests & Rivers
                or ( (cyPlot.isHills() or cyPlot.isLake()) and (max(iabsX, iabsY) < 5) )                       # Hills & Lakes
                or ( (cyPlot.isPeak() or (cyPlot.getFeatureType() == eOasis)) and (max(iabsX, iabsY) < 6) )    # Mountains & Oases
                or ( eBT==eBanana or eBT==eClam or eBT==eCorn or eBT==eCow or eBT==eCrab or eBT==eDeer or eBT==eDye or eBT==eFish or eBT==eFur or eBT==eGems or eBT==eGold or eBT==eIncense or eBT==eIvory or eBT==eMarble or eBT==ePig or eBT==eRice or eBT==eSheep or eBT==eSilk or eBT==eSilver or eBT==eSpices or eBT==eStone or eBT==eSugar or eBT==eWhale or eBT==eWheat or eBT==eWine )   ):                                                 # Boni

            cyPlot.setRevealed(iTeam, True, False, -1)
 
We can find how many plots belong to the same "Area" of a plot via Plot:GetArea():GetPlotCount() but this does not tell us if a land area is detached or is part of a series of small continents all jammed together, I don't think. In Civ5 each individual landmass was its own "Area" with an assigned Area ID #, but with the way Civ6 jams multiple continents into the same landmass I am not sure this is true for Civ6 and I have not tested in any way to determine if it is or is not like Civ5.
AFAIK it's mostly the same as for civ5.

An area is either a landmass (which could include multiple continents) or a water body.

Mountains and impassable plots (like ice or some NW) define their own area.
 
Is this part of an AI script?

I've not done this in Civ 6, but in other ventures, getting a unit to figure out it's on some kind of dead-end structure involves using variations of the A* routine, which you can find examples of online. Basically you would determine you are on an island if the Scout could find no paths to a movable tile, and if the total number of tiles considered was beneath some threshold.

I don't know how doable A* is with Civ 6 Lua. Presumably some version of it is done in the core DLL files. I can say I have written A* routines in old Flash ActionScript and if done correctly it may not need excessive overhead. It does depend somewhat though on how frequently you need to call this routine.

Something to think about: is it the unit that knows this, or the AI Player? Both are somewhat different considerations. Especially if you are okay with an AI Player only "realizing" they are on an island every 10-20 turns or so instead of with every move.
 
@isau AI Player, and the algorithm doesn't run every turn, no need for that. Rather every 3-5 turns. It is not for operational purposes, but for deciding about high-level strategies.
As for now I've implemented a very simple yet effective approach that checks for what I call "an extended coast". So, basically if a tile has sea water within N tiles, then it is a CoastN tile. Standard Lua IsCoastalLand() basically checks for Coast1.
I tested several maps and calculated ratio of Coast2 and Coast3 to the total land, then assigned kind of "how landy or islandy the map is" factor and got a strong correlation (R2>0.99).
 
BTW there may be a way to cheat a litlt
@isau AI Player, and the algorithm doesn't run every turn, no need for that. Rather every 3-5 turns. It is not for operational purposes, but for deciding about high-level strategies.
As for now I've implemented a very simple yet effective approach that checks for what I call "an extended coast". So, basically if a tile has sea water within N tiles, then it is a CoastN tile. Standard Lua IsCoastalLand() basically checks for Coast1.
I tested several maps and calculated ratio of Coast2 and Coast3 to the total land, then assigned kind of "how landy or islandy the map is" factor and got a strong correlation (R2>0.99).


Sounds like you've got something good going. Congrats.
 
Just read this now, but for what its worth your concept of analysing the ratio of Coast1, Coast2, Coast3 : Total Land I think is a very practical idea and I'm sure will be successful.

An efficiency you may have is that those ratios are likely to be highly correlated, so you may in fact obtain what you want by reducing your input features to just 1 ratio, e.g. coast2 : Total land.

Testing on several maps and to obtain some broad ranges was also a good idea. Can't offer improvements!
 
An efficiency you may have is that those ratios are likely to be highly correlated, so you may in fact obtain what you want by reducing your input features to just 1 ratio, e.g. coast2 : Total land.
Indeed, they are.
I decided to use Coast2 as it gives best results.
For Coast1 results tend to be closer to each other, and they got mixed sometimes.
For Coast3 the trend line is not straight for heavy coasts and islands.
So, Coast2 it is then.
 
Back
Top Bottom