Browse Source

Extract Crawl to a library

Also adds a test and a benchmark
pull/7318/head
Gleb Mazovetskiy 2 years ago
parent
commit
624afafe58
  1. 8
      Source/CMakeLists.txt
  2. 74
      Source/crawl.cpp
  3. 58
      Source/crawl.hpp
  4. 1
      Source/engine/path.cpp
  5. 60
      Source/lighting.cpp
  6. 49
      Source/lighting.h
  7. 1
      Source/lua/modules/dev/monsters.cpp
  8. 1
      Source/missiles.cpp
  9. 1
      Source/monster.cpp
  10. 18
      test/CMakeLists.txt
  11. 25
      test/crawl_benchmark.cpp
  12. 9
      test/crawl_test.cpp

8
Source/CMakeLists.txt

@ -343,6 +343,13 @@ target_link_libraries(libdevilutionx_codec PRIVATE
libdevilutionx_log libdevilutionx_log
) )
add_devilutionx_object_library(libdevilutionx_crawl
crawl.cpp
)
target_link_libraries(libdevilutionx_crawl PUBLIC
tl
)
add_devilutionx_object_library(libdevilutionx_file_util add_devilutionx_object_library(libdevilutionx_file_util
utils/file_util.cpp utils/file_util.cpp
) )
@ -398,6 +405,7 @@ target_link_libraries(libdevilutionx PUBLIC
tl tl
unordered_dense::unordered_dense unordered_dense::unordered_dense
libdevilutionx_codec libdevilutionx_codec
libdevilutionx_crawl
libdevilutionx_format_int libdevilutionx_format_int
libdevilutionx_file_util libdevilutionx_file_util
libdevilutionx_parse_int libdevilutionx_parse_int

74
Source/crawl.cpp

@ -0,0 +1,74 @@
#include "crawl.hpp"
#include <type_traits>
#include <function_ref.hpp>
#include "engine/displacement.hpp"
namespace devilution {
namespace {
bool CrawlFlipsX(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored, mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsXY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored, mirrored.flipXY(), mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
}
} // namespace
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function)
{
if (radius == 0)
return function(Displacement { 0, 0 });
if (!CrawlFlipsY({ 0, static_cast<int>(radius) }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(i), static_cast<int>(radius) }, function))
return false;
}
if (radius > 1) {
if (!CrawlFlipsXY({ static_cast<int>(radius) - 1, static_cast<int>(radius) - 1 }, function))
return false;
}
if (!CrawlFlipsX({ static_cast<int>(radius), 0 }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(radius), static_cast<int>(i) }, function))
return false;
}
return true;
}
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function)
{
for (unsigned i = minRadius; i <= maxRadius; i++) {
if (!DoCrawl(i, function))
return false;
}
return true;
}
} // namespace devilution

58
Source/crawl.hpp

@ -0,0 +1,58 @@
#include <type_traits>
#include <function_ref.hpp>
#include "engine/displacement.hpp"
namespace devilution {
/**
* CrawlTable specifies X- and Y-coordinate deltas from a missile target coordinate.
*
* n=4
*
* y
* ^
* | 1
* | 3#4
* | 2
* +-----> x
*
* n=16
*
* y
* ^
* | 314
* | B7 8C
* | F # G
* | D9 AE
* | 526
* +-------> x
*/
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function);
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function);
template <typename F>
auto Crawl(unsigned radius, F function) -> std::invoke_result_t<decltype(function), Displacement>
{
std::invoke_result_t<decltype(function), Displacement> result;
DoCrawl(radius, [&result, &function](Displacement displacement) -> bool {
result = function(displacement);
return !result;
});
return result;
}
template <typename F>
auto Crawl(unsigned minRadius, unsigned maxRadius, F function) -> std::invoke_result_t<decltype(function), Displacement>
{
std::invoke_result_t<decltype(function), Displacement> result;
DoCrawl(minRadius, maxRadius, [&result, &function](Displacement displacement) -> bool {
result = function(displacement);
return !result;
});
return result;
}
} // namespace devilution

1
Source/engine/path.cpp

@ -10,6 +10,7 @@
#include <function_ref.hpp> #include <function_ref.hpp>
#include "crawl.hpp"
#include "levels/gendung.h" #include "levels/gendung.h"
#include "lighting.h" #include "lighting.h"
#include "objects.h" #include "objects.h"

60
Source/lighting.cpp

@ -113,33 +113,6 @@ DVL_ALWAYS_INLINE uint8_t GetLight(Point position)
return dLight[position.x][position.y]; return dLight[position.x][position.y];
} }
bool CrawlFlipsX(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored, mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsXY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored, mirrored.flipXY(), mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
}
bool TileAllowsLight(Point position) bool TileAllowsLight(Point position)
{ {
if (!InDungeonBounds(position)) if (!InDungeonBounds(position))
@ -161,39 +134,6 @@ void DoVisionFlags(Point position, MapExplorationType doAutomap, bool visible)
} // namespace } // namespace
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function)
{
if (radius == 0)
return function(Displacement { 0, 0 });
if (!CrawlFlipsY({ 0, static_cast<int>(radius) }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(i), static_cast<int>(radius) }, function))
return false;
}
if (radius > 1) {
if (!CrawlFlipsXY({ static_cast<int>(radius) - 1, static_cast<int>(radius) - 1 }, function))
return false;
}
if (!CrawlFlipsX({ static_cast<int>(radius), 0 }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(radius), static_cast<int>(i) }, function))
return false;
}
return true;
}
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function)
{
for (unsigned i = minRadius; i <= maxRadius; i++) {
if (!DoCrawl(i, function))
return false;
}
return true;
}
void DoUnLight(Point position, uint8_t radius) void DoUnLight(Point position, uint8_t radius)
{ {
radius++; radius++;

49
Source/lighting.h

@ -86,53 +86,4 @@ void lighting_color_cycling();
constexpr int MaxCrawlRadius = 18; constexpr int MaxCrawlRadius = 18;
/**
* CrawlTable specifies X- and Y-coordinate deltas from a missile target coordinate.
*
* n=4
*
* y
* ^
* | 1
* | 3#4
* | 2
* +-----> x
*
* n=16
*
* y
* ^
* | 314
* | B7 8C
* | F # G
* | D9 AE
* | 526
* +-------> x
*/
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function);
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function);
template <typename F>
auto Crawl(unsigned radius, F function) -> std::invoke_result_t<decltype(function), Displacement>
{
std::invoke_result_t<decltype(function), Displacement> result;
DoCrawl(radius, [&result, &function](Displacement displacement) -> bool {
result = function(displacement);
return !result;
});
return result;
}
template <typename F>
auto Crawl(unsigned minRadius, unsigned maxRadius, F function) -> std::invoke_result_t<decltype(function), Displacement>
{
std::invoke_result_t<decltype(function), Displacement> result;
DoCrawl(minRadius, maxRadius, [&result, &function](Displacement displacement) -> bool {
result = function(displacement);
return !result;
});
return result;
}
} // namespace devilution } // namespace devilution

1
Source/lua/modules/dev/monsters.cpp

@ -6,6 +6,7 @@
#include <sol/sol.hpp> #include <sol/sol.hpp>
#include "crawl.hpp"
#include "levels/gendung.h" #include "levels/gendung.h"
#include "lighting.h" #include "lighting.h"
#include "lua/metadoc.hpp" #include "lua/metadoc.hpp"

1
Source/missiles.cpp

@ -11,6 +11,7 @@
#include "control.h" #include "control.h"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "crawl.hpp"
#include "cursor.h" #include "cursor.h"
#include "dead.h" #include "dead.h"
#ifdef _DEBUG #ifdef _DEBUG

1
Source/monster.cpp

@ -18,6 +18,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "control.h" #include "control.h"
#include "crawl.hpp"
#include "cursor.h" #include "cursor.h"
#include "dead.h" #include "dead.h"
#include "engine/load_cl2.hpp" #include "engine/load_cl2.hpp"

18
test/CMakeLists.txt

@ -24,7 +24,6 @@ set(tests
drlg_l4_test drlg_l4_test
effects_test effects_test
inv_test inv_test
lighting_test
math_test math_test
missiles_test missiles_test
pack_test pack_test
@ -40,24 +39,30 @@ set(tests
) )
set(standalone_tests set(standalone_tests
codec_test codec_test
crawl_test
file_util_test file_util_test
format_int_test format_int_test
parse_int_test parse_int_test
str_cat_test str_cat_test
utf8_test utf8_test
) )
set(benchmarks
crawl_benchmark)
include(Fixtures.cmake) include(Fixtures.cmake)
foreach(test_target ${tests} ${standalone_tests}) foreach(test_target ${tests} ${standalone_tests} ${benchmarks})
add_executable(${test_target} "${test_target}.cpp") add_executable(${test_target} "${test_target}.cpp")
gtest_discover_tests(${test_target})
set_target_properties(${test_target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set_target_properties(${test_target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
if(GPERF) if(GPERF)
target_link_libraries(${test_target} PUBLIC ${GPERFTOOLS_LIBRARIES}) target_link_libraries(${test_target} PUBLIC ${GPERFTOOLS_LIBRARIES})
endif() endif()
endforeach() endforeach()
foreach(test_target ${tests} ${standalone_tests})
gtest_discover_tests(${test_target})
endforeach()
foreach(test_target ${tests}) foreach(test_target ${tests})
target_link_libraries(${test_target} PRIVATE test_main) target_link_libraries(${test_target} PRIVATE test_main)
endforeach() endforeach()
@ -67,6 +72,11 @@ foreach(test_target ${standalone_tests})
target_include_directories(${test_target} PRIVATE "${PROJECT_SOURCE_DIR}/Source") target_include_directories(${test_target} PRIVATE "${PROJECT_SOURCE_DIR}/Source")
endforeach() endforeach()
foreach(target ${benchmarks})
target_link_libraries(${target} PRIVATE benchmark::benchmark benchmark::benchmark_main)
target_include_directories(${target} PRIVATE "${PROJECT_SOURCE_DIR}/Source")
endforeach()
add_library(app_fatal_for_testing OBJECT app_fatal_for_testing.cpp) add_library(app_fatal_for_testing OBJECT app_fatal_for_testing.cpp)
target_sources(app_fatal_for_testing INTERFACE $<TARGET_OBJECTS:app_fatal_for_testing>) target_sources(app_fatal_for_testing INTERFACE $<TARGET_OBJECTS:app_fatal_for_testing>)
@ -74,6 +84,8 @@ add_library(language_for_testing OBJECT language_for_testing.cpp)
target_sources(language_for_testing INTERFACE $<TARGET_OBJECTS:language_for_testing>) target_sources(language_for_testing INTERFACE $<TARGET_OBJECTS:language_for_testing>)
target_link_libraries(codec_test PRIVATE libdevilutionx_codec app_fatal_for_testing) target_link_libraries(codec_test PRIVATE libdevilutionx_codec app_fatal_for_testing)
target_link_libraries(crawl_test PRIVATE libdevilutionx_crawl)
target_link_libraries(crawl_benchmark PRIVATE libdevilutionx_crawl)
target_link_libraries(file_util_test PRIVATE libdevilutionx_file_util app_fatal_for_testing) target_link_libraries(file_util_test PRIVATE libdevilutionx_file_util app_fatal_for_testing)
target_link_libraries(format_int_test PRIVATE libdevilutionx_format_int language_for_testing) target_link_libraries(format_int_test PRIVATE libdevilutionx_format_int language_for_testing)
target_link_libraries(parse_int_test PRIVATE libdevilutionx_parse_int) target_link_libraries(parse_int_test PRIVATE libdevilutionx_parse_int)

25
test/crawl_benchmark.cpp

@ -0,0 +1,25 @@
#include <benchmark/benchmark.h>
#include "crawl.hpp"
#include "engine/displacement.hpp"
namespace devilution {
namespace {
void BM_Crawl(benchmark::State &state)
{
const int radius = state.range(0);
for (auto _ : state) {
int sum;
Crawl(0, radius, [&sum](Displacement d) {
sum += d.deltaX + d.deltaY;
return false;
});
benchmark::DoNotOptimize(sum);
}
}
BENCHMARK(BM_Crawl)->RangeMultiplier(4)->Range(1, 20);
} // namespace
} // namespace devilution

9
test/lighting_test.cpp → test/crawl_test.cpp

@ -3,14 +3,14 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "control.h" #include "crawl.hpp"
#include "lighting.h" #include "engine/displacement.hpp"
namespace devilution { namespace devilution {
namespace { namespace {
using ::testing::ElementsAre; using ::testing::ElementsAre;
TEST(Lighting, CrawlTables) TEST(CrawlTest, BasicTest)
{ {
bool added[40][40]; bool added[40][40];
memset(added, 0, sizeof(added)); memset(added, 0, sizeof(added));
@ -18,6 +18,7 @@ TEST(Lighting, CrawlTables)
int x = 20; int x = 20;
int y = 20; int y = 20;
constexpr int MaxCrawlRadius = 18;
Crawl(0, MaxCrawlRadius, [&](Displacement displacement) { Crawl(0, MaxCrawlRadius, [&](Displacement displacement) {
int dx = x + displacement.deltaX; int dx = x + displacement.deltaX;
int dy = y + displacement.deltaY; int dy = y + displacement.deltaY;
@ -37,7 +38,7 @@ TEST(Lighting, CrawlTables)
} }
} }
TEST(Lighting, CrawlTablesVisitationOrder) TEST(CrawlTest, VisitationOrderTest)
{ {
std::vector<Displacement> order; std::vector<Displacement> order;
Crawl(0, 2, [&](Displacement displacement) { Crawl(0, 2, [&](Displacement displacement) {
Loading…
Cancel
Save