mirror of
https://github.com/bensuperpc/astar.git
synced 2025-02-02 07:46:38 +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…
x
Reference in New Issue
Block a user