mirror of
https://github.com/bensuperpc/astar.git
synced 2024-12-30 12:34:26 +01:00
Add files
Signed-off-by: Bensuperpc <bensuperpc@gmail.com>
This commit is contained in:
commit
7d81e22900
259
.clang-format
Executable file
259
.clang-format
Executable file
@ -0,0 +1,259 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Chromium
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: false
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAfterAttributes: Never
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 144
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: true
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: false
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PackConstructorInitializers: NextLine
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Leave
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
- ParseTestProto
|
||||
- ParsePartialTestProto
|
||||
CanonicalDelimiter: pb
|
||||
BasedOnStyle: google
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
- NS_SWIFT_NAME
|
||||
- PP_STRINGIZE
|
||||
- STRINGIZE
|
||||
...
|
||||
|
155
.clang-tidy
Normal file
155
.clang-tidy
Normal file
@ -0,0 +1,155 @@
|
||||
---
|
||||
# Enable ALL the things! Except not really
|
||||
# misc-non-private-member-variables-in-classes: the options don't do anything
|
||||
# modernize-use-nodiscard: too aggressive, attribute is situationally useful
|
||||
Checks: "*,\
|
||||
-google-readability-todo,\
|
||||
-altera-*,\
|
||||
-fuchsia-*,\
|
||||
fuchsia-multiple-inheritance,\
|
||||
-llvm-header-guard,\
|
||||
-llvm-include-order,\
|
||||
-llvmlibc-*,\
|
||||
-modernize-use-nodiscard,\
|
||||
-misc-non-private-member-variables-in-classes"
|
||||
WarningsAsErrors: ''
|
||||
CheckOptions:
|
||||
- key: 'bugprone-argument-comment.StrictMode'
|
||||
value: 'true'
|
||||
# Prefer using enum classes with 2 values for parameters instead of bools
|
||||
- key: 'bugprone-argument-comment.CommentBoolLiterals'
|
||||
value: 'true'
|
||||
- key: 'bugprone-misplaced-widening-cast.CheckImplicitCasts'
|
||||
value: 'true'
|
||||
- key: 'bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression'
|
||||
value: 'true'
|
||||
- key: 'bugprone-suspicious-string-compare.WarnOnLogicalNotComparison'
|
||||
value: 'true'
|
||||
- key: 'readability-simplify-boolean-expr.ChainedConditionalReturn'
|
||||
value: 'true'
|
||||
- key: 'readability-simplify-boolean-expr.ChainedConditionalAssignment'
|
||||
value: 'true'
|
||||
- key: 'readability-uniqueptr-delete-release.PreferResetCall'
|
||||
value: 'true'
|
||||
- key: 'cppcoreguidelines-init-variables.MathHeader'
|
||||
value: '<cmath>'
|
||||
- key: 'cppcoreguidelines-narrowing-conversions.PedanticMode'
|
||||
value: 'true'
|
||||
- key: 'readability-else-after-return.WarnOnUnfixable'
|
||||
value: 'true'
|
||||
- key: 'readability-else-after-return.WarnOnConditionVariables'
|
||||
value: 'true'
|
||||
- key: 'readability-inconsistent-declaration-parameter-name.Strict'
|
||||
value: 'true'
|
||||
- key: 'readability-qualified-auto.AddConstToQualified'
|
||||
value: 'true'
|
||||
- key: 'readability-redundant-access-specifiers.CheckFirstDeclaration'
|
||||
value: 'true'
|
||||
# These seem to be the most common identifier styles
|
||||
- key: 'readability-identifier-naming.AbstractClassCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ClassCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ClassConstantCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ClassMemberCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ClassMethodCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ConstantCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ConstantMemberCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ConstantParameterCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ConstantPointerParameterCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ConstexprFunctionCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ConstexprMethodCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ConstexprVariableCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.EnumCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.EnumConstantCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.FunctionCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.GlobalConstantCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.GlobalConstantPointerCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.GlobalFunctionCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.GlobalPointerCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.GlobalVariableCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.InlineNamespaceCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.LocalConstantCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.LocalConstantPointerCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.LocalPointerCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.LocalVariableCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.MacroDefinitionCase'
|
||||
value: 'UPPER_CASE'
|
||||
- key: 'readability-identifier-naming.MemberCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.MethodCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.NamespaceCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ParameterCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ParameterPackCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.PointerParameterCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.PrivateMemberCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.PrivateMemberPrefix'
|
||||
value: 'm_'
|
||||
- key: 'readability-identifier-naming.PrivateMethodCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ProtectedMemberCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ProtectedMemberPrefix'
|
||||
value: 'm_'
|
||||
- key: 'readability-identifier-naming.ProtectedMethodCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.PublicMemberCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.PublicMethodCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ScopedEnumConstantCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.StaticConstantCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.StaticVariableCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.StructCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.TemplateParameterCase'
|
||||
value: 'CamelCase'
|
||||
- key: 'readability-identifier-naming.TemplateTemplateParameterCase'
|
||||
value: 'CamelCase'
|
||||
- key: 'readability-identifier-naming.TypeAliasCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.TypedefCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.TypeTemplateParameterCase'
|
||||
value: 'CamelCase'
|
||||
- key: 'readability-identifier-naming.UnionCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.ValueTemplateParameterCase'
|
||||
value: 'CamelCase'
|
||||
- key: 'readability-identifier-naming.VariableCase'
|
||||
value: 'lower_case'
|
||||
- key: 'readability-identifier-naming.VirtualMethodCase'
|
||||
value: 'lower_case'
|
||||
...
|
6
.codespellrc
Normal file
6
.codespellrc
Normal file
@ -0,0 +1,6 @@
|
||||
[codespell]
|
||||
builtin = clear,rare,en-GB_to_en-US,names,informal,code
|
||||
check-filenames =
|
||||
check-hidden =
|
||||
skip = */.git,*/build,*/prefix
|
||||
quiet-level = 2
|
185
.github/workflows/ci.yml
vendored
Executable file
185
.github/workflows/ci.yml
vendored
Executable file
@ -0,0 +1,185 @@
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with: { python-version: "3.8" }
|
||||
|
||||
- name: Install codespell
|
||||
run: pip3 install codespell
|
||||
|
||||
- name: Lint
|
||||
if: always()
|
||||
run: cmake -D FORMAT_COMMAND=clang-format-14 -P cmake/lint.cmake
|
||||
|
||||
- name: Spell check
|
||||
if: always()
|
||||
run: cmake -P cmake/spell.cmake
|
||||
|
||||
coverage:
|
||||
needs: [lint]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
# To enable coverage, delete the last line from the conditional below and
|
||||
# edit the "<name>" placeholder to your GitHub name.
|
||||
# If you do not wish to use codecov, then simply delete this job from the
|
||||
# workflow.
|
||||
if: github.repository_owner == 'bensuperpc'
|
||||
&& false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install LCov
|
||||
run: sudo apt-get update -q
|
||||
&& sudo apt-get install lcov -q -y
|
||||
|
||||
- name: Configure
|
||||
run: cmake --preset=ci-coverage
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build/coverage -j 2
|
||||
|
||||
- name: Test
|
||||
working-directory: build/coverage
|
||||
run: ctest --output-on-failure --no-tests=error -j 2
|
||||
|
||||
- name: Process coverage info
|
||||
run: cmake --build build/coverage -t coverage
|
||||
|
||||
- name: Submit to codecov.io
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: build/coverage/coverage.info
|
||||
|
||||
sanitize:
|
||||
needs: [lint]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
env: { CXX: clang++-14 }
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Configure
|
||||
run: cmake --preset=ci-sanitize
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build/sanitize -j 2
|
||||
|
||||
- name: Test
|
||||
working-directory: build/sanitize
|
||||
env:
|
||||
ASAN_OPTIONS: "strict_string_checks=1:\
|
||||
detect_stack_use_after_return=1:\
|
||||
check_initialization_order=1:\
|
||||
strict_init_order=1:\
|
||||
detect_leaks=1"
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
run: ctest --output-on-failure --no-tests=error -j 2
|
||||
|
||||
test:
|
||||
needs: [lint]
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-12, ubuntu-22.04, windows-2022]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install static analyzers
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: >-
|
||||
sudo apt-get install clang-tidy-14 cppcheck -y -q
|
||||
|
||||
sudo update-alternatives --install
|
||||
/usr/bin/clang-tidy clang-tidy
|
||||
/usr/bin/clang-tidy-14 140
|
||||
|
||||
- name: Setup MultiToolTask
|
||||
if: matrix.os == 'windows-2022'
|
||||
run: |
|
||||
Add-Content "$env:GITHUB_ENV" 'UseMultiToolTask=true'
|
||||
Add-Content "$env:GITHUB_ENV" 'EnforceProcessCountAcrossBuilds=true'
|
||||
|
||||
- name: Configure
|
||||
shell: pwsh
|
||||
run: cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])"
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build --config Release -j 2
|
||||
|
||||
- name: Install
|
||||
run: cmake --install build --config Release --prefix prefix
|
||||
|
||||
- name: Test
|
||||
working-directory: build
|
||||
run: ctest --output-on-failure --no-tests=error -C Release -j 2
|
||||
|
||||
docs:
|
||||
# Deploy docs only when builds succeed
|
||||
needs: [sanitize, test]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
# To enable, first you have to create an orphaned gh-pages branch:
|
||||
#
|
||||
# git switch --orphan gh-pages
|
||||
# git commit --allow-empty -m "Initial commit"
|
||||
# git push -u origin gh-pages
|
||||
#
|
||||
# Edit the <name> placeholder below to your GitHub name, so this action
|
||||
# runs only in your repository and no one else's fork. After these, delete
|
||||
# this comment and the last line in the conditional below.
|
||||
# If you do not wish to use GitHub Pages for deploying documentation, then
|
||||
# simply delete this job similarly to the coverage one.
|
||||
if: github.ref == 'refs/heads/master'
|
||||
&& github.event_name == 'push'
|
||||
&& github.repository_owner == 'bensuperpc'
|
||||
&& false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with: { python-version: "3.8" }
|
||||
|
||||
- name: Install m.css dependencies
|
||||
run: pip3 install jinja2 Pygments
|
||||
|
||||
- name: Install Doxygen
|
||||
run: sudo apt-get update -q
|
||||
&& sudo apt-get install doxygen -q -y
|
||||
|
||||
- name: Build docs
|
||||
run: cmake "-DPROJECT_SOURCE_DIR=$PWD" "-DPROJECT_BINARY_DIR=$PWD/build"
|
||||
-P cmake/docs-ci.cmake
|
||||
|
||||
- name: Deploy docs
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: build/docs/html
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
**/.DS_Store
|
||||
.idea/
|
||||
.vs/
|
||||
.vscode/
|
||||
build/
|
||||
cmake-build-*/
|
||||
prefix/
|
||||
.clangd
|
||||
CMakeLists.txt.user
|
||||
compile_commands.json
|
||||
venv/*
|
103
BUILDING.md
Normal file
103
BUILDING.md
Normal file
@ -0,0 +1,103 @@
|
||||
# Building with CMake
|
||||
|
||||
## Build
|
||||
|
||||
This project doesn't require any special command-line flags to build to keep
|
||||
things simple.
|
||||
|
||||
### Building with Make
|
||||
|
||||
You can use the Makefile provided in the root of the project to easily build multiple presets:
|
||||
|
||||
```sh
|
||||
make base # Build the base preset
|
||||
```
|
||||
|
||||
```sh
|
||||
make debug # Build the debug preset
|
||||
```
|
||||
|
||||
### Building with CMake
|
||||
|
||||
Here are the steps for building in release mode with a single-configuration
|
||||
generator, like the Unix Makefiles one:
|
||||
|
||||
```sh
|
||||
cmake -S . -B build -D CMAKE_BUILD_TYPE=Release
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
Here are the steps for building in release mode with a multi-configuration
|
||||
generator, like the Visual Studio ones:
|
||||
|
||||
```sh
|
||||
cmake -S . -B build
|
||||
cmake --build build --config Release
|
||||
```
|
||||
|
||||
### Building with MSVC
|
||||
|
||||
Note that MSVC by default is not standards compliant and you need to pass some
|
||||
flags to make it behave properly. See the `flags-windows` preset in the
|
||||
[CMakePresets.json](CMakePresets.json) file for the flags and with what
|
||||
variable to provide them to CMake during configuration.
|
||||
|
||||
### Building on Apple Silicon
|
||||
|
||||
CMake supports building on Apple Silicon properly since 3.20.1. Make sure you
|
||||
have the [latest version][1] installed.
|
||||
|
||||
## Install
|
||||
|
||||
This project doesn't require any special command-line flags to install to keep
|
||||
things simple. As a prerequisite, the project has to be built with the above
|
||||
commands already.
|
||||
|
||||
The below commands require at least CMake 3.15 to run, because that is the
|
||||
version in which [Install a Project][2] was added.
|
||||
|
||||
Here is the command for installing the release mode artifacts with a
|
||||
single-configuration generator, like the Unix Makefiles one:
|
||||
|
||||
```sh
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
Here is the command for installing the release mode artifacts with a
|
||||
multi-configuration generator, like the Visual Studio ones:
|
||||
|
||||
```sh
|
||||
cmake --install build --config Release
|
||||
```
|
||||
|
||||
### CMake package
|
||||
|
||||
This project exports a CMake package to be used with the [`find_package`][3]
|
||||
command of CMake:
|
||||
|
||||
* Package name: `astar`
|
||||
* Target name: `astar::astar`
|
||||
|
||||
Example usage:
|
||||
|
||||
```cmake
|
||||
find_package(astar REQUIRED)
|
||||
# Declare the imported target as a build requirement using PRIVATE, where
|
||||
# project_target is a target created in the consuming project
|
||||
target_link_libraries(
|
||||
project_target PRIVATE
|
||||
astar::astar
|
||||
)
|
||||
```
|
||||
|
||||
### Note to packagers
|
||||
|
||||
The `CMAKE_INSTALL_INCLUDEDIR` is set to a path other than just `include` if
|
||||
the project is configured as a top level project to avoid indirectly including
|
||||
other libraries when installed to a common prefix. Please review the
|
||||
[install-rules.cmake](cmake/install-rules.cmake) file for the full set of
|
||||
install rules.
|
||||
|
||||
[1]: https://cmake.org/download/
|
||||
[2]: https://cmake.org/cmake/help/latest/manual/cmake.1.html#install-a-project
|
||||
[3]: https://cmake.org/cmake/help/latest/command/find_package.html
|
60
CMakeLists.txt
Normal file
60
CMakeLists.txt
Normal file
@ -0,0 +1,60 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
include(cmake/prelude.cmake)
|
||||
|
||||
project(
|
||||
astar
|
||||
VERSION 0.1.0
|
||||
DESCRIPTION "astar"
|
||||
HOMEPAGE_URL "bensuperpc.org"
|
||||
LANGUAGES NONE
|
||||
)
|
||||
|
||||
include(cmake/project-is-top-level.cmake)
|
||||
include(cmake/variables.cmake)
|
||||
|
||||
# ---- Declare library ----
|
||||
|
||||
add_library(astar_astar INTERFACE)
|
||||
add_library(astar::astar ALIAS astar_astar)
|
||||
|
||||
set_property(
|
||||
TARGET astar_astar PROPERTY
|
||||
EXPORT_NAME astar
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
astar_astar ${warning_guard}
|
||||
INTERFACE
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
||||
)
|
||||
|
||||
target_compile_features(astar_astar INTERFACE cxx_std_20)
|
||||
|
||||
# ---- Install rules ----
|
||||
|
||||
if(NOT CMAKE_SKIP_INSTALL_RULES)
|
||||
include(cmake/install-rules.cmake)
|
||||
endif()
|
||||
|
||||
# ---- Examples ----
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
option(BUILD_EXAMPLES "Build examples tree." "${astar_DEVELOPER_MODE}")
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(example)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ---- Developer mode ----
|
||||
|
||||
if(NOT astar_DEVELOPER_MODE)
|
||||
return()
|
||||
elseif(NOT PROJECT_IS_TOP_LEVEL)
|
||||
message(
|
||||
AUTHOR_WARNING
|
||||
"Developer mode is intended for developers of astar"
|
||||
)
|
||||
endif()
|
||||
|
||||
include(cmake/dev-mode.cmake)
|
247
CMakePresets.json
Executable file
247
CMakePresets.json
Executable file
@ -0,0 +1,247 @@
|
||||
{
|
||||
"version": 2,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 14,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "cmake-pedantic",
|
||||
"hidden": true,
|
||||
"warnings": {
|
||||
"dev": true,
|
||||
"deprecated": true,
|
||||
"uninitialized": true,
|
||||
"unusedCli": true,
|
||||
"systemVars": false
|
||||
},
|
||||
"errors": {
|
||||
"dev": false,
|
||||
"deprecated": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-mode",
|
||||
"hidden": true,
|
||||
"inherits": "cmake-pedantic",
|
||||
"cacheVariables": {
|
||||
"astar_DEVELOPER_MODE": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cppcheck",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_CPPCHECK": "cppcheck;--inline-suppr",
|
||||
"CMAKE_C_CPPCHECK": "cppcheck;--inline-suppr"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "clang-tidy",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_CLANG_TIDY": "clang-tidy;--header-filter=^${sourceDir}/",
|
||||
"CMAKE_C_CLANG_TIDY": "clang-tidy;--header-filter=^${sourceDir}/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-std",
|
||||
"description": "This preset makes sure the project actually builds with at least the specified standard",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_EXTENSIONS": "ON",
|
||||
"CMAKE_CXX_STANDARD": "20",
|
||||
"CMAKE_CXX_STANDARD_REQUIRED": "ON",
|
||||
"CMAKE_C_EXTENSIONS": "ON",
|
||||
"CMAKE_C_STANDARD": "17",
|
||||
"CMAKE_C_STANDARD_REQUIRED": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "flags-gcc-clang",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -pipe -fstack-protector-strong -fstack-clash-protection -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wformat-security",
|
||||
"CMAKE_C_FLAGS": "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -pipe -fstack-protector-strong -fstack-clash-protection -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wformat-security",
|
||||
"CMAKE_EXE_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now",
|
||||
"CMAKE_SHARED_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "flags-appleclang",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "-pipe -fstack-protector-strong -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast",
|
||||
"CMAKE_C_FLAGS": "-pipe -fstack-protector-strong -Wall -Wextra -Wpedantic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "flags-msvc",
|
||||
"description": "Note that all the flags after /W4 are required for MSVC to conform to the language standard",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "/sdl /guard:cf /utf-8 /diagnostics:caret /w14165 /w44242 /w44254 /w44263 /w34265 /w34287 /w44296 /w44365 /w44388 /w44464 /w14545 /w14546 /w14547 /w14549 /w14555 /w34619 /w34640 /w24826 /w14905 /w14906 /w14928 /w45038 /W4 /permissive- /volatile:iso /Zc:inline /Zc:preprocessor /Zc:enumTypes /Zc:lambda /Zc:__cplusplus /Zc:externConstexpr /Zc:throwingNew /EHsc",
|
||||
"CMAKE_EXE_LINKER_FLAGS": "/machine:x64 /guard:cf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "flags-cuda",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CUDA_FLAGS": "--default-stream per-thread -Xfatbin=-compress-all -arch=all-major -Xcompiler=-Wall,-Wextra,-Wconversion,-Wsign-conversion,-Wcast-qual,-Wundef,-Wshadow,-Wunused,-Wnull-dereference,-Wdouble-promotion,-Wimplicit-fallthrough,-Wextra-semi,-Woverloaded-virtual,-Wnon-virtual-dtor,-Wformat-security",
|
||||
"CMAKE_CUDA_ARCHITECTURES": "50;52;53;60;61;62;70;72;75;80;86;87;89;90",
|
||||
"CUDA_PROPAGATE_HOST_FLAGS": "OFF",
|
||||
"CMAKE_CUDA_SEPARABLE_COMPILATION": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "flags-debugger",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "-O0 -g3 -ggdb3 -Wall -Wextra -Wpedantic -pg",
|
||||
"CMAKE_C_FLAGS": "-O0 -g3 -ggdb3 -Wall -Wextra -Wpedantic -pg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-cuda",
|
||||
"description": "This preset makes sure the project actually builds with at least the specified standard",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_CUDA_STANDARD": "17",
|
||||
"CMAKE_CUDA_STANDARD_REQUIRED": "ON",
|
||||
"CMAKE_CUDA_EXTENSIONS": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-linux",
|
||||
"generator": "Unix Makefiles",
|
||||
"hidden": true,
|
||||
"inherits": ["flags-gcc-clang", "ci-std", "ci-cuda", "flags-cuda"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-darwin",
|
||||
"generator": "Unix Makefiles",
|
||||
"hidden": true,
|
||||
"inherits": ["flags-appleclang", "ci-std"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-base",
|
||||
"generator": "Unix Makefiles",
|
||||
"hidden": true,
|
||||
"inherits": ["ci-std", "flags-gcc-clang", "dev-mode", "flags-cuda", "ci-cuda"]
|
||||
},
|
||||
{
|
||||
"name": "ci-win64",
|
||||
"inherits": ["flags-msvc", "ci-std"],
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"architecture": "x64",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "coverage-linux",
|
||||
"binaryDir": "${sourceDir}/build/coverage",
|
||||
"inherits": "ci-linux",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"ENABLE_COVERAGE": "ON",
|
||||
"CMAKE_BUILD_TYPE": "Coverage",
|
||||
"CMAKE_CXX_FLAGS_COVERAGE": "-O0 -g3 --coverage -fkeep-inline-functions -fkeep-static-functions",
|
||||
"CMAKE_EXE_LINKER_FLAGS_COVERAGE": "--coverage",
|
||||
"CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-coverage",
|
||||
"inherits": ["coverage-linux", "dev-mode"],
|
||||
"cacheVariables": {
|
||||
"COVERAGE_HTML_COMMAND": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-sanitize",
|
||||
"binaryDir": "${sourceDir}/build/sanitize",
|
||||
"inherits": ["ci-linux", "dev-mode"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Sanitize",
|
||||
"CMAKE_CXX_FLAGS_SANITIZE": "-Og -U_FORTIFY_SOURCE -g3 -fsanitize=address,undefined,leak -fno-omit-frame-pointer -fno-common",
|
||||
"CMAKE_C_FLAGS_SANITIZE": "-Og -U_FORTIFY_SOURCE -g3"
|
||||
},
|
||||
"environment": {
|
||||
"ASAN_OPTIONS": "strict_string_checks=1 detect_stack_use_after_return=1 check_initialization_order=1 strict_init_order=1 detect_leaks=1",
|
||||
"UBSAN_OPTIONS": "print_stacktrace=1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-build",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "base",
|
||||
"binaryDir": "${sourceDir}/build/base",
|
||||
"inherits": ["ci-base"],
|
||||
"hidden": false,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "base-clang",
|
||||
"binaryDir": "${sourceDir}/build/base-clang",
|
||||
"inherits": ["ci-base"],
|
||||
"hidden": false,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gprof",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/build/gprof",
|
||||
"inherits": ["ci-std", "flags-debugger", "dev-mode"],
|
||||
"hidden": false,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "debugger",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/build/debugger",
|
||||
"inherits": ["ci-std", "flags-debugger", "dev-mode"],
|
||||
"hidden": false,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-common",
|
||||
"hidden": true,
|
||||
"inherits": ["dev-mode", "clang-tidy", "cppcheck"],
|
||||
"cacheVariables": {
|
||||
"BUILD_MCSS_DOCS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-macos",
|
||||
"inherits": ["ci-build", "ci-darwin", "dev-mode"]
|
||||
},
|
||||
{
|
||||
"name": "ci-ubuntu",
|
||||
"inherits": ["ci-build", "ci-linux", "dev-common"]
|
||||
},
|
||||
{
|
||||
"name": "ci-windows",
|
||||
"inherits": ["ci-build", "ci-win64", "dev-mode"]
|
||||
}
|
||||
]
|
||||
}
|
69
CMakeUserPresets.json
Normal file
69
CMakeUserPresets.json
Normal file
@ -0,0 +1,69 @@
|
||||
{
|
||||
"version": 2,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 14,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "dev-linux",
|
||||
"binaryDir": "${sourceDir}/build/dev-linux",
|
||||
"inherits": ["dev-common", "ci-linux"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-darwin",
|
||||
"binaryDir": "${sourceDir}/build/dev-darwin",
|
||||
"inherits": ["dev-common", "ci-darwin"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-win64",
|
||||
"binaryDir": "${sourceDir}/build/dev-win64",
|
||||
"inherits": ["dev-common", "ci-win64"],
|
||||
"environment": {
|
||||
"UseMultiToolTask": "true",
|
||||
"EnforceProcessCountAcrossBuilds": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev",
|
||||
"binaryDir": "${sourceDir}/build/dev",
|
||||
"inherits": "dev-linux"
|
||||
},
|
||||
{
|
||||
"name": "dev-coverage",
|
||||
"binaryDir": "${sourceDir}/build/coverage",
|
||||
"inherits": ["dev-mode", "coverage-linux"]
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"configurePreset": "dev",
|
||||
"configuration": "Debug",
|
||||
"jobs": 16
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"configurePreset": "dev",
|
||||
"configuration": "Debug",
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
},
|
||||
"execution": {
|
||||
"jobs": 16,
|
||||
"noTestsAction": "error"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
5
CODE_OF_CONDUCT.md
Normal file
5
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Code of Conduct
|
||||
|
||||
* You will be judged by your contributions first, and your sense of humor
|
||||
second.
|
||||
* Nobody owes you anything.
|
19
CONTRIBUTING.md
Normal file
19
CONTRIBUTING.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Contributing
|
||||
|
||||
<!--
|
||||
Short overview, rules, general guidelines, notes about pull requests and
|
||||
style should go here.
|
||||
-->
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Please see the [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) document.
|
||||
|
||||
## Getting started
|
||||
|
||||
Helpful notes for developers can be found in the [`HACKING.md`](HACKING.md)
|
||||
document.
|
||||
|
||||
In addition to he above, if you use the presets file as instructed, then you
|
||||
should NOT check it into source control, just as the CMake documentation
|
||||
suggests.
|
149
HACKING.md
Normal file
149
HACKING.md
Normal file
@ -0,0 +1,149 @@
|
||||
# Hacking
|
||||
|
||||
Here is some wisdom to help you build and test this project as a developer and
|
||||
potential contributor.
|
||||
|
||||
If you plan to contribute, please read the [CONTRIBUTING](CONTRIBUTING.md)
|
||||
guide.
|
||||
|
||||
## Developer mode
|
||||
|
||||
Build system targets that are only useful for developers of this project are
|
||||
hidden if the `astar_DEVELOPER_MODE` option is disabled. Enabling this
|
||||
option makes tests and other developer targets and options available. Not
|
||||
enabling this option means that you are a consumer of this project and thus you
|
||||
have no need for these targets and options.
|
||||
|
||||
Developer mode is always set to on in CI workflows.
|
||||
|
||||
### Presets
|
||||
|
||||
This project makes use of [presets][1] to simplify the process of configuring
|
||||
the project. As a developer, you are recommended to always have the [latest
|
||||
CMake version][2] installed to make use of the latest Quality-of-Life
|
||||
additions.
|
||||
|
||||
You have a few options to pass `astar_DEVELOPER_MODE` to the configure
|
||||
command, but this project prefers to use presets.
|
||||
|
||||
As a developer, you should create a `CMakeUserPresets.json` file at the root of
|
||||
the project:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 2,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 14,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"binaryDir": "${sourceDir}/build/dev",
|
||||
"inherits": ["dev-mode", "ci-<os>"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"configurePreset": "dev",
|
||||
"configuration": "Debug"
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"configurePreset": "dev",
|
||||
"configuration": "Debug",
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You should replace `<os>` in your newly created presets file with the name of
|
||||
the operating system you have, which may be `win64`, `linux` or `darwin`. You
|
||||
can see what these correspond to in the
|
||||
[`CMakePresets.json`](CMakePresets.json) file.
|
||||
|
||||
`CMakeUserPresets.json` is also the perfect place in which you can put all
|
||||
sorts of things that you would otherwise want to pass to the configure command
|
||||
in the terminal.
|
||||
|
||||
> **Note**
|
||||
> Some editors are pretty greedy with how they open projects with presets.
|
||||
> Some just randomly pick a preset and start configuring without your consent,
|
||||
> which can be confusing. Make sure that your editor configures when you
|
||||
> actually want it to, for example in CLion you have to make sure only the
|
||||
> `dev-dev preset` has `Enable profile` ticked in
|
||||
> `File > Settings... > Build, Execution, Deployment > CMake` and in Visual
|
||||
> Studio you have to set the option `Never run configure step automatically`
|
||||
> in `Tools > Options > CMake` **prior to opening the project**, after which
|
||||
> you can manually configure using `Project > Configure Cache`.
|
||||
|
||||
### Configure, build and test
|
||||
|
||||
If you followed the above instructions, then you can configure, build and test
|
||||
the project respectively with the following commands from the project root on
|
||||
any operating system with any build system:
|
||||
|
||||
```sh
|
||||
cmake --preset=dev
|
||||
cmake --build --preset=dev
|
||||
ctest --preset=dev
|
||||
```
|
||||
|
||||
If you are using a compatible editor (e.g. VSCode) or IDE (e.g. CLion, VS), you
|
||||
will also be able to select the above created user presets for automatic
|
||||
integration.
|
||||
|
||||
Please note that both the build and test commands accept a `-j` flag to specify
|
||||
the number of jobs to use, which should ideally be specified to the number of
|
||||
threads your CPU has. You may also want to add that to your preset using the
|
||||
`jobs` property, see the [presets documentation][1] for more details.
|
||||
|
||||
### Developer mode targets
|
||||
|
||||
These are targets you may invoke using the build command from above, with an
|
||||
additional `-t <target>` flag:
|
||||
|
||||
#### `coverage`
|
||||
|
||||
Available if `ENABLE_COVERAGE` is enabled. This target processes the output of
|
||||
the previously run tests when built with coverage configuration. The commands
|
||||
this target runs can be found in the `COVERAGE_TRACE_COMMAND` and
|
||||
`COVERAGE_HTML_COMMAND` cache variables. The trace command produces an info
|
||||
file by default, which can be submitted to services with CI integration. The
|
||||
HTML command uses the trace command's output to generate an HTML document to
|
||||
`<binary-dir>/coverage_html` by default.
|
||||
|
||||
#### `docs`
|
||||
|
||||
Available if `BUILD_MCSS_DOCS` is enabled. Builds to documentation using
|
||||
Doxygen and m.css. The output will go to `<binary-dir>/docs` by default
|
||||
(customizable using `DOXYGEN_OUTPUT_DIRECTORY`).
|
||||
|
||||
#### `format-check` and `format-fix`
|
||||
|
||||
These targets run the clang-format tool on the codebase to check errors and to
|
||||
fix them respectively. Customization available using the `FORMAT_PATTERNS` and
|
||||
`FORMAT_COMMAND` cache variables.
|
||||
|
||||
#### `run-examples`
|
||||
|
||||
Runs all the examples created by the `add_example` command.
|
||||
|
||||
#### `spell-check` and `spell-fix`
|
||||
|
||||
These targets run the codespell tool on the codebase to check errors and to fix
|
||||
them respectively. Customization available using the `SPELL_COMMAND` cache
|
||||
variable.
|
||||
|
||||
[1]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html
|
||||
[2]: https://cmake.org/download/
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Bensuperpc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
162
Makefile
Executable file
162
Makefile
Executable file
@ -0,0 +1,162 @@
|
||||
#//////////////////////////////////////////////////////////////
|
||||
#// ____ //
|
||||
#// | __ ) ___ _ __ ___ _ _ _ __ ___ _ __ _ __ ___ //
|
||||
#// | _ \ / _ \ '_ \/ __| | | | '_ \ / _ \ '__| '_ \ / __| //
|
||||
#// | |_) | __/ | | \__ \ |_| | |_) | __/ | | |_) | (__ //
|
||||
#// |____/ \___|_| |_|___/\__,_| .__/ \___|_| | .__/ \___| //
|
||||
#// |_| |_| //
|
||||
#//////////////////////////////////////////////////////////////
|
||||
#// //
|
||||
#// sandbox, 2023 //
|
||||
#// Created: 04, June, 2021 //
|
||||
#// Modified: 18, November, 2023 //
|
||||
#// file: - //
|
||||
#// - //
|
||||
#// Source: //
|
||||
#// OS: ALL //
|
||||
#// CPU: ALL //
|
||||
#// //
|
||||
#//////////////////////////////////////////////////////////////
|
||||
|
||||
PROJECT_NAME := world_of_blocks
|
||||
|
||||
PARALLEL := 1
|
||||
|
||||
GENERATOR := Ninja
|
||||
PROJECT_ROOT := .
|
||||
|
||||
CTEST_TIMEOUT := 1500
|
||||
CTEST_OPTIONS := --output-on-failure --timeout $(CTEST_TIMEOUT) --parallel $(PARALLEL) --verbose
|
||||
|
||||
# LANG := en
|
||||
# LANG=$(LANG)
|
||||
# -Werror=float-equal
|
||||
|
||||
.PHONY: build
|
||||
build: base
|
||||
|
||||
.PHONY: all
|
||||
all: release debug minsizerel coverage relwithdebinfo minsizerel relwithdebinfo release-clang \
|
||||
debug-clang base base-clang sanitize sanitize-clang gprof $(DOCKCROSS_IMAGE) docker valgrind gdb
|
||||
|
||||
.PHONY: base
|
||||
base:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=$@
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: base-clang
|
||||
base-clang:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=$@
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: release
|
||||
release:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=base -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: release-clang
|
||||
release-clang:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=base -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: debug
|
||||
debug:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=dev -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: debug-clang
|
||||
debug-clang:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=dev -DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=dev-coverage -DCMAKE_BUILD_TYPE=Coverage
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
cmake --build build/$@ --target $@
|
||||
|
||||
.PHONY: sanitize
|
||||
sanitize:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=ci-sanitize
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
sanitize-clang:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=ci-sanitize \
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: minsizerel
|
||||
minsizerel:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=dev -DCMAKE_BUILD_TYPE=MinSizeRel
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: relwithdebinfo
|
||||
relwithdebinfo:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=dev -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
cmake --build build/$@
|
||||
ctest $(CTEST_OPTIONS) --test-dir build/$@
|
||||
|
||||
.PHONY: gprof
|
||||
gprof:
|
||||
cmake --preset=$@ -G $(GENERATOR)
|
||||
cmake --build build/$@
|
||||
@echo "Run executable and after gprof <exe> gmon.out | less"
|
||||
|
||||
.PHONY: perf
|
||||
perf:
|
||||
cmake --preset=base -G $(GENERATOR)
|
||||
cmake --build build/base
|
||||
perf record --all-user -e branch-misses ./build/base/bin/$(PROJECT_NAME)
|
||||
|
||||
.PHONY: graph
|
||||
graph:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --graphviz=build/$@/graph.dot
|
||||
cmake --build build/base
|
||||
dot -Tpng -o build/$@/graph.png build/$@/graph.dot
|
||||
|
||||
.PHONY: valgrind
|
||||
valgrind:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=debugger
|
||||
cmake --build build/$@
|
||||
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=build/$@/valgrind.log ./build/$@/bin/$(PROJECT_NAME)
|
||||
|
||||
.PHONY: gdb
|
||||
gdb:
|
||||
cmake -B build/$@ -S $(PROJECT_ROOT) -G $(GENERATOR) --preset=debugger
|
||||
cmake --build build/$@
|
||||
gdb build/$@/bin/$(PROJECT_NAME)
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
cmake -D FORMAT_COMMAND=clang-format -P cmake/lint.cmake
|
||||
cmake -P cmake/spell.cmake
|
||||
|
||||
.PHONY: format
|
||||
format:
|
||||
time find . -regex '.*\.\(cpp\|cxx\|hpp\|hxx\|c\|h\|cu\|cuh\|cuhpp\|tpp\)' -not -path '*/build/*' -not -path '.git/*' | parallel clang-format -style=file -i {} \;
|
||||
|
||||
.PHONY: cloc
|
||||
cloc:
|
||||
cloc --fullpath --not-match-d="(build|.git)" --not-match-f="(.git)" .
|
||||
|
||||
.PHONY: update
|
||||
update:
|
||||
# git submodule update --recursive --remote --force --rebase
|
||||
git submodule update --init --recursive
|
||||
git pull --recurse-submodules --all --progress
|
||||
|
||||
.PHONY: clear
|
||||
clear:
|
||||
rm -rf build/*
|
207
README.md
Executable file
207
README.md
Executable file
@ -0,0 +1,207 @@
|
||||
# astar
|
||||
|
||||
Fast and easy to use header only 2D astar algorithm library in C++20.
|
||||
|
||||
I made it for learning how the astar algorithm works, try to make the fastest, tested and configurable as possible for my needs (future games and works).
|
||||
|
||||
# How does it work
|
||||
|
||||
It is an [astar algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm), the main idea is to find the shortest path between two points in a grid/map.
|
||||
|
||||
# Screenshots
|
||||
|
||||
![astar](resources/Screenshot_20240128_093812.png)
|
||||
|
||||
# Features
|
||||
|
||||
* [x] Header-only library C++20
|
||||
* [x] Support 2D map
|
||||
* [ ] Support 3D map
|
||||
* [x] Configurable heuristic function and movement cost
|
||||
* [x] Configurable (diagonal and more) movement
|
||||
* [x] Debug mode in template argument and lambda function
|
||||
* [x] Support direct access and not access to the map
|
||||
* [x] Unit tests and benchmarks
|
||||
|
||||
# How to use it
|
||||
|
||||
This project is a header-only library and easy to use, just copy the `include/astar` folder in your project and include the `astar/astar.hpp` header or via CMake FetchContent_Declare.
|
||||
|
||||
Now you can use the `Astar::Astar` class to find the shortest path between two points in a grid.
|
||||
|
||||
```cpp
|
||||
#include <astar/astar.hpp>
|
||||
#include <iostream>
|
||||
|
||||
auto main() -> int {
|
||||
// Create the template class with optional a type (e.g. uint32_t) and a boolean
|
||||
// if you want enable debug mode (AStar::AStar<uint32_t, true>)
|
||||
AStar::AStar pathFinder;
|
||||
|
||||
// Define the map size (width, height)
|
||||
pathFinder.setWorldSize({10, 10});
|
||||
|
||||
// Set the heuristic function (manhattan, euclidean, octagonal etc...), it is optional, default is euclidean
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
|
||||
// if you want to enable diagonal movement, it is optional, default is false
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
// Add a obstacle point (5, 5) and (5, 6)
|
||||
pathFinder.addObstacle({5, 5});
|
||||
pathFinder.addObstacle({5, 6});
|
||||
|
||||
// Find the path from (0, 0) to (9, 9)
|
||||
auto path = pathFinder.findPath({0, 0}, {9, 9});
|
||||
|
||||
// Print the path
|
||||
for (auto& p : path) {
|
||||
std::cout << p.x << " " << p.y << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Alternative version (direct access to the map)
|
||||
|
||||
You can use the alternative version of the library if you want astar have direct access to the map, this version is faster than the non-direct access version.
|
||||
|
||||
```cpp
|
||||
#include <astar/astar.hpp>
|
||||
#include <iostream>
|
||||
|
||||
auto main() -> int {
|
||||
// Create the template class with optional a type (e.g. uint32_t) and a boolean
|
||||
// if you want enable debug mode (AStar::AStar<uint32_t, true>)
|
||||
AStar::AStarFast pathFinder;
|
||||
|
||||
// Set the heuristic function (manhattan, euclidean, octagonal etc...), it is optional, default is euclidean
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
|
||||
// if you want to enable diagonal movement, it is optional, default is false
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
// Create world 9x9 filled with 0
|
||||
std::vector<uint32_t> world(9 * 9, 0);
|
||||
|
||||
// set lambda function to check if is an obstacle (value == 1)
|
||||
auto isObstacle = [](uint32_t value) -> bool { return value == 1; };
|
||||
pathFinder.setObstacle(isObstacle);
|
||||
|
||||
// Add a obstacle point (5, 5) and (5, 6)
|
||||
world[5 + 5 * 9] = 1;
|
||||
world[5 + 6 * 9] = 1;
|
||||
|
||||
// Find the path from (0, 0) to (9, 9), it it equal to 0, then the path is not found
|
||||
// This version of findPath() is faster due direct access to the world
|
||||
auto path = pathFinder.findPath({0, 0}, {9, 9}, world, {9, 9});
|
||||
|
||||
// Print the path
|
||||
for (auto& p : path) {
|
||||
std::cout << p.x << " " << p.y << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Debug mode
|
||||
|
||||
You can enable the debug mode to call a lambda function when new node is visiting by the algorithm and when new node is added to the open list.
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
|
||||
#include <astar/astar.hpp>
|
||||
|
||||
auto main() -> int {
|
||||
// Enable debug mode with template argument, this helps avoid performance issues on non-debug classes
|
||||
AStar::AStar<uint32_t, true> pathFinder;
|
||||
|
||||
// Set lambda function to debug current node
|
||||
std::function<void(const AStar::Node<uint32_t>* node)> debugCurrentNode = [](const AStar::Node<uint32_t>* node) {
|
||||
std::cout << "Current node: " << node->pos.x << ", " << node->pos.y << std::endl;
|
||||
};
|
||||
pathFinder.setDebugCurrentNode(debugCurrentNode);
|
||||
|
||||
// Set lambda function to debug open node
|
||||
std::function<void(const AStar::Node<uint32_t>* node)> debugOpenNode = [](const AStar::Node<uint32_t>* node) {
|
||||
std::cout << "Add to open list: " << node->pos.x << ", " << node->pos.y << std::endl;
|
||||
};
|
||||
pathFinder.setDebugOpenNode(debugOpenNode);
|
||||
|
||||
// Define the map size (width, height)
|
||||
pathFinder.setWorldSize({10, 10});
|
||||
|
||||
// Set the heuristic function (manhattan, euclidean, octagonal etc...), it is optional, default is euclidean
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
|
||||
// if you want to enable diagonal movement, it is optional, default is false
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
// Add a obstacle point (5, 5) and (5, 6)
|
||||
pathFinder.addObstacle({5, 5});
|
||||
pathFinder.addObstacle({5, 6});
|
||||
|
||||
// Find the path from (0, 0) to (9, 9)
|
||||
auto path = pathFinder.findPath({0, 0}, {9, 9});
|
||||
|
||||
// Print the path
|
||||
for (auto& p : path) {
|
||||
std::cout << p.x << " " << p.y << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
# Building and installing
|
||||
|
||||
See the [BUILDING](BUILDING.md) document.
|
||||
|
||||
# Contributing
|
||||
|
||||
See the [CONTRIBUTING](CONTRIBUTING.md) document.
|
||||
|
||||
# Sources, references and ideas
|
||||
|
||||
You can find here the sources, references, libs and ideas that I have used to make this library.
|
||||
|
||||
## Astar
|
||||
|
||||
Sources and references that I have used to make this library.
|
||||
|
||||
* [Wikipedia A* search algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm)
|
||||
* [A* Pathfinding](https://www.youtube.com/watch?v=-L-WgKMFuhE)
|
||||
* [AStar](https://github.com/yatima1460/AStar)
|
||||
* [Introduction to A*](https://theory.stanford.edu/~amitp/GameProgramming/AStarComparison.html)
|
||||
* [Easy A* (star) Pathfinding](https://medium.com/@nicholas.w.swift/easy-a-star-pathfinding-7e6689c7f7b2)
|
||||
* [a-star](https://www.ce.unipr.it/people/medici/a-star.html)$
|
||||
* [A* Search Algorithm](https://yuminlee2.medium.com/a-search-algorithm-42c1a13fcf9f)
|
||||
|
||||
## Bench others astar implementations
|
||||
|
||||
The list of others astar implementations that I have benchmarked to compare the performance of my implementation.
|
||||
|
||||
* [A* Search Algorithm](https://www.geeksforgeeks.org/a-search-algorithm/)
|
||||
* [a-star](https://github.com/daancode/a-star)
|
||||
* [A-Star-Search-Algorithm](https://github.com/lychengrex/A-Star-Search-Algorithm)
|
||||
* [Pathfinding](https://github.com/Gerard097/Pathfinding)
|
||||
|
||||
## Libraries
|
||||
|
||||
Libraries used in this project.
|
||||
|
||||
* [cmake-init](https://github.com/friendlyanon/cmake-init)
|
||||
* [google test](https://github.com/google/googletest)
|
||||
* [google benchmark](https://github.com/google/benchmark)
|
||||
* [Raylib](https://github.com/raysan5/raylib)
|
||||
|
||||
# Others
|
||||
|
||||
* [Benchmark visualization](https://int-i.github.io/python/2021-11-07/matplotlib-google-benchmark-visualization/)
|
||||
|
||||
# Licensing
|
||||
|
||||
[LICENSE](LICENSE)
|
33
cmake/coverage.cmake
Normal file
33
cmake/coverage.cmake
Normal file
@ -0,0 +1,33 @@
|
||||
# ---- Variables ----
|
||||
|
||||
# We use variables separate from what CTest uses, because those have
|
||||
# customization issues
|
||||
set(
|
||||
COVERAGE_TRACE_COMMAND
|
||||
lcov -c -q
|
||||
-o "${PROJECT_BINARY_DIR}/coverage.info"
|
||||
-d "${PROJECT_BINARY_DIR}"
|
||||
--include "${PROJECT_SOURCE_DIR}/*"
|
||||
CACHE STRING
|
||||
"; separated command to generate a trace for the 'coverage' target"
|
||||
)
|
||||
|
||||
set(
|
||||
COVERAGE_HTML_COMMAND
|
||||
genhtml --legend -f -q
|
||||
"${PROJECT_BINARY_DIR}/coverage.info"
|
||||
-p "${PROJECT_SOURCE_DIR}"
|
||||
-o "${PROJECT_BINARY_DIR}/coverage_html"
|
||||
CACHE STRING
|
||||
"; separated command to generate an HTML report for the 'coverage' target"
|
||||
)
|
||||
|
||||
# ---- Coverage target ----
|
||||
|
||||
add_custom_target(
|
||||
coverage
|
||||
COMMAND ${COVERAGE_TRACE_COMMAND}
|
||||
COMMAND ${COVERAGE_HTML_COMMAND}
|
||||
COMMENT "Generating coverage report"
|
||||
VERBATIM
|
||||
)
|
21
cmake/dev-mode.cmake
Normal file
21
cmake/dev-mode.cmake
Normal file
@ -0,0 +1,21 @@
|
||||
include(cmake/folders.cmake)
|
||||
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
option(BUILD_MCSS_DOCS "Build documentation using Doxygen and m.css" OFF)
|
||||
if(BUILD_MCSS_DOCS)
|
||||
include(cmake/docs.cmake)
|
||||
endif()
|
||||
|
||||
option(ENABLE_COVERAGE "Enable coverage support separate from CTest's" OFF)
|
||||
if(ENABLE_COVERAGE)
|
||||
include(cmake/coverage.cmake)
|
||||
endif()
|
||||
|
||||
include(cmake/lint-targets.cmake)
|
||||
include(cmake/spell-targets.cmake)
|
||||
|
||||
add_folders(Project)
|
112
cmake/docs-ci.cmake
Normal file
112
cmake/docs-ci.cmake
Normal file
@ -0,0 +1,112 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
foreach(var IN ITEMS PROJECT_BINARY_DIR PROJECT_SOURCE_DIR)
|
||||
if(NOT DEFINED "${var}")
|
||||
message(FATAL_ERROR "${var} must be defined")
|
||||
endif()
|
||||
endforeach()
|
||||
set(bin "${PROJECT_BINARY_DIR}")
|
||||
set(src "${PROJECT_SOURCE_DIR}")
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
set(mcss_SOURCE_DIR "${bin}/docs/.ci")
|
||||
if(NOT IS_DIRECTORY "${mcss_SOURCE_DIR}")
|
||||
file(MAKE_DIRECTORY "${mcss_SOURCE_DIR}")
|
||||
file(
|
||||
DOWNLOAD
|
||||
https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip
|
||||
"${mcss_SOURCE_DIR}/mcss.zip"
|
||||
STATUS status
|
||||
EXPECTED_MD5 00cd2757ebafb9bcba7f5d399b3bec7f
|
||||
)
|
||||
if(NOT status MATCHES "^0;")
|
||||
message(FATAL_ERROR "Download failed with ${status}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" -E tar xf mcss.zip
|
||||
WORKING_DIRECTORY "${mcss_SOURCE_DIR}"
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
if(NOT result EQUAL "0")
|
||||
message(FATAL_ERROR "Extraction failed with ${result}")
|
||||
endif()
|
||||
file(REMOVE "${mcss_SOURCE_DIR}/mcss.zip")
|
||||
endif()
|
||||
|
||||
find_program(Python3_EXECUTABLE NAMES python3 python)
|
||||
if(NOT Python3_EXECUTABLE)
|
||||
message(FATAL_ERROR "Python executable was not found")
|
||||
endif()
|
||||
|
||||
# ---- Process project() call in CMakeLists.txt ----
|
||||
|
||||
file(READ "${src}/CMakeLists.txt" content)
|
||||
|
||||
string(FIND "${content}" "project(" index)
|
||||
if(index EQUAL "-1")
|
||||
message(FATAL_ERROR "Could not find \"project(\"")
|
||||
endif()
|
||||
string(SUBSTRING "${content}" "${index}" -1 content)
|
||||
|
||||
string(FIND "${content}" "\n)\n" index)
|
||||
if(index EQUAL "-1")
|
||||
message(FATAL_ERROR "Could not find \"\\n)\\n\"")
|
||||
endif()
|
||||
string(SUBSTRING "${content}" 0 "${index}" content)
|
||||
|
||||
file(WRITE "${bin}/docs-ci.project.cmake" "docs_${content}\n)\n")
|
||||
|
||||
macro(list_pop_front list out)
|
||||
list(GET "${list}" 0 "${out}")
|
||||
list(REMOVE_AT "${list}" 0)
|
||||
endmacro()
|
||||
|
||||
function(docs_project name)
|
||||
cmake_parse_arguments(PARSE_ARGV 1 "" "" "VERSION;DESCRIPTION;HOMEPAGE_URL" LANGUAGES)
|
||||
set(PROJECT_NAME "${name}" PARENT_SCOPE)
|
||||
if(DEFINED _VERSION)
|
||||
set(PROJECT_VERSION "${_VERSION}" PARENT_SCOPE)
|
||||
string(REGEX MATCH "^[0-9]+(\\.[0-9]+)*" versions "${_VERSION}")
|
||||
string(REPLACE . ";" versions "${versions}")
|
||||
set(suffixes MAJOR MINOR PATCH TWEAK)
|
||||
while(NOT versions STREQUAL "" AND NOT suffixes STREQUAL "")
|
||||
list_pop_front(versions version)
|
||||
list_pop_front(suffixes suffix)
|
||||
set("PROJECT_VERSION_${suffix}" "${version}" PARENT_SCOPE)
|
||||
endwhile()
|
||||
endif()
|
||||
if(DEFINED _DESCRIPTION)
|
||||
set(PROJECT_DESCRIPTION "${_DESCRIPTION}" PARENT_SCOPE)
|
||||
endif()
|
||||
if(DEFINED _HOMEPAGE_URL)
|
||||
set(PROJECT_HOMEPAGE_URL "${_HOMEPAGE_URL}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
include("${bin}/docs-ci.project.cmake")
|
||||
|
||||
# ---- Generate docs ----
|
||||
|
||||
if(NOT DEFINED DOXYGEN_OUTPUT_DIRECTORY)
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY "${bin}/docs")
|
||||
endif()
|
||||
set(out "${DOXYGEN_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(file IN ITEMS Doxyfile conf.py)
|
||||
configure_file("${src}/docs/${file}.in" "${bin}/docs/${file}" @ONLY)
|
||||
endforeach()
|
||||
|
||||
set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py")
|
||||
set(config "${bin}/docs/conf.py")
|
||||
|
||||
file(REMOVE_RECURSE "${out}/html" "${out}/xml")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}"
|
||||
WORKING_DIRECTORY "${bin}/docs"
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
if(NOT result EQUAL "0")
|
||||
message(FATAL_ERROR "m.css returned with ${result}")
|
||||
endif()
|
46
cmake/docs.cmake
Normal file
46
cmake/docs.cmake
Normal file
@ -0,0 +1,46 @@
|
||||
# ---- Dependencies ----
|
||||
|
||||
set(extract_timestamps "")
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
|
||||
set(extract_timestamps DOWNLOAD_EXTRACT_TIMESTAMP YES)
|
||||
endif()
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
mcss URL
|
||||
https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip
|
||||
URL_MD5 00cd2757ebafb9bcba7f5d399b3bec7f
|
||||
SOURCE_DIR "${PROJECT_BINARY_DIR}/mcss"
|
||||
UPDATE_DISCONNECTED YES
|
||||
${extract_timestamps}
|
||||
)
|
||||
FetchContent_MakeAvailable(mcss)
|
||||
|
||||
find_package(Python3 3.6 REQUIRED)
|
||||
|
||||
# ---- Declare documentation target ----
|
||||
|
||||
set(
|
||||
DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/docs"
|
||||
CACHE PATH "Path for the generated Doxygen documentation"
|
||||
)
|
||||
|
||||
set(working_dir "${PROJECT_BINARY_DIR}/docs")
|
||||
|
||||
foreach(file IN ITEMS Doxyfile conf.py)
|
||||
configure_file("docs/${file}.in" "${working_dir}/${file}" @ONLY)
|
||||
endforeach()
|
||||
|
||||
set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py")
|
||||
set(config "${working_dir}/conf.py")
|
||||
|
||||
add_custom_target(
|
||||
docs
|
||||
COMMAND "${CMAKE_COMMAND}" -E remove_directory
|
||||
"${DOXYGEN_OUTPUT_DIRECTORY}/html"
|
||||
"${DOXYGEN_OUTPUT_DIRECTORY}/xml"
|
||||
COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}"
|
||||
COMMENT "Building documentation using Doxygen and m.css"
|
||||
WORKING_DIRECTORY "${working_dir}"
|
||||
VERBATIM
|
||||
)
|
21
cmake/folders.cmake
Normal file
21
cmake/folders.cmake
Normal file
@ -0,0 +1,21 @@
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS YES)
|
||||
|
||||
# Call this function at the end of a directory scope to assign a folder to
|
||||
# targets created in that directory. Utility targets will be assigned to the
|
||||
# UtilityTargets folder, otherwise to the ${name}Targets folder. If a target
|
||||
# already has a folder assigned, then that target will be skipped.
|
||||
function(add_folders name)
|
||||
get_property(targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
|
||||
foreach(target IN LISTS targets)
|
||||
get_property(folder TARGET "${target}" PROPERTY FOLDER)
|
||||
if(DEFINED folder)
|
||||
continue()
|
||||
endif()
|
||||
set(folder Utility)
|
||||
get_property(type TARGET "${target}" PROPERTY TYPE)
|
||||
if(NOT type STREQUAL "UTILITY")
|
||||
set(folder "${name}")
|
||||
endif()
|
||||
set_property(TARGET "${target}" PROPERTY FOLDER "${folder}Targets")
|
||||
endforeach()
|
||||
endfunction()
|
1
cmake/install-config.cmake
Normal file
1
cmake/install-config.cmake
Normal file
@ -0,0 +1 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/astarTargets.cmake")
|
66
cmake/install-rules.cmake
Normal file
66
cmake/install-rules.cmake
Normal file
@ -0,0 +1,66 @@
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
set(
|
||||
CMAKE_INSTALL_INCLUDEDIR "include/astar-${PROJECT_VERSION}"
|
||||
CACHE STRING ""
|
||||
)
|
||||
set_property(CACHE CMAKE_INSTALL_INCLUDEDIR PROPERTY TYPE PATH)
|
||||
endif()
|
||||
|
||||
# Project is configured with no languages, so tell GNUInstallDirs the lib dir
|
||||
set(CMAKE_INSTALL_LIBDIR lib CACHE PATH "")
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# find_package(<package>) call for consumers to find this project
|
||||
set(package astar)
|
||||
|
||||
install(
|
||||
DIRECTORY include/
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
COMPONENT astar_Development
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS astar_astar
|
||||
EXPORT astarTargets
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${package}ConfigVersion.cmake"
|
||||
COMPATIBILITY SameMajorVersion
|
||||
ARCH_INDEPENDENT
|
||||
)
|
||||
|
||||
# Allow package maintainers to freely override the path for the configs
|
||||
set(
|
||||
astar_INSTALL_CMAKEDIR "${CMAKE_INSTALL_DATADIR}/${package}"
|
||||
CACHE STRING "CMake package config location relative to the install prefix"
|
||||
)
|
||||
set_property(CACHE astar_INSTALL_CMAKEDIR PROPERTY TYPE PATH)
|
||||
mark_as_advanced(astar_INSTALL_CMAKEDIR)
|
||||
|
||||
install(
|
||||
FILES cmake/install-config.cmake
|
||||
DESTINATION "${astar_INSTALL_CMAKEDIR}"
|
||||
RENAME "${package}Config.cmake"
|
||||
COMPONENT astar_Development
|
||||
)
|
||||
|
||||
install(
|
||||
FILES "${PROJECT_BINARY_DIR}/${package}ConfigVersion.cmake"
|
||||
DESTINATION "${astar_INSTALL_CMAKEDIR}"
|
||||
COMPONENT astar_Development
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT astarTargets
|
||||
NAMESPACE astar::
|
||||
DESTINATION "${astar_INSTALL_CMAKEDIR}"
|
||||
COMPONENT astar_Development
|
||||
)
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
include(CPack)
|
||||
endif()
|
13
cmake/lib/backward-cpp.cmake
Normal file
13
cmake/lib/backward-cpp.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
backward-cpp
|
||||
GIT_REPOSITORY https://github.com/bombela/backward-cpp.git
|
||||
GIT_TAG 0ddfadc4b0f5c53e63259fe804ee595e6f01f4df) # 23-10-2022
|
||||
|
||||
FetchContent_MakeAvailable(backward-cpp)
|
||||
|
||||
# TODO: target_include_directories instead of include_directories
|
||||
include_directories(${backward-cpp_SOURCE_DIR})
|
70
cmake/lib/benchmark.cmake
Executable file
70
cmake/lib/benchmark.cmake
Executable file
@ -0,0 +1,70 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
find_package(benchmark QUIET)
|
||||
|
||||
if (NOT benchmark_FOUND)
|
||||
message(STATUS "benchmark not found on system, downloading...")
|
||||
include(FetchContent)
|
||||
|
||||
set(CMAKE_CXX_CLANG_TIDY_TMP "${CMAKE_CXX_CLANG_TIDY}")
|
||||
set(CMAKE_CXX_CLANG_TIDY "")
|
||||
|
||||
FetchContent_Declare(
|
||||
googlebenchmark
|
||||
GIT_REPOSITORY https://github.com/google/benchmark.git
|
||||
GIT_TAG ca8d0f7b613ac915cd6b161ab01b7be449d1e1cd
|
||||
#GIT_SHALLOW TRUE
|
||||
) # 12-10-2023
|
||||
|
||||
# Disable tests on google benchmark
|
||||
set(BENCHMARK_ENABLE_TESTING
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
set(BENCHMARK_ENABLE_WERROR
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
set(BENCHMARK_FORCE_WERROR
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
|
||||
set(BENCHMARK_ENABLE_INSTALL
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
|
||||
set(BENCHMARK_DOWNLOAD_DEPENDENCIES
|
||||
ON
|
||||
CACHE BOOL "" FORCE)
|
||||
|
||||
set(BENCHMARK_CXX_LINKER_FLAGS
|
||||
""
|
||||
CACHE STRING "" FORCE)
|
||||
|
||||
set(BENCHMARK_CXX_LIBRARIES
|
||||
""
|
||||
CACHE STRING "" FORCE)
|
||||
|
||||
set(BENCHMARK_CXX_FLAGS
|
||||
""
|
||||
CACHE STRING "" FORCE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE
|
||||
""
|
||||
CACHE STRING "" FORCE)
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS
|
||||
""
|
||||
CACHE STRING "" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(googlebenchmark)
|
||||
# Lib: benchmark::benchmark benchmark::benchmark_main
|
||||
|
||||
set(CMAKE_CXX_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY_TMP}")
|
||||
|
||||
set_target_properties(benchmark
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
)
|
||||
endif()
|
22
cmake/lib/boost.cmake
Executable file
22
cmake/lib/boost.cmake
Executable file
@ -0,0 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
if(NOT DEFINED BOOST_INCLUDE_LIBRARIES)
|
||||
set(BOOST_INCLUDE_LIBRARIES system)
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT DEFINED BOOST_ENABLE_CMAKE)
|
||||
set(BOOST_ENABLE_CMAKE ON)
|
||||
endif()
|
||||
|
||||
|
||||
FetchContent_Declare(
|
||||
Boost
|
||||
GIT_REPOSITORY https://github.com/boostorg/boost.git
|
||||
GIT_TAG boost-1.81.0
|
||||
#GIT_SHALLOW TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(Boost)
|
||||
|
15
cmake/lib/drogon.cmake
Normal file
15
cmake/lib/drogon.cmake
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
# https://github.com/drogonframework/drogon/issues/1288#issuecomment-1163902139
|
||||
FetchContent_Declare(drogon
|
||||
GIT_REPOSITORY https://github.com/drogonframework/drogon.git
|
||||
GIT_TAG v1.8.4 # 08-04-2023
|
||||
)
|
||||
|
||||
# Reset CXX_FLAGS to avoid warnings from drogon
|
||||
set(CMAKE_CXX_FLAGS_OLD "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-std=c++17 -O3")
|
||||
|
||||
FetchContent_MakeAvailable(drogon)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_OLD}")
|
11
cmake/lib/fast_noise2.cmake
Normal file
11
cmake/lib/fast_noise2.cmake
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
set(FASTNOISE2_NOISETOOL OFF CACHE BOOL "Build Noise Tool" FORCE)
|
||||
|
||||
FetchContent_Declare(FastNoise2
|
||||
GIT_REPOSITORY https://github.com/Auburn/FastNoise2.git
|
||||
GIT_TAG 0928ca22cd4cfd50e9b17cec4fe9d867b59c3943 # 2023-06-07
|
||||
)
|
||||
FetchContent_MakeAvailable(FastNoise2)
|
32
cmake/lib/gtest.cmake
Executable file
32
cmake/lib/gtest.cmake
Executable file
@ -0,0 +1,32 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
find_package(GTest QUIET)
|
||||
|
||||
if (NOT GTEST_FOUND)
|
||||
message(STATUS "GTest not found on system, downloading...")
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG 2dd1c131950043a8ad5ab0d2dda0e0970596586a) # 12-10-2023
|
||||
|
||||
# Disable tests on gtest
|
||||
set(gtest_build_tests
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
set(gtest_build_samples
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
# Lib: gtest gtest_main
|
||||
|
||||
set_target_properties(gtest
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
)
|
||||
endif()
|
31
cmake/lib/json.cmake
Executable file
31
cmake/lib/json.cmake
Executable file
@ -0,0 +1,31 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
find_package(nlohmann_json QUIET)
|
||||
|
||||
if (NOT nlohmann_json_FOUND)
|
||||
message(STATUS "nlohmann_json not found on system, downloading...")
|
||||
include(FetchContent)
|
||||
|
||||
#set(CMAKE_MODULE_PATH
|
||||
# ""
|
||||
# CACHE STRING "" FORCE)
|
||||
|
||||
#set(NLOHMANN_JSON_SYSTEM_INCLUDE
|
||||
# ""
|
||||
# CACHE STRING "" FORCE)
|
||||
|
||||
FetchContent_Declare(nlohmann_json
|
||||
GIT_REPOSITORY https://github.com/nlohmann/json.git
|
||||
GIT_TAG f56c6e2e30241b9245161a86ae9fecf6543bf411 # 2023-11-26
|
||||
)
|
||||
FetchContent_MakeAvailable(nlohmann_json)
|
||||
# nlohmann_json::nlohmann_json
|
||||
set_target_properties(nlohmann_json
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
)
|
||||
include_directories(${nlohmann_json_SOURCE_DIR}/include)
|
||||
endif()
|
42
cmake/lib/opencv.cmake
Normal file
42
cmake/lib/opencv.cmake
Normal file
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
set(OpenCV_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
find_package(OpenCV QUIET)
|
||||
|
||||
if (NOT OpenCV_FOUND)
|
||||
#set(OpenCV_STATIC ON)
|
||||
set(BUILD_EXAMPLES CACHE BOOL OFF)
|
||||
set(BUILD_DOCS CACHE BOOL OFF)
|
||||
set(BUILD_TESTS CACHE BOOL OFF)
|
||||
set(BUILD_PERF_TESTS CACHE BOOL OFF)
|
||||
#set(BUILD_PACKAGE CACHE BOOL OFF)
|
||||
|
||||
|
||||
set(BUILD_opencv_apps CACHE BOOL OFF)
|
||||
|
||||
FetchContent_Declare(
|
||||
OpenCV
|
||||
GIT_REPOSITORY https://github.com/opencv/opencv.git
|
||||
GIT_TAG 4.7.0
|
||||
#GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(OpenCV)
|
||||
#set(OpenCV_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
#include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
#message(FATAL_ERROR "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
|
||||
#find_package(OpenCV REQUIRED)
|
||||
|
||||
#include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
#target_include_directories("${NAME}" PRIVATE
|
||||
#${OPENCV_CONFIG_FILE_INCLUDE_DIR}
|
||||
#${OPENCV_MODULE_opencv_core_LOCATION}/include
|
||||
#${OPENCV_MODULE_opencv_highgui_LOCATION}/include
|
||||
#)
|
||||
#target_link_libraries("${NAME}" PRIVATE opencv_core opencv_highgui)
|
||||
#target_link_libraries("${NAME}" PRIVATE ${OpenCV_LIBS})
|
||||
#opencv_add_module()
|
||||
|
||||
endif()
|
6
cmake/lib/openmp.cmake
Executable file
6
cmake/lib/openmp.cmake
Executable file
@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
# message("OpenMP found")
|
||||
endif()
|
14
cmake/lib/perlin_noise.cmake
Executable file
14
cmake/lib/perlin_noise.cmake
Executable file
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(perlin_noise
|
||||
GIT_REPOSITORY https://github.com/Reputeless/PerlinNoise.git
|
||||
GIT_TAG bdf39fe92b2a585cdef485bcec2bca8ab5614095 # 2022-12-30
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
FetchContent_MakeAvailable(perlin_noise)
|
||||
include_directories("${perlin_noise_SOURCE_DIR}")
|
18
cmake/lib/pybind11.cmake
Executable file
18
cmake/lib/pybind11.cmake
Executable file
@ -0,0 +1,18 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED)
|
||||
find_package(pybind11)
|
||||
# add_subdirectory(pybind11)
|
||||
|
||||
if (NOT pybind11_FOUND)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
pybind11
|
||||
GIT_REPOSITORY https://github.com/pybind/pybind11.git
|
||||
GIT_TAG v2.10.3
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(pybind11)
|
||||
endif()
|
||||
|
||||
#pybind11_add_module(${PROJECT_NAME} main.cpp)
|
17
cmake/lib/raygui.cmake
Executable file
17
cmake/lib/raygui.cmake
Executable file
@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
set(BUILD_RAYLIB_CPP_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||
|
||||
find_package(raygui QUIET)
|
||||
|
||||
if (NOT raygui_FOUND)
|
||||
FetchContent_Declare(raygui
|
||||
GIT_REPOSITORY https://github.com/raysan5/raygui.git
|
||||
GIT_TAG 4.0
|
||||
)
|
||||
FetchContent_MakeAvailable(raygui)
|
||||
include_directories(${raygui_SOURCE_DIR})
|
||||
include_directories(${raygui_SOURCE_DIR}/src)
|
||||
endif()
|
13
cmake/lib/raylib-cpp.cmake
Executable file
13
cmake/lib/raylib-cpp.cmake
Executable file
@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
#find_package(raylib_cpp QUIET)
|
||||
|
||||
if (NOT raylib_cpp_FOUND)
|
||||
FetchContent_Declare(raylib_cpp
|
||||
GIT_REPOSITORY https://github.com/RobLoach/raylib-cpp.git
|
||||
GIT_TAG v5.0.0 # 08-12-2023
|
||||
)
|
||||
FetchContent_MakeAvailable(raylib_cpp)
|
||||
endif()
|
47
cmake/lib/raylib.cmake
Executable file
47
cmake/lib/raylib.cmake
Executable file
@ -0,0 +1,47 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
find_package(raylib QUIET)
|
||||
|
||||
if (NOT raylib_FOUND AND NOT FETCHCONTENT_FULLY_DISCONNECTED)
|
||||
message(STATUS "raylib not found on system, downloading...")
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
if(NOT DEFINED BUILD_EXAMPLES)
|
||||
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED BUILD_GAMES)
|
||||
set(BUILD_GAMES OFF CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED INCLUDE_EVERYTHING)
|
||||
set(INCLUDE_EVERYTHING ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED OPENGL_VERSION)
|
||||
#set(OPENGL_VERSION OFF CACHE STRING "4.3" FORCE)
|
||||
endif()
|
||||
|
||||
#set (CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/install CACHE PATH "default install path" FORCE)
|
||||
#set (CMAKE_INSTALL_LIBDIR ${CMAKE_BINARY_DIR}/lib CACHE PATH "default install path" FORCE)
|
||||
|
||||
#message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
|
||||
FetchContent_Declare(raylib
|
||||
GIT_REPOSITORY https://github.com/raysan5/raylib.git
|
||||
GIT_TAG 5.0 # 08-12-2023
|
||||
)
|
||||
FetchContent_MakeAvailable(raylib)
|
||||
|
||||
set_target_properties(raylib
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
)
|
||||
|
||||
set(raylib_FOUND TRUE)
|
||||
else()
|
||||
find_package(raylib 5.0.0 REQUIRED)
|
||||
endif()
|
11
cmake/lib/spdlog.cmake
Normal file
11
cmake/lib/spdlog.cmake
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
spdlog
|
||||
GIT_REPOSITORY https://github.com/gabime/spdlog.git
|
||||
GIT_TAG 7e635fca68d014934b4af8a1cf874f63989352b7) # 2023-07-09
|
||||
|
||||
FetchContent_MakeAvailable(spdlog)
|
||||
include_directories("${spdlog_SOURCE_DIR}")
|
14
cmake/lib/threadpool.cmake
Normal file
14
cmake/lib/threadpool.cmake
Normal file
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(bs-thread-pool
|
||||
GIT_REPOSITORY https://github.com/bshoshany/thread-pool.git
|
||||
GIT_TAG 6790920f61ab3e928ddaea835ab6a803d467f41d # 2023-12-28
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
FetchContent_MakeAvailable(bs-thread-pool)
|
||||
include_directories("${bs-thread-pool_SOURCE_DIR}/include")
|
10
cmake/lib/vector.cmake
Executable file
10
cmake/lib/vector.cmake
Executable file
@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
vector
|
||||
GIT_REPOSITORY https://github.com/bensuperpc/vector.git
|
||||
GIT_TAG 9febb9c84e7b73e6c621afd920dd3c8bb47a130c) # 2022-10-23
|
||||
|
||||
FetchContent_MakeAvailable(vector)
|
16
cmake/lib/zlib.cmake
Executable file
16
cmake/lib/zlib.cmake
Executable file
@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
find_package(zlib QUIET)
|
||||
|
||||
set(ZLIB_LIBRARY zlib)
|
||||
|
||||
if (NOT zlib_FOUND)
|
||||
FetchContent_Declare(
|
||||
zlib
|
||||
GIT_REPOSITORY https://github.com/madler/zlib.git
|
||||
GIT_TAG v1.2.13
|
||||
)
|
||||
FetchContent_MakeAvailable(zlib)
|
||||
endif()
|
34
cmake/lint-targets.cmake
Normal file
34
cmake/lint-targets.cmake
Normal file
@ -0,0 +1,34 @@
|
||||
set(
|
||||
FORMAT_PATTERNS
|
||||
source/*.cpp source/*.hpp
|
||||
include/*.hpp
|
||||
test/*.cpp test/*.hpp
|
||||
example/*.cpp example/*.hpp
|
||||
CACHE STRING
|
||||
"; separated patterns relative to the project source dir to format"
|
||||
)
|
||||
|
||||
set(FORMAT_COMMAND clang-format CACHE STRING "Formatter to use")
|
||||
|
||||
add_custom_target(
|
||||
format-check
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "FORMAT_COMMAND=${FORMAT_COMMAND}"
|
||||
-D "PATTERNS=${FORMAT_PATTERNS}"
|
||||
-P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
COMMENT "Linting the code"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
format-fix
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "FORMAT_COMMAND=${FORMAT_COMMAND}"
|
||||
-D "PATTERNS=${FORMAT_PATTERNS}"
|
||||
-D FIX=YES
|
||||
-P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
COMMENT "Fixing the code"
|
||||
VERBATIM
|
||||
)
|
52
cmake/lint.cmake
Normal file
52
cmake/lint.cmake
Normal file
@ -0,0 +1,52 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
macro(default name)
|
||||
if(NOT DEFINED "${name}")
|
||||
set("${name}" "${ARGN}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
default(FORMAT_COMMAND clang-format)
|
||||
default(
|
||||
PATTERNS
|
||||
source/*.cpp source/*.hpp
|
||||
include/*.hpp
|
||||
test/*.cpp test/*.hpp
|
||||
example/*.cpp example/*.hpp
|
||||
)
|
||||
default(FIX NO)
|
||||
|
||||
set(flag --output-replacements-xml)
|
||||
set(args OUTPUT_VARIABLE output)
|
||||
if(FIX)
|
||||
set(flag -i)
|
||||
set(args "")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE files ${PATTERNS})
|
||||
set(badly_formatted "")
|
||||
set(output "")
|
||||
string(LENGTH "${CMAKE_SOURCE_DIR}/" path_prefix_length)
|
||||
|
||||
foreach(file IN LISTS files)
|
||||
execute_process(
|
||||
COMMAND "${FORMAT_COMMAND}" --style=file "${flag}" "${file}"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
RESULT_VARIABLE result
|
||||
${args}
|
||||
)
|
||||
if(NOT result EQUAL "0")
|
||||
message(FATAL_ERROR "'${file}': formatter returned with ${result}")
|
||||
endif()
|
||||
if(NOT FIX AND output MATCHES "\n<replacement offset")
|
||||
string(SUBSTRING "${file}" "${path_prefix_length}" -1 relative_file)
|
||||
list(APPEND badly_formatted "${relative_file}")
|
||||
endif()
|
||||
set(output "")
|
||||
endforeach()
|
||||
|
||||
if(NOT badly_formatted STREQUAL "")
|
||||
list(JOIN badly_formatted "\n" bad_list)
|
||||
message("The following files are badly formatted:\n\n${bad_list}\n")
|
||||
message(FATAL_ERROR "Run again with FIX=YES to fix these files.")
|
||||
endif()
|
10
cmake/prelude.cmake
Normal file
10
cmake/prelude.cmake
Normal file
@ -0,0 +1,10 @@
|
||||
# ---- In-source guard ----
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"In-source builds are not supported. "
|
||||
"Please read the BUILDING document before trying to build this project. "
|
||||
"You may need to delete 'CMakeCache.txt' and 'CMakeFiles/' first."
|
||||
)
|
||||
endif()
|
6
cmake/project-is-top-level.cmake
Normal file
6
cmake/project-is-top-level.cmake
Normal file
@ -0,0 +1,6 @@
|
||||
# This variable is set by project() in CMake 3.21+
|
||||
string(
|
||||
COMPARE EQUAL
|
||||
"${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}"
|
||||
PROJECT_IS_TOP_LEVEL
|
||||
)
|
22
cmake/spell-targets.cmake
Normal file
22
cmake/spell-targets.cmake
Normal file
@ -0,0 +1,22 @@
|
||||
set(SPELL_COMMAND codespell CACHE STRING "Spell checker to use")
|
||||
|
||||
add_custom_target(
|
||||
spell-check
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "SPELL_COMMAND=${SPELL_COMMAND}"
|
||||
-P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
COMMENT "Checking spelling"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
spell-fix
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "SPELL_COMMAND=${SPELL_COMMAND}"
|
||||
-D FIX=YES
|
||||
-P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
COMMENT "Fixing spelling errors"
|
||||
VERBATIM
|
||||
)
|
31
cmake/spell.cmake
Executable file
31
cmake/spell.cmake
Executable file
@ -0,0 +1,31 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
macro(default name)
|
||||
if(NOT DEFINED "${name}")
|
||||
set("${name}" "${ARGN}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
default(SPELL_COMMAND codespell)
|
||||
default(FIX NO)
|
||||
|
||||
set(flag "")
|
||||
if(FIX)
|
||||
set(flag -w)
|
||||
endif()
|
||||
|
||||
set(flag "${flag}" --ignore-words codespell.ignore-words.txt)
|
||||
|
||||
execute_process(
|
||||
COMMAND "${SPELL_COMMAND}" ${flag}
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
|
||||
if(result EQUAL "65")
|
||||
message(FATAL_ERROR "Run again with FIX=YES to fix these errors.")
|
||||
elseif(result EQUAL "64")
|
||||
message(FATAL_ERROR "Spell checker printed the usage info. Bad arguments?")
|
||||
elseif(NOT result EQUAL "0")
|
||||
message(FATAL_ERROR "Spell checker returned with ${result}")
|
||||
endif()
|
9
cmake/utile/ccache.cmake
Executable file
9
cmake/utile/ccache.cmake
Executable file
@ -0,0 +1,9 @@
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
|
||||
if(CCACHE_PROGRAM)
|
||||
message(NOTICE "-- ccache is enabled (found here: ${CCACHE_PROGRAM})")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "\"${CCACHE_PROGRAM}\"")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "\"${CCACHE_PROGRAM}\"")
|
||||
else()
|
||||
message(WARNING "-- ccache has not been found")
|
||||
endif()
|
11
cmake/utile/distcc.cmake
Executable file
11
cmake/utile/distcc.cmake
Executable file
@ -0,0 +1,11 @@
|
||||
find_program(DISTCC_PROGRAM distcc)
|
||||
|
||||
message(WARNING "distcc module is in beta.")
|
||||
|
||||
if(DISTCC_PROGRAM)
|
||||
message(NOTICE "distcc is enabled (found here: ${DISTCC_PROGRAM})")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "\"${DISTCC_PROGRAM}\"")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "\"${DISTCC_PROGRAM}\"")
|
||||
else()
|
||||
message(NOTICE "distcc has not been found")
|
||||
endif()
|
11
cmake/utile/lto.cmake
Executable file
11
cmake/utile/lto.cmake
Executable file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.9.0)
|
||||
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT supported OUTPUT error)
|
||||
|
||||
if(supported)
|
||||
message(STATUS "IPO / LTO enabled")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
else()
|
||||
message(STATUS "IPO / LTO not supported: <${error}>")
|
||||
endif()
|
9
cmake/utile/ninja_color.cmake
Executable file
9
cmake/utile/ninja_color.cmake
Executable file
@ -0,0 +1,9 @@
|
||||
|
||||
option (FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." TRUE)
|
||||
if (${FORCE_COLORED_OUTPUT})
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
add_compile_options (-fdiagnostics-color=always)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_compile_options (-fcolor-diagnostics)
|
||||
endif ()
|
||||
endif ()
|
28
cmake/variables.cmake
Normal file
28
cmake/variables.cmake
Normal file
@ -0,0 +1,28 @@
|
||||
# ---- Developer mode ----
|
||||
|
||||
# Developer mode enables targets and code paths in the CMake scripts that are
|
||||
# only relevant for the developer(s) of astar
|
||||
# Targets necessary to build the project must be provided unconditionally, so
|
||||
# consumers can trivially build and package the project
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
option(astar_DEVELOPER_MODE "Enable developer mode" OFF)
|
||||
endif()
|
||||
|
||||
# ---- Warning guard ----
|
||||
|
||||
# target_include_directories with the SYSTEM modifier will request the compiler
|
||||
# to omit warnings from the provided paths, if the compiler supports that
|
||||
# This is to provide a user experience similar to find_package when
|
||||
# add_subdirectory or FetchContent is used to consume this project
|
||||
set(warning_guard "")
|
||||
if(NOT PROJECT_IS_TOP_LEVEL)
|
||||
option(
|
||||
astar_INCLUDES_WITH_SYSTEM
|
||||
"Use SYSTEM modifier for astar's includes, disabling warnings"
|
||||
ON
|
||||
)
|
||||
mark_as_advanced(astar_INCLUDES_WITH_SYSTEM)
|
||||
if(astar_INCLUDES_WITH_SYSTEM)
|
||||
set(warning_guard SYSTEM)
|
||||
endif()
|
||||
endif()
|
1
codespell.ignore-words.txt
Normal file
1
codespell.ignore-words.txt
Normal file
@ -0,0 +1 @@
|
||||
|
32
docs/Doxyfile.in
Normal file
32
docs/Doxyfile.in
Normal file
@ -0,0 +1,32 @@
|
||||
# Configuration for Doxygen for use with CMake
|
||||
# Only options that deviate from the default are included
|
||||
# To create a new Doxyfile containing all available options, call `doxygen -g`
|
||||
|
||||
# Get Project name and version from CMake
|
||||
PROJECT_NAME = "@PROJECT_NAME@"
|
||||
PROJECT_NUMBER = "@PROJECT_VERSION@"
|
||||
|
||||
# Add sources
|
||||
INPUT = "@PROJECT_SOURCE_DIR@/README.md" "@PROJECT_SOURCE_DIR@/include" "@PROJECT_SOURCE_DIR@/docs/pages"
|
||||
EXTRACT_ALL = YES
|
||||
RECURSIVE = YES
|
||||
OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIRECTORY@"
|
||||
|
||||
# Use the README as a main page
|
||||
USE_MDFILE_AS_MAINPAGE = "@PROJECT_SOURCE_DIR@/README.md"
|
||||
|
||||
# set relative include paths
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = "@PROJECT_SOURCE_DIR@/include" "@PROJECT_SOURCE_DIR@"
|
||||
STRIP_FROM_INC_PATH =
|
||||
|
||||
# We use m.css to generate the html documentation, so we only need XML output
|
||||
GENERATE_XML = YES
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_LATEX = NO
|
||||
XML_PROGRAMLISTING = NO
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# Include all directories, files and namespaces in the documentation
|
||||
# Disable to include only explicitly documented objects
|
||||
M_SHOW_UNDOCUMENTED = YES
|
6
docs/conf.py.in
Normal file
6
docs/conf.py.in
Normal file
@ -0,0 +1,6 @@
|
||||
DOXYFILE = 'Doxyfile'
|
||||
|
||||
LINKS_NAVBAR1 = [
|
||||
(None, 'pages', [(None, 'about')]),
|
||||
(None, 'namespaces', []),
|
||||
]
|
7
docs/pages/about.dox
Normal file
7
docs/pages/about.dox
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @page about About
|
||||
* @section about-doxygen Doxygen documentation
|
||||
* This page is auto generated using
|
||||
* <a href="https://www.doxygen.nl/">Doxygen</a>, making use of some useful
|
||||
* <a href="https://www.doxygen.nl/manual/commands.html">special commands</a>.
|
||||
*/
|
27
example/CMakeLists.txt
Normal file
27
example/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(astarExamples CXX)
|
||||
|
||||
include(../cmake/project-is-top-level.cmake)
|
||||
include(../cmake/folders.cmake)
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
find_package(astar REQUIRED)
|
||||
endif()
|
||||
|
||||
add_custom_target(run-examples)
|
||||
|
||||
function(add_example NAME)
|
||||
add_executable("${NAME}" "${NAME}.cpp")
|
||||
target_link_libraries("${NAME}" PRIVATE astar::astar)
|
||||
target_compile_features("${NAME}" PRIVATE cxx_std_20)
|
||||
add_custom_target("run_${NAME}" COMMAND "${NAME}" VERBATIM)
|
||||
add_dependencies("run_${NAME}" "${NAME}")
|
||||
add_dependencies(run-examples "run_${NAME}")
|
||||
endfunction()
|
||||
|
||||
add_example(basic_example)
|
||||
add_example(debug_example)
|
||||
add_example(basic_fast_example)
|
||||
|
||||
add_folders(Example)
|
31
example/basic_example.cpp
Normal file
31
example/basic_example.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <astar/astar.hpp>
|
||||
#include <iostream>
|
||||
|
||||
auto main() -> int {
|
||||
// Create the template class with optional a type (e.g. uint32_t) and a boolean
|
||||
// if you want enable debug mode (AStar::AStar<uint32_t, true>)
|
||||
AStar::AStar pathFinder;
|
||||
|
||||
// Define the map size (width, height)
|
||||
pathFinder.setWorldSize({10, 10});
|
||||
|
||||
// Set the heuristic function (manhattan, euclidean, octagonal etc...), it is optional, default is euclidean
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
|
||||
// if you want to enable diagonal movement, it is optional, default is false
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
// Add a obstacle point (5, 5) and (5, 6)
|
||||
pathFinder.addObstacle({5, 5});
|
||||
pathFinder.addObstacle({5, 6});
|
||||
|
||||
// Find the path from (0, 0) to (9, 9), it it equal to 0, then the path is not found
|
||||
auto path = pathFinder.findPath({0, 0}, {9, 9});
|
||||
|
||||
// Print the path
|
||||
for (auto& p : path) {
|
||||
std::cout << p.x << " " << p.y << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
36
example/basic_fast_example.cpp
Executable file
36
example/basic_fast_example.cpp
Executable file
@ -0,0 +1,36 @@
|
||||
#include <astar/astar.hpp>
|
||||
#include <iostream>
|
||||
|
||||
auto main() -> int {
|
||||
// Create the template class with optional a type (e.g. uint32_t) and a boolean
|
||||
// if you want enable debug mode (AStar::AStar<uint32_t, true>)
|
||||
AStar::AStarFast pathFinder;
|
||||
|
||||
// Set the heuristic function (manhattan, euclidean, octagonal etc...), it is optional, default is euclidean
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
|
||||
// if you want to enable diagonal movement, it is optional, default is false
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
// Create world 9x9 filled with 0
|
||||
std::vector<uint32_t> world(9 * 9, 0);
|
||||
|
||||
// set lambda function to check if is an obstacle (value == 1)
|
||||
auto isObstacle = [](uint32_t value) -> bool { return value == 1; };
|
||||
pathFinder.setObstacle(isObstacle);
|
||||
|
||||
// Add a obstacle point (5, 5) and (5, 6)
|
||||
world[5 + 5 * 9] = 1;
|
||||
world[5 + 6 * 9] = 1;
|
||||
|
||||
// Find the path from (0, 0) to (9, 9), it it equal to 0, then the path is not found
|
||||
// This version of findPath() is faster due direct access to the world
|
||||
auto path = pathFinder.findPath({0, 0}, {9, 9}, world, {9, 9});
|
||||
|
||||
// Print the path
|
||||
for (auto& p : path) {
|
||||
std::cout << p.x << " " << p.y << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
43
example/debug_example.cpp
Normal file
43
example/debug_example.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <astar/astar.hpp>
|
||||
|
||||
auto main() -> int {
|
||||
// Enable debug mode with template argument, this helps avoid performance issues on non-debug classes
|
||||
AStar::AStar<uint32_t, true> pathFinder;
|
||||
|
||||
// Set lambda function to debug current node
|
||||
std::function<void(const AStar::Node<uint32_t>* node)> debugCurrentNode = [](const AStar::Node<uint32_t>* node) {
|
||||
std::cout << "Current node: " << node->pos.x << ", " << node->pos.y << std::endl;
|
||||
};
|
||||
pathFinder.setDebugCurrentNode(debugCurrentNode);
|
||||
|
||||
// Set lambda function to debug open node
|
||||
std::function<void(const AStar::Node<uint32_t>* node)> debugOpenNode = [](const AStar::Node<uint32_t>* node) {
|
||||
std::cout << "Add to open list: " << node->pos.x << ", " << node->pos.y << std::endl;
|
||||
};
|
||||
pathFinder.setDebugOpenNode(debugOpenNode);
|
||||
|
||||
// Define the map size (width, height)
|
||||
pathFinder.setWorldSize({10, 10});
|
||||
|
||||
// Set the heuristic function (manhattan, euclidean, octagonal etc...), it is optional, default is euclidean
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
|
||||
// if you want to enable diagonal movement, it is optional, default is false
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
// Add a obstacle point (5, 5) and (5, 6)
|
||||
pathFinder.addObstacle({5, 5});
|
||||
pathFinder.addObstacle({5, 6});
|
||||
|
||||
// Find the path from (0, 0) to (9, 9)
|
||||
auto path = pathFinder.findPath({0, 0}, {9, 9});
|
||||
|
||||
// Print the path
|
||||
for (auto& p : path) {
|
||||
std::cout << p.x << " " << p.y << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
360
include/astar/astar.hpp
Normal file
360
include/astar/astar.hpp
Normal file
@ -0,0 +1,360 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
template <typename T>
|
||||
concept ArithmeticType = std::is_arithmetic<T>::value;
|
||||
|
||||
template <typename T>
|
||||
concept IntegerType = std::is_integral<T>::value;
|
||||
|
||||
template <typename T>
|
||||
concept FloatingPointType = std::is_floating_point<T>::value;
|
||||
|
||||
namespace AStar {
|
||||
|
||||
template <IntegerType T = int32_t>
|
||||
class Vec2 {
|
||||
public:
|
||||
Vec2() = default;
|
||||
Vec2(T x_, T y_) : x(x_), y(y_) {}
|
||||
|
||||
bool operator==(const Vec2& pos) const noexcept { return (x == pos.x && y == pos.y); }
|
||||
Vec2 operator=(const Vec2& pos) noexcept {
|
||||
x = pos.x;
|
||||
y = pos.y;
|
||||
return *this;
|
||||
}
|
||||
Vec2 operator+(const Vec2& pos) noexcept { return {x + pos.x, y + pos.y}; }
|
||||
Vec2 operator-(const Vec2& pos) noexcept { return {x - pos.x, y - pos.y}; }
|
||||
Vec2 operator*(const Vec2& pos) noexcept { return {x * pos.x, y * pos.y}; }
|
||||
Vec2 operator/(const Vec2& pos) noexcept { return {x / pos.x, y / pos.y}; }
|
||||
struct hash {
|
||||
size_t operator()(const Vec2& pos) const noexcept { return std::hash<size_t>()(pos.x ^ (pos.y << 4)); }
|
||||
};
|
||||
|
||||
T x = 0;
|
||||
T y = 0;
|
||||
};
|
||||
typedef Vec2<int32_t> Vec2i;
|
||||
|
||||
template <IntegerType T = uint32_t>
|
||||
class Node {
|
||||
public:
|
||||
explicit Node() : pos(Vec2i(0, 0)), parentNode(nullptr) {}
|
||||
explicit Node(const Vec2i& pos, Node* parent = nullptr) : pos(pos), parentNode(parent) {}
|
||||
explicit Node(const Vec2i& pos, const T pathCost, const T heuristicCost, Node* parent = nullptr)
|
||||
: pathCost(pathCost), heuristicCost(heuristicCost), pos(pos), parentNode(parent) {}
|
||||
inline T getTotalCost() const noexcept { return pathCost + heuristicCost; }
|
||||
struct hash {
|
||||
size_t operator()(const Node* node) const noexcept { return std::hash<size_t>()(node->pos.x ^ (node->pos.y << 4)); }
|
||||
};
|
||||
|
||||
T pathCost = 0;
|
||||
T heuristicCost = 0;
|
||||
Vec2i pos = {0, 0};
|
||||
Node* parentNode = nullptr;
|
||||
};
|
||||
|
||||
namespace Heuristic {
|
||||
static inline Vec2i deltaVec(const Vec2i& source, const Vec2i& target) noexcept {
|
||||
return {std::abs(source.x - target.x), std::abs(source.y - target.y)};
|
||||
}
|
||||
|
||||
static inline uint32_t manhattan(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept {
|
||||
auto delta = deltaVec(source, target);
|
||||
return weight * (delta.x + delta.y);
|
||||
}
|
||||
|
||||
static inline uint32_t octagonal(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept {
|
||||
auto delta = deltaVec(source, target);
|
||||
return weight * (delta.x + delta.y) + (-6) * std::min(delta.x, delta.y);
|
||||
}
|
||||
|
||||
static inline uint32_t euclidean(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept {
|
||||
auto delta = deltaVec(source, target);
|
||||
return weight * static_cast<uint32_t>(std::sqrt(std::pow(delta.x, 2) + std::pow(delta.y, 2)));
|
||||
}
|
||||
|
||||
static inline uint32_t chebyshev(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept {
|
||||
auto delta = deltaVec(source, target);
|
||||
return weight * std::max(delta.x, delta.y);
|
||||
}
|
||||
|
||||
static inline uint32_t euclideanNoSQR(const Vec2i& source, const Vec2i& target, const uint32_t weight) noexcept {
|
||||
auto delta = deltaVec(source, target);
|
||||
return weight * static_cast<uint32_t>(std::pow(delta.x, 2) + std::pow(delta.y, 2));
|
||||
}
|
||||
|
||||
static constexpr uint32_t dijkstra([[maybe_unused]] const Vec2i& source,
|
||||
[[maybe_unused]] const Vec2i& target,
|
||||
const uint32_t weight = 0) noexcept {
|
||||
return 0;
|
||||
}
|
||||
}; // namespace Heuristic
|
||||
|
||||
template <IntegerType T = uint32_t, bool enableDebug = false>
|
||||
class AStarVirtual {
|
||||
public:
|
||||
explicit AStarVirtual()
|
||||
: _heuristicFunction(&Heuristic::euclidean),
|
||||
_directionsCount(4),
|
||||
_heuristicWeight(10),
|
||||
_mouvemementCost(10),
|
||||
_debugCurrentNode([](Node<T>*) {}),
|
||||
_debugOpenNode([](Node<T>*) {}) {
|
||||
_directions = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
|
||||
}
|
||||
void setHeuristic(const std::function<uint32_t(Vec2i, Vec2i, uint32_t)>& heuristic) {
|
||||
_heuristicFunction = std::bind(heuristic, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
}
|
||||
std::function<uint32_t(Vec2i, Vec2i, uint32_t)>& getHeuristic() noexcept { return _heuristicFunction; }
|
||||
|
||||
void setHeuristicWeight(const uint32_t weight) noexcept { _heuristicWeight = weight; }
|
||||
uint32_t getHeuristicWeight() const noexcept { return _heuristicWeight; }
|
||||
|
||||
void setDiagonalMovement(const bool enableDiagonalMovement) noexcept {
|
||||
_directionsCount = (enableDiagonalMovement ? _directions.size() : _directions.size() / 2);
|
||||
}
|
||||
|
||||
void setMouvemementCost(const size_t cost) noexcept { _mouvemementCost = cost; }
|
||||
size_t getMouvemementCost() const noexcept { return _mouvemementCost; }
|
||||
|
||||
void setCustomDirections(const std::vector<Vec2i>& directions) noexcept {
|
||||
_directions = directions;
|
||||
_directionsCount = static_cast<size_t>(directions.size());
|
||||
}
|
||||
|
||||
std::vector<Vec2i>& getDirections() noexcept { return _directions; }
|
||||
|
||||
void setDebugCurrentNode(const std::function<void(Node<T>*)>& debugCurrentNode) noexcept { _debugCurrentNode = debugCurrentNode; }
|
||||
void setDebugOpenNode(const std::function<void(Node<T>*)>& debugOpenNode) noexcept { _debugOpenNode = debugOpenNode; }
|
||||
|
||||
protected:
|
||||
std::function<uint32_t(Vec2i, Vec2i, uint32_t)> _heuristicFunction;
|
||||
std::vector<Vec2i> _directions;
|
||||
size_t _directionsCount;
|
||||
T _heuristicWeight;
|
||||
size_t _mouvemementCost = 10;
|
||||
|
||||
// Only used if enableDebug is true
|
||||
std::function<void(Node<T>*)> _debugCurrentNode;
|
||||
std::function<void(Node<T>*)> _debugOpenNode;
|
||||
};
|
||||
|
||||
template <IntegerType T = uint32_t, bool enableDebug = false>
|
||||
class AStar final : public AStarVirtual<T, enableDebug> {
|
||||
public:
|
||||
explicit AStar() {}
|
||||
|
||||
std::vector<Vec2i> findPath(const Vec2i source, const Vec2i& target) {
|
||||
if (target.x < 0 || target.x >= _worldSize.x || target.y < 0 || target.y >= _worldSize.y) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Node<T>* currentNode = nullptr;
|
||||
|
||||
auto compareFn = [](const Node<T>* a, const Node<T>* b) { return a->getTotalCost() > b->getTotalCost(); };
|
||||
std::priority_queue<Node<T>*, std::vector<Node<T>*>, decltype(compareFn)> openNodeVecPQueue =
|
||||
std::priority_queue<Node<T>*, std::vector<Node<T>*>, decltype(compareFn)>(compareFn);
|
||||
|
||||
std::unordered_map<Vec2i, Node<T>*, Vec2i::hash> openNodeMap;
|
||||
std::unordered_map<Vec2i, Node<T>*, Vec2i::hash> closedNodeMap;
|
||||
|
||||
openNodeVecPQueue.push(new Node<T>(source));
|
||||
openNodeMap.insert({source, openNodeVecPQueue.top()});
|
||||
|
||||
while (!openNodeVecPQueue.empty()) {
|
||||
currentNode = openNodeVecPQueue.top();
|
||||
|
||||
if constexpr (enableDebug) {
|
||||
AStarVirtual<T, enableDebug>::_debugCurrentNode(currentNode);
|
||||
}
|
||||
|
||||
if (currentNode->pos == target) {
|
||||
break;
|
||||
}
|
||||
|
||||
openNodeVecPQueue.pop();
|
||||
openNodeMap.erase(currentNode->pos);
|
||||
closedNodeMap.insert({currentNode->pos, currentNode});
|
||||
|
||||
for (size_t i = 0; i < AStarVirtual<T, enableDebug>::_directionsCount; ++i) {
|
||||
Vec2i newPos = currentNode->pos + AStarVirtual<T, enableDebug>::_directions[i];
|
||||
|
||||
if (_obstacles.contains(newPos)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (closedNodeMap.contains(newPos)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newPos.x < 0 || newPos.x >= _worldSize.x || newPos.y < 0 || newPos.y >= _worldSize.y) {
|
||||
continue;
|
||||
}
|
||||
|
||||
T nextCost = currentNode->pathCost + AStarVirtual<T, enableDebug>::_mouvemementCost;
|
||||
Node<T>* nextNode = openNodeMap.find(newPos) != openNodeMap.end() ? openNodeMap[newPos] : nullptr;
|
||||
|
||||
if (nextNode == nullptr) {
|
||||
nextNode = new Node<T>(newPos, currentNode);
|
||||
nextNode->pathCost = nextCost;
|
||||
nextNode->heuristicCost = static_cast<T>(AStarVirtual<T, enableDebug>::_heuristicFunction(
|
||||
nextNode->pos, target, AStarVirtual<T, enableDebug>::_heuristicWeight));
|
||||
openNodeVecPQueue.push(nextNode);
|
||||
openNodeMap.insert({nextNode->pos, nextNode});
|
||||
} else if (nextCost < nextNode->pathCost) {
|
||||
nextNode->parentNode = currentNode;
|
||||
nextNode->pathCost = nextCost;
|
||||
}
|
||||
|
||||
if constexpr (enableDebug) {
|
||||
AStarVirtual<T, enableDebug>::_debugOpenNode(nextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Vec2i> path;
|
||||
|
||||
if (currentNode->pos == target) [[likely]] {
|
||||
path.reserve(currentNode->getTotalCost() / 10);
|
||||
while (currentNode != nullptr) {
|
||||
path.push_back(currentNode->pos);
|
||||
currentNode = currentNode->parentNode;
|
||||
}
|
||||
}
|
||||
for (auto& [key, value] : openNodeMap) {
|
||||
delete value;
|
||||
}
|
||||
|
||||
for (auto& [key, value] : closedNodeMap) {
|
||||
delete value;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void addObstacle(const Vec2i& pos) { _obstacles.insert(pos); }
|
||||
void removeObstacle(const Vec2i& pos) { _obstacles.erase(pos); }
|
||||
std::unordered_set<Vec2i, Vec2i::hash>& getObstacles() noexcept { return _obstacles; }
|
||||
|
||||
void clear() { _obstacles.clear(); }
|
||||
void setWorldSize(const Vec2i& worldSize_) noexcept { _worldSize = worldSize_; }
|
||||
|
||||
private:
|
||||
std::unordered_set<Vec2i, Vec2i::hash> _obstacles;
|
||||
Vec2i _worldSize = {0, 0};
|
||||
};
|
||||
|
||||
// Fast AStar are faster than normal AStar but use more ram and direct access to the map
|
||||
template <IntegerType T = uint32_t, bool enableDebug = false, IntegerType U = uint32_t>
|
||||
class AStarFast final : public AStarVirtual<T, enableDebug> {
|
||||
public:
|
||||
explicit AStarFast() : _isObstacleFunction([](U value) { return value == 1; }) {}
|
||||
|
||||
// Same as AStar::findPath() but use direct access to the map
|
||||
std::vector<Vec2i> findPath(const Vec2i& source, const Vec2i& target, const std::vector<U>& map, const Vec2i& worldSize) {
|
||||
if (target.x < 0 || target.x >= worldSize.x || target.y < 0 || target.y >= worldSize.y) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Node<T>* currentNode = nullptr;
|
||||
|
||||
auto compareFn = [](const Node<T>* a, const Node<T>* b) { return a->getTotalCost() > b->getTotalCost(); };
|
||||
std::priority_queue<Node<T>*, std::vector<Node<T>*>, decltype(compareFn)> openNodeVecPQueue =
|
||||
std::priority_queue<Node<T>*, std::vector<Node<T>*>, decltype(compareFn)>(compareFn);
|
||||
std::unordered_map<Vec2i, Node<T>*, Vec2i::hash> openNodeMap;
|
||||
std::unordered_map<Vec2i, Node<T>*, Vec2i::hash> closedNodeMap;
|
||||
|
||||
openNodeVecPQueue.push(new Node<T>(source));
|
||||
openNodeMap.insert({source, openNodeVecPQueue.top()});
|
||||
|
||||
while (!openNodeVecPQueue.empty()) {
|
||||
currentNode = openNodeVecPQueue.top();
|
||||
|
||||
if constexpr (enableDebug) {
|
||||
AStarVirtual<T, enableDebug>::_debugCurrentNode(currentNode);
|
||||
}
|
||||
|
||||
if (currentNode->pos == target) {
|
||||
break;
|
||||
}
|
||||
|
||||
openNodeVecPQueue.pop();
|
||||
openNodeMap.erase(currentNode->pos);
|
||||
closedNodeMap.insert({currentNode->pos, currentNode});
|
||||
|
||||
for (size_t i = 0; i < AStarVirtual<T, enableDebug>::_directionsCount; ++i) {
|
||||
Vec2i newPos = currentNode->pos + AStarVirtual<T, enableDebug>::_directions[i];
|
||||
|
||||
if (_isObstacleFunction(map[newPos.x + newPos.y * worldSize.x])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (closedNodeMap.contains(newPos)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newPos.x < 0 || newPos.x >= worldSize.x || newPos.y < 0 || newPos.y >= worldSize.y) {
|
||||
continue;
|
||||
}
|
||||
|
||||
T nextCost = currentNode->pathCost + AStarVirtual<T, enableDebug>::_mouvemementCost;
|
||||
Node<T>* nextNode = openNodeMap.find(newPos) != openNodeMap.end() ? openNodeMap[newPos] : nullptr;
|
||||
if (nextNode == nullptr) {
|
||||
nextNode = new Node<T>(newPos, currentNode);
|
||||
nextNode->pathCost = nextCost;
|
||||
nextNode->heuristicCost = static_cast<T>(AStarVirtual<T, enableDebug>::_heuristicFunction(
|
||||
nextNode->pos, target, AStarVirtual<T, enableDebug>::_heuristicWeight));
|
||||
openNodeVecPQueue.push(nextNode);
|
||||
openNodeMap.insert({nextNode->pos, nextNode});
|
||||
} else if (nextCost < nextNode->pathCost) [[likely]] {
|
||||
nextNode->parentNode = currentNode;
|
||||
nextNode->pathCost = nextCost;
|
||||
}
|
||||
|
||||
if constexpr (enableDebug) {
|
||||
AStarVirtual<T, enableDebug>::_debugOpenNode(nextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Vec2i> path;
|
||||
|
||||
if (currentNode->pos == target) [[likely]] {
|
||||
path.reserve(currentNode->getTotalCost() / 10);
|
||||
while (currentNode != nullptr) {
|
||||
path.push_back(currentNode->pos);
|
||||
currentNode = currentNode->parentNode;
|
||||
}
|
||||
}
|
||||
for (auto& [key, value] : openNodeMap) {
|
||||
delete value;
|
||||
}
|
||||
|
||||
for (auto& [key, value] : closedNodeMap) {
|
||||
delete value;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
void setObstacle(const std::function<bool(U)>& isObstacleFunction) noexcept { _isObstacleFunction = isObstacleFunction; }
|
||||
std::function<bool(U)>& getObstacle() noexcept { return _isObstacleFunction; }
|
||||
|
||||
private:
|
||||
std::function<bool(U)> _isObstacleFunction;
|
||||
};
|
||||
|
||||
} // namespace AStar
|
BIN
resources/Screenshot_20240128_093812.png
Normal file
BIN
resources/Screenshot_20240128_093812.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
82
test/CMakeLists.txt
Normal file
82
test/CMakeLists.txt
Normal file
@ -0,0 +1,82 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(astarTests LANGUAGES C CXX)
|
||||
|
||||
include(../cmake/project-is-top-level.cmake)
|
||||
include(../cmake/folders.cmake)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
find_package(astar REQUIRED)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
||||
|
||||
function(test_bench_generator TEST_BENCH_NAME IS_TEST ADD_TO_TEST)
|
||||
if (IS_TEST)
|
||||
add_executable("${TEST_BENCH_NAME}" "source/test/${TEST_BENCH_NAME}.cpp" source/generator/generator.cpp source/generator/generator.hpp)
|
||||
else()
|
||||
add_executable("${TEST_BENCH_NAME}" "source/benchmark/${TEST_BENCH_NAME}.cpp" source/generator/generator.cpp source/generator/generator.hpp)
|
||||
endif()
|
||||
|
||||
|
||||
if (IS_TEST)
|
||||
target_link_libraries("${TEST_BENCH_NAME}" PRIVATE gtest)
|
||||
else()
|
||||
target_link_libraries("${TEST_BENCH_NAME}" PRIVATE benchmark::benchmark)
|
||||
endif()
|
||||
|
||||
target_link_libraries("${TEST_BENCH_NAME}" PRIVATE astar::astar)
|
||||
target_link_libraries("${TEST_BENCH_NAME}" PRIVATE raylib)
|
||||
target_link_libraries("${TEST_BENCH_NAME}" PRIVATE FastNoise2)
|
||||
#target_link_libraries("${TEST_BENCH_NAME}" PRIVATE spdlog::spdlog nlohmann_json::nlohmann_json)
|
||||
|
||||
#if (OpenMP_FOUND OR OpenMP_CXX_FOUND)
|
||||
# target_link_libraries("${TEST_BENCH_NAME}" PRIVATE OpenMP::OpenMP_CXX)
|
||||
#endif()
|
||||
|
||||
set_target_properties("${TEST_BENCH_NAME}"
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
)
|
||||
|
||||
#if(NOT CMAKE_BUILD_TYPE MATCHES Debug AND NOT CMAKE_BUILD_TYPE MATCHES Coverage)
|
||||
# add_test(NAME "${TEST_BENCH_NAME}" COMMAND $<TARGET_FILE:${TEST_BENCH_NAME}>)
|
||||
#elseif()
|
||||
# message(STATUS "Disable ${BENCH_NAME}, Performance benchmark test only run on Release/RelWithDebInfo/MinSizeRel")
|
||||
#endif()
|
||||
|
||||
if (ADD_TO_TEST)
|
||||
add_test(NAME "${TEST_BENCH_NAME}" COMMAND $<TARGET_FILE:${TEST_BENCH_NAME}>)
|
||||
endif()
|
||||
target_compile_features("${TEST_BENCH_NAME}" PRIVATE cxx_std_20)
|
||||
endfunction()
|
||||
|
||||
# ---- Tests ----
|
||||
|
||||
if(NOT WIN32)
|
||||
include(../cmake/lib/gtest.cmake)
|
||||
include(../cmake/lib/benchmark.cmake)
|
||||
#include(../cmake/lib/openmp.cmake)
|
||||
include(../cmake/lib/raygui.cmake)
|
||||
|
||||
include(../cmake/lib/raylib.cmake)
|
||||
include(../cmake/lib/fast_noise2.cmake)
|
||||
#include(../cmake/lib/spdlog.cmake)
|
||||
#include(../cmake/lib/json.cmake)
|
||||
include(../cmake/utile/ccache.cmake)
|
||||
|
||||
include_directories(source)
|
||||
|
||||
test_bench_generator(astar_test true true)
|
||||
test_bench_generator(astar_bench false true)
|
||||
test_bench_generator(path_finder false false)
|
||||
endif()
|
||||
|
||||
# ---- End-of-file commands ----
|
||||
|
||||
add_folders(Test)
|
195
test/source/benchmark/astar_bench.cpp
Normal file
195
test/source/benchmark/astar_bench.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
#include "astar/astar.hpp"
|
||||
#include "generator/generator.hpp"
|
||||
|
||||
static constexpr int64_t multiplier = 4;
|
||||
static constexpr int64_t minRange = 16;
|
||||
static constexpr int64_t maxRange = 256;
|
||||
static constexpr int64_t minThreadRange = 1;
|
||||
static constexpr int64_t maxThreadRange = 1;
|
||||
static constexpr int64_t repetitions = 1;
|
||||
|
||||
static void DoSetup([[maybe_unused]] const benchmark::State& state) {}
|
||||
|
||||
static void DoTeardown([[maybe_unused]] const benchmark::State& state) {}
|
||||
|
||||
template <IntegerType T>
|
||||
static void astar_bench(benchmark::State& state) {
|
||||
auto range = state.range(0);
|
||||
|
||||
int mapWidth = range;
|
||||
int mapHeight = range;
|
||||
|
||||
float lacunarity = 1.6f;
|
||||
float octaves = 6;
|
||||
float gain = 3.5f;
|
||||
float frequency = 1.7f;
|
||||
float weightedStrength = 0.034f;
|
||||
float multiplier = 118;
|
||||
|
||||
Generator generator(-972960945);
|
||||
benchmark::DoNotOptimize(generator);
|
||||
generator.setLacunarity(lacunarity);
|
||||
generator.setOctaves((uint32_t)octaves);
|
||||
generator.setGain(gain);
|
||||
generator.setFrequency(frequency);
|
||||
generator.setWeightedStrength(weightedStrength);
|
||||
generator.setMultiplier((uint32_t)multiplier);
|
||||
|
||||
std::vector<uint32_t> heightmap = generator.generate2dMeightmap(0, 0, 0, mapWidth, 0, mapHeight);
|
||||
benchmark::DoNotOptimize(heightmap);
|
||||
|
||||
std::vector<uint8_t> blocks = std::vector<uint8_t>(mapWidth * mapHeight, 0);
|
||||
benchmark::DoNotOptimize(blocks);
|
||||
|
||||
AStar::AStar<T, false> pathFinder;
|
||||
benchmark::DoNotOptimize(pathFinder);
|
||||
pathFinder.setWorldSize({mapWidth, mapHeight});
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclidean);
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
for (uint64_t x = 0; x < mapWidth; x++) {
|
||||
for (uint64_t y = 0; y < mapHeight; y++) {
|
||||
uint64_t index = x + y * mapWidth;
|
||||
uint8_t value = static_cast<uint8_t>(heightmap[index]);
|
||||
|
||||
if (value < 128) {
|
||||
blocks[index] = 0;
|
||||
} else {
|
||||
blocks[index] = 1;
|
||||
pathFinder.addObstacle({static_cast<int32_t>(x), static_cast<int32_t>(y)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blocks[0] = 0;
|
||||
pathFinder.removeObstacle({0, 0});
|
||||
blocks[mapWidth * mapHeight - 1] = 0;
|
||||
pathFinder.removeObstacle({mapWidth - 1, mapHeight - 1});
|
||||
|
||||
AStar::Vec2i source(0, 0);
|
||||
AStar::Vec2i target(mapWidth - 1, mapHeight - 1);
|
||||
|
||||
std::vector<AStar::Vec2i> path;
|
||||
benchmark::DoNotOptimize(path);
|
||||
|
||||
for (auto _ : state) {
|
||||
path = pathFinder.findPath(source, target);
|
||||
state.PauseTiming();
|
||||
if (path.size() == 0) {
|
||||
state.SkipWithError("No path found");
|
||||
}
|
||||
state.ResumeTiming();
|
||||
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations());
|
||||
state.SetBytesProcessed(state.iterations() * sizeof(path));
|
||||
}
|
||||
|
||||
BENCHMARK(astar_bench<uint32_t>)
|
||||
->Name("astar_bench<uint32_t>")
|
||||
->RangeMultiplier(multiplier)
|
||||
->Range(minRange, maxRange)
|
||||
->ThreadRange(minThreadRange, maxThreadRange)
|
||||
->Unit(benchmark::kNanosecond)
|
||||
->Setup(DoSetup)
|
||||
->Teardown(DoTeardown)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime()
|
||||
->Repetitions(repetitions);
|
||||
|
||||
template <IntegerType T>
|
||||
static void astar_bench_fast(benchmark::State& state) {
|
||||
auto range = state.range(0);
|
||||
|
||||
int mapWidth = range;
|
||||
int mapHeight = range;
|
||||
|
||||
float lacunarity = 1.6f;
|
||||
float octaves = 6;
|
||||
float gain = 3.5f;
|
||||
float frequency = 1.7f;
|
||||
float weighted_strength = 0.034f;
|
||||
float multiplier = 118;
|
||||
|
||||
Generator generator(-972960945);
|
||||
benchmark::DoNotOptimize(generator);
|
||||
generator.setLacunarity(lacunarity);
|
||||
generator.setOctaves((uint32_t)octaves);
|
||||
generator.setGain(gain);
|
||||
generator.setFrequency(frequency);
|
||||
generator.setWeightedStrength(0.0f);
|
||||
generator.setMultiplier((uint32_t)multiplier);
|
||||
|
||||
std::vector<uint32_t> heightmap = generator.generate2dMeightmap(0, 0, 0, mapWidth, 0, mapHeight);
|
||||
benchmark::DoNotOptimize(heightmap);
|
||||
|
||||
std::vector<uint32_t> blocks = std::vector<uint32_t>(mapWidth * mapHeight, 0);
|
||||
benchmark::DoNotOptimize(blocks);
|
||||
|
||||
AStar::AStarFast<T, false, uint32_t> pathFinder;
|
||||
benchmark::DoNotOptimize(pathFinder);
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclidean);
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
for (uint64_t x = 0; x < mapWidth; x++) {
|
||||
for (uint64_t y = 0; y < mapHeight; y++) {
|
||||
uint64_t index = x + y * mapWidth;
|
||||
uint8_t value = static_cast<uint8_t>(heightmap[index]);
|
||||
|
||||
if (value < 128) {
|
||||
blocks[index] = 0;
|
||||
} else {
|
||||
blocks[index] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blocks[0] = 0;
|
||||
blocks[mapWidth * mapHeight - 1] = 0;
|
||||
|
||||
AStar::Vec2i source(0, 0);
|
||||
AStar::Vec2i target(mapWidth - 1, mapHeight - 1);
|
||||
|
||||
std::vector<AStar::Vec2i> path;
|
||||
benchmark::DoNotOptimize(path);
|
||||
|
||||
for (auto _ : state) {
|
||||
path = pathFinder.findPath(source, target, blocks, {mapWidth, mapHeight});
|
||||
state.PauseTiming();
|
||||
if (path.size() == 0) {
|
||||
state.SkipWithError("No path found");
|
||||
}
|
||||
state.ResumeTiming();
|
||||
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations());
|
||||
state.SetBytesProcessed(state.iterations() * sizeof(path));
|
||||
}
|
||||
|
||||
BENCHMARK(astar_bench_fast<uint32_t>)
|
||||
->Name("astar_bench_fast<uint32_t>")
|
||||
->RangeMultiplier(multiplier)
|
||||
->Range(minRange, maxRange)
|
||||
->ThreadRange(minThreadRange, maxThreadRange)
|
||||
->Unit(benchmark::kNanosecond)
|
||||
->Setup(DoSetup)
|
||||
->Teardown(DoTeardown)
|
||||
->MeasureProcessCPUTime()
|
||||
->UseRealTime()
|
||||
->Repetitions(repetitions);
|
||||
|
||||
// Run the benchmark
|
||||
// BENCHMARK_MAIN();
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::benchmark::Initialize(&argc, argv);
|
||||
::benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
258
test/source/benchmark/path_finder.cpp
Normal file
258
test/source/benchmark/path_finder.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
#include <array> // std::array
|
||||
#include <chrono> // std::chrono::system_clock
|
||||
#include <cmath> // std::abs
|
||||
#include <cstdint> // std::uint32_t
|
||||
#include <iostream> // std::cout, std::endl
|
||||
#include <map> // std::map
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <random> // std::random_device, std::mt19937, std::uniform_int_distribution
|
||||
#include <vector> // std::vector
|
||||
|
||||
#include "astar/astar.hpp"
|
||||
#include "generator/generator.hpp"
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
extern "C" {
|
||||
#include "src/raygui.h"
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
// Set log level for Raylib
|
||||
SetTraceLogLevel(LOG_WARNING);
|
||||
|
||||
const int screenWidth = 1920;
|
||||
const int screenHeight = 1080;
|
||||
|
||||
const int mapWidth = 192;
|
||||
const int mapHeight = 108;
|
||||
|
||||
const uint32_t targetFPS = 120;
|
||||
|
||||
const uint32_t ImageUpdatePerSecond = 30;
|
||||
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_MSAA_4X_HINT);
|
||||
InitWindow(screenWidth, screenHeight, "Path finder by Bensuperpc");
|
||||
|
||||
SetTargetFPS(targetFPS);
|
||||
|
||||
float lacunarity = 1.6f;
|
||||
float octaves = 6;
|
||||
float gain = 3.5f;
|
||||
float frequency = 1.7f;
|
||||
float weighted_strength = 0.034f;
|
||||
float multiplier = 118;
|
||||
|
||||
Generator generator_2(-972960945);
|
||||
generator_2.setLacunarity(lacunarity);
|
||||
generator_2.setOctaves((uint32_t)octaves);
|
||||
generator_2.setGain(gain);
|
||||
generator_2.setFrequency(frequency);
|
||||
generator_2.setWeightedStrength(0.0f);
|
||||
generator_2.setMultiplier((uint32_t)multiplier);
|
||||
|
||||
AStar::AStar<uint32_t, false> pathFinder;
|
||||
pathFinder.setWorldSize({mapWidth, mapHeight});
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
size_t manhattanPathSize = 0;
|
||||
size_t euclideanPathSize = 0;
|
||||
size_t euclideanNoSQRPathSize = 0;
|
||||
size_t octagonalPathSize = 0;
|
||||
size_t chebyshevPathSize = 0;
|
||||
size_t dijkstraPathSize = 0;
|
||||
|
||||
std::vector<uint32_t> heightmap;
|
||||
|
||||
heightmap = generator_2.generate2dMeightmap(0, 0, 0, mapWidth, 0, mapHeight);
|
||||
|
||||
std::vector<uint8_t> blocks = std::vector<uint8_t>(mapWidth * mapHeight, 0);
|
||||
|
||||
uint64_t framesCounter = 0;
|
||||
|
||||
bool needUpdate = true;
|
||||
|
||||
while (!WindowShouldClose()) {
|
||||
framesCounter++;
|
||||
if (IsKeyPressed(KEY_S)) {
|
||||
const std::string filename = "screenshot_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count()) + ".png";
|
||||
TakeScreenshot(filename.c_str());
|
||||
}
|
||||
if (IsKeyPressed(KEY_R)) {
|
||||
generator_2.randomizeSeed();
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
if (framesCounter % (targetFPS / ImageUpdatePerSecond) == 0) {
|
||||
if (needUpdate) {
|
||||
needUpdate = false;
|
||||
generator_2.setLacunarity(lacunarity);
|
||||
generator_2.setOctaves((uint32_t)octaves);
|
||||
generator_2.setGain(gain);
|
||||
generator_2.setFrequency(frequency);
|
||||
generator_2.setWeightedStrength(weighted_strength);
|
||||
generator_2.setMultiplier((uint32_t)multiplier);
|
||||
|
||||
pathFinder.clear();
|
||||
|
||||
heightmap = generator_2.generate2dMeightmap(0, 0, 0, screenWidth, 0, screenHeight);
|
||||
|
||||
for (uint64_t x = 0; x < mapWidth; x++) {
|
||||
for (uint64_t y = 0; y < mapHeight; y++) {
|
||||
uint64_t index = x + y * mapWidth;
|
||||
uint8_t value = static_cast<uint8_t>(heightmap[index]);
|
||||
|
||||
if (value < 128) {
|
||||
blocks[index] = 0;
|
||||
} else {
|
||||
blocks[index] = 1;
|
||||
pathFinder.addObstacle({static_cast<int32_t>(x), static_cast<int32_t>(y)});
|
||||
}
|
||||
}
|
||||
}
|
||||
blocks[0] = 0;
|
||||
pathFinder.removeObstacle({0, 0});
|
||||
blocks[mapWidth * mapHeight - 1] = 0;
|
||||
pathFinder.removeObstacle({mapWidth - 1, mapHeight - 1});
|
||||
|
||||
pathFinder.setHeuristic(AStar::Heuristic::manhattan);
|
||||
auto start1 = std::chrono::high_resolution_clock::now();
|
||||
auto path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1});
|
||||
auto stop1 = std::chrono::high_resolution_clock::now();
|
||||
if (path.empty()) {
|
||||
std::cout << "Path not found" << std::endl;
|
||||
}
|
||||
auto duration1 = std::chrono::duration_cast<std::chrono::microseconds>(stop1 - start1);
|
||||
std::cout << "Path search: " << duration1.count() << " microseconds" << std::endl;
|
||||
|
||||
manhattanPathSize = path.size();
|
||||
for (auto& i : path) {
|
||||
uint64_t index = i.x + i.y * mapWidth;
|
||||
blocks[index] = 2;
|
||||
}
|
||||
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclidean);
|
||||
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1});
|
||||
euclideanPathSize = path.size();
|
||||
|
||||
for (auto& i : path) {
|
||||
uint64_t index = i.x + i.y * mapWidth;
|
||||
blocks[index] = 3;
|
||||
}
|
||||
|
||||
pathFinder.setHeuristic(AStar::Heuristic::octagonal);
|
||||
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1});
|
||||
octagonalPathSize = path.size();
|
||||
|
||||
for (auto& i : path) {
|
||||
uint64_t index = i.x + i.y * mapWidth;
|
||||
blocks[index] = 4;
|
||||
}
|
||||
|
||||
pathFinder.setHeuristic(AStar::Heuristic::chebyshev);
|
||||
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1});
|
||||
chebyshevPathSize = path.size();
|
||||
|
||||
for (auto& i : path) {
|
||||
uint64_t index = i.x + i.y * mapWidth;
|
||||
blocks[index] = 5;
|
||||
}
|
||||
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclideanNoSQR);
|
||||
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1});
|
||||
euclideanNoSQRPathSize = path.size();
|
||||
|
||||
for (auto& i : path) {
|
||||
uint64_t index = i.x + i.y * mapWidth;
|
||||
blocks[index] = 6;
|
||||
}
|
||||
|
||||
pathFinder.setHeuristic(AStar::Heuristic::dijkstra);
|
||||
path = pathFinder.findPath({0, 0}, {mapWidth - 1, mapHeight - 1});
|
||||
dijkstraPathSize = path.size();
|
||||
|
||||
for (auto& i : path) {
|
||||
uint64_t index = i.x + i.y * mapWidth;
|
||||
blocks[index] = 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
BeginDrawing();
|
||||
|
||||
// Draw white if blocks[index] == 0 else black
|
||||
int size = 10;
|
||||
for (uint64_t x = 0; x < mapWidth; x++) {
|
||||
for (uint64_t y = 0; y < mapHeight; y++) {
|
||||
uint64_t index = x + y * mapWidth;
|
||||
if (blocks[index] == 0) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, WHITE);
|
||||
} else if (blocks[index] == 1) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, BLACK);
|
||||
} else if (blocks[index] == 2) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, RED);
|
||||
} else if (blocks[index] == 3) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, GREEN);
|
||||
} else if (blocks[index] == 4) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, BLUE);
|
||||
} else if (blocks[index] == 5) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, YELLOW);
|
||||
} else if (blocks[index] == 6) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, ORANGE);
|
||||
} else if (blocks[index] == 7) {
|
||||
DrawRectangle(static_cast<float>(x * size), static_cast<float>(y * size), size, size, PURPLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display FPS
|
||||
DrawRectangle(screenWidth - 90, 10, 80, 20, Fade(SKYBLUE, 0.95f));
|
||||
DrawText(TextFormat("FPS: %02d", GetFPS()), screenWidth - 80, 15, 15, DARKGRAY);
|
||||
|
||||
DrawRectangle(0, 0, 275, 200, Fade(SKYBLUE, 0.95f));
|
||||
DrawRectangleLines(0, 0, 275, 200, BLUE);
|
||||
GuiSlider((Rectangle){70, 10, 165, 20}, "Lacunarity", TextFormat("%2.3f", lacunarity), &lacunarity, -0.0f, 5.0f);
|
||||
GuiSlider((Rectangle){70, 40, 165, 20}, "Octaves", TextFormat("%2.3f", octaves), &octaves, 1, 12);
|
||||
GuiSlider((Rectangle){70, 70, 165, 20}, "Gain", TextFormat("%2.3f", gain), &gain, -0.0f, 16.0f);
|
||||
GuiSlider((Rectangle){70, 100, 165, 20}, "Frequency", TextFormat("%2.3f", frequency), &frequency, -0.0f, 10.0f);
|
||||
GuiSlider((Rectangle){70, 130, 165, 20}, "Weight", TextFormat("%2.3f", weighted_strength), &weighted_strength, -5.0f, 5.0f);
|
||||
GuiSlider((Rectangle){70, 160, 165, 20}, "Multiplier", TextFormat("%2.3f", multiplier), &multiplier, 1, 512);
|
||||
|
||||
// display info each color for each heuristic
|
||||
DrawRectangle(0, 200, 275, 190, Fade(SKYBLUE, 0.95f));
|
||||
DrawRectangleLines(0, 200, 275, 190, BLUE);
|
||||
|
||||
std::string manhattanText = "Manhattan: " + std::to_string(manhattanPathSize);
|
||||
DrawRectangle(10, 210, 20, 20, RED);
|
||||
DrawText(manhattanText.c_str(), 40, 210, 20, DARKGRAY);
|
||||
|
||||
std::string euclideanText = "Euclidean: " + std::to_string(euclideanPathSize);
|
||||
DrawRectangle(10, 240, 20, 20, GREEN);
|
||||
DrawText(euclideanText.c_str(), 40, 240, 20, DARKGRAY);
|
||||
|
||||
std::string octagonalText = "Octagonal: " + std::to_string(octagonalPathSize);
|
||||
DrawRectangle(10, 270, 20, 20, BLUE);
|
||||
DrawText(octagonalText.c_str(), 40, 270, 20, DARKGRAY);
|
||||
|
||||
std::string chebyshevText = "Chebyshev: " + std::to_string(chebyshevPathSize);
|
||||
DrawRectangle(10, 300, 20, 20, YELLOW);
|
||||
DrawText(chebyshevText.c_str(), 40, 300, 20, DARKGRAY);
|
||||
|
||||
std::string euclideanNoSQRText = "EuclideanNoSQR: " + std::to_string(euclideanNoSQRPathSize);
|
||||
DrawRectangle(10, 330, 20, 20, ORANGE);
|
||||
DrawText(euclideanNoSQRText.c_str(), 40, 330, 20, DARKGRAY);
|
||||
|
||||
std::string dijkstraText = "Dijkstra: " + std::to_string(dijkstraPathSize);
|
||||
DrawRectangle(10, 360, 20, 20, PURPLE);
|
||||
DrawText(dijkstraText.c_str(), 40, 360, 20, DARKGRAY);
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
|
||||
return 0;
|
||||
}
|
310
test/source/generator/generator.cpp
Normal file
310
test/source/generator/generator.cpp
Normal file
@ -0,0 +1,310 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
// #include <omp.h>
|
||||
|
||||
#include "generator.hpp"
|
||||
|
||||
Generator::Generator(int32_t _seed) : seed(_seed) {
|
||||
fnSimplex = FastNoise::New<FastNoise::Perlin>();
|
||||
fnFractal = FastNoise::New<FastNoise::FractalFBm>();
|
||||
|
||||
fnFractal->SetSource(fnSimplex);
|
||||
fnFractal->SetOctaveCount(octaves);
|
||||
fnFractal->SetGain(gain);
|
||||
fnFractal->SetLacunarity(lacunarity);
|
||||
fnFractal->SetWeightedStrength(weighted_strength);
|
||||
}
|
||||
|
||||
Generator::Generator() {
|
||||
fnSimplex = FastNoise::New<FastNoise::Perlin>();
|
||||
fnFractal = FastNoise::New<FastNoise::FractalFBm>();
|
||||
|
||||
fnFractal->SetSource(fnSimplex);
|
||||
fnFractal->SetOctaveCount(octaves);
|
||||
fnFractal->SetGain(gain);
|
||||
fnFractal->SetLacunarity(lacunarity);
|
||||
fnFractal->SetWeightedStrength(weighted_strength);
|
||||
|
||||
randomizeSeed();
|
||||
}
|
||||
|
||||
Generator::~Generator() {}
|
||||
|
||||
void Generator::reseed(int32_t _seed) {
|
||||
this->seed = _seed;
|
||||
}
|
||||
|
||||
int32_t Generator::randomizeSeed() {
|
||||
std::random_device rd;
|
||||
std::mt19937_64 gen(rd());
|
||||
std::uniform_int_distribution<uint32_t> dis(std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max());
|
||||
this->seed = dis(gen);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
uint32_t Generator::get_seed() const {
|
||||
return seed;
|
||||
}
|
||||
|
||||
void Generator::setOctaves(uint32_t _octaves) {
|
||||
this->octaves = _octaves;
|
||||
fnFractal->SetOctaveCount(octaves);
|
||||
}
|
||||
|
||||
uint32_t Generator::getOctaves() const {
|
||||
return octaves;
|
||||
}
|
||||
|
||||
void Generator::setLacunarity(float _lacunarity) {
|
||||
this->lacunarity = _lacunarity;
|
||||
fnFractal->SetLacunarity(lacunarity);
|
||||
}
|
||||
|
||||
float Generator::getLacunarity() const {
|
||||
return lacunarity;
|
||||
}
|
||||
|
||||
void Generator::setGain(float _gain) {
|
||||
this->gain = _gain;
|
||||
fnFractal->SetGain(gain);
|
||||
}
|
||||
|
||||
float Generator::getGain() const {
|
||||
return gain;
|
||||
}
|
||||
|
||||
void Generator::setFrequency(float _frequency) {
|
||||
this->frequency = _frequency;
|
||||
}
|
||||
|
||||
float Generator::getFrequency() const {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
void Generator::setWeightedStrength(float _weighted_strength) {
|
||||
this->weighted_strength = _weighted_strength;
|
||||
fnFractal->SetWeightedStrength(weighted_strength);
|
||||
}
|
||||
|
||||
float Generator::getWeightedStrength() const {
|
||||
return weighted_strength;
|
||||
}
|
||||
|
||||
void Generator::setMultiplier(uint32_t _multiplier) {
|
||||
this->multiplier = _multiplier;
|
||||
}
|
||||
|
||||
uint32_t Generator::getMultiplier() const {
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Generator::generate2dMeightmap(const int32_t begin_x,
|
||||
[[maybe_unused]] const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
[[maybe_unused]] const uint32_t size_y,
|
||||
const uint32_t size_z) {
|
||||
constexpr bool debug = false;
|
||||
|
||||
std::vector<uint32_t> heightmap(size_x * size_z);
|
||||
|
||||
std::vector<float> noise_output(size_x * size_z);
|
||||
|
||||
if (fnFractal.get() == nullptr) {
|
||||
std::cout << "fnFractal is nullptr" << std::endl;
|
||||
return heightmap;
|
||||
}
|
||||
|
||||
fnFractal->GenUniformGrid2D(noise_output.data(), begin_x, begin_z, size_x, size_z, frequency, seed);
|
||||
|
||||
// Convert noise_output to heightmap
|
||||
for (uint32_t i = 0; i < size_x * size_z; i++) {
|
||||
heightmap[i] = static_cast<uint32_t>((noise_output[i] + 1.0) * multiplier);
|
||||
if constexpr (debug) {
|
||||
std::cout << "i: " << i << ", value: " << noise_output[i] << ", heightmap: " << heightmap[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (debug) {
|
||||
// cout max and min
|
||||
auto minmax = std::minmax_element(heightmap.begin(), heightmap.end());
|
||||
std::cout << "min: " << static_cast<int32_t>(*minmax.first) << std::endl;
|
||||
std::cout << "max: " << static_cast<int32_t>(*minmax.second) << std::endl;
|
||||
}
|
||||
return heightmap;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Generator::generate3dHeightmap(const int32_t begin_x,
|
||||
const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z) {
|
||||
constexpr bool debug = false;
|
||||
|
||||
std::vector<uint32_t> heightmap(size_x * size_y * size_z);
|
||||
|
||||
std::vector<float> noise_output(size_x * size_y * size_z);
|
||||
|
||||
if (fnFractal.get() == nullptr) {
|
||||
std::cout << "fnFractal is nullptr" << std::endl;
|
||||
return heightmap;
|
||||
}
|
||||
|
||||
fnFractal->GenUniformGrid3D(noise_output.data(), begin_x, begin_y, begin_z, size_x, size_y, size_z, frequency, seed);
|
||||
|
||||
// Convert noise_output to heightmap
|
||||
for (uint32_t i = 0; i < size_x * size_y * size_z; i++) {
|
||||
heightmap[i] = static_cast<uint32_t>((noise_output[i] + 1.0) * multiplier);
|
||||
if constexpr (debug) {
|
||||
std::cout << "i: " << i << ", noise_output: " << noise_output[i] << ", heightmap: " << heightmap[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (debug) {
|
||||
// cout max and min
|
||||
auto minmax = std::minmax_element(heightmap.begin(), heightmap.end());
|
||||
std::cout << "min: " << static_cast<int32_t>(*minmax.first) << std::endl;
|
||||
std::cout << "max: " << static_cast<int32_t>(*minmax.second) << std::endl;
|
||||
}
|
||||
|
||||
return heightmap;
|
||||
}
|
||||
|
||||
/*
|
||||
std::unique_ptr<Chunk> Generator::generateChunk(const int32_t chunk_x,
|
||||
const int32_t chunk_y,
|
||||
const int32_t chunk_z,
|
||||
const bool generate_3d_terrain) {
|
||||
const int32_t real_x = chunk_x * Chunk::chunk_size_x;
|
||||
const int32_t real_y = chunk_y * Chunk::chunk_size_y;
|
||||
const int32_t real_z = chunk_z * Chunk::chunk_size_z;
|
||||
|
||||
std::vector<Block> blocks;
|
||||
|
||||
std::unique_ptr<Chunk> _chunk = std::make_unique<Chunk>();
|
||||
|
||||
if (generate_3d_terrain) {
|
||||
blocks = std::move(generate3d(real_x, real_y, real_z, Chunk::chunk_size_x, Chunk::chunk_size_y, Chunk::chunk_size_z));
|
||||
} else {
|
||||
blocks = std::move(generate2d(real_x, real_y, real_z, Chunk::chunk_size_x, Chunk::chunk_size_y, Chunk::chunk_size_z));
|
||||
}
|
||||
|
||||
_chunk->set_blocks(blocks);
|
||||
_chunk->set_chuck_pos(chunk_x, chunk_y, chunk_z);
|
||||
|
||||
return _chunk;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Chunk>> Generator::generateChunks(const int32_t begin_chunk_x,
|
||||
const int32_t begin_chunk_y,
|
||||
const int32_t begin_chunk_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z,
|
||||
const bool generate_3d_terrain) {
|
||||
constexpr bool debug = false;
|
||||
|
||||
std::vector<std::unique_ptr<Chunk>> chunks;
|
||||
chunks.reserve(size_x * size_y * size_z);
|
||||
|
||||
#pragma omp parallel for collapse(3) schedule(auto)
|
||||
for (int32_t x = begin_chunk_x; x < begin_chunk_x + size_x; x++) {
|
||||
for (int32_t z = begin_chunk_y; z < begin_chunk_y + size_z; z++) {
|
||||
for (int32_t y = begin_chunk_z; y < begin_chunk_z + size_y; y++) {
|
||||
auto gen_chunk = generateChunk(x, y, z, generate_3d_terrain);
|
||||
#pragma omp critical
|
||||
chunks.emplace_back(std::move(gen_chunk));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
std::vector<Block> Generator::generate2d(const int32_t begin_x,
|
||||
const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z) {
|
||||
constexpr bool debug = false;
|
||||
|
||||
std::vector<uint32_t> heightmap;
|
||||
std::vector<Block> blocks = std::vector<Block>(size_x * size_y * size_z, Block());
|
||||
|
||||
heightmap = std::move(generate2dMeightmap(begin_x, begin_y, begin_z, size_x, size_y, size_z));
|
||||
|
||||
// Generate blocks
|
||||
for (uint32_t x = 0; x < size_x; x++) {
|
||||
for (uint32_t z = 0; z < size_z; z++) {
|
||||
// Noise value is divided by 4 to make it smaller and it is used as the height of the Block (z)
|
||||
std::vector<Block>::size_type vec_index = math::convert_to_1d(x, z, size_x, size_z);
|
||||
|
||||
uint32_t noise_value = heightmap[vec_index] / 4;
|
||||
|
||||
for (uint32_t y = 0; y < size_y; y++) {
|
||||
// Calculate real y from begin_y
|
||||
vec_index = math::convert_to_1d(x, y, z, size_x, size_y, size_z);
|
||||
|
||||
if constexpr (debug) {
|
||||
std::cout << "x: " << x << ", z: " << z << ", y: " << y << " index: " << vec_index
|
||||
<< ", noise: " << static_cast<int32_t>(noise_value) << std::endl;
|
||||
}
|
||||
|
||||
Block& current_block = blocks[vec_index];
|
||||
|
||||
// If the noise value is greater than the current Block, make it air
|
||||
if (noise_value > 120) {
|
||||
current_block.block_type = block_type::stone;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
std::vector<Block> Generator::generate3d(const int32_t begin_x,
|
||||
const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z) {
|
||||
constexpr bool debug = false;
|
||||
|
||||
std::vector<Block> blocks = std::vector<Block>(size_x * size_y * size_z, Block());
|
||||
|
||||
std::vector<uint32_t> heightmap = generate3dHeightmap(begin_x, begin_y, begin_z, size_x, size_y, size_z);
|
||||
|
||||
// Generate blocks
|
||||
for (uint32_t x = 0; x < size_x; x++) {
|
||||
for (uint32_t z = 0; z < size_z; z++) {
|
||||
for (uint32_t y = 0; y < size_y; y++) {
|
||||
size_t vec_index = math::convert_to_1d(x, y, z, size_x, size_y, size_z);
|
||||
const uint32_t noise_value = heightmap[vec_index];
|
||||
auto& current_block = blocks[vec_index];
|
||||
|
||||
if constexpr (debug) {
|
||||
std::cout << "x: " << x << ", z: " << z << ", y: " << y << " index: " << vec_index
|
||||
<< ", noise: " << static_cast<int32_t>(noise_value) << std::endl;
|
||||
}
|
||||
|
||||
if (noise_value > 120) {
|
||||
current_block.block_type = block_type::stone;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
*/
|
115
test/source/generator/generator.hpp
Normal file
115
test/source/generator/generator.hpp
Normal file
@ -0,0 +1,115 @@
|
||||
#ifndef WORLD_OF_CUBE_GENERATOR_HPP
|
||||
#define WORLD_OF_CUBE_GENERATOR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
// #include <omp.h>
|
||||
|
||||
#ifndef FASTNOISE_HPP_INCLUDED
|
||||
#define FASTNOISE_HPP_INCLUDED
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
#pragma clang system_header
|
||||
#endif
|
||||
#include "FastNoise/FastNoise.h"
|
||||
#endif
|
||||
|
||||
class Generator {
|
||||
public:
|
||||
explicit Generator(int32_t _seed);
|
||||
|
||||
explicit Generator();
|
||||
|
||||
~Generator();
|
||||
|
||||
void reseed(int32_t _seed);
|
||||
|
||||
int32_t randomizeSeed();
|
||||
|
||||
uint32_t get_seed() const;
|
||||
|
||||
void setOctaves(uint32_t _octaves);
|
||||
|
||||
uint32_t getOctaves() const;
|
||||
|
||||
void setLacunarity(float _lacunarity);
|
||||
|
||||
float getLacunarity() const;
|
||||
|
||||
void setGain(float _gain);
|
||||
|
||||
float getGain() const;
|
||||
|
||||
void setFrequency(float _frequency);
|
||||
float getFrequency() const;
|
||||
|
||||
void setWeightedStrength(float _weighted_strength);
|
||||
float getWeightedStrength() const;
|
||||
|
||||
void setMultiplier(uint32_t _multiplier);
|
||||
|
||||
uint32_t getMultiplier() const;
|
||||
|
||||
std::vector<uint32_t> generate2dMeightmap(const int32_t begin_x,
|
||||
[[maybe_unused]] const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
[[maybe_unused]] const uint32_t size_y,
|
||||
const uint32_t size_z);
|
||||
|
||||
std::vector<uint32_t> generate3dHeightmap(const int32_t begin_x,
|
||||
const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z);
|
||||
/*
|
||||
std::unique_ptr<Chunk> generateChunk(const int32_t chunk_x, const int32_t chunk_y, const int32_t chunk_z, const bool generate_3d_terrain);
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Chunk>> generateChunks(const int32_t begin_chunk_x,
|
||||
const int32_t begin_chunk_y,
|
||||
const int32_t begin_chunk_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z,
|
||||
const bool generate_3d_terrain);
|
||||
|
||||
std::vector<Block> generate2d(const int32_t begin_x,
|
||||
const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z);
|
||||
|
||||
std::vector<Block> generate3d(const int32_t begin_x,
|
||||
const int32_t begin_y,
|
||||
const int32_t begin_z,
|
||||
const uint32_t size_x,
|
||||
const uint32_t size_y,
|
||||
const uint32_t size_z);
|
||||
*/
|
||||
private:
|
||||
// default seed
|
||||
int32_t seed = 404;
|
||||
FastNoise::SmartNode<FastNoise::Perlin> fnSimplex;
|
||||
FastNoise::SmartNode<FastNoise::FractalFBm> fnFractal;
|
||||
|
||||
int32_t octaves = 6;
|
||||
float lacunarity = 0.5f;
|
||||
float gain = 3.5f;
|
||||
float frequency = 0.4f;
|
||||
float weighted_strength = 0.0f;
|
||||
uint32_t multiplier = 128;
|
||||
};
|
||||
|
||||
#endif // WORLD_OF_CUBE_GENERATOR_HPP
|
87
test/source/test/astar_test.cpp
Normal file
87
test/source/test/astar_test.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "astar/astar.hpp"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(AStar, basic_path_1) {
|
||||
int mapWidth = 4;
|
||||
int mapHeight = 4;
|
||||
AStar::AStar pathFinder;
|
||||
pathFinder.setWorldSize({mapWidth, mapWidth});
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclidean);
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
AStar::Vec2i source(0, 0);
|
||||
AStar::Vec2i target(mapWidth - 1, mapHeight - 1);
|
||||
|
||||
std::cout << "AStar::AStar pathFinder;" << std::endl;
|
||||
auto path = pathFinder.findPath(source, target);
|
||||
|
||||
EXPECT_EQ(path.size(), 4);
|
||||
|
||||
for (size_t i = 0; i < path.size(); i++) {
|
||||
EXPECT_EQ(path[i].x, path.size() - i - 1);
|
||||
EXPECT_EQ(path[i].y, path.size() - i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AStar, basic_path_2) {
|
||||
int mapWidth = 10;
|
||||
int mapHeight = 10;
|
||||
AStar::AStar pathFinder;
|
||||
pathFinder.setWorldSize({mapWidth, mapWidth});
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclidean);
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
AStar::Vec2i source(0, 0);
|
||||
AStar::Vec2i target(mapWidth - 1, mapHeight - 1);
|
||||
|
||||
auto path = pathFinder.findPath(source, target);
|
||||
|
||||
EXPECT_EQ(path.size(), 10);
|
||||
|
||||
for (size_t i = 0; i < path.size(); i++) {
|
||||
EXPECT_EQ(path[i].x, path.size() - i - 1);
|
||||
EXPECT_EQ(path[i].y, path.size() - i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AStar, basic_diagonal_path_wrong_1) {
|
||||
int mapWidth = 10;
|
||||
int mapHeight = 10;
|
||||
AStar::AStar pathFinder;
|
||||
pathFinder.setWorldSize({mapWidth, mapHeight});
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclidean);
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
AStar::Vec2i source(0, 0);
|
||||
AStar::Vec2i target(19, 19);
|
||||
|
||||
auto path = pathFinder.findPath(source, target);
|
||||
|
||||
EXPECT_EQ(path.size(), 0);
|
||||
}
|
||||
|
||||
TEST(AStar, basic_diagonal_path_wrong_2) {
|
||||
int mapWidth = 10;
|
||||
int mapHeight = 10;
|
||||
AStar::AStar pathFinder;
|
||||
pathFinder.setWorldSize({mapWidth, mapHeight});
|
||||
pathFinder.setHeuristic(AStar::Heuristic::euclidean);
|
||||
pathFinder.setDiagonalMovement(true);
|
||||
|
||||
pathFinder.addObstacle({0, 1});
|
||||
pathFinder.addObstacle({1, 1});
|
||||
pathFinder.addObstacle({1, 0});
|
||||
|
||||
AStar::Vec2i source(0, 0);
|
||||
AStar::Vec2i target(9, 9);
|
||||
|
||||
auto path = pathFinder.findPath(source, target);
|
||||
|
||||
EXPECT_EQ(path.size(), 0);
|
||||
}
|
||||
|
||||
auto main(int argc, char** argv) -> int {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
91
tools/graphic.py
Executable file
91
tools/graphic.py
Executable file
@ -0,0 +1,91 @@
|
||||
# Based on work: https://int-i.github.io/python/2021-11-07/matplotlib-google-benchmark-visualization/
|
||||
# Modified by: Bensuperpc
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from itertools import groupby
|
||||
import json
|
||||
import operator
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import seaborn as sns
|
||||
import pandas as pd
|
||||
|
||||
# Extract the benchmark name from the benchmark name string
|
||||
def extract_label_from_benchmark(benchmark):
|
||||
bench_full_name = benchmark['name']
|
||||
bench_name = bench_full_name.split('/')[0] # Remove all after /
|
||||
if (bench_name.startswith('BM_')): # Remove if string start with BM_
|
||||
return bench_name[3:] # Remove BM_
|
||||
else:
|
||||
return bench_name
|
||||
|
||||
# Extract the benchmark size from the benchmark
|
||||
def extract_size_from_benchmark(benchmark):
|
||||
bench_name = benchmark['name']
|
||||
return bench_name.split('/')[1] # Remove all before /
|
||||
|
||||
if __name__ == "__main__":
|
||||
# ./prog_name --benchmark_format=json --benchmark_out=result.json
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('path', help='benchmark result json file')
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.path) as file:
|
||||
benchmark_result = json.load(file)
|
||||
benchmarks = benchmark_result['benchmarks']
|
||||
elapsed_times = groupby(benchmarks, extract_label_from_benchmark)
|
||||
|
||||
data1 = None
|
||||
data2 = None
|
||||
|
||||
for key, group in elapsed_times:
|
||||
benchmark = list(group)
|
||||
x = list(map(extract_size_from_benchmark, benchmark))
|
||||
y1 = list(map(operator.itemgetter('bytes_per_second'), benchmark))
|
||||
y2 = list(map(operator.itemgetter('items_per_second'), benchmark))
|
||||
|
||||
if data1 is None:
|
||||
data1 = pd.DataFrame({'size': x, key: y1})
|
||||
else:
|
||||
data1[key] = y1
|
||||
|
||||
if data2 is None:
|
||||
data2 = pd.DataFrame({'size': x, key: y2})
|
||||
else:
|
||||
data2[key] = y2
|
||||
|
||||
df1 = pd.melt(data1, id_vars=['size'], var_name='Benchmark', value_name='bytes_per_second')
|
||||
df1_max_indices = df1.groupby(['size', 'Benchmark'])['bytes_per_second'].transform(max) == df1['bytes_per_second']
|
||||
df1 = df1.loc[df1_max_indices]
|
||||
df1.reset_index(drop=True, inplace=True)
|
||||
|
||||
|
||||
df2 = pd.melt(data2, id_vars=['size'], var_name='Benchmark', value_name='items_per_second')
|
||||
df2_max_indices = df2.groupby(['size', 'Benchmark'])['items_per_second'].transform(max) == df2['items_per_second']
|
||||
df2 = df2.loc[df2_max_indices]
|
||||
df2.reset_index(drop=True, inplace=True)
|
||||
|
||||
sns.set_theme()
|
||||
|
||||
fig, ax = plt.subplots(2, 1)
|
||||
|
||||
fig.set_size_inches(16, 9)
|
||||
fig.set_dpi(96)
|
||||
|
||||
sns.lineplot(data=df1, x='size', y='bytes_per_second', hue='Benchmark', ax=ax[0])
|
||||
sns.lineplot(data=df2, x='size', y='items_per_second', hue='Benchmark', ax=ax[1])
|
||||
|
||||
ax[0].set_title('Bytes per second')
|
||||
ax[1].set_title('Items per second')
|
||||
|
||||
ax[0].set_xlabel('Array size')
|
||||
ax[1].set_xlabel('Array size')
|
||||
|
||||
ax[0].set_ylabel('byte per second')
|
||||
ax[1].set_ylabel('items per second')
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig('benchmark.png', bbox_inches='tight', dpi=300)
|
||||
|
||||
plt.show()
|
Loading…
Reference in New Issue
Block a user