-
Notifications
You must be signed in to change notification settings - Fork 481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stranded dwarf detector #3658
Comments
I'm going to try to grab this one and make a lua script. I thought of an edge case optimization too. I currently have thoughts for 3 iterations of the script (all in the same PR).
Some future add-ons possible would be able to list witch citizens are ignored, add them without having to wait for a popup, and general list management. Maybe also configure how often to check and have a status view? I'm not expecting 1 & 2 to take more than today, but 3 might take longer. If you don't hear back in 2 weeks you can assume I got busy and have someone take over/redo it. |
Got something working, and it seems pretty efficient. I've not written any DF scripts before though so I'm going in blind on the APIs. Next step is making it an alert and having it run periodically. Once I have that running I'll get a PR up and see about the ignoring feature. -- Detects and alerts when a citizen is stranded
-- by Azrazalea
local strandedUnits = {}
-- True means stranded, False means not stranded, nil means not processed
-- Used for optimizations
local strandedUnitIds = {}
local citizens = dfhack.units.getCitizens()
-- Outer loop, left-hand of find operation
for leftIndex, leftCitizen in pairs(citizens) do
local isFirst = leftIndex == 1
-- Citizens that already have been determined safe don't need processing
if strandedUnitIds[leftCitizen.id] == false then goto done end
-- Inner loop, right-hand of find operation
for rightIndex, rightCitizen in pairs(citizens) do
-- Citizens that already have been determined stranded are not helpful to check
if leftCitizen.id == rightCitizen.id or strandedUnitIds[rightCitizen.id] == true then goto nextCitizen end
if dfhack.maps.canWalkBetween(leftCitizen.pos, rightCitizen.pos) then
-- Assignments are cheap enough that it's probably not worth checking if we have already set these
strandedUnitIds[leftCitizen.id] = false
strandedUnitIds[rightCitizen.id] = false
-- If we don't use goto here the first time, then in the best case where everyone can reach everyone we only have
-- to do the inner loop once! In worse cases we'll have to do more work anyway, so this is probably worth it.
if not isFirst then goto done end
end
::nextCitizen::
end
-- Possibly stranded dwarves won't be in this list unless already processed
-- This even works for the first dwarf, since they would be in here already if not stranded
if #citizens == #strandedUnitIds then goto stopProcessing end
-- If we never hit the done or stopProcessing goto then we are stranded.
strandedUnitIds[leftCitizen.id] = true
table.insert(strandedUnits, leftCitizen)
::done::
end
::stopProcessing::
-- From warn-starving
local function getSexString(sex)
local sym = df.pronoun_type.attrs[sex].symbol
if not sym then
return ""
end
return "("..sym..")"
end
print("Number of stranded: ")
print(#strandedUnits)
for _, unit in pairs(strandedUnits) do
print('['..dfhack.units.getProfessionName(unit)..'] '..dfhack.TranslateName(dfhack.units.getVisibleName(unit))..' '..getSexString(unit.sex)..' Stress category: '..dfhack.units.getStressCategory(unit))
end |
When you're ready for feedback, feel free to open a PR. It's much easier to attach comments to specific lines in a PR review. |
However, let me just mention that I think this can be done in O(N) by grouping units by their pathability group id and then counting the groups. See |
@myk002 Yeah I was just showing that I was working on it. I assumed by the issue description there wasn't something easy like that, my lack of DF internals knowledge is making it a little hard for me to understand how the group is being calculated but it definitely looks like that'll work! Awesome. |
@myk002 Alright, got it rewritten using pathability groups! I'll have a PR up later tonight |
This came out of a discussion on Discord: a tool to detect dwarfs that have been cut off from the rest of the fort. This originated as a suggestion for detecting dwarfs that are stuck in trees, but we realized it may have other utility (such as detecting a dig or build error that cuts off part of the fort from the rest of the fort).
The idea is to iterate over all units, and for each unit, see if that unit can path to any other unit, using
dfhack.maps.canWalkBetween
. Any unit that cannot path to at least one other unit is presumably stranded somewhere and possibly in need of rescue.The calculation is O(n^2) in the number of units, so might not want to run this too very often, but the average case cost is actually a lot lower because the iteration for any given unit can stop when any unit it can path to is found, and the
canWalkBetween
check is very cheap, so running this several times per game day is fairly reasonable.The text was updated successfully, but these errors were encountered: