Skip to content

Commit 32ab239

Browse files
authored
Merge pull request #75961 from CLIDragon/closest_points_first
Add a variant of closest_points_first that takes a predicate
2 parents c4a84a2 + f5ce0cd commit 32ab239

File tree

9 files changed

+126
-56
lines changed

9 files changed

+126
-56
lines changed

src/activity_item_handling.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3809,8 +3809,7 @@ int get_auto_consume_moves( Character &you, const bool food )
38093809
bool try_fuel_fire( player_activity &act, Character &you, const bool starting_fire )
38103810
{
38113811
const tripoint_bub_ms pos = you.pos_bub();
3812-
std::vector<tripoint_bub_ms> adjacent = closest_points_first( pos, PICKUP_RANGE );
3813-
adjacent.erase( adjacent.begin() );
3812+
std::vector<tripoint_bub_ms> adjacent = closest_points_first( pos, 1, PICKUP_RANGE );
38143813

38153814
map &here = get_map();
38163815
std::optional<tripoint_bub_ms> best_fire =

src/map.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5162,8 +5162,7 @@ std::pair<item *, tripoint_bub_ms> map::_add_item_or_charges( const tripoint_bub
51625162
if( overflow && copies_remaining > 0 ) {
51635163
// ...otherwise try to overflow to adjacent tiles (if permitted)
51645164
const int max_dist = 2;
5165-
std::vector<tripoint_bub_ms> tiles = closest_points_first( pos, max_dist );
5166-
tiles.erase( tiles.begin() ); // we already tried this position
5165+
std::vector<tripoint_bub_ms> tiles = closest_points_first( pos, 1, max_dist );
51675166
const int max_path_length = 4 * max_dist;
51685167
const pathfinding_settings setting( 0, max_dist, max_path_length, 0, false, false, true, false,
51695168
false, false );

src/monattack.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,9 +2153,7 @@ bool mattack::formblob( monster *z )
21532153
}
21542154

21552155
bool didit = false;
2156-
std::vector<tripoint_bub_ms> pts = closest_points_first( z->pos_bub(), 1 );
2157-
// Don't check own tile
2158-
pts.erase( pts.begin() );
2156+
std::vector<tripoint_bub_ms> pts = closest_points_first( z->pos_bub(), 1, 1 );
21592157
creature_tracker &creatures = get_creature_tracker();
21602158
for( const tripoint_bub_ms &dest : pts ) {
21612159
Creature *critter = creatures.creature_at( dest );

src/monmove.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "options.h"
4242
#include "pathfinding.h"
4343
#include "pimpl.h"
44+
#include "point.h"
4445
#include "rng.h"
4546
#include "scent_map.h"
4647
#include "sounds.h"
@@ -1800,11 +1801,14 @@ bool monster::attack_at( const tripoint_bub_ms &p )
18001801
static tripoint_bub_ms find_closest_stair( const tripoint_bub_ms &near_this,
18011802
const ter_furn_flag stair_type )
18021803
{
1803-
map &here = get_map();
1804-
for( const tripoint_bub_ms &candidate : closest_points_first( near_this, 10 ) ) {
1805-
if( here.has_flag( stair_type, candidate ) ) {
1806-
return candidate;
1807-
}
1804+
const map &here = get_map();
1805+
std::optional<tripoint_bub_ms> candidate = find_point_closest_first( near_this, 0, 10, [&here,
1806+
stair_type]( const tripoint_bub_ms & candidate ) {
1807+
return here.has_flag( stair_type, candidate );
1808+
} );
1809+
1810+
if( candidate != std::nullopt ) {
1811+
return *candidate;
18081812
}
18091813
// we didn't find it
18101814
return near_this;

src/npc.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,9 +1175,9 @@ void npc::place_on_map( map *here )
11751175
return;
11761176
}
11771177

1178-
for( const tripoint_abs_ms &p : closest_points_first( pos_abs(), SEEX + 1 ) ) {
1179-
if( g->is_empty( here, p ) ) {
1180-
setpos( here, here->get_bub( p ) );
1178+
for( const tripoint_bub_ms &p : closest_points_first( pos_bub(), 1, SEEX + 1 ) ) {
1179+
if( g->is_empty( p ) ) {
1180+
setpos( p );
11811181
return;
11821182
}
11831183
}

src/npcmove.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3176,8 +3176,7 @@ void npc::avoid_friendly_fire()
31763176

31773177
tripoint_bub_ms center = midpoint_round_to_nearest( fr_pts );
31783178

3179-
std::vector<tripoint_bub_ms> candidates = closest_points_first( pos_bub(), 1 );
3180-
candidates.erase( candidates.begin() );
3179+
std::vector<tripoint_bub_ms> candidates = closest_points_first( pos_bub(), 1, 1 );
31813180
std::sort( candidates.begin(), candidates.end(),
31823181
[&tar, &center]( const tripoint_bub_ms & l, const tripoint_bub_ms & r ) {
31833182
return ( rl_dist( l, tar ) - rl_dist( l, center ) ) <

src/point.cpp

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -117,21 +117,42 @@ std::istream &operator>>( std::istream &is, tripoint &pos )
117117
return is;
118118
}
119119

120+
std::optional<int> rectangle_size( int min_dist, int max_dist )
121+
{
122+
min_dist = std::max( min_dist, 0 );
123+
max_dist = std::max( max_dist, 0 );
124+
125+
if( min_dist > max_dist ) {
126+
return std::nullopt;
127+
}
128+
129+
const int min_edge = min_dist * 2 + 1;
130+
const int max_edge = max_dist * 2 + 1;
131+
132+
const int n = max_edge * max_edge - ( min_edge - 2 ) * ( min_edge - 2 ) + ( min_dist == 0 ? 1 : 0 );
133+
return n;
134+
}
135+
120136
std::vector<tripoint> closest_points_first( const tripoint &center, int max_dist )
121137
{
122138
return closest_points_first( center, 0, max_dist );
123139
}
124140

125141
std::vector<tripoint> closest_points_first( const tripoint &center, int min_dist, int max_dist )
126142
{
127-
const std::vector<point> points = closest_points_first( center.xy(), min_dist, max_dist );
143+
std::optional<int> n = rectangle_size( min_dist, max_dist );
144+
145+
if( n == std::nullopt ) {
146+
return {};
147+
}
128148

129149
std::vector<tripoint> result;
130-
result.reserve( points.size() );
150+
result.reserve( *n );
131151

132-
for( const point &p : points ) {
133-
result.emplace_back( p, center.z );
134-
}
152+
find_point_closest_first( center, min_dist, max_dist, [&result]( const tripoint & p ) {
153+
result.push_back( p );
154+
return false;
155+
} );
135156

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

144165
std::vector<point> closest_points_first( const point &center, int min_dist, int max_dist )
145166
{
146-
min_dist = std::max( min_dist, 0 );
147-
max_dist = std::max( max_dist, 0 );
167+
std::optional<int> n = rectangle_size( min_dist, max_dist );
148168

149-
if( min_dist > max_dist ) {
169+
if( n == std::nullopt ) {
150170
return {};
151171
}
152172

153-
const int min_edge = min_dist * 2 + 1;
154-
const int max_edge = max_dist * 2 + 1;
155-
156-
const int n = max_edge * max_edge - ( min_edge - 2 ) * ( min_edge - 2 );
157-
const bool is_center_included = min_dist == 0;
158-
159173
std::vector<point> result;
160-
result.reserve( n + ( is_center_included ? 1 : 0 ) );
161-
162-
if( is_center_included ) {
163-
result.push_back( center );
164-
}
174+
result.reserve( *n );
165175

166-
int x_init = std::max( min_dist, 1 );
167-
point p( x_init, 1 - x_init );
168-
169-
point d( point::east );
170-
171-
for( int i = 0; i < n; i++ ) {
172-
result.push_back( center + p );
173-
174-
if( p.x == p.y || ( p.x < 0 && p.x == -p.y ) || ( p.x > 0 && p.x == 1 - p.y ) ) {
175-
std::swap( d.x, d.y );
176-
d.x = -d.x;
177-
}
178-
179-
p.x += d.x;
180-
p.y += d.y;
181-
}
176+
find_point_closest_first( center, min_dist, max_dist, [&result]( const point & p ) {
177+
result.push_back( p );
178+
return false;
179+
} );
182180

183181
return result;
184182
}
183+
184+
template <typename PredicateFn, typename Point>
185+
std::optional<Point> find_point_closest_first( const Point &center, int max_dist,
186+
PredicateFn &&fn )
187+
{
188+
return find_point_closest_first( center, 0, max_dist, fn );
189+
}

src/point.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <cstdint>
99
#include <cstdlib>
1010
#include <functional>
11+
#include <optional>
1112
#include <ostream>
1213
#include <vector>
1314

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

362+
template <typename PredicateFn, typename Point>
363+
std::optional<Point> find_point_closest_first( const Point &center, int min_dist, int max_dist,
364+
PredicateFn &&fn );
365+
366+
template <typename PredicateFn, typename Point>
367+
std::optional<Point> find_point_closest_first( const Point &center, int max_dist,
368+
PredicateFn &&fn );
369+
370+
371+
// Calculate the number of tiles in a square from min_dist to max_dist about an arbitrary centre.
372+
std::optional<int> rectangle_size( int min_dist, int max_dist );
373+
361374
// Make point hashable so it can be used as an unordered_set or unordered_map key,
362375
// or a component of one.
363376
namespace std
@@ -442,4 +455,56 @@ inline constexpr const std::array<tripoint, 8> eight_horizontal_neighbors = { {
442455
}
443456
};
444457

458+
/* Return points in a clockwise spiral from min_dist to max_dist, inclusive, ordered by
459+
* the closest points first. The distance is calculated using roguelike distances, so
460+
* movement in any direction only counts as 1.
461+
*
462+
* The predicate function is evaluated on each point. If the function returns true, the
463+
* point is returned. If the predicate function never returns true then std::nullopt is
464+
* returned once max_dist is reached.
465+
*
466+
* @param center The center of the spiral.
467+
* @param min_dist minimum distance to start the spiral from.
468+
* @param max_dist greatest distance from the centre that the spiral will go to.
469+
* @returns std::nullopt if min_dist > max_dist or predicate_fn evaluated to true for
470+
* no points.
471+
*/
472+
template <typename PredicateFn, typename Point>
473+
std::optional<Point> find_point_closest_first( const Point &center, int min_dist, int max_dist,
474+
PredicateFn &&predicate_fn )
475+
{
476+
const std::optional<int> n = rectangle_size( min_dist, max_dist );
477+
478+
if( n == std::nullopt ) {
479+
return {};
480+
}
481+
482+
const bool is_center_included = min_dist == 0;
483+
484+
if( is_center_included && predicate_fn( center ) ) {
485+
return center;
486+
}
487+
488+
int x_init = std::max( min_dist, 1 );
489+
point p {x_init, 1 - x_init};
490+
491+
point d = point::east;
492+
493+
for( int i = is_center_included; i < *n; i++ ) {
494+
const Point next = Point{ center.raw() + p.raw() };
495+
if( predicate_fn( next ) ) {
496+
return next;
497+
}
498+
499+
if( p.x == p.y || ( p.x < 0 && p.x == -p.y ) || ( p.x > 0 && p.x == 1 - p.y ) ) {
500+
std::swap( d.x, d.y );
501+
d.x = -d.x;
502+
}
503+
504+
p += d;
505+
}
506+
507+
return std::nullopt;
508+
}
509+
445510
#endif // CATA_SRC_POINT_H

src/ranged.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,6 +2240,7 @@ static void cycle_action( item &weap, const itype_id &ammo, map *here, const tri
22402240
} ), tiles.end() );
22412241
tripoint_bub_ms eject{ tiles.empty() ? pos : random_entry( tiles ) };
22422242

2243+
22432244
// for turrets try and drop casings or linkages directly to any CARGO part on the same tile
22442245
const std::optional<vpart_reference> ovp_cargo = weap.has_flag( flag_VEHICLE )
22452246
? here->veh_at( pos ).cargo()
@@ -3161,12 +3162,12 @@ tripoint_bub_ms target_ui::choose_initial_target()
31613162

31623163
// Try closest practice target
31633164
map &here = get_map();
3164-
const std::vector<tripoint_bub_ms> nearby = closest_points_first( src, range );
3165-
const auto target_spot = std::find_if( nearby.begin(), nearby.end(),
3166-
[this, &here]( const tripoint_bub_ms & pt ) {
3165+
std::optional<tripoint_bub_ms> target_spot = find_point_closest_first( src, 0, range, [this,
3166+
&here]( const tripoint_bub_ms & pt ) {
31673167
return here.tr_at( pt ).id == tr_practice_target && this->you->sees( pt );
31683168
} );
3169-
if( target_spot != nearby.end() ) {
3169+
3170+
if( target_spot != std::nullopt ) {
31703171
return *target_spot;
31713172
}
31723173

0 commit comments

Comments
 (0)