Skip to content
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

Add a variant of closest_points_first that takes a predicate #75961

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
3 changes: 1 addition & 2 deletions src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3809,8 +3809,7 @@ int get_auto_consume_moves( Character &you, const bool food )
bool try_fuel_fire( player_activity &act, Character &you, const bool starting_fire )
{
const tripoint_bub_ms pos = you.pos_bub();
std::vector<tripoint_bub_ms> adjacent = closest_points_first( pos, PICKUP_RANGE );
adjacent.erase( adjacent.begin() );
std::vector<tripoint_bub_ms> adjacent = closest_points_first( pos, 1, PICKUP_RANGE );

map &here = get_map();
std::optional<tripoint_bub_ms> best_fire =
Expand Down
3 changes: 1 addition & 2 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5160,8 +5160,7 @@ std::pair<item *, tripoint_bub_ms> map::_add_item_or_charges( const tripoint_bub
if( overflow && copies_remaining > 0 ) {
// ...otherwise try to overflow to adjacent tiles (if permitted)
const int max_dist = 2;
std::vector<tripoint_bub_ms> tiles = closest_points_first( pos, max_dist );
tiles.erase( tiles.begin() ); // we already tried this position
std::vector<tripoint_bub_ms> tiles = closest_points_first( pos, 1, max_dist );
const int max_path_length = 4 * max_dist;
const pathfinding_settings setting( 0, max_dist, max_path_length, 0, false, false, true, false,
false, false );
Expand Down
4 changes: 1 addition & 3 deletions src/monattack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2153,9 +2153,7 @@ bool mattack::formblob( monster *z )
}

bool didit = false;
std::vector<tripoint_bub_ms> pts = closest_points_first( z->pos_bub(), 1 );
// Don't check own tile
pts.erase( pts.begin() );
std::vector<tripoint_bub_ms> pts = closest_points_first( z->pos_bub(), 1, 1 );
creature_tracker &creatures = get_creature_tracker();
for( const tripoint_bub_ms &dest : pts ) {
Creature *critter = creatures.creature_at( dest );
Expand Down
14 changes: 9 additions & 5 deletions src/monmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "options.h"
#include "pathfinding.h"
#include "pimpl.h"
#include "point.h"
#include "rng.h"
#include "scent_map.h"
#include "sounds.h"
Expand Down Expand Up @@ -1800,11 +1801,14 @@ bool monster::attack_at( const tripoint_bub_ms &p )
static tripoint_bub_ms find_closest_stair( const tripoint_bub_ms &near_this,
const ter_furn_flag stair_type )
{
map &here = get_map();
for( const tripoint_bub_ms &candidate : closest_points_first( near_this, 10 ) ) {
if( here.has_flag( stair_type, candidate ) ) {
return candidate;
}
const map &here = get_map();
std::optional<tripoint_bub_ms> candidate = find_point_closest_first( near_this, 0, 10, [&here,
stair_type]( const tripoint_bub_ms & candidate ) {
return here.has_flag( stair_type, candidate );
} );

if( candidate != std::nullopt ) {
return *candidate;
}
// we didn't find it
return near_this;
Expand Down
6 changes: 3 additions & 3 deletions src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1175,9 +1175,9 @@ void npc::place_on_map( map *here )
return;
}

for( const tripoint_abs_ms &p : closest_points_first( pos_abs(), SEEX + 1 ) ) {
if( g->is_empty( here, p ) ) {
setpos( here, here->get_bub( p ) );
for( const tripoint_bub_ms &p : closest_points_first( pos_bub(), 1, SEEX + 1 ) ) {
if( g->is_empty( p ) ) {
setpos( p );
return;
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/npcmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3176,8 +3176,7 @@ void npc::avoid_friendly_fire()

tripoint_bub_ms center = midpoint_round_to_nearest( fr_pts );

std::vector<tripoint_bub_ms> candidates = closest_points_first( pos_bub(), 1 );
candidates.erase( candidates.begin() );
std::vector<tripoint_bub_ms> candidates = closest_points_first( pos_bub(), 1, 1 );
std::sort( candidates.begin(), candidates.end(),
[&tar, &center]( const tripoint_bub_ms & l, const tripoint_bub_ms & r ) {
return ( rl_dist( l, tar ) - rl_dist( l, center ) ) <
Expand Down
75 changes: 40 additions & 35 deletions src/point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,42 @@ std::istream &operator>>( std::istream &is, tripoint &pos )
return is;
}

std::optional<int> rectangle_size( int min_dist, int max_dist )
{
min_dist = std::max( min_dist, 0 );
max_dist = std::max( max_dist, 0 );

if( min_dist > max_dist ) {
return std::nullopt;
}

const int min_edge = min_dist * 2 + 1;
const int max_edge = max_dist * 2 + 1;

const int n = max_edge * max_edge - ( min_edge - 2 ) * ( min_edge - 2 ) + ( min_dist == 0 ? 1 : 0 );
return n;
}

std::vector<tripoint> closest_points_first( const tripoint &center, int max_dist )
{
return closest_points_first( center, 0, max_dist );
}

std::vector<tripoint> closest_points_first( const tripoint &center, int min_dist, int max_dist )
{
const std::vector<point> points = closest_points_first( center.xy(), min_dist, max_dist );
std::optional<int> n = rectangle_size( min_dist, max_dist );

if( n == std::nullopt ) {
return {};
}

std::vector<tripoint> result;
result.reserve( points.size() );
result.reserve( *n );

for( const point &p : points ) {
result.emplace_back( p, center.z );
}
find_point_closest_first( center, min_dist, max_dist, [&result]( const tripoint & p ) {
result.push_back( p );
return false;
} );

return result;
}
Expand All @@ -143,42 +164,26 @@ std::vector<point> closest_points_first( const point &center, int max_dist )

std::vector<point> closest_points_first( const point &center, int min_dist, int max_dist )
{
min_dist = std::max( min_dist, 0 );
max_dist = std::max( max_dist, 0 );
std::optional<int> n = rectangle_size( min_dist, max_dist );

if( min_dist > max_dist ) {
if( n == std::nullopt ) {
return {};
}

const int min_edge = min_dist * 2 + 1;
const int max_edge = max_dist * 2 + 1;

const int n = max_edge * max_edge - ( min_edge - 2 ) * ( min_edge - 2 );
const bool is_center_included = min_dist == 0;

std::vector<point> result;
result.reserve( n + ( is_center_included ? 1 : 0 ) );

if( is_center_included ) {
result.push_back( center );
}
result.reserve( *n );

int x_init = std::max( min_dist, 1 );
point p( x_init, 1 - x_init );

point d( point::east );

for( int i = 0; i < n; i++ ) {
result.push_back( center + p );

if( p.x == p.y || ( p.x < 0 && p.x == -p.y ) || ( p.x > 0 && p.x == 1 - p.y ) ) {
std::swap( d.x, d.y );
d.x = -d.x;
}

p.x += d.x;
p.y += d.y;
}
find_point_closest_first( center, min_dist, max_dist, [&result]( const point & p ) {
result.push_back( p );
return false;
} );

return result;
}

template <typename PredicateFn, typename Point>
std::optional<Point> find_point_closest_first( const Point &center, int max_dist,
PredicateFn &&fn )
{
return find_point_closest_first( center, 0, max_dist, fn );
}
65 changes: 65 additions & 0 deletions src/point.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <optional>
#include <ostream>
#include <vector>

Expand Down Expand Up @@ -358,6 +359,18 @@ std::vector<tripoint> closest_points_first( const tripoint &center, int min_dist
std::vector<point> closest_points_first( const point &center, int max_dist );
std::vector<point> closest_points_first( const point &center, int min_dist, int max_dist );

template <typename PredicateFn, typename Point>
std::optional<Point> find_point_closest_first( const Point &center, int min_dist, int max_dist,
PredicateFn &&fn );

template <typename PredicateFn, typename Point>
std::optional<Point> find_point_closest_first( const Point &center, int max_dist,
PredicateFn &&fn );


// Calculate the number of tiles in a square from min_dist to max_dist about an arbitrary centre.
std::optional<int> rectangle_size( int min_dist, int max_dist );

// Make point hashable so it can be used as an unordered_set or unordered_map key,
// or a component of one.
namespace std
Expand Down Expand Up @@ -442,4 +455,56 @@ inline constexpr const std::array<tripoint, 8> eight_horizontal_neighbors = { {
}
};

/* Return points in a clockwise spiral from min_dist to max_dist, inclusive, ordered by
* the closest points first. The distance is calculated using roguelike distances, so
* movement in any direction only counts as 1.
*
* The predicate function is evaluated on each point. If the function returns true, the
* point is returned. If the predicate function never returns true then std::nullopt is
* returned once max_dist is reached.
*
* @param center The center of the spiral.
* @param min_dist minimum distance to start the spiral from.
* @param max_dist greatest distance from the centre that the spiral will go to.
* @returns std::nullopt if min_dist > max_dist or predicate_fn evaluated to true for
* no points.
*/
template <typename PredicateFn, typename Point>
std::optional<Point> find_point_closest_first( const Point &center, int min_dist, int max_dist,
PredicateFn &&predicate_fn )
{
const std::optional<int> n = rectangle_size( min_dist, max_dist );

if( n == std::nullopt ) {
return {};
}

const bool is_center_included = min_dist == 0;

if( is_center_included && predicate_fn( center ) ) {
return center;
}

int x_init = std::max( min_dist, 1 );
point p {x_init, 1 - x_init};

point d = point::east;

for( int i = is_center_included; i < *n; i++ ) {
const Point next = Point{ center.raw() + p.raw() };
if( predicate_fn( next ) ) {
return next;
}

if( p.x == p.y || ( p.x < 0 && p.x == -p.y ) || ( p.x > 0 && p.x == 1 - p.y ) ) {
std::swap( d.x, d.y );
d.x = -d.x;
}

p += d;
}

return std::nullopt;
}

#endif // CATA_SRC_POINT_H
9 changes: 5 additions & 4 deletions src/ranged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2238,6 +2238,7 @@ static void cycle_action( item &weap, const itype_id &ammo, const tripoint_bub_m
} ), tiles.end() );
tripoint_bub_ms eject{ tiles.empty() ? pos : random_entry( tiles ) };


// for turrets try and drop casings or linkages directly to any CARGO part on the same tile
const std::optional<vpart_reference> ovp_cargo = weap.has_flag( flag_VEHICLE )
? here.veh_at( pos ).cargo()
Expand Down Expand Up @@ -3156,12 +3157,12 @@ tripoint_bub_ms target_ui::choose_initial_target()

// Try closest practice target
map &here = get_map();
const std::vector<tripoint_bub_ms> nearby = closest_points_first( src, range );
const auto target_spot = std::find_if( nearby.begin(), nearby.end(),
[this, &here]( const tripoint_bub_ms & pt ) {
std::optional<tripoint_bub_ms> target_spot = find_point_closest_first( src, 0, range, [this,
&here]( const tripoint_bub_ms & pt ) {
return here.tr_at( pt ).id == tr_practice_target && this->you->sees( pt );
} );
if( target_spot != nearby.end() ) {

if( target_spot != std::nullopt ) {
return *target_spot;
}

Expand Down
Loading