fix(bots): a bank a bot can press, and one it can walk to #237

Merged
sickday merged 4 commits from fix/bank-stands-and-site-pairing into main 2026-08-19 01:52:06 +00:00
Owner

Reported as fishers at Barbarian Village that fish one pack and then forget
their rod: they come back to the water, cannot fish, and walk east again.
The rod is in the pack the whole time. :working's first clause is
backpack_free == 0 -> travel_to_bank, so "cannot fish" and "walks back to
the bank" are the same tick -- the bank never opened, and the pack was still
full. Three faults, each hidden by the one in front of it.

The pairing only ever asked distance. same_plane_bank/2 took the nearest
bank by chebyshev inside the same map area, and for both Barbarian Village
grounds that is booth 7409 at {0, 3147, 3449} -- 38 tiles against Edgeville's
57, and inside the Cooking Guild: a fourteen-tile room with the Head chef at
{0, 3143, 3444} and a door in front of it. The arithmetic was right every
time and the answer was a bank no bot can enter.

The derived stand could not press the booth anyway, on 49 of 74 banks.
standable/1 scored ring candidates by the size of the connected region they
stand in, which answers whether a bot can get out of there and never whether
it can press the booth from there. The nearest open tile to a booth is
regularly its diagonal, and a diagonal is the one neighbour
Flags.interactable_from?/4 refuses -- Edgeville, Varrock, Draynor, Al Kharid,
Falador, Ardougne and Seers' among them. It stayed invisible because a loc
click routes itself: Movement.approach/4 walks the player into reach on the
way to firing, so one step off a diagonal is free. It is free right up until
the tile the bot clicked from is in another component, where approach/4
answers [] -- which is also its answer for "you are already standing there".
The click then fires from out of reach and the engine says nothing, because a
refusal a person would read in the chatbox does not exist for a bot.

And the bank leg stopped three tiles short of the answer. Bot.Sites had
already chosen which face of the booth to work from; reach: 3 threw that away
and made the click re-derive it from wherever the walk happened to end.

So: booth_stand/2 filters the ring through Contract.Reach before scoring it,
and every one of the 49 has a workable tile inside the nudge, so no bank is
lost to the stricter question. enclosure/1 is a bounded 3,000-tile fill from
each bank's stand, run once per bank at derivation -- a fill that saturates is
the open world and pairs with anything, one that stops short is a pocket, and
only a site standing inside it may have that bank. Twenty-five of seventy-four
are pockets. The fill is deliberately not stored: a site holds its bank by
value, and nine hundred copies of a three-thousand-tile set is the collision
map again. @bank_reach is 1 in both gathering goals, so the leg ends on the
stand rather than near it.

Barbarian Village pairs with Edgeville now. Watched on a live sitting: the
booth opens, twenty-six fish land in the bank, the bot walks back and
re-acquires the spot at its new index, having relocated while the bot was
away.

The stricter pairing drops sites whose only bank in range was a pocket they
are not in -- trees 800 -> 679, rocks 72 -> 48, fishing grounds 33 -> 25.
Every one of those was a site a bot would have walked to and then failed at,
and a site table that offers a click the engine would refuse is worse than one
that offers none. Arctic pine derives no site at all now, because Neitiznot's
bank is one of the pockets; its test is retargeted at the chop verb it was
really about, and a second test names the gap and says to delete itself when
it closes. That gap is that nothing opens a door into a bank pocket:
Bot.Obstacle.between/2 asks whether the bot is shut in, not whether the
destination is, so outside the fill hits its budget, answers not shut in, and
no door is ever tried.

Bot.Sites.nearest_bank/1 still answers by distance alone. It is asked at
runtime by a bot that has a position and no budget for a flood fill, so it can
still hand a gated bank to Bot.Travel.recover/2 or to a pker looking for home.

Reported as fishers at Barbarian Village that fish one pack and then forget their rod: they come back to the water, cannot fish, and walk east again. The rod is in the pack the whole time. `:working`'s first clause is `backpack_free == 0 -> travel_to_bank`, so "cannot fish" and "walks back to the bank" are the same tick -- the bank never opened, and the pack was still full. Three faults, each hidden by the one in front of it. The pairing only ever asked distance. `same_plane_bank/2` took the nearest bank by chebyshev inside the same map area, and for both Barbarian Village grounds that is booth 7409 at {0, 3147, 3449} -- 38 tiles against Edgeville's 57, and inside the Cooking Guild: a fourteen-tile room with the Head chef at {0, 3143, 3444} and a door in front of it. The arithmetic was right every time and the answer was a bank no bot can enter. The derived stand could not press the booth anyway, on 49 of 74 banks. standable/1 scored ring candidates by the size of the connected region they stand in, which answers whether a bot can get out of there and never whether it can press the booth from there. The nearest open tile to a booth is regularly its diagonal, and a diagonal is the one neighbour Flags.interactable_from?/4 refuses -- Edgeville, Varrock, Draynor, Al Kharid, Falador, Ardougne and Seers' among them. It stayed invisible because a loc click routes itself: Movement.approach/4 walks the player into reach on the way to firing, so one step off a diagonal is free. It is free right up until the tile the bot clicked from is in another component, where approach/4 answers [] -- which is also its answer for "you are already standing there". The click then fires from out of reach and the engine says nothing, because a refusal a person would read in the chatbox does not exist for a bot. And the bank leg stopped three tiles short of the answer. Bot.Sites had already chosen which face of the booth to work from; reach: 3 threw that away and made the click re-derive it from wherever the walk happened to end. So: booth_stand/2 filters the ring through Contract.Reach before scoring it, and every one of the 49 has a workable tile inside the nudge, so no bank is lost to the stricter question. enclosure/1 is a bounded 3,000-tile fill from each bank's stand, run once per bank at derivation -- a fill that saturates is the open world and pairs with anything, one that stops short is a pocket, and only a site standing inside it may have that bank. Twenty-five of seventy-four are pockets. The fill is deliberately not stored: a site holds its bank by value, and nine hundred copies of a three-thousand-tile set is the collision map again. @bank_reach is 1 in both gathering goals, so the leg ends on the stand rather than near it. Barbarian Village pairs with Edgeville now. Watched on a live sitting: the booth opens, twenty-six fish land in the bank, the bot walks back and re-acquires the spot at its new index, having relocated while the bot was away. The stricter pairing drops sites whose only bank in range was a pocket they are not in -- trees 800 -> 679, rocks 72 -> 48, fishing grounds 33 -> 25. Every one of those was a site a bot would have walked to and then failed at, and a site table that offers a click the engine would refuse is worse than one that offers none. Arctic pine derives no site at all now, because Neitiznot's bank is one of the pockets; its test is retargeted at the chop verb it was really about, and a second test names the gap and says to delete itself when it closes. That gap is that nothing opens a door into a bank pocket: Bot.Obstacle.between/2 asks whether the bot is shut in, not whether the destination is, so outside the fill hits its budget, answers not shut in, and no door is ever tried. Bot.Sites.nearest_bank/1 still answers by distance alone. It is asked at runtime by a bot that has a position and no budget for a flood fill, so it can still hand a gated bank to Bot.Travel.recover/2 or to a pker looking for home.
fix(bots): a bank a bot can press, and one it can walk to
All checks were successful
ci / gates (pull_request) Successful in 4m3s
9cb8741bb3
Reported as fishers at Barbarian Village that fish one pack and then forget
their rod: they come back to the water, cannot fish, and walk east again.
The rod is in the pack the whole time. `:working`'s first clause is
`backpack_free == 0 -> travel_to_bank`, so "cannot fish" and "walks back to
the bank" are the same tick -- the bank never opened, and the pack was still
full. Three faults, each hidden by the one in front of it.

The pairing only ever asked distance. `same_plane_bank/2` took the nearest
bank by chebyshev inside the same map area, and for both Barbarian Village
grounds that is booth 7409 at {0, 3147, 3449} -- 38 tiles against Edgeville's
57, and inside the Cooking Guild: a fourteen-tile room with the Head chef at
{0, 3143, 3444} and a door in front of it. The arithmetic was right every
time and the answer was a bank no bot can enter.

The derived stand could not press the booth anyway, on 49 of 74 banks.
standable/1 scored ring candidates by the size of the connected region they
stand in, which answers whether a bot can get out of there and never whether
it can press the booth from there. The nearest open tile to a booth is
regularly its diagonal, and a diagonal is the one neighbour
Flags.interactable_from?/4 refuses -- Edgeville, Varrock, Draynor, Al Kharid,
Falador, Ardougne and Seers' among them. It stayed invisible because a loc
click routes itself: Movement.approach/4 walks the player into reach on the
way to firing, so one step off a diagonal is free. It is free right up until
the tile the bot clicked from is in another component, where approach/4
answers [] -- which is also its answer for "you are already standing there".
The click then fires from out of reach and the engine says nothing, because a
refusal a person would read in the chatbox does not exist for a bot.

And the bank leg stopped three tiles short of the answer. Bot.Sites had
already chosen which face of the booth to work from; reach: 3 threw that away
and made the click re-derive it from wherever the walk happened to end.

So: booth_stand/2 filters the ring through Contract.Reach before scoring it,
and every one of the 49 has a workable tile inside the nudge, so no bank is
lost to the stricter question. enclosure/1 is a bounded 3,000-tile fill from
each bank's stand, run once per bank at derivation -- a fill that saturates is
the open world and pairs with anything, one that stops short is a pocket, and
only a site standing inside it may have that bank. Twenty-five of seventy-four
are pockets. The fill is deliberately not stored: a site holds its bank by
value, and nine hundred copies of a three-thousand-tile set is the collision
map again. @bank_reach is 1 in both gathering goals, so the leg ends on the
stand rather than near it.

Barbarian Village pairs with Edgeville now. Watched on a live sitting: the
booth opens, twenty-six fish land in the bank, the bot walks back and
re-acquires the spot at its new index, having relocated while the bot was
away.

The stricter pairing drops sites whose only bank in range was a pocket they
are not in -- trees 800 -> 679, rocks 72 -> 48, fishing grounds 33 -> 25.
Every one of those was a site a bot would have walked to and then failed at,
and a site table that offers a click the engine would refuse is worse than one
that offers none. Arctic pine derives no site at all now, because Neitiznot's
bank is one of the pockets; its test is retargeted at the chop verb it was
really about, and a second test names the gap and says to delete itself when
it closes. That gap is that nothing opens a door into a bank pocket:
Bot.Obstacle.between/2 asks whether the bot is shut in, not whether the
destination is, so outside the fill hits its budget, answers not shut in, and
no door is ever tried.

Bot.Sites.nearest_bank/1 still answers by distance alone. It is asked at
runtime by a bot that has a position and no budget for a flood fill, so it can
still hand a gated bank to Bot.Travel.recover/2 or to a pker looking for home.
test(bots): ask the rotator's own level for the site it is spawned at
All checks were successful
ci / gates (pull_request) Successful in 3m25s
120f8f84e8
The rotation world test picked its spawn from `rock_sites(41)` and put a
**level-5** body on it. That held only while the closest site-and-bank pair in
the world happened to be a level-1 rock: Port Khazard, nine tiles. Moving the
derived bank stands onto tiles the booth can actually be pressed from shifted
Lovakengj's to seven, so the closest pair became a level-30 rock the rotator
cannot touch. It then set off for the nearest rock it *can* mine -- 168 tiles
across Kourend -- and the await timed out, which reads as a bank that would
not open and is a body standing at rocks that are not its.

Ask at `rotation_levels(:miner, config).mining` and the fixture is the bot's
own question again. It is the same mistake the comment three lines down
already warns about for the tools, one line up: a number that is right for the
table is not right for the body.
Merge branch 'main' into fix/bank-stands-and-site-pairing
Some checks failed
ci / gates (pull_request) Has been cancelled
5f635adf9c
Merge branch 'main' into fix/bank-stands-and-site-pairing
All checks were successful
ci / gates (pull_request) Successful in 3m46s
build / image (push) Successful in 56s
ci / gates (push) Successful in 3m46s
302d2fcbb0
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Revenant/Server!237
No description provided.