diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..8309462e --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: google +ColumnLimit: 100 +AccessModifierOffset: -2 + diff --git a/.gitignore b/.gitignore index 4c2e7458..d1a38deb 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,11 @@ cmake-build-*/ #mac .DS_Store + +#savedata/ #issues with xml save location + +savedata/GPAgent/*.xml +#AgentData_*.xml + + +site diff --git a/.gitmodules b/.gitmodules index 55d6c6d9..989cd848 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,15 @@ [submodule "third_party/SFML"] path = third_party/SFML url = https://github.com/SFML/SFML.git +[submodule "third_party/PEGTL"] + path = third_party/PEGTL + url = https://github.com/taocpp/PEGTL +[submodule "third_party/json"] + path = third_party/json + url = https://github.com/nlohmann/json.git +[submodule "third_party/tinyxml2"] + path = third_party/tinyxml2 + url = https://github.com/leethomason/tinyxml2.git +[submodule "third_party/json"] + path = third_party/json + url = https://github.com/nlohmann/json.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 473b61f6..9bdd123c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,27 +6,27 @@ project(CSE_491) # For now, default to building both the main app and tests set(BUILD_MAIN 1) set(BUILD_TESTS 1) -if("${CMAKE_BUILD_TYPE}" STREQUAL "Test") - set(BUILD_MAIN 0) - set(BUILD_TESTS 1) -endif() +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Test") + set(BUILD_MAIN 0) + set(BUILD_TESTS 1) +endif () # Create a function to make .cmake files simpler function(add_source_to_target TARGET_NAME SOURCE_PATH) - message(STATUS "Loading source: ${SOURCE_PATH}") - target_sources(${TARGET_NAME} - PRIVATE ${CMAKE_SOURCE_DIR}/${SOURCE_PATH} + message(STATUS "Loading source: ${SOURCE_PATH}") + target_sources(${TARGET_NAME} + PRIVATE ${CMAKE_SOURCE_DIR}/${SOURCE_PATH} ) endfunction() # Set the necessary C++ flags, some of which are configuration-specific set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wcast-align -Winfinite-recursion -Wnon-virtual-dtor -Wnull-dereference -Woverloaded-virtual -pedantic") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wcast-align -Winfinite-recursion -Wnon-virtual-dtor -Wnull-dereference -Woverloaded-virtual -pedantic") set(CMAKE_CXX_FLAGS_DEBUG "-g") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") - +set(CMAKE_CXX_FLAGS_COVERAGE "-O2 -g -fcoverage-mapping -fprofile-instr-generate -fprofile-arcs") # Place all executables in the executable directory set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/executable) @@ -34,63 +34,169 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/executable) # Move assets to build directory file(COPY ./assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -# Build the main application executables, if requested -if(${BUILD_MAIN}) + +#option(BUILD_CLANG_LLVM "Build with clang for LLVM" OFF) +option(SANITIZE_MEMORY "Build with sanitizers for GP" OFF) +if (SANITIZE_MEMORY) + + set(BUILD_MAIN 0) + set(BUILD_TESTS 0) + + set(CMAKE_CXX_COMPILER "/opt/homebrew/opt/llvm/bin/clang++") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory") + + set(XML_SRC_DIR third_party/tinyxml2) + set(XML_BUILD_DIR xml_build) + add_subdirectory(${XML_SRC_DIR} ${XML_BUILD_DIR}) + + #added the executable + add_executable(gp_train_main source/gp_train_main.cpp) + + #linking the targets + target_sources(gp_train_main PRIVATE source/core/Entity.cpp) + target_include_directories(gp_train_main + PRIVATE ${CMAKE_SOURCE_DIR}/source/core + ${CMAKE_SOURCE_DIR}/source/Agents + ) + target_link_libraries(gp_train_main + PRIVATE tinyxml2 + PRIVATE pthread + ) + + +endif () + + + + + +# Build the gp_train_main executable, if requested without SFML and Catch2 +option(BUILD_GP_ONLY "Build only gp_main.cpp" OFF) +if (BUILD_GP_ONLY) + set(BUILD_MAIN 0) + set(BUILD_TESTS 0) + + set(XML_SRC_DIR third_party/tinyxml2) + set(XML_BUILD_DIR xml_build) + add_subdirectory(${XML_SRC_DIR} ${XML_BUILD_DIR}) + + # List of executables + set(EXECUTABLES gp_train_main gp_selective_runner_main gp_train_cgp_main gp_train_lgp_main) + + # Common source files and include directories + set(COMMON_SOURCES source/core/Entity.cpp) + set(COMMON_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/source/core ${CMAKE_SOURCE_DIR}/source/Agents) + + # Common libraries to link with + set(COMMON_LIBRARIES tinyxml2 pthread) + + # Loop to configure each executable + foreach(EXECUTABLE IN LISTS EXECUTABLES) + add_executable(${EXECUTABLE} source/${EXECUTABLE}.cpp) + target_sources(${EXECUTABLE} PRIVATE ${COMMON_SOURCES}) + target_include_directories(${EXECUTABLE} PRIVATE ${COMMON_INCLUDE_DIRS}) + target_link_libraries(${EXECUTABLE} PRIVATE ${COMMON_LIBRARIES}) + endforeach() + +endif () + +# Typically you don't care so much for a third party library's tests to be +# run from your own project's code. +set(JSON_BuildTests OFF CACHE INTERNAL "") +# Configure json +set(JSON_SRC_DIR third_party/json) +set(JSON_BUILD_DIR json_build) +add_subdirectory(${JSON_SRC_DIR} ${JSON_BUILD_DIR}) + +# Build the test executables, if requested +if (${BUILD_TESTS}) + + # Configure Catch + set(CATCH_SRC_DIR third_party/Catch2) + set(CATCH_BUILD_DIR catch_build) + add_subdirectory(${CATCH_SRC_DIR} ${CATCH_BUILD_DIR}) + + + # Configure only the networking portion of SFML + if (NOT ${BUILD_MAIN}) + set(SFML_BUILD_WINDOW FALSE) + set(SFML_BUILD_GRAPHICS FALSE) + set(SFML_BUILD_AUDIO FALSE) + set(SFML_SRC_DIR third_party/SFML) + set(SFML_BUILD_DIR sfml_build) + add_subdirectory(${SFML_SRC_DIR} ${SFML_BUILD_DIR}) + + set(XML_SRC_DIR third_party/tinyxml2) + set(XML_BUILD_DIR xml_build) + add_subdirectory(${XML_SRC_DIR} ${XML_BUILD_DIR}) + + + endif () + + + # Setup CTest + include(CTest) + enable_testing() + + # Tunnel into test directory CMake infrastructure + add_subdirectory(tests) +endif () + +if (${BUILD_MAIN}) +# line to set santizers +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=[sanitizer]") +# can be set to address, undefined, thread, memory, or leak + +# Enable the SFML interface (graphics unavailable for tests on GitHub) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_SFML_INTERFACE") # Configure all of SFML set(SFML_SRC_DIR third_party/SFML) set(SFML_BUILD_DIR sfml_build) add_subdirectory(${SFML_SRC_DIR} ${SFML_BUILD_DIR}) + # Configure PEGTL + set(PEGTL_INCLUDE_DIR third_party/PEGTL/include) + + #configure the xml library + set(XML_SRC_DIR third_party/tinyxml2) + set(XML_BUILD_DIR xml_build) + add_subdirectory(${XML_SRC_DIR} ${XML_BUILD_DIR}) + + # Find all the main files for the various applications # Currently this means any *.cpp file in the root of source file(GLOB EXE_SOURCES CONFIGURE_DEPENDS RELATIVE ${CMAKE_SOURCE_DIR}/source source/*.cpp) message(STATUS "List of main files to build: ${EXE_SOURCES}") - # Loop through each executable and build it! - foreach(EXE_SOURCE ${EXE_SOURCES}) - # Rip the .cpp off the end of the string - string(REPLACE ".cpp" "" EXE_NAME ${EXE_SOURCE}) - # Create list of source files (currently just the one .cpp file) - # Create executable and link to includes / libraries - add_executable(${EXE_NAME} ${CMAKE_SOURCE_DIR}/source/${EXE_SOURCE}) - target_include_directories(${EXE_NAME} - PRIVATE ${CMAKE_SOURCE_DIR}/source - ) - target_link_libraries(${EXE_NAME} - PRIVATE sfml-window sfml-audio sfml-graphics sfml-system sfml-network - ) - if(EXISTS ${CMAKE_SOURCE_DIR}/source/${EXE_NAME}.cmake) - message(STATUS "Loading ${EXE_NAME}.cmake") - include(${CMAKE_SOURCE_DIR}/source/${EXE_NAME}.cmake) - else() - message(WARNING "Cannot find ${EXE_NAME}.cmake") - endif() - endforeach() -endif() -# Build the test executables, if requested -if(${BUILD_TESTS}) - - # Configure Catch - set(CATCH_SRC_DIR third_party/Catch2) - set(CATCH_BUILD_DIR catch_build) - add_subdirectory(${CATCH_SRC_DIR} ${CATCH_BUILD_DIR}) - - # Configure only the networking portion of SFML - if(NOT ${BUILD_MAIN}) - set(SFML_BUILD_WINDOW FALSE) - set(SFML_BUILD_GRAPHICS FALSE) - set(SFML_BUILD_AUDIO FALSE) - set(SFML_SRC_DIR third_party/SFML) - set(SFML_BUILD_DIR sfml_build) - add_subdirectory(${SFML_SRC_DIR} ${SFML_BUILD_DIR}) - endif() - - # Setup CTest - include(CTest) - enable_testing() - - # Tunnel into test directory CMake infrastructure - add_subdirectory(tests) -endif() + + # Loop through each executable and build it! + foreach (EXE_SOURCE ${EXE_SOURCES}) + # Rip the .cpp off the end of the string + string(REPLACE ".cpp" "" EXE_NAME ${EXE_SOURCE}) + # Create list of source files (currently just the one .cpp file) + # Create executable and link to includes / libraries + add_executable(${EXE_NAME} ${CMAKE_SOURCE_DIR}/source/${EXE_SOURCE} ${CMAKE_SOURCE_DIR}/source/core/Entity.cpp) + target_include_directories(${EXE_NAME} + PRIVATE ${CMAKE_SOURCE_DIR}/source ${PEGTL_INCLUDE_DIR} + ) + target_link_libraries(${EXE_NAME} + PRIVATE sfml-window sfml-audio sfml-graphics sfml-system sfml-network + nlohmann_json::nlohmann_json + ) + + target_link_libraries(${EXE_NAME} + PRIVATE tinyxml2 + ) + + if (EXISTS ${CMAKE_SOURCE_DIR}/source/${EXE_NAME}.cmake) + message(STATUS "Loading ${EXE_NAME}.cmake") + include(${CMAKE_SOURCE_DIR}/source/${EXE_NAME}.cmake) + else () + message(WARNING "Cannot find ${EXE_NAME}.cmake") + endif () + endforeach () +endif () diff --git a/assets/grids/default_maze2.grid b/assets/grids/default_maze2.grid new file mode 100644 index 00000000..2ef68706 --- /dev/null +++ b/assets/grids/default_maze2.grid @@ -0,0 +1,29 @@ + # # # # +# ### # ########## # ########## # ######### # +# # # # # # # # # # # # +# # ### ## # ### # ############ ##### ### # # +# # # # # # # # # # # +# ##### # # # ### # ###### ###### ##### ### # +# # # # # # # # # # # +##### # ###### # ###### # ## # ###### ####### # ## # +# # # # ## # # # # +# ############## ##### # # # ###### # ######### # +# # # # # # # # # # +############### # ### ###### # # #### # # ##### # # +# # # # # # # # # # # +# ############### ##### # # ######## ##### # # # +# # # # # # # # +# #################### ########### # ######### # +# # # # # +# # # ################### ############# ########## # +# # # # # +# ################ ############### ####### # +# # # # # # # +# # # # # ##################################### # # +# # # # # # # # # +# # # # # # ################################### # # +# # # # # # # # +# # ################################ # # +# # # # # # # # # # +# # # # # # # ############################### # # + # # # # # # # # # # diff --git a/assets/grids/empty_maze.grid b/assets/grids/empty_maze.grid new file mode 100644 index 00000000..5b833eab --- /dev/null +++ b/assets/grids/empty_maze.grid @@ -0,0 +1,9 @@ + * + * + * + * + * + * + * + * + * diff --git a/assets/grids/group4_maze.grid b/assets/grids/group4_maze.grid index 3b3f3cc1..4c3ba641 100644 --- a/assets/grids/group4_maze.grid +++ b/assets/grids/group4_maze.grid @@ -1,5 +1,5 @@ - # g## # - # # ###### ## + w# g## # + u# # ###### ## # # # # # # # # # # # # # # # # diff --git a/assets/grids/lang_load_test.grid b/assets/grids/lang_load_test.grid new file mode 100644 index 00000000..9fd14d47 --- /dev/null +++ b/assets/grids/lang_load_test.grid @@ -0,0 +1,9 @@ + # ## # + # # ###### ## + # # # # # # + # # # # # # # + # # # +1#####3########### # + ## + wwwwwwwwwwww######### + diff --git a/assets/grids/second_floor.grid b/assets/grids/second_floor.grid new file mode 100644 index 00000000..441839ab --- /dev/null +++ b/assets/grids/second_floor.grid @@ -0,0 +1,44 @@ + +# # # ######### ### ####### ### # # # +###### # # # ##### # # # # # # # # # +###### ## # # ## ###### # +######## g# ## # # ### # # # # ## # # +######### ## # ## # # # # # # +# # # ## ##### # ## ## # # +####### # ### ## ## ## ## # ### # ## ## # +####### # ### ## # ## ## # # ### +####### # # # ## # # ### # # # ## ### +## ## # ## # ## # #### # # # +# ### # # ## # # # ## # # ## # ## ## +##### # ## ## # # # # ## # ## # ## +#### ############################# ############## +### ### ### # # # ## ## ## # # # # # # ## +## ##### # ## ## # # ## # ### # # # # +# ## ## ### # ## ## #### ### # ## ##### +######## # # ## # # ## # ###### # +# # ## # # # # ## # # ## # ## +# # ## # ### ## # # # ##### ## # # +# # # # #### ## # ### # # ## # # # +# #### ### ## # ## # #### # # ### ## +# ##### ### ## # ## # ## ### # # ## +# ##### # ### ## ### # # # +#### ### ## # ### ## # # # ## # +# # # # # # ## ### # # # ### ## +# ### # # ## ## # ## # # # ### +## # # ### # ## # ## ## # # #### # +# ### ## # ## # # # # # # ## ## +## # ## ## #### ## # ## # # ## # +## # # #### # # # # # ## # ##### # # +# # # ### ### # ## ## # ## ### # +## # # # ### ## # # # ## ## # # +# # # # ### ## # ## # # # # +# # # # ## ## ## ##### ###### # # # ### +# ## ####### # ###### ## # # # ## # # +## ##### # # ## ##### # # ## ## # # +# ### # #### # ## # ## # # # ### # # +# # # # # ## ## # # # # ## # # +# ## # ### # # ### # # ## ## # #### # # +# # # ### # # # ## # # # # ### ## +# # ## ### # # ##### ## # # #### # # +# #### ## # ## # ##### # # ## # # ## + diff --git a/assets/grids/team8_grid_large.grid b/assets/grids/team8_grid_large.grid index 120a46ca..882429f7 100644 --- a/assets/grids/team8_grid_large.grid +++ b/assets/grids/team8_grid_large.grid @@ -1,5 +1,5 @@ -^^^ ^^^~~ ^^^^^^^^^^^^^^ ^^^^^^ -^ ^^~~ ^^^^^^^^^^^^^^^^^^^ ^^^^^ +^^^ ^^^~~ ^^^^^^^^^^^^^^} ^^^^^^ +^ } ^^~~ ^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^ ~~~ ^^^^^^^^^^^^^ ^^^^^ ~~^ ^^^^^ ^^ ^^^^ ~~~^^^ ^ ^^ ^^^ @@ -8,13 +8,13 @@ ^ ~~~^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^ ^ ^^~~ ^^^^^^^^^^^^ ^^^^^^^ ^ ^^^~~ ^^^ ^^^^^^^ ^^^ ^^^^ -^ ^^^~~~^^^^^^^^^ ^^^^^^^^^^^^~~~~~ +^ { ^^^~~~^^^^^^^^^ ^^^^^^^^^^^^~~~~~ ^^ ^^^^~~~~^^^^^^^^^^ ^^^^^^^^^^^^^~~~~~~~~ ^^^ ^ ~~~~~^^^^^^^^^ ^^^^^^^^^~~~~~~~~~^^^^^ ^^^ ^^~~~~~~^^^^^ ^^^^^~~~~~~~^^^^^^^ ^^^ ^ ^ ~~~~~~~~##~~~~~~~^^^^^^^^^^ ^^^ ^^ ^^^^^ ~~~##~~~~^^^^^^^^^ ^^^^ ^^ ^^^^^^^^^^ ^^ ^^ -^ ^^^^^^^^^^^^^ ^^^ ^ +^ ^^^^^^^^^^^^^ ^^^ ^ { ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ No newline at end of file diff --git a/assets/grids/team8_grid_v2.grid b/assets/grids/team8_grid_v2.grid index 928d3fb1..5475cc32 100644 --- a/assets/grids/team8_grid_v2.grid +++ b/assets/grids/team8_grid_v2.grid @@ -1,150 +1,150 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ No newline at end of file +$$$$$$$$$$$ ~ $$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$~~$$$$$$$$$$$^^^^^^^^^^^ +$$$$$$$$$$$$ ~ $$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$~~$$$$$$$$$$^^^^^^^^^^^^ +$$$$$$$$$$$$$ ~ $$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$ ~ $$$$$$$$$$$$$$$$$$$$$$~~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$~~$$$$$$^^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$ ~~ $$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$~$$$$ ^^^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ~~ ^^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$~~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ~ ^^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$^^^ ~ ^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$~$$$$$$$$$$$$$$$$$$$$$$$$$$^^^^^^^^^^^^^^ ~~ ^^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$$$$$$$$~~$$$$ $$$$$$$$$~~$$$$$$$$$$$$$$$$$$$$$$$$^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$$$$$$ ~ $$$~$$$$$$$$$$$$$$$$$$$$$^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^ +$$$$$$$$$$$$$$$$$ # ~~ $$$$$$$$$$ ^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^ +$$$$$$$$$$$$ # ~ ^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^ +$$$$$$$ ~~ ~~ ^^^^^^^^^^^^^^^^^ ~~ ^^^^^^^^^^^^^^^^^^^ + ~ ~ ^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^^^ ~~~ + ~ ~~ ^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^^ ~~~~ + ~ # ^^^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^^^ ~~~ + ~~ # ^^^^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^^ ~~~ + ~ ~~ ^^^^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^^ ~~ + ~~ ~ ^^^^^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^~~ + ~ ^^^^~~^^ ^^^^^^^^^^^^^^^^^^^^^^ ~~ ^^^^^^^^^^^^^^^^~~ + ~~ ^^^^^^^^~^^^^ ^^^^^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^^^~^ + ~~ ^^^^^^^^^^~~^^^^ ^^^^^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^~~^ + ~~~~^^^^^^^^^~^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ~~ ^^^^^^^^^^~^^^ + ^^^^^^^~~~~^^^^^^~^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ~ ^^^^^^^^~~^^^ + ~~~~~~~~~ ^^^^^^^^^^^^^~~^^^^ ~~^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ~ ( ^^^^^^~~^^^^^ +~~~~~ ~~~~~~~ ^^^^^^^^^^^^^^^^~~^^ ~ ^^^^^^^^^^^^^^^^^^^^^^^ ~~ ~~~^^~~^^^^^^ + ~~~~^^^^^^^^^^^^^^^^~~~~ ~~ ^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~^^^^^^^^ + ^^~~~^^^^^^^^^^^^^^^^^~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~^^^^^^^^^^^ + ^^^^^~~^^^^^^^^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~^^^^^^^^^^^ + ^^^^^^^~~^^^^^^^^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~^^^^^^^^^ + ^^^^^^^^^~^^^^^^^^^^^^^^^^ ~~ ^^^^^^^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~ ^^^^^^^ + ^^^^^^^^^^~^^^^^ ^^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~ ^^^ +^ ^^^^^^^^^^~~^^^ ^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~ +^ ^^^^^^^^^^^^~^^ ^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~~ +^ ^^^^^^^^^^^^~^^ ^^^^^^^^^ ~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~~~ +^^ ^^^^^^^^^^^^^~^ { ^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~~~~~ +^^ ^^^^^^^^^^^^~~ ^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~~~~~ +^^ ^^^^^^^^^^^^~^ ^^^^^^^^^^ ~~ ^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~~~~~ +^^^ ^^^^^^^^^^^^^~^ ^^^^^^^^^^ ~~ ^^^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~~~~ +^^^ ^^^^^^^^^^^^^~~^ ^^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^^^^ # ~~~~~~~~~~~~~~~ } +^^^^ ^^^^^^^^^^^^^^~^^ ^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~~ +^^^^^ ^^^^^^^^^^^^^^^^~^^ ^^^^^^^^ ~ ^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^~^ ^^^^^^^^^ ~~ ^^^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^~~ ^^^^^^^^ ~ ^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^~ ^^^^^^^^^ ~ ^^^^^^^^^^^^^^^ ~ ~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^~^^^ ^^^^^^^^^^ ~ ^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^ ~~ ^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^ ^^^^^^^^^^^~~^^^^^^^^^^^^^ ~ ^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^ ^^^^^^^^^^~~^^^^^^^^^^^^ ~ ^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^ ^^^^^^^^^^~~^^^^^^^^^^ ~~ ^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^ ^^^^^^^^^^~~^^^^^^^^^ ~ ^^^^^^ ~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^ ^^^^^^^^^^^~^^^^^^^^ ~ ^^^ ~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^ ^^^^^^^^^^^^~^^^^^^^^ ~~ ~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^ ^^^^^^^^^^^^^~~^^^^^^ ~ ~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^ ^^^^^^^^^^^^^^~^^^^ ~ ~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^~^^^^ ~~ ~~~~~~~~~~~~~ ~ +^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^~^^ ~ ~~~~~~~~~ ~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~ ~ ~~~~ ~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~ ~ ~~ ^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~ ~ ^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~ ~ ^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~ ~ ^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^ ~ ~~ ~~ ^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^ ~~ ~ ~ ^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^ ~ ~ ~ ^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^ ~ ~ ~ ^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^ ~ ~ ^^~~^^ ^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ ~~ ~~ ^^^^^ ^^^^^^~^^^^ ^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^ ~ ~ ^^^^^^^^^^^^ ^^^^^^^^^^~^^^^ ^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^ ~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^ ~ ~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^ ~~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^ ^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^ ~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^ ^^^^^^^^^^^^^^^^^^ +^^^^^^^^ ~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^ ^^^^^^^^^^^^^^^^ +^^^^^^^^ ~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^ ^^^^^^^^^^^^^^ +^^^^^^^^ ~~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^ ^^^^^^^^^^^^^ +^^^^^^^^^ ~~~ ~~~~~ ~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^ ^^^^^^^^^^^^^ +^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^ ^^^^^^^^^^^ +^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~ ~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^ ^^^^^^^^^^^ +^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^ ^^^^^^^^^^^^^ +^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^ ^^^^^^^^^^^^^ +^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^ ^^^^^^^^^^^^^^ +^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^^^ ^^^^^^^^^^^^^^^^ +^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~ ^^~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~ ^^^~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~ ) ^^^~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~ ^^^~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~ } ~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~~ +^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^~~~~ +^^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^~^^^^^^^^^^^^^^ ^^^^^^^^~~~~~ +^^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^~~^^^^^^^^^^ ^^^^^~~~~~~ +^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^^^^^^^ ^^^^^~^^^^^^^ ^^^^~~~~~~~ +^^^^^^^^ ^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^^^^^ ~~^^^ ^^^~~~~~~~ +^^ ^ ^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^ ~~ ~~~~~ ^~~~~~~~~ + ^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ ~~~~~ ~~~ ~~~~~~~~~ + ^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ ~~~~ ~~~~~~~~~~~~ + ^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~ ~~~~~~~~~~ + ^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~ + ^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~ + ^^^^^^^^^^^^^^^^^ ~~~ ~~~~~~~~~~~~~~ ~~~~~~~~~~ + ^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~ ~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^ ~~~ ~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^ ~~~ ~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^ ~~ ~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^ ~~~ ~~~~~~~~~~~~~~ +^^^^^ ^^^^^ ~~ ~~~~~~~~~~~~~~~ +^^^ ~~ ~~~~~~~~~~~~~~~ +^ ~~ ~~~~~~~~~~~~~~~~ + ~~ ~~~~~~~~~~~~~~~~ + ~~~ ~~~~~~~~~~~~~~~~~ + ~~ ~~~~~~~~~~~~~~~~~~ + ~~ ~~~~~~~~~~~~~~~~~~~ + ## ~~~~~~~~~~~~~~~~~~~~ + ~~ ~~~~~~~~~~~~~~~~~~~~~ + ~~ { ~~~~~~~~~~~~~~~~~~~~~~~ + ~~~ ^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ ^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ ^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ ^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ ^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~ ^^^^^^^^ ^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ( ~~ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ^^^^~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ^^^^^^^^^~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ) + ^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ^^^^^^^^^^^^^^^~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/assets/grids/third_floor.grid b/assets/grids/third_floor.grid new file mode 100644 index 00000000..9d431ae0 --- /dev/null +++ b/assets/grids/third_floor.grid @@ -0,0 +1,20 @@ + # # + # ## # + # ## # + # # + # +# ## # +# # +## ## +### ### +#### #### +##### ##### +###### ###### +####### ####### +####### ####### +###### ###### +##### ww##### +#### ww #### +### ww ### +## ww g ## +#################### diff --git a/assets/input.json b/assets/input.json new file mode 100644 index 00000000..02c0db07 --- /dev/null +++ b/assets/input.json @@ -0,0 +1,42 @@ + +[ + { + "name": "player", + "x": 3, + "y": 3, + "entities": [ + + ], + "hasInventory": false, + "properties": {} + }, + { + "name": "pacer1", + "x": 10, + "y": 5, + "entities": [ + "fire_sword" + + ], + "hasInventory": false, + "properties": { + "Health": 30.0, + "Strength": 10.0, + "Defense": 5.0 + } + }, + { + "name": "pacer2", + "x": 23, + "y": 8, + "entities": [ + + ], + "hasInventory": false, + "properties": { + "Health": 30.0, + "Strength": 8.0, + "Defense": 4.0 + } + } +] \ No newline at end of file diff --git a/assets/scripts/g4_agent_attack.ws b/assets/scripts/g4_agent_attack.ws new file mode 100644 index 00000000..2d92f987 --- /dev/null +++ b/assets/scripts/g4_agent_attack.ws @@ -0,0 +1,50 @@ +# agent=attacker +# opponent=defender + +# == stats that matter == +# Strength: base damage (on agent) +# Damage: additional damage (from items) +# Defense: reduced damage (on agent) +# Armor: reduced damage (from items) + +print(agent," attacks ",opponent) + +str=getProperty(agent,"Strength") +def=getProperty(opponent,"Defense") +print("Base=",str,",",def) + +# Check agent equipped item +if (getInventorySize(agent)){ + # Treat this as the equipped item + item=getInventoryItem(agent,0) + if (hasProperty(item,"Damage")){ + str=str+getProperty(item,"Damage") + } +} +print("Str=",str) + +# Check opponent equipped item +if (getInventorySize(opponent)){ + # Treat this as the equipped item + item=getInventoryItem(opponent,0) + if (hasProperty(item,"Armor")){ + def=def+getProperty(item,"Armor") + } +} +print("Def=",def) + +# Calculate damage +diff=str-def +if (diff<=0){ + diff=1 +} +damage=rand(1,2*diff) +print(damage," damage") + +hp=getProperty(opponent,"Health")-damage +if (hp<0){ + hp=0 + setProperty(opponent,"Dead",1) + setProperty(opponent,"symbol","x") +} +setProperty(opponent,"Health",hp) diff --git a/assets/scripts/g4_world_2_load.ws b/assets/scripts/g4_world_2_load.ws new file mode 100644 index 00000000..46c27e7b --- /dev/null +++ b/assets/scripts/g4_world_2_load.ws @@ -0,0 +1,18 @@ +# Load the actual world +loadWorld("../assets/grids/second_floor.grid") + +# Load the agents for this world +loadAgents("../assets/second_floor_input.json") + +# Reset player position +print(player) +setAgentPosition(player,0,0) + +# Place items for second floor +addItem("Hammer","H",20,43,"Damage",35) +addItem("Dagger","D",12,1,"Damage",10) +addItem("Leather Armor","+",1,6,"Armor",6) + +# Set link to next world +next_world = "../assets/scripts/g4_world_3_load.ws" + diff --git a/assets/scripts/g4_world_3_load.ws b/assets/scripts/g4_world_3_load.ws new file mode 100644 index 00000000..3d228270 --- /dev/null +++ b/assets/scripts/g4_world_3_load.ws @@ -0,0 +1,12 @@ +# Load the actual world +loadWorld("../assets/grids/third_floor.grid") + +# Load the agents for this world +loadAgents("../assets/third_floor_input.json") + +# Reset player position +setAgentPosition(player,0,0) + +# Set game end indicator +next_world = "GAME_END" + diff --git a/assets/scripts/g4_world_load.ws b/assets/scripts/g4_world_load.ws new file mode 100644 index 00000000..fe33bd63 --- /dev/null +++ b/assets/scripts/g4_world_load.ws @@ -0,0 +1,31 @@ +# List of cell types +floor_id = addCellType("floor", "Floor that you can easily walk over.", " ") +flag_id = addCellType("flag", "Goal flag for a game end state", "g","Goal") +wall_id = addCellType("wall", "Impenetrable wall that you must find a way around.", "#", CELL_WALL) +hidden_warp_id = addCellType("hidden_warp", "Hidden warp tile that warps to floor 3.", "u","Warp") +water_id = addCellType("water","Water that distinguishes fire.","w",CELL_WATER) + +# Load the actual world +loadWorld("../assets/grids/group4_maze.grid") + +# Place the player agent into the world +# Name is interface to play nicely with the 2D interface +player=addAgent("Player2D","Interface","@",0,0) +setProperty(player,"Health",100.0) +setProperty(player,"Strength",7.0) +setProperty(player,"Defense",7.0) +setAgentPosition(player,0,0) + +# Place items +addItem("Sword of Power","S",1,2,"Damage",20) +addItem("Inferno Slicer","S",3,4,"Damage",12.5,"Speed",15.0,"Burning Duration",2.5) +addItem("Daedric Armor","+",5,0,"Armor",20,"ExtraSpace",5) +addItem("Axe of Health","A",1,3,"Damage",8.5,"Health",35) +addItem("Electric Dagger","D",6,2,"Damage",25) +chest = addItem("Ender Chest","C",0,4,"Chest",1) +fire_dagger = addItem("Fire Dagger","D",-1,-1,"Damage",15.0) +addInventoryItem(chest,fire_dagger) + +# Set link to next world +next_world = "../assets/scripts/g4_world_2_load.ws" + diff --git a/assets/scripts/player_move.ws b/assets/scripts/player_move.ws new file mode 100644 index 00000000..9e7995c4 --- /dev/null +++ b/assets/scripts/player_move.ws @@ -0,0 +1,39 @@ +move(act_id,cx,cy){ + if(action_id==act_id){ + nx,ny=cx,cy + } +} + +_="Handle player movement" +x,y=getAgentPosition(agent) +nx,ny=0,0 + +move(0,x,y) +move(MOVE_UP,x,y-1) +move(MOVE_DOWN,x,y+1) +move(MOVE_LEFT,x-1,y) +move(MOVE_RIGHT,x+1,y) + +if(isValid(nx,ny)){ + if(isTraversable(agent,nx,ny)){ + _="Check for an agent at this position: attack if this is the case" + opponent=findAgentAt(nx,ny) + if(opponent!=ID_NONE){ + _="Agent exists, attack it (opponent=id of opponent)" + str=getProperty(agent,"Strength") + def=getProperty(opponent,"Defense") + damage=rand(1,str-def) + + hp=getProperty(opponent,"Health")-damage + if (hp<0){ + hp=0 + setProperty(opponent,"symbol","x") + } + setProperty(opponent,"Health",hp) + } + if(opponent==ID_NONE){ + _="Only set position if movement is allowed" + setAgentPosition(agent,nx,ny) + } + } +} diff --git a/assets/scripts/world_script.ws b/assets/scripts/world_script.ws new file mode 100644 index 00000000..fb514d3f --- /dev/null +++ b/assets/scripts/world_script.ws @@ -0,0 +1,23 @@ +_="List of cell types" +floor=addCellType("floor","An empty space"," ") +wall=addCellType("wall","A solid wall","#",CELL_WALL) +one=addCellType("one","The number 1","1",CELL_WALL) +two=addCellType("water","A water tile","w",CELL_WATER) +three=addCellType("three","The number 3","3","Collectible") + +_="Load the actual world" +loadWorld("../assets/grids/lang_load_test.grid") + +_="Place the player agent into the world" +player=addAgent("Player","PlayerAgent","%",1,1) +setProperty(player,"DoAction","../assets/scripts/player_move.ws") +setProperty(player,"Strength",7) +setProperty(player,"Defense",2) +setProperty(player,"Health",10) + +player2=addAgent("Player","PlayerAgent2","&",3,3) +setProperty(player2,"DoAction","../assets/scripts/player_move.ws") +setProperty(player2,"Strength",4) +setProperty(player2,"Defense",3) +setProperty(player2,"Health",15) + diff --git a/assets/second_floor_input.json b/assets/second_floor_input.json new file mode 100644 index 00000000..1c1b8bef --- /dev/null +++ b/assets/second_floor_input.json @@ -0,0 +1,30 @@ +[ + { + "name": "Imp", + "x": 3, + "y": 1, + "entities": [ + "chocolate_bar" + ], + "hasInventory": false, + "properties":{ + "Health":30.0, + "Defense":5.0, + "Strength":3.0 + } + }, + { + "name": "Pinky", + "x": 11, + "y": 2, + "entities": [ + + ], + "hasInventory": false, + "properties":{ + "Health":70.0, + "Defense":15.0, + "Strength":10.0 + } + } +] diff --git a/assets/third_floor_input.json b/assets/third_floor_input.json new file mode 100644 index 00000000..a1d9a604 --- /dev/null +++ b/assets/third_floor_input.json @@ -0,0 +1,17 @@ +[ + { + "name": "Jim Harbaugh", + "x": 7, + "y": 8, + "entities": [ + "invisibility_cloak" + ], + "hasInventory": false, + "properties":{ + "Health":1.0, + "Defense":24.0, + "Strength":36.0, + "Boss":1.0 + } + } +] diff --git a/assets/walls/portal3,png.png b/assets/walls/portal3.png similarity index 100% rename from assets/walls/portal3,png.png rename to assets/walls/portal3.png diff --git a/docs/Group_7.md b/docs/Group_7.md index e69de29b..8c167417 100644 --- a/docs/Group_7.md +++ b/docs/Group_7.md @@ -0,0 +1,85 @@ +# Group 7 : Genetic Programming Agents +-- -- +authors: Aman, Simon, Rajmeet, Jason + + + + + +(Img: Rajmeet, Simon, Jason, Aman) + +## Introduction + +## GP Agent Base Class + +## LGP Agent + +## CGP Agent + +## GP Loop + + +## It runs on my machine +we have used cmake to ensure that our code compiles on all platforms. but.... +we have tested our code on the following machines/architectures: +- Windows 11 +- Windows 10 +- Ubuntu 20.04 +- HPCC Cluster Centos7 +- MacOS Sonoma (ARM) +- mlcollard/linux-dev (Docker Container) + +Tested in the following IDEs: +- CLion +- VSCode + +Tested on the following compilers: +- gcc 9.3.0 +- Apple clang 12.0.0 +- LLVM clang 11.0.0 + +### Profiled with and optimized with: +- clion profiler +
/ + + + +- Xcode instruments +
+ + +- intel vtune +
+ + +- very sleepy +Didnt deserve a screenshot. /s + +- code coverage in clion + + + +### Sanitized with: + +- clang sanitizer Memory +- valgrind +- gcc sanitizer Memory +- gcc sanitizer address + - Used to find and fix memory UB in the code. + + + +## Other Contributions + +### EasyLogging +Created a logging class that is can be used to log debug messages in debug mode. Teams can be specified to log with different levels of verbosity. This is useful for debugging and profiling. + +### CMake +Initial cmake setup for the project. This is useful for cross platform compilation and testing. + +### serializationUsingTinyXML2 +Created and tested a serialization class that can be used to serialize and deserialize objects to and from xml files. This is useful for saving and loading the state of the GP agents. +Implemented serialization pattern using tinyxml2 library. + +### mkdocs documentation +Created and tested a mkdocs documentation for the project. This is useful for creating a website for the project. \ No newline at end of file diff --git a/docs/assets/GP_Group7/CodeCoverage_Clion.png b/docs/assets/GP_Group7/CodeCoverage_Clion.png new file mode 100644 index 00000000..ffbebb6e Binary files /dev/null and b/docs/assets/GP_Group7/CodeCoverage_Clion.png differ diff --git a/docs/assets/GP_Group7/Group7Photo.jpeg b/docs/assets/GP_Group7/Group7Photo.jpeg new file mode 100644 index 00000000..b934a44a Binary files /dev/null and b/docs/assets/GP_Group7/Group7Photo.jpeg differ diff --git a/docs/assets/GP_Group7/ProfilerGP_Clion.png b/docs/assets/GP_Group7/ProfilerGP_Clion.png new file mode 100644 index 00000000..d14f7764 Binary files /dev/null and b/docs/assets/GP_Group7/ProfilerGP_Clion.png differ diff --git a/docs/assets/GP_Group7/ProfilerGP_IntelVtune.png b/docs/assets/GP_Group7/ProfilerGP_IntelVtune.png new file mode 100644 index 00000000..8e0e267b Binary files /dev/null and b/docs/assets/GP_Group7/ProfilerGP_IntelVtune.png differ diff --git a/docs/assets/GP_Group7/ProfilerGP_Xcode.png b/docs/assets/GP_Group7/ProfilerGP_Xcode.png new file mode 100644 index 00000000..071f2a26 Binary files /dev/null and b/docs/assets/GP_Group7/ProfilerGP_Xcode.png differ diff --git a/docs/assets/GP_Group7/UB_Behavior.png b/docs/assets/GP_Group7/UB_Behavior.png new file mode 100644 index 00000000..32a618cd Binary files /dev/null and b/docs/assets/GP_Group7/UB_Behavior.png differ diff --git a/in_class/SetCover/generate.cpp b/in_class/SetCover/generate.cpp new file mode 100644 index 00000000..c6199283 --- /dev/null +++ b/in_class/SetCover/generate.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +using subset_t = std::vector; +using instance_t = std::vector; + +void PrintSetCover(int U, const instance_t & sets) { + std::cout << U << " " << sets.size() << '\n'; + for (const auto & set : sets) { + for (size_t i = 0; i < set.size(); ++i) { + if (i) std::cout << " "; + std::cout << set[i]; + } + std::cout << '\n'; + } +} + +// Test to make sure that there IS a possible solution (i.e., all entities are available) +bool TestLegal(int U, const instance_t & sets) { + // Scan values in any set. + std::unordered_set full_set; + for (const auto & set : sets) { + // if (set.size() == 0) { + // std::cerr << "Set size zero!" << std::endl; + // return false; // No sets can be empty. + // } + for (int value : set) full_set.insert(value); + } + + // Test if all values are available. + for (int i = 0; i < U; ++i) { + if (!full_set.count(i)) { + std::cerr << "Not fully covered" << std::endl; + return false; + } + } + return true; +} + +instance_t GenerateSetCover(int U, int N, double P, int attempt=0) +{ + if (attempt > 100) { + std::cerr << "ERROR: Made 100 attempts; unable to generate with these parameters!" << std::endl; + exit(1); + } + + static std::random_device rd; // Seed + static std::mt19937 gen(rd()); // Standard mersenne_twister_engine + static std::uniform_real_distribution<> dis(0.0, 1.0); + + instance_t sets(N); + + // Randomly fill in each set, tracking total count as we go. + for (auto & set : sets) { + for (size_t i = 0; i < U; ++i) { + if (dis(gen) < P) set.push_back(i); + } + } + + // If this attempt isn't legal, try again. + if (!TestLegal(U, sets)) return GenerateSetCover(U, N, P, attempt+1); + return sets; +} + +int main(int argc, char * argv[]) +{ + if (argc != 4) { + std::cerr << "This program generates instances of the set cover problem, where the minimum number\n" + << "of subsets must be selected that cover all of the entiteis in a universal set.\n" + << "\n" + << "Format: " << argv[0] << " [U] [N] [P]\n" + << " where U is the size of the universal set (total number of entities),\n" + << " N is the number of subsets to consider in the cover,\n" + << " and P is the probability of an entity being in a given subset.\n" + << std::endl; + exit(1); + } + + std::string U_str(argv[1]); int U = std::stoi(U_str); + std::string N_str(argv[2]); int N = std::stoi(N_str); + std::string P_str(argv[3]); double P = std::stod(P_str); + auto sets = GenerateSetCover(U, N, P); + PrintSetCover(U, sets); +} diff --git a/in_class/SetCover/solve.cpp b/in_class/SetCover/solve.cpp new file mode 100644 index 00000000..5091d3fc --- /dev/null +++ b/in_class/SetCover/solve.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include + +static constexpr size_t MAX_ENTRY = 1000; + +struct SetCover { + size_t U; + std::vector> sets; + std::vector> bsets; + + // A prospective solution is a set of IDs of which subsets to use. + using solution_t = std::vector; + + void Load() { + size_t N; + std::cin >> U >> N; + sets.resize(N); + + std::string line; + size_t value; + std::getline(std::cin, line); // Skip the remainder of the first line + + for (size_t i = 0; i < N; ++i) { + std::getline(std::cin, line); // Read the whole line for each subset + std::istringstream iss(line); + + while (iss >> value) { // Extract numbers from the line + sets[i].push_back(value); + } + } + + // Fill out bitsets. + bsets.resize(sets.size()); + for (size_t i = 0; i < sets.size(); ++i) { + for (size_t value : sets[i]) { + bsets[i][value] = true; + } + } + } + + void Print() const { + std::cout << U << " " << sets.size() << '\n'; + for (const auto & set : sets) { + for (size_t value : set) std::cout << value << ' '; + std::cout << '\n'; + } + } + + void PrintSolution(const solution_t & sol) const { + for (size_t id : sol) { + std::cout << id << " :"; + for (size_t value : sets[id]) { + std::cout << " " << value; + } + std::cout << '\n'; + } + } + + // Generate the first solution of a given size. + solution_t FirstSolution(size_t sol_size) const { + solution_t sol(sol_size); + for (size_t i = 0; i < sol_size; ++i) { + sol[i] = i; + } + return sol; + } + + // Move to the next solution of this size. Return 'false' if not possible. + bool NextSolution(solution_t & solution, size_t pos=0) const { + // What is the roll-over value for this position? + size_t cap = U; + if (pos < solution.size()-1) cap = solution[pos+1]; + + // Increment this position + solution[pos]++; + + // If this position has hit the cap, consider next position! + if (solution[pos] >= cap) { + // If we are at the last position, just return false. + if (pos == solution.size() - 1) return false; + + // Otherwise reset it to lowest and move on. + if (pos == 0) solution[0] = 0; + else solution[pos] = solution[pos-1]+1; + + return NextSolution(solution, pos+1); + } + + return true; + } + + bool IsLegal(const solution_t & sol) { + std::bitset result; + for (size_t id : sol) { + result |= bsets[id]; + } + + return result.all(); + + // // Scan values in any set. + // std::unordered_set full_set; + // for (size_t id : sol) { + // const auto & set = sets[id]; + // for (int value : set) full_set.insert(value); + // } + + // // Test if all values are available. + // for (int i = 0; i < U; ++i) { + // if (!full_set.count(i)) return false; + // } + // return true; + } + + bool Solve(int sol_size) { + SetCover::solution_t sol = FirstSolution(sol_size); + do { + if (IsLegal(sol)) { + std::cout << "FOUND!\n"; + PrintSolution(sol); + return true; + } + } while (NextSolution(sol)); + return false; + } +}; + +int main(int argc, char * argv[]) +{ + int sol_size = 4; + if (argc > 1) sol_size = std::atoi(argv[1]); + + SetCover sc; + sc.Load(); + + if (!sc.Solve(sol_size)) { + std::cout << "NOT FOUND. :-(" << std::endl; + } +} \ No newline at end of file diff --git a/in_class/SetCover/test_set-100.sc b/in_class/SetCover/test_set-100.sc new file mode 100644 index 00000000..6da8f205 --- /dev/null +++ b/in_class/SetCover/test_set-100.sc @@ -0,0 +1,101 @@ +60 100 +51 +11 31 53 +11 12 17 43 48 +16 +9 +5 30 32 35 39 48 +18 24 38 39 43 58 + + +35 +13 34 +33 +36 +13 58 +0 4 7 11 35 49 +2 5 15 +33 +44 + +25 29 +2 34 40 46 52 +22 +8 21 47 50 56 +34 36 +41 43 +14 41 45 +21 50 55 +9 11 45 +29 53 +34 +53 +3 10 +7 16 +0 26 +18 35 +13 + + +0 +10 56 +17 25 +38 +2 47 +4 14 39 42 44 47 + +31 42 +32 41 + +26 29 51 53 +35 39 + +19 24 35 +17 30 34 40 +12 35 37 +22 27 33 51 + +52 +6 7 20 + +12 32 49 50 51 54 + +1 33 + +34 48 +8 20 +40 + +54 +37 +28 44 +34 38 +3 12 13 38 43 50 +2 +24 27 +6 29 35 57 + +13 42 +38 59 +24 26 +16 +13 26 37 + +16 33 45 46 56 +12 31 59 +11 32 33 51 56 +5 +51 +7 14 16 +34 40 56 +5 +57 +25 41 +33 + +22 +6 8 23 27 +33 +15 52 +41 53 +45 diff --git a/in_class/SetCover/test_set-100b.sc b/in_class/SetCover/test_set-100b.sc new file mode 100644 index 00000000..88326ed7 --- /dev/null +++ b/in_class/SetCover/test_set-100b.sc @@ -0,0 +1,101 @@ +60 100 +2 4 16 28 33 +3 15 16 29 33 35 37 42 +7 8 17 45 +1 3 23 44 55 +15 29 33 42 45 +13 14 25 27 44 59 +14 41 45 47 55 +33 37 39 53 +23 44 45 56 +4 6 47 +16 17 31 33 54 56 +0 10 11 31 33 37 38 40 41 +5 11 12 22 40 43 48 +1 39 50 51 +5 9 28 29 31 51 +6 7 11 24 28 29 47 59 +2 3 4 5 14 16 25 33 35 43 47 54 56 +0 1 13 16 30 46 52 +0 6 27 46 +12 14 16 34 53 55 +6 17 20 28 35 44 55 +26 +1 7 8 19 21 22 29 31 48 55 +14 17 18 21 28 31 32 37 45 +17 19 37 43 47 51 +22 24 25 31 40 49 +33 56 +8 15 16 17 21 32 48 +1 7 20 22 41 46 56 +5 8 21 32 40 51 +7 13 29 57 +8 9 18 29 30 36 37 43 45 48 51 55 58 +2 4 9 10 20 28 36 50 +3 4 10 16 23 38 +4 8 10 19 23 42 53 58 +0 15 18 38 42 57 +2 6 56 +3 29 30 40 45 52 +3 33 34 36 +12 28 30 35 37 40 42 47 56 +13 17 19 24 25 26 28 31 47 48 55 +8 17 26 34 44 46 53 +1 17 25 46 59 +13 17 19 23 +11 26 33 53 57 59 +19 35 49 +23 42 46 51 56 57 +11 13 24 31 33 49 51 +46 52 +7 18 34 36 +14 15 22 28 +1 7 9 17 52 +8 29 43 49 +0 2 18 31 36 42 +11 21 32 37 45 +9 17 45 59 +5 6 14 29 45 49 58 +7 21 47 48 54 +29 31 35 38 48 55 59 +8 37 +6 32 41 45 +5 11 31 33 40 +2 16 38 40 47 50 +14 53 +10 22 24 27 35 37 50 54 +16 35 +30 33 46 59 +9 26 41 +6 17 30 31 32 42 +3 23 31 41 43 46 47 55 +16 22 29 35 36 37 40 +3 25 35 36 39 46 50 56 58 + +6 10 12 23 +14 32 37 45 53 54 58 59 +5 7 19 33 35 37 42 44 +2 5 13 22 27 32 38 +1 15 23 51 55 57 +16 25 36 49 +3 50 57 +1 43 45 54 55 +8 13 26 35 37 38 41 46 58 +4 8 13 19 21 24 56 +9 21 22 48 +14 25 53 54 +0 16 21 28 38 54 59 +13 24 25 31 49 57 +9 15 18 26 36 45 48 51 +0 9 12 25 34 39 46 +11 16 31 44 +13 39 45 48 52 56 58 +0 15 19 +1 34 38 41 46 53 +6 10 16 23 44 57 +0 10 20 29 35 38 42 50 54 55 59 +6 12 26 29 55 59 +7 18 20 44 56 57 +6 21 34 38 42 +0 5 13 27 29 45 46 48 +1 7 32 48 49 53 55 diff --git a/in_class/SetCover/test_set-100c.sc b/in_class/SetCover/test_set-100c.sc new file mode 100644 index 00000000..7659f067 --- /dev/null +++ b/in_class/SetCover/test_set-100c.sc @@ -0,0 +1,101 @@ +60 100 +1 3 4 6 7 8 9 13 15 16 17 20 22 23 25 26 33 35 36 39 45 47 50 51 52 53 55 57 +0 5 6 9 12 18 19 29 30 32 35 37 40 42 43 48 51 53 57 +0 2 3 4 8 11 15 21 22 24 25 26 32 34 35 39 40 48 49 50 51 52 54 55 57 59 +4 5 8 12 14 15 19 22 24 25 26 27 29 30 31 32 33 36 40 41 42 44 46 50 51 58 +0 3 8 9 11 13 15 16 18 19 28 29 33 36 38 40 45 46 50 52 56 57 58 59 +1 2 3 7 8 13 15 17 18 20 26 27 29 31 32 34 37 38 40 41 43 47 51 52 54 55 59 +1 4 5 6 7 8 10 11 12 15 16 17 18 19 20 24 25 26 27 28 29 31 34 37 40 44 45 47 52 53 54 +2 4 5 10 13 14 15 16 17 20 21 23 24 25 31 32 33 37 38 41 42 45 46 48 53 54 55 56 +9 12 14 15 16 18 19 21 22 25 26 31 33 35 37 39 43 46 52 54 +0 2 4 9 10 12 15 21 27 30 35 36 39 41 44 49 52 56 57 58 59 +0 3 5 8 9 10 11 12 13 15 16 18 20 23 24 31 32 33 36 37 39 41 42 45 46 50 53 55 57 +1 7 9 11 18 20 22 25 27 28 29 34 36 38 44 45 50 55 57 +0 1 8 10 11 14 15 17 19 23 24 26 27 29 31 35 44 48 54 58 +0 2 4 6 9 11 13 14 16 22 25 30 31 35 37 41 42 45 48 54 56 +3 4 5 6 9 10 11 13 14 15 17 19 21 25 26 28 33 34 38 39 45 46 50 53 54 56 +3 4 7 8 10 13 16 22 24 26 29 34 35 38 39 40 43 44 49 51 58 59 +1 2 3 4 5 7 10 11 12 13 16 18 19 21 22 23 24 26 28 30 31 35 36 37 39 41 44 45 48 52 53 54 +0 2 6 8 9 10 13 14 15 17 20 22 24 27 28 32 35 44 45 46 51 52 57 58 59 +7 8 10 12 13 17 23 26 28 32 34 35 42 43 45 53 56 +0 1 2 3 7 8 9 10 11 12 13 16 17 18 20 23 25 28 35 36 38 39 41 42 43 44 46 47 50 53 57 58 +0 3 5 7 10 12 15 16 17 20 27 31 32 34 36 37 38 40 41 43 46 48 49 51 52 54 56 59 +0 1 2 4 7 11 12 14 18 21 22 23 25 26 31 32 36 37 38 39 40 41 42 45 47 48 50 51 +0 1 5 8 10 11 15 18 21 23 24 26 32 35 39 46 47 49 51 55 58 59 +4 6 8 11 13 15 16 17 22 26 29 32 35 38 40 43 44 45 46 47 52 53 54 +0 3 4 7 8 9 11 12 13 16 27 29 30 32 33 35 38 39 45 46 47 49 51 54 56 57 +4 8 12 13 14 16 17 19 20 21 23 24 25 26 27 31 34 38 39 46 47 48 52 55 59 +0 1 4 5 6 9 11 13 18 19 24 29 30 32 34 35 37 40 41 42 43 45 49 53 56 57 +2 10 11 12 13 16 18 20 23 24 25 27 32 33 37 40 42 44 46 47 48 51 52 53 57 +0 1 7 9 10 12 19 20 21 22 26 33 35 44 50 55 58 +2 3 6 7 8 9 14 16 26 28 29 30 31 32 33 34 35 38 39 44 49 52 53 54 55 56 57 +4 6 7 9 10 13 16 17 19 20 21 22 26 27 30 36 37 41 43 44 46 48 49 52 55 56 +0 1 3 4 6 11 13 16 18 21 23 26 28 32 35 36 43 46 48 50 52 53 54 55 57 +1 2 3 6 15 17 19 21 26 27 35 37 39 40 45 46 57 58 +1 4 5 9 11 17 20 21 26 27 30 31 33 35 37 39 49 50 51 52 56 57 +3 4 5 6 7 8 9 13 14 16 19 22 23 24 27 28 29 30 34 36 39 41 44 49 52 54 55 57 +2 5 6 9 10 11 13 20 24 25 27 29 35 39 42 43 45 49 53 56 +1 2 4 5 9 14 22 26 37 38 39 41 42 43 45 47 48 51 52 56 57 +3 4 6 8 9 11 12 13 15 17 18 19 22 23 27 29 31 32 33 34 35 38 40 41 43 50 51 58 59 +0 5 11 13 14 17 20 27 31 35 36 39 40 41 46 47 49 50 54 57 +0 1 4 5 7 11 13 14 16 17 18 21 22 24 27 33 35 36 37 38 42 45 47 48 53 54 56 57 59 +1 9 10 11 13 14 24 25 26 27 28 29 34 37 40 44 45 46 50 53 54 56 57 59 +0 3 4 5 11 14 16 17 18 19 22 26 29 31 33 34 38 39 45 46 48 50 52 53 55 56 57 +3 11 12 13 19 22 23 24 26 27 30 32 33 34 36 38 42 43 45 47 51 52 58 59 +0 5 8 10 11 12 13 14 16 18 21 24 25 28 29 30 32 34 35 40 46 48 51 52 54 55 56 +1 2 3 6 9 11 12 14 16 18 19 21 22 23 25 28 32 41 42 49 51 52 53 54 55 56 57 58 +2 3 4 6 7 8 11 13 16 17 21 24 26 29 33 36 37 39 41 42 44 47 48 50 52 53 54 58 +0 3 4 5 6 8 9 10 12 15 16 17 18 19 24 27 29 31 32 35 36 41 44 51 52 53 55 58 59 +2 3 5 11 12 19 26 28 29 30 31 33 34 37 40 44 45 49 51 53 55 57 +1 2 3 6 7 11 12 15 17 18 20 24 25 29 30 33 39 41 44 46 48 51 53 55 +0 1 2 4 8 10 11 16 20 21 23 25 26 34 35 38 39 42 50 53 56 58 +1 2 6 9 11 12 15 16 20 25 27 30 32 33 34 35 36 37 38 42 49 56 57 58 59 +1 2 4 6 8 9 11 12 13 14 18 24 25 26 27 28 32 35 37 38 39 40 41 42 44 55 58 +2 6 9 11 17 19 22 24 27 29 31 33 35 37 38 39 41 43 45 47 51 52 53 54 58 +4 8 11 13 14 17 18 19 23 27 31 32 33 34 35 36 38 39 46 47 48 49 53 59 +0 3 5 7 8 10 11 14 17 19 22 23 25 26 27 28 29 36 41 44 45 46 47 50 52 55 58 +1 3 5 6 10 12 13 14 15 18 29 33 37 39 42 48 49 52 56 57 +1 2 3 5 6 8 9 10 11 12 14 15 17 20 25 27 31 33 35 39 41 43 46 47 50 51 54 55 56 57 58 +1 3 6 9 11 21 23 27 28 30 32 37 38 45 48 51 55 56 57 59 +0 1 2 4 5 7 11 12 14 15 17 20 29 32 33 38 47 48 50 52 58 +1 4 7 8 10 11 13 15 16 17 19 21 22 26 30 33 38 40 42 43 45 47 48 54 55 56 57 +1 4 6 7 16 17 18 21 25 28 30 31 32 33 34 38 41 42 44 50 53 54 55 56 57 +0 5 7 8 9 17 22 25 27 29 30 32 37 41 42 47 48 51 53 54 55 57 +1 10 11 14 15 18 19 21 22 28 30 33 34 35 38 43 48 49 51 55 58 +4 5 6 7 9 10 11 15 17 19 20 23 28 29 31 36 42 44 45 48 50 51 52 55 59 +4 5 8 16 19 21 24 25 26 29 30 31 32 35 36 45 47 48 53 54 55 56 57 59 +0 4 7 9 10 11 12 13 19 21 26 27 29 32 35 36 37 38 39 40 43 49 50 51 54 56 58 +4 7 8 10 13 14 15 18 22 24 28 29 30 31 32 37 38 41 43 44 47 48 49 50 53 55 58 +4 6 8 12 13 15 17 18 28 29 35 36 43 45 46 48 53 57 +0 1 3 7 9 10 11 12 13 14 17 18 21 22 23 29 31 34 35 46 47 48 50 51 53 54 59 +0 5 8 9 11 17 21 23 28 29 30 32 33 34 36 37 41 43 46 49 54 56 58 +0 1 11 17 21 22 25 26 28 31 35 37 38 39 40 41 43 46 48 50 51 54 58 +0 3 4 5 9 11 14 15 20 23 25 29 32 33 39 40 41 42 44 46 47 49 51 53 58 59 +0 2 3 10 14 15 16 18 20 21 28 30 31 33 35 40 43 45 51 52 54 58 +0 1 2 7 8 9 13 15 16 18 24 25 26 27 29 31 40 42 43 46 49 50 51 52 53 58 +6 8 12 13 14 17 19 25 28 29 31 32 33 35 36 37 40 41 44 45 46 47 48 49 50 51 55 58 59 +10 15 21 22 23 24 26 29 30 31 32 36 38 40 41 43 46 47 52 53 55 +0 1 2 6 8 9 11 14 15 20 24 26 29 30 31 32 34 36 38 41 44 46 53 54 55 57 58 +2 3 6 8 12 20 21 22 23 27 30 32 39 40 42 43 44 46 47 51 52 53 54 59 +0 1 3 4 6 9 13 21 24 25 26 27 28 29 30 34 37 41 43 47 50 54 55 58 +1 3 4 6 8 9 10 11 13 16 17 19 20 21 23 29 30 31 33 35 37 38 39 41 42 43 45 48 51 55 56 57 58 59 +3 5 7 8 10 13 14 19 27 33 39 41 42 44 47 48 51 52 53 56 59 +3 6 7 9 11 14 17 20 21 27 28 29 30 32 34 36 38 42 43 44 45 46 51 55 56 57 +0 1 4 7 8 10 13 16 17 20 23 27 31 32 34 35 38 39 41 43 45 46 47 49 52 54 58 59 +0 2 3 6 8 9 10 12 13 14 18 20 21 23 24 25 26 28 31 47 49 51 52 53 54 56 59 +0 3 5 7 8 9 11 12 15 16 17 18 21 22 23 27 28 30 31 34 35 37 41 42 44 45 47 51 55 56 59 +1 2 7 9 10 11 14 16 17 18 19 20 21 28 30 31 33 34 35 36 37 40 44 45 46 48 52 56 59 +2 3 5 9 10 14 17 20 21 23 26 34 35 36 40 48 50 51 52 57 58 +0 1 3 6 13 14 15 16 17 22 23 24 26 28 34 35 36 40 43 44 45 47 50 53 54 56 58 +3 5 8 10 12 13 16 20 21 26 27 28 29 30 34 36 37 38 39 40 41 45 46 48 50 54 56 +1 4 6 8 9 11 12 13 15 21 24 26 27 28 29 31 33 34 36 39 40 53 55 +3 6 9 14 15 19 20 21 23 24 27 31 33 39 41 49 54 58 +0 2 3 5 7 10 11 17 20 21 22 25 26 28 30 32 38 40 42 45 46 50 51 53 56 57 59 +2 5 7 8 10 12 15 16 19 28 29 31 32 33 35 37 38 39 41 42 44 45 46 52 53 56 59 +0 2 6 7 9 18 21 25 30 32 33 34 38 44 47 48 53 56 +0 8 9 17 19 20 21 22 26 28 31 32 33 43 44 47 48 52 53 54 56 57 58 59 +0 2 4 7 8 15 17 19 21 25 29 30 32 34 36 37 39 41 44 47 48 52 53 56 59 +2 5 6 12 14 15 16 19 20 25 26 30 32 33 34 35 42 43 46 47 48 50 54 55 57 +0 3 4 6 7 8 11 12 17 21 24 26 27 28 29 30 31 32 34 38 39 40 44 47 50 53 55 57 59 +0 1 4 6 7 8 10 13 14 15 18 19 20 22 25 26 27 28 30 35 41 51 52 55 56 58 +4 6 7 9 10 11 12 13 15 16 20 22 24 25 28 31 34 36 43 45 48 50 52 56 57 59 diff --git a/in_class/SetCover/test_set-100d.sc b/in_class/SetCover/test_set-100d.sc new file mode 100644 index 00000000..7b153c40 --- /dev/null +++ b/in_class/SetCover/test_set-100d.sc @@ -0,0 +1,101 @@ +1000 100 +0 2 7 8 9 11 13 15 17 20 26 29 31 34 35 36 38 42 43 44 46 49 52 53 56 60 65 67 73 76 77 78 79 81 86 87 90 93 94 95 99 100 105 108 112 114 115 120 121 124 125 128 129 130 131 133 137 138 140 144 147 149 150 152 153 158 159 162 164 165 168 169 172 174 175 177 179 180 181 182 184 185 189 195 201 209 212 213 214 215 217 222 224 225 226 230 235 236 240 241 242 245 246 247 249 250 253 259 262 264 265 266 269 271 273 274 275 276 277 279 282 283 287 288 296 301 304 305 306 309 310 317 321 322 324 325 329 332 334 336 337 338 339 340 341 342 348 355 358 360 361 362 363 365 368 371 372 377 379 380 381 384 386 389 390 392 393 394 395 396 397 399 400 403 405 407 408 409 411 412 413 415 425 436 440 441 444 445 449 451 454 455 458 459 461 463 464 467 470 472 473 474 479 480 481 484 494 498 502 504 505 506 510 513 514 517 520 523 524 525 526 527 530 535 537 539 543 548 550 551 552 560 566 568 569 570 571 572 573 576 579 581 582 583 584 586 589 590 591 592 596 603 609 612 615 616 619 620 621 628 629 635 640 641 644 645 661 662 667 670 671 674 678 679 682 683 686 688 689 693 694 697 699 702 704 705 707 708 709 710 711 712 713 716 719 720 721 724 725 726 727 728 729 731 733 734 737 740 744 745 749 751 753 756 758 759 760 761 762 763 764 767 768 770 771 774 775 776 779 781 793 797 801 803 804 806 808 809 812 817 819 825 826 827 835 838 839 843 845 848 855 857 860 863 866 868 869 871 873 877 878 879 880 881 882 884 886 887 889 890 896 898 899 900 903 904 905 912 915 916 924 925 926 927 930 931 937 944 949 950 951 954 955 957 958 962 963 965 966 969 977 979 981 983 985 986 987 988 989 990 992 994 995 999 +1 2 4 5 7 16 19 20 21 23 26 29 34 38 40 45 46 47 49 51 57 59 60 61 62 63 67 68 72 74 75 77 78 79 80 81 85 86 89 93 94 96 101 102 105 107 108 111 112 113 116 117 119 122 123 124 128 131 133 134 135 139 145 146 147 149 151 152 155 156 157 161 162 164 170 172 173 176 177 178 180 181 182 184 185 187 188 192 195 197 200 203 209 212 213 214 216 218 220 221 222 224 228 230 232 234 239 243 244 246 248 252 254 259 261 263 265 267 269 274 276 277 281 282 285 287 296 299 304 306 307 309 311 314 315 318 320 323 324 327 329 334 335 336 337 341 346 348 356 357 361 362 364 366 369 374 375 380 388 391 394 395 400 406 407 412 413 415 419 420 424 425 428 430 431 432 435 436 440 442 443 447 450 455 458 460 461 463 464 466 467 469 470 473 474 475 477 478 480 483 491 492 495 496 498 499 503 505 506 509 521 522 523 524 527 529 532 533 536 537 540 541 544 545 546 547 551 553 556 557 559 561 562 563 565 569 570 571 573 574 575 576 577 581 582 585 586 588 590 594 596 601 602 604 613 617 620 621 624 625 631 633 634 635 638 640 643 644 645 646 647 648 649 651 652 653 655 656 657 658 660 661 663 664 666 667 668 669 671 676 681 682 684 687 688 689 692 693 695 696 697 702 710 712 717 718 720 722 728 729 734 738 739 745 747 748 749 750 751 752 756 759 763 765 773 774 775 777 778 788 789 793 794 797 803 808 812 813 817 823 825 826 829 830 831 835 836 838 839 840 846 848 854 855 857 861 863 864 865 867 872 873 874 875 880 885 887 888 890 892 895 902 903 907 908 910 911 912 915 916 918 923 926 927 929 932 934 935 939 942 943 945 947 948 950 951 954 955 956 960 961 966 971 973 976 978 982 988 991 993 994 996 998 +2 5 6 7 16 23 24 28 30 35 36 37 44 47 49 52 55 56 66 71 72 74 76 79 82 86 89 90 91 95 97 98 101 103 105 111 116 117 118 119 120 125 129 131 132 137 138 139 141 143 145 149 153 155 158 159 161 163 164 167 168 169 172 176 180 182 187 190 193 197 198 200 204 205 206 207 211 212 213 218 219 220 231 242 246 249 250 252 253 254 255 260 279 282 283 293 294 300 311 313 314 315 321 322 324 325 331 337 339 343 347 348 349 353 354 355 359 363 365 368 371 373 374 375 377 379 382 383 393 394 395 397 399 401 402 403 404 406 408 409 410 411 413 418 421 424 425 426 427 430 432 433 436 438 440 441 443 445 448 452 455 456 457 460 461 462 466 468 469 472 474 478 483 487 491 492 494 495 497 505 507 510 515 517 518 519 520 521 523 529 530 532 534 535 537 538 541 542 543 544 547 550 553 556 557 559 561 565 566 568 573 575 576 585 586 590 594 596 597 598 599 601 603 605 611 614 617 621 630 631 632 636 638 642 643 646 647 649 650 653 660 661 662 663 664 667 672 674 676 679 682 688 696 699 702 703 705 709 712 717 718 720 723 729 732 734 737 740 742 748 752 753 754 759 763 766 770 771 773 774 775 779 785 787 792 796 801 806 807 810 813 816 818 832 833 836 837 838 839 840 841 844 848 854 855 856 858 866 877 878 879 880 886 890 891 896 897 898 899 902 903 905 908 911 912 913 916 917 918 920 921 922 924 925 926 931 938 939 940 942 944 950 951 952 953 956 957 962 964 966 969 972 973 981 984 985 991 992 998 +0 4 6 10 12 14 15 19 20 21 22 24 25 27 30 32 37 39 42 43 46 48 53 54 55 58 60 66 68 70 77 78 80 82 85 87 89 94 96 97 100 102 104 106 107 108 109 110 113 114 121 122 124 132 133 138 144 146 147 152 155 156 158 166 167 170 173 178 179 180 183 185 187 188 190 195 196 200 201 202 209 210 212 213 214 216 224 228 230 233 235 237 238 241 248 249 250 251 256 258 259 261 262 269 270 272 273 274 276 281 283 284 285 287 299 300 301 302 303 305 307 308 309 310 313 314 320 322 324 342 345 348 349 350 356 357 358 359 360 367 369 371 372 375 379 381 384 387 389 391 394 400 401 402 403 404 407 409 414 420 423 424 425 428 429 431 438 443 444 446 448 450 455 457 458 459 460 461 462 466 467 470 471 472 473 474 476 477 479 480 481 482 483 484 485 486 487 488 491 495 496 500 505 506 507 508 510 511 512 513 514 515 516 517 520 521 523 526 527 528 530 532 536 537 542 543 551 552 554 556 558 566 567 568 570 571 572 575 580 581 583 586 590 591 593 594 601 602 603 605 606 608 610 611 613 614 615 618 621 623 625 632 633 635 647 648 649 650 652 653 654 658 660 663 668 673 679 682 684 685 686 688 689 690 692 694 698 699 700 708 711 715 717 718 720 722 723 725 726 732 735 738 740 741 742 745 747 749 750 752 754 756 758 763 765 767 768 770 771 772 781 782 783 786 788 791 792 798 799 800 802 805 808 809 810 812 815 816 817 820 824 826 829 831 833 836 838 840 841 845 846 850 853 854 855 856 860 861 864 866 867 870 874 876 877 879 886 890 896 898 899 901 902 903 904 910 912 915 917 919 920 923 926 927 931 932 937 950 951 953 955 959 960 962 967 969 970 971 975 978 979 984 990 991 997 998 +3 5 6 7 9 13 18 21 24 25 26 28 35 36 37 38 39 42 43 44 47 51 53 55 64 68 74 76 77 78 80 90 91 92 94 96 99 101 103 105 106 108 110 112 113 114 115 116 118 122 125 128 129 131 134 137 139 142 144 145 147 149 153 154 156 162 164 167 168 170 171 173 176 177 178 183 184 187 190 191 192 195 197 198 199 203 205 207 210 213 219 224 226 228 230 234 235 236 238 239 240 241 243 245 247 251 254 258 259 262 263 266 272 278 279 280 282 283 285 289 290 294 298 300 302 308 309 310 312 314 315 317 319 326 330 333 337 342 343 345 346 349 350 352 355 356 357 358 359 362 363 364 365 366 377 381 382 383 384 387 394 397 398 399 400 404 405 406 407 408 410 413 415 417 420 423 425 426 427 428 429 435 441 442 443 447 449 452 454 456 458 464 470 471 473 477 480 482 483 484 485 491 492 493 495 498 513 515 516 518 523 524 531 533 534 540 541 542 544 545 548 549 550 551 553 554 557 559 561 566 567 569 570 571 574 575 578 583 592 593 594 597 598 599 601 604 606 607 608 609 610 612 619 623 624 625 629 631 634 636 637 639 640 650 654 655 658 660 663 666 672 673 675 676 677 678 686 687 689 690 692 699 703 704 706 707 710 712 717 719 720 726 727 731 732 733 736 737 739 741 746 748 750 751 755 761 763 766 767 772 776 777 778 784 786 793 795 796 801 803 806 807 810 812 813 816 818 826 827 834 835 836 838 839 845 846 847 849 852 853 856 863 864 865 866 868 870 872 874 878 885 886 888 890 893 895 898 899 900 901 902 904 906 908 909 911 914 915 921 922 923 925 927 929 935 937 938 939 942 943 944 945 946 951 952 956 961 963 966 968 970 971 972 977 984 985 988 992 994 996 997 998 +1 2 3 6 7 11 14 15 19 20 21 27 28 29 30 31 35 36 38 39 40 44 45 49 51 52 56 57 61 66 67 68 69 73 74 79 82 85 87 90 91 92 93 94 95 98 105 107 115 117 119 120 121 124 127 130 132 133 134 135 136 137 138 139 144 150 152 156 157 160 164 168 171 172 173 174 175 178 181 182 191 192 193 195 203 204 208 211 215 217 219 221 222 224 225 226 228 231 236 238 240 241 242 243 249 250 251 256 257 258 259 260 263 264 268 272 275 276 277 278 280 284 287 288 289 292 295 297 298 299 300 305 309 312 314 316 318 324 327 328 330 338 339 341 343 344 348 350 352 355 358 360 362 364 366 367 368 369 375 376 382 384 385 386 390 392 393 396 402 403 405 406 410 414 415 416 417 419 422 424 427 428 430 433 437 438 439 442 444 446 449 450 452 458 460 461 462 464 465 466 469 471 472 474 478 480 483 484 485 487 488 490 492 495 500 503 507 508 515 516 518 523 532 539 540 542 543 546 549 551 552 558 559 560 561 565 568 569 575 578 581 582 584 588 589 590 591 593 594 597 598 599 601 602 604 608 610 613 616 618 625 628 632 634 637 639 644 645 646 651 652 654 655 657 661 663 664 666 671 672 677 680 682 685 686 687 688 689 692 696 698 703 704 707 708 709 711 715 716 718 720 721 722 726 728 729 733 745 749 750 751 755 759 761 766 767 768 771 773 775 778 781 783 784 786 794 796 800 801 804 807 809 811 812 813 816 821 826 828 829 833 836 839 841 842 848 850 855 856 857 858 871 874 875 878 880 885 886 887 888 892 894 897 899 901 906 907 909 910 911 916 917 919 922 924 928 930 940 948 951 952 955 956 960 961 963 967 969 972 974 975 976 977 979 981 989 990 991 995 998 +2 3 4 9 12 15 16 17 18 19 21 22 24 26 32 35 36 39 40 41 42 45 46 48 50 53 54 56 66 67 70 71 72 74 78 81 82 83 89 91 92 96 97 99 102 103 105 106 108 109 111 115 116 117 118 120 121 123 124 125 127 128 129 130 133 136 142 144 146 147 150 152 153 156 158 160 164 165 170 172 174 176 179 180 184 185 187 188 189 191 192 196 198 199 201 203 207 211 217 218 220 222 224 228 229 230 232 234 238 239 240 244 252 253 254 256 267 270 273 275 277 280 282 283 284 286 288 289 293 294 296 298 299 300 302 310 311 312 317 319 321 322 325 328 332 333 334 335 336 339 341 342 347 355 359 360 363 364 365 366 368 369 372 381 384 386 389 392 393 400 401 402 409 410 411 414 415 417 420 422 423 431 433 436 437 438 440 445 447 449 456 465 468 471 473 478 479 484 486 487 490 492 493 494 497 498 499 501 502 506 507 508 509 513 515 516 519 522 524 525 527 529 532 536 539 540 542 545 549 550 553 559 561 565 570 576 577 579 581 582 585 586 587 596 598 599 606 607 609 610 611 613 616 619 621 622 624 625 628 629 635 638 642 646 647 652 653 654 655 657 661 665 669 670 671 672 673 674 675 676 677 680 683 684 689 690 692 693 694 698 700 703 709 710 713 715 717 718 722 723 724 730 732 734 736 738 740 743 746 750 752 753 760 764 769 772 775 776 777 778 779 780 784 786 789 793 801 802 803 808 811 813 816 820 822 825 830 831 835 839 841 842 845 847 850 856 858 859 860 863 869 870 875 878 880 889 890 891 894 897 900 901 902 903 907 909 914 915 917 921 922 926 929 936 937 946 949 950 954 961 963 964 967 972 976 978 979 982 983 985 988 993 994 999 +0 6 9 13 14 16 17 22 23 26 27 28 31 35 36 38 41 42 44 54 55 59 60 61 63 65 69 73 82 84 87 90 93 97 98 102 103 104 105 107 109 110 113 116 118 119 124 125 129 132 134 135 137 138 140 143 147 148 150 152 153 154 155 157 159 161 162 163 164 165 166 168 176 177 178 179 183 184 188 190 191 194 195 199 201 205 206 208 211 212 220 222 224 225 229 234 235 236 240 242 246 254 256 258 259 260 261 262 266 267 268 270 271 278 282 284 285 286 289 298 300 303 304 306 310 311 312 313 314 322 326 332 338 339 340 342 343 350 353 355 358 359 361 363 366 375 378 381 385 386 387 388 389 390 393 399 402 403 404 406 407 414 415 416 417 419 420 422 423 425 429 431 433 434 437 439 440 441 444 447 449 451 453 455 457 460 463 464 468 469 470 471 474 479 480 484 485 486 487 502 506 508 512 515 517 520 522 523 525 526 528 530 531 532 537 538 539 544 545 546 549 555 558 562 566 570 575 576 580 581 582 586 587 590 593 594 596 602 605 610 611 612 613 614 618 621 625 627 628 629 630 631 632 633 639 642 645 650 653 654 655 662 663 665 666 669 674 679 680 682 683 684 685 686 687 694 696 700 701 703 706 707 709 710 715 716 718 719 720 723 731 736 745 749 751 754 755 759 763 764 771 772 774 777 782 783 784 787 793 800 802 804 806 808 809 810 813 816 818 820 828 835 844 846 847 849 850 851 853 855 857 858 862 865 867 869 870 871 877 881 882 885 886 887 889 890 893 894 895 896 903 904 911 912 914 917 918 919 922 924 926 929 931 935 940 941 943 944 945 946 948 949 953 957 958 959 965 972 974 975 979 980 987 988 989 991 +2 5 7 13 16 19 20 21 22 25 26 28 29 30 36 37 38 40 42 43 44 46 47 49 52 55 58 59 62 63 65 69 70 71 73 78 81 82 84 86 87 90 91 93 94 96 100 102 110 114 117 120 122 123 124 125 128 130 134 135 139 141 142 143 145 147 148 152 153 154 158 164 165 166 167 168 170 172 175 180 182 191 192 197 200 201 205 206 210 211 217 218 221 223 225 231 233 239 240 241 244 246 248 249 250 251 252 254 256 259 260 265 269 270 273 274 281 282 284 287 289 290 292 294 296 298 300 309 312 313 315 322 329 330 332 335 341 346 348 353 357 367 368 370 372 376 377 385 386 387 389 391 395 398 408 409 410 411 416 417 420 422 423 425 427 429 430 434 436 441 442 443 447 448 449 452 455 456 460 467 468 474 475 479 482 485 490 491 492 495 498 500 501 504 505 508 510 512 514 515 516 518 523 528 530 533 537 538 539 540 542 543 545 547 548 552 553 556 560 564 571 572 573 574 575 580 582 585 588 589 590 591 595 597 604 608 609 610 617 619 620 622 624 625 627 630 631 632 633 635 649 653 654 655 656 663 664 666 668 671 672 673 676 678 680 682 687 688 689 691 692 695 699 702 704 705 707 710 716 717 724 725 726 733 734 736 742 745 749 750 751 753 755 756 758 761 762 771 774 779 787 790 794 800 801 802 807 808 809 812 814 815 819 821 823 826 832 835 837 840 841 847 858 859 862 865 866 867 868 870 876 878 880 883 884 886 889 892 893 897 901 902 904 905 908 909 910 911 912 913 914 916 917 918 923 925 926 927 931 941 948 951 952 954 960 962 964 966 971 972 973 975 977 979 980 982 985 986 991 992 993 +0 1 5 6 7 9 10 12 13 15 16 23 26 28 29 32 33 42 43 45 48 49 53 55 57 58 59 61 62 63 66 67 68 69 70 72 73 75 76 79 81 82 85 89 91 96 100 104 106 108 110 111 114 115 116 117 122 129 130 132 134 135 137 139 145 146 154 155 156 157 161 162 164 165 167 171 172 175 179 183 188 191 193 194 201 203 205 206 209 212 213 217 219 221 222 223 227 229 231 232 234 240 245 247 251 256 257 258 259 260 261 266 268 269 272 274 275 279 281 285 286 289 292 293 296 298 299 301 306 310 312 313 318 321 323 324 325 326 329 331 332 333 335 337 338 340 341 345 347 349 354 360 361 362 365 366 368 370 371 374 379 388 389 390 397 400 402 404 405 413 416 418 419 421 422 423 424 426 427 430 431 433 437 441 442 444 446 447 448 457 458 463 465 466 470 475 477 480 481 483 484 485 486 487 495 497 498 501 502 503 506 507 508 512 516 517 521 524 525 526 528 534 535 538 540 542 544 548 552 555 557 559 562 570 571 572 574 576 579 580 582 585 589 594 598 599 601 602 606 607 610 611 613 621 623 625 637 638 641 643 648 650 651 655 656 657 662 663 664 666 675 678 680 682 686 687 688 689 690 691 692 696 700 702 708 709 710 713 718 719 720 723 725 726 728 730 738 739 740 741 742 745 746 748 750 753 754 758 760 761 765 766 767 770 772 774 778 779 785 788 789 795 798 800 802 803 805 806 811 814 815 816 817 818 819 826 827 829 830 831 836 840 848 850 854 856 859 861 862 866 870 873 877 880 882 883 885 888 889 892 895 897 899 902 903 904 907 908 911 913 916 917 921 923 924 927 929 930 935 939 941 947 949 951 952 955 956 959 962 964 966 968 971 972 973 974 976 978 980 984 987 991 995 997 +2 4 5 6 8 10 11 13 14 15 17 18 22 24 30 32 34 39 41 42 49 52 56 58 60 70 71 73 74 80 85 87 88 90 92 93 94 95 101 102 103 109 112 116 119 120 121 123 124 127 129 130 134 139 140 142 147 148 149 150 152 155 156 158 159 160 165 169 170 173 179 181 184 188 190 191 194 195 196 197 198 200 202 208 212 213 215 219 221 223 224 225 228 231 233 235 239 240 243 244 253 254 262 263 264 270 274 275 279 280 281 282 285 286 288 289 291 295 296 298 299 300 301 302 303 306 310 314 315 316 317 318 320 324 326 327 329 332 333 335 336 337 343 347 348 353 360 361 362 363 364 365 372 374 380 381 386 388 390 391 392 394 403 404 407 409 410 411 412 414 417 425 426 427 430 437 439 443 445 448 449 452 454 455 459 461 464 466 467 471 473 474 476 477 479 480 483 486 487 488 490 493 495 497 498 500 503 504 508 509 510 512 513 516 520 524 530 532 536 538 539 541 545 547 551 552 553 555 559 560 565 574 576 577 578 581 582 585 591 592 593 594 598 600 601 602 603 605 606 607 608 611 614 616 617 619 624 625 627 631 633 634 635 639 640 644 647 650 651 652 654 655 656 661 664 665 668 672 674 682 691 692 695 696 703 705 709 715 716 719 724 726 728 733 737 739 741 743 744 749 750 755 757 758 760 762 763 768 769 772 776 781 784 785 786 790 792 793 798 799 800 801 806 807 809 810 812 816 818 819 821 824 825 826 827 832 834 838 840 841 842 843 844 845 846 847 850 851 854 860 862 864 865 869 870 871 873 877 878 879 880 882 883 886 888 889 890 891 893 896 898 901 902 905 906 908 913 914 916 920 924 927 929 930 935 937 940 943 945 949 951 952 953 954 961 963 965 966 968 969 971 974 975 976 978 980 981 983 986 991 995 +0 2 6 9 10 11 12 15 16 17 18 19 20 26 27 30 32 34 36 37 38 40 43 45 46 48 50 52 53 59 61 62 65 67 69 70 71 74 76 78 82 83 84 87 89 93 96 99 100 104 105 106 108 110 111 113 114 116 118 122 123 125 129 130 131 132 133 135 136 137 139 140 141 144 150 153 155 156 159 160 161 169 170 173 174 176 178 179 181 186 187 188 191 192 196 197 198 200 208 215 222 223 227 230 231 233 234 235 237 238 245 246 247 248 249 254 255 258 259 263 265 271 280 282 283 287 288 289 291 292 305 307 308 309 310 312 317 318 321 323 324 325 326 328 329 341 343 348 349 354 357 358 359 360 361 362 365 366 367 376 377 378 386 387 391 392 393 405 409 411 412 414 415 416 418 420 422 424 425 429 430 435 437 440 442 443 445 446 448 452 453 454 456 461 463 464 468 469 471 474 477 479 485 489 492 496 500 503 506 507 513 515 517 521 523 532 533 536 540 541 543 549 551 552 554 555 558 560 563 564 565 567 570 571 577 580 582 584 587 589 592 593 594 596 597 598 601 602 605 610 611 612 613 616 617 620 624 628 630 632 633 634 635 637 638 641 642 643 644 650 651 654 656 658 661 665 666 670 671 672 673 674 678 680 687 689 690 692 695 697 698 703 704 705 707 711 712 713 714 715 716 721 723 729 730 732 738 740 744 745 746 747 748 749 751 755 760 762 763 766 770 772 774 778 779 781 783 784 786 787 795 797 800 801 802 803 804 806 807 812 814 815 816 818 820 822 823 828 830 831 833 836 838 839 843 844 847 848 852 855 857 858 863 867 868 869 870 871 872 873 875 880 882 885 886 891 893 895 897 898 903 905 908 911 912 914 917 918 920 923 924 927 928 930 932 933 936 938 944 947 949 952 954 958 960 962 964 965 967 968 969 972 976 978 980 982 986 987 989 990 991 995 +0 6 7 10 12 13 15 16 18 21 22 23 26 29 30 31 32 46 51 52 53 55 56 57 58 59 60 62 66 70 72 80 82 84 85 86 88 94 97 104 105 106 109 112 115 120 121 122 130 131 134 136 138 139 140 142 147 150 151 153 156 157 162 164 167 168 169 172 173 177 178 179 182 184 190 191 193 196 197 198 201 205 206 210 211 213 214 216 217 219 220 221 224 231 233 236 239 245 246 248 251 254 256 258 260 264 267 269 272 274 275 280 282 284 289 293 299 301 306 312 313 314 318 321 323 325 328 329 335 336 337 340 343 344 345 346 348 354 356 357 359 360 363 367 369 372 377 380 381 388 389 393 395 397 400 405 406 408 409 410 411 412 413 414 416 417 418 421 422 426 427 430 432 435 436 437 442 444 445 446 447 450 454 457 459 463 466 468 472 474 477 479 486 491 493 494 499 500 503 504 505 506 507 508 509 517 518 519 521 522 526 527 528 530 532 535 536 537 539 541 542 548 549 553 555 557 563 565 567 568 569 577 579 581 582 585 586 590 597 598 599 601 608 610 612 614 615 616 617 620 626 628 631 632 636 638 640 641 642 643 645 646 649 653 654 656 657 661 666 667 672 673 680 682 683 686 688 690 691 693 695 697 699 704 706 707 708 710 712 713 714 717 723 729 730 735 742 744 747 750 754 757 758 759 761 764 765 768 769 776 777 779 780 782 783 785 789 791 800 803 804 805 807 811 812 814 816 819 823 825 826 828 834 835 837 841 851 853 859 861 864 868 869 877 879 881 882 890 893 895 896 898 902 905 906 912 914 915 919 921 922 923 924 925 926 930 931 933 935 940 941 942 943 944 945 946 947 948 951 954 955 961 962 965 971 974 978 982 986 990 993 997 998 +4 7 9 10 12 13 15 17 19 24 27 32 37 39 42 44 46 49 50 51 53 55 56 62 63 67 69 70 74 75 77 78 79 81 85 86 87 89 90 91 92 93 94 95 101 102 103 106 109 110 111 112 115 118 120 121 124 126 129 131 132 133 137 142 143 144 146 147 149 150 151 155 157 159 162 164 165 168 169 174 176 177 181 184 186 187 190 193 194 197 200 201 203 204 206 207 209 210 211 212 214 215 216 217 220 221 223 228 229 230 231 232 233 243 245 246 248 249 251 253 254 256 257 262 266 269 271 272 274 275 276 279 281 283 284 286 292 293 294 296 297 300 301 302 303 304 305 309 315 323 326 329 330 339 341 342 343 344 346 349 351 352 357 361 362 363 367 369 370 371 372 373 379 380 381 383 385 390 391 395 397 398 399 405 410 412 413 419 421 422 423 424 425 426 433 437 440 441 444 445 449 450 451 452 453 456 458 461 462 463 471 473 475 477 482 486 487 488 489 490 493 494 498 499 504 505 506 509 510 515 516 517 518 519 520 522 523 524 533 534 535 539 541 547 556 557 559 567 568 572 573 578 581 583 586 589 593 594 595 596 598 604 605 607 608 609 613 615 617 622 623 625 626 628 631 632 637 640 642 643 645 649 650 652 654 655 659 662 663 664 667 668 669 671 677 682 690 691 692 693 700 703 706 714 717 718 720 721 722 723 724 725 726 728 730 736 741 742 746 747 748 749 750 752 753 754 756 757 762 765 772 773 776 777 781 786 790 791 795 798 799 801 803 804 805 808 809 812 814 816 817 820 821 823 825 828 831 834 836 837 838 839 841 842 843 846 847 848 849 852 855 859 860 862 864 867 869 871 875 877 879 881 882 886 891 894 897 899 900 905 907 910 913 917 922 926 928 929 931 939 943 947 948 949 951 954 956 957 959 961 964 969 971 972 973 978 986 988 989 990 992 993 995 997 999 +0 4 7 11 12 15 16 20 23 25 26 34 36 37 39 40 41 43 44 45 47 49 50 51 52 56 59 62 69 74 75 81 82 85 89 93 94 97 98 99 103 104 105 106 113 115 120 121 124 127 128 130 132 136 137 138 140 142 146 152 153 155 156 161 163 167 168 170 171 174 175 176 179 180 181 182 184 188 192 196 197 202 206 207 213 215 216 218 220 222 224 227 229 230 233 234 236 237 239 240 241 243 245 247 248 250 255 256 258 262 263 264 269 274 275 280 281 282 284 286 289 292 295 297 298 303 304 306 310 311 312 315 317 318 325 327 334 336 340 344 348 349 350 352 355 357 360 363 364 365 368 371 373 374 377 378 379 380 381 383 386 391 392 400 401 402 404 406 408 410 411 412 414 417 421 423 426 428 430 431 437 438 439 447 452 454 458 459 460 462 463 466 468 469 470 477 478 480 481 487 494 496 501 502 504 505 506 507 511 512 513 514 516 517 520 530 531 532 534 536 540 543 544 546 550 551 552 557 558 559 562 565 566 571 573 575 577 582 587 593 596 598 602 603 605 606 607 609 616 619 621 622 623 624 626 628 629 630 635 640 641 643 645 654 655 656 657 661 663 664 665 666 669 672 673 674 677 682 683 684 687 688 689 690 694 697 698 703 708 710 713 715 716 718 719 721 723 725 726 729 731 735 740 749 750 751 753 759 760 762 763 764 766 767 773 781 782 783 784 785 787 790 792 794 796 798 799 803 804 805 807 808 812 813 815 818 819 822 827 828 832 834 842 846 849 850 851 853 855 856 857 861 863 864 866 870 871 873 874 875 876 878 879 880 885 886 888 889 892 895 897 898 901 902 906 908 909 910 911 913 914 915 917 918 921 923 924 928 930 933 934 935 948 957 963 966 971 972 978 981 982 984 988 989 992 993 994 997 998 +0 1 4 6 7 10 13 15 18 19 22 23 24 31 32 33 34 38 39 40 41 42 44 45 47 49 50 52 53 54 55 59 62 64 65 66 67 68 69 70 72 73 74 78 83 85 87 91 93 97 99 102 105 107 108 109 110 111 112 113 119 121 122 127 129 131 132 135 138 144 153 154 155 162 163 166 172 174 177 179 181 184 187 188 193 194 195 198 200 203 206 207 208 211 212 216 218 221 223 224 225 227 228 229 231 232 233 238 239 241 244 248 255 261 263 264 273 274 275 276 278 281 282 283 284 285 287 289 290 291 292 293 295 300 303 305 310 312 316 317 320 324 325 332 334 335 336 342 346 347 350 351 352 353 354 356 357 358 361 362 363 369 370 372 373 375 378 380 389 393 395 398 400 402 403 404 406 408 409 412 416 419 428 430 431 433 434 435 437 442 446 448 449 450 452 458 460 463 464 465 468 471 476 477 479 480 482 483 484 487 488 489 495 507 511 514 517 520 521 523 530 533 537 538 543 548 551 553 556 562 575 578 579 580 582 586 587 591 596 597 598 599 605 606 607 611 612 616 618 619 624 627 628 634 636 639 640 641 643 654 655 656 657 658 662 665 666 669 670 671 672 673 674 683 685 688 689 693 695 697 698 705 706 711 715 717 720 728 729 730 732 733 734 735 738 739 740 742 747 749 750 753 762 770 773 780 786 787 788 790 793 795 797 799 800 801 803 806 810 811 812 813 814 816 818 821 823 824 825 826 828 829 831 832 833 834 835 836 838 840 841 844 845 850 852 853 854 856 857 868 869 870 871 873 875 876 879 881 884 885 890 891 895 896 899 902 904 911 913 915 917 918 919 922 925 926 930 931 932 933 935 936 943 945 947 948 950 952 953 954 959 960 962 966 968 973 974 978 979 980 981 986 987 993 998 +5 6 7 9 12 13 14 16 18 22 25 29 30 31 32 40 41 46 49 50 52 53 54 55 56 57 58 61 66 73 74 75 85 87 88 90 96 98 100 101 104 106 110 113 116 121 122 124 125 127 132 133 134 135 138 141 145 146 148 149 150 151 153 157 159 163 171 172 177 178 182 183 187 189 194 200 204 206 207 211 212 215 216 217 218 220 223 224 225 226 227 232 233 234 235 236 238 240 247 253 256 257 259 260 261 263 265 266 267 269 270 271 273 275 278 280 281 284 287 293 294 298 299 300 303 306 308 310 317 320 321 329 330 331 332 336 341 343 344 346 350 351 353 354 355 356 358 361 362 368 369 372 374 375 377 378 381 382 389 391 392 394 397 398 401 403 405 406 407 410 419 420 421 423 424 430 433 438 442 444 448 451 454 457 459 464 467 469 476 477 481 482 487 489 490 492 493 495 496 498 503 508 510 511 513 514 516 518 519 520 521 522 524 526 527 528 529 532 534 540 544 545 546 547 555 556 558 559 560 561 562 563 564 565 566 569 570 571 572 573 579 580 585 588 591 592 594 597 600 601 603 605 606 611 612 613 615 617 620 621 623 625 627 628 632 634 635 636 637 639 642 644 647 649 650 651 657 660 662 665 670 671 674 677 679 680 681 684 688 689 690 691 692 693 697 702 704 705 706 709 711 712 713 716 718 720 721 722 726 727 729 730 734 735 739 741 746 748 752 753 754 756 758 759 760 761 763 766 767 768 770 772 773 778 779 781 783 787 789 790 792 793 795 797 798 805 806 807 811 812 813 816 817 820 821 827 831 832 835 839 845 854 857 860 861 863 864 865 868 869 872 874 876 877 878 881 882 885 887 891 892 893 895 897 898 899 904 909 910 911 914 915 918 920 921 924 927 932 934 943 951 953 960 969 970 971 972 974 975 977 979 980 981 982 983 984 991 992 993 996 +0 4 5 6 15 18 29 33 36 38 39 41 43 45 50 51 56 57 65 67 70 72 80 82 89 91 96 97 101 105 106 109 110 113 115 116 117 132 133 135 136 140 141 144 145 148 151 161 165 172 173 175 177 179 188 189 193 195 203 206 207 214 219 220 222 223 225 227 230 232 234 235 237 241 242 243 244 245 246 248 249 250 252 258 260 263 264 266 269 274 276 278 279 282 284 286 287 288 294 295 296 297 299 302 303 306 310 311 312 313 315 323 325 329 332 334 335 338 340 343 344 345 347 348 351 352 354 358 360 361 365 366 367 369 370 372 373 374 375 377 378 379 381 382 383 385 388 389 390 394 395 398 399 401 402 403 407 410 412 416 417 418 420 421 423 425 427 428 429 434 435 437 439 441 445 446 448 449 451 453 454 455 462 463 467 471 472 473 478 481 482 483 488 489 495 496 497 499 503 505 506 509 511 513 517 519 520 521 523 527 529 531 535 537 538 539 541 542 547 552 553 555 557 558 559 560 561 564 568 569 570 572 576 577 579 581 582 583 584 585 586 590 595 599 600 602 604 608 611 614 615 616 617 620 627 630 634 638 639 642 646 647 648 651 652 654 662 663 667 668 669 674 677 678 680 681 683 684 685 687 688 691 696 698 703 706 708 709 716 719 729 730 731 732 734 737 741 743 745 750 751 757 758 759 762 764 765 766 767 769 770 772 776 777 779 781 789 791 796 798 800 801 809 811 812 814 816 818 820 822 824 825 829 830 832 838 841 843 848 850 851 853 858 861 865 867 868 872 882 884 889 890 892 893 894 895 900 903 906 909 911 913 915 916 923 926 927 928 929 932 936 937 938 939 943 948 950 951 952 953 955 958 963 964 969 971 981 982 986 987 988 993 995 997 999 +0 5 10 11 12 15 16 19 21 22 23 24 25 29 30 34 36 37 39 40 41 46 48 50 51 53 59 62 67 75 81 84 85 86 87 91 92 94 97 99 101 108 111 114 115 119 123 124 126 131 133 135 136 142 145 147 148 149 150 152 153 154 155 157 160 170 174 175 179 183 184 186 188 190 193 194 196 203 208 210 212 214 215 216 217 218 222 228 230 234 240 243 244 247 254 260 261 265 267 268 274 275 276 288 292 294 296 300 301 303 309 311 313 314 321 323 324 327 329 333 334 339 342 343 344 345 346 347 348 352 355 356 357 359 360 362 364 366 368 369 370 374 375 376 377 381 383 387 395 400 401 403 405 412 413 418 419 420 421 426 427 428 432 433 434 438 439 443 445 453 462 463 464 470 472 476 477 478 482 483 486 487 490 493 494 501 502 506 507 510 513 519 521 524 525 526 528 533 540 541 542 545 546 552 557 561 567 581 582 585 586 588 590 593 594 602 608 614 617 619 620 622 626 630 641 645 646 657 662 664 668 669 670 672 673 675 676 677 678 679 681 683 686 688 690 691 695 697 701 702 706 707 708 709 711 712 713 715 720 726 730 732 733 735 736 739 741 742 744 746 748 749 751 752 753 755 758 761 762 770 780 782 783 787 789 790 792 794 799 800 803 809 811 812 813 818 819 823 824 826 827 828 832 835 843 853 854 855 857 859 860 862 864 865 867 868 871 872 873 875 876 877 881 882 883 891 894 895 896 898 902 904 909 910 911 914 918 925 926 928 930 931 940 942 943 944 949 954 959 963 966 968 971 972 973 974 976 977 981 984 992 993 996 998 999 +2 6 8 10 12 13 14 21 23 24 25 30 34 35 38 39 40 41 42 44 51 54 57 58 63 66 67 75 76 79 80 83 86 87 90 92 95 96 97 98 100 102 103 105 107 108 110 114 117 122 123 124 125 126 132 137 142 145 146 150 151 154 155 157 158 159 163 164 167 170 173 174 175 179 186 187 188 194 201 202 203 204 205 209 211 218 220 221 222 224 227 228 231 232 234 238 240 241 244 245 246 247 249 258 260 261 267 270 271 276 277 278 289 290 291 292 293 297 298 301 303 308 311 312 313 318 322 323 325 328 330 332 333 337 340 343 346 347 350 351 352 354 357 359 365 366 369 370 372 375 376 377 378 381 383 384 387 390 391 392 393 396 400 402 403 407 409 412 416 420 425 426 427 430 433 434 436 438 442 447 452 453 458 459 466 467 468 472 478 482 483 484 487 497 500 502 503 514 515 517 518 519 520 529 530 532 533 535 536 537 541 543 544 545 546 547 548 549 551 554 555 559 561 562 565 567 569 573 579 581 582 587 589 591 595 596 597 598 599 600 601 605 608 609 610 611 612 613 619 620 624 629 633 635 646 647 648 653 656 658 665 669 671 676 678 681 683 688 690 695 696 700 702 703 713 715 717 719 722 723 731 732 734 740 741 744 750 751 756 759 763 764 768 770 772 773 777 779 783 786 787 803 806 808 810 811 817 823 825 826 828 829 831 836 840 842 844 846 848 852 854 860 861 863 864 874 875 877 885 886 892 893 894 895 897 904 906 908 911 912 914 915 919 921 923 925 929 931 933 937 938 940 945 947 950 952 953 957 960 962 963 965 971 972 979 981 982 986 989 994 996 998 +0 3 7 8 10 11 17 22 23 24 25 30 31 32 33 40 41 44 48 49 51 52 53 54 56 60 61 63 64 66 69 74 78 79 81 86 89 93 99 103 113 115 118 120 121 128 129 134 135 139 142 143 144 148 152 154 156 157 160 162 163 164 166 167 170 177 178 179 180 182 184 187 193 198 204 210 215 216 217 221 222 225 228 230 232 233 235 236 237 239 241 247 256 260 264 265 267 273 274 275 277 278 280 281 282 283 284 285 289 292 295 297 299 304 308 310 312 314 316 318 321 322 323 325 327 329 331 333 337 338 339 342 343 344 348 352 353 354 359 363 368 371 373 374 375 376 377 378 382 386 390 391 393 394 396 397 400 405 406 407 409 413 414 415 416 419 426 428 430 435 438 442 444 447 448 450 451 452 453 455 459 463 468 471 474 477 478 480 482 483 484 488 489 491 493 496 497 498 499 502 503 511 521 526 527 530 532 533 534 535 537 545 546 552 556 559 561 563 564 570 571 573 574 575 576 577 578 579 582 583 584 587 588 589 590 594 595 596 609 610 613 615 618 619 621 623 624 626 627 630 632 633 634 640 644 645 646 653 656 659 660 664 666 668 670 676 677 678 679 681 683 686 689 691 698 699 701 706 707 714 715 721 727 729 732 735 739 741 742 748 750 752 753 754 756 758 760 762 763 765 766 770 772 774 776 777 780 781 783 784 786 787 793 794 795 799 801 802 814 815 817 818 820 822 824 825 826 827 828 829 832 833 839 840 843 845 847 850 851 852 853 854 857 858 859 861 866 870 874 877 880 882 885 886 888 889 890 892 895 896 897 905 906 907 910 911 913 916 917 918 919 921 927 929 933 940 944 947 949 950 951 956 958 959 961 962 963 966 969 973 975 978 981 982 983 988 989 990 997 998 +0 6 11 12 13 16 20 27 31 34 35 39 43 45 46 50 52 55 56 57 59 60 62 64 65 70 72 73 74 75 76 77 81 84 86 87 89 92 95 97 99 103 105 106 107 109 110 111 112 114 115 119 121 123 129 130 131 134 137 138 139 141 142 143 145 148 149 153 154 159 167 170 173 180 181 182 185 187 189 190 194 201 203 204 207 213 214 216 220 225 226 231 233 236 237 241 242 250 254 255 258 259 262 263 265 266 267 273 274 277 279 280 282 284 286 287 290 294 298 302 306 307 308 310 311 312 313 315 319 320 321 325 327 328 329 330 333 334 335 336 347 348 349 354 356 358 360 361 366 367 368 369 370 375 376 377 381 383 386 392 394 395 397 398 401 404 407 408 409 410 412 413 417 418 420 424 425 427 428 429 433 434 435 438 440 441 445 454 455 456 460 461 462 463 466 468 470 471 475 476 484 485 486 490 491 492 493 494 497 502 504 506 507 509 510 512 513 514 519 520 521 522 526 534 535 536 542 543 544 545 548 549 560 562 563 565 566 568 569 571 575 576 579 581 587 593 597 599 600 601 602 603 605 608 610 613 617 620 621 628 633 636 637 639 641 642 654 656 657 659 660 663 664 665 668 670 678 682 684 686 687 688 689 691 692 695 696 697 699 700 703 705 707 708 710 711 722 725 726 727 729 731 733 734 736 738 743 745 747 749 751 752 753 754 757 759 760 764 765 767 768 777 778 779 783 784 786 791 798 808 812 813 814 817 820 821 822 826 829 830 831 832 833 839 840 842 846 847 849 850 851 855 857 858 859 861 862 866 868 869 870 871 872 873 874 875 876 879 883 887 892 896 899 900 903 905 907 908 909 912 916 921 922 926 931 934 937 944 945 946 953 961 962 966 972 973 975 976 978 980 981 984 985 986 987 989 990 991 995 998 +0 2 5 7 9 10 13 18 20 21 22 23 24 28 34 38 41 42 43 44 46 49 51 52 56 57 58 59 60 65 66 73 75 80 81 82 84 86 87 88 90 91 92 93 97 100 103 104 107 110 115 116 121 123 124 128 131 134 135 140 142 143 144 150 154 160 161 163 165 166 168 176 180 183 185 186 188 189 190 191 194 195 196 197 198 202 205 208 210 213 214 219 220 221 228 229 230 231 234 235 237 242 244 246 247 251 252 253 257 259 260 261 268 272 273 274 277 282 284 287 292 293 294 295 298 303 308 309 310 311 315 316 323 324 325 326 330 338 343 345 350 355 358 359 360 361 362 364 365 370 373 374 377 379 382 384 386 387 391 393 394 398 399 401 402 403 405 410 413 414 416 417 418 420 422 423 424 433 434 436 437 444 446 450 453 461 463 464 466 467 469 474 476 477 478 480 481 486 489 490 491 493 494 496 498 499 500 503 505 509 510 512 513 514 515 522 524 526 529 530 537 538 541 543 544 549 553 554 555 556 557 559 567 568 570 571 574 575 577 579 582 588 591 595 596 597 599 603 605 606 608 609 614 616 617 620 621 622 623 624 627 632 639 640 645 647 649 650 652 653 654 655 656 658 662 663 664 667 668 669 671 673 676 677 680 684 687 693 694 695 701 704 706 712 716 718 724 726 729 731 735 737 739 747 748 750 752 754 755 760 762 763 765 766 767 769 770 771 774 780 781 782 783 784 785 786 788 789 790 793 799 800 805 811 813 817 818 819 824 825 827 828 829 830 831 835 836 838 840 841 847 848 852 853 855 856 857 859 864 867 869 871 875 876 878 879 880 882 883 884 888 890 891 893 894 896 898 904 905 906 907 909 911 912 913 918 919 922 926 928 930 935 938 940 942 943 945 949 952 953 954 958 960 962 965 966 967 968 974 978 980 981 982 983 994 +0 3 4 5 6 9 10 12 19 21 23 24 25 26 27 31 38 40 44 48 50 54 56 57 58 73 78 81 82 84 86 88 89 90 94 95 101 103 104 105 107 109 113 114 122 128 129 131 132 134 135 136 138 141 144 153 155 156 159 160 161 164 172 173 176 177 180 181 182 185 186 189 190 191 193 198 199 200 202 205 208 210 214 215 224 226 228 229 233 239 240 241 243 245 249 252 253 254 257 260 264 269 272 273 279 282 284 285 286 287 288 289 290 291 293 297 298 299 303 304 306 307 308 310 313 316 320 325 327 329 333 334 337 339 342 343 349 350 351 355 360 365 367 369 370 371 375 376 378 379 382 383 385 386 387 388 390 393 395 396 400 403 404 405 408 409 411 414 415 416 417 419 421 424 426 431 433 434 437 439 442 444 451 452 454 457 458 459 462 464 466 467 470 471 472 473 479 480 481 482 483 485 487 488 490 492 496 498 499 500 501 503 504 505 508 512 513 515 518 519 521 522 523 528 533 536 537 539 541 543 550 551 552 553 559 561 566 567 569 576 577 578 579 580 583 584 585 587 588 590 591 596 598 603 605 606 608 610 612 613 614 618 619 624 627 628 629 634 635 636 638 642 643 644 646 653 658 660 661 662 664 665 667 671 674 680 681 682 683 686 695 699 700 703 709 714 717 718 725 726 730 733 737 742 743 744 745 747 751 752 753 754 756 758 762 769 774 777 784 786 789 792 793 795 796 801 802 806 812 813 815 816 820 823 825 829 833 834 835 837 839 840 842 844 847 848 850 851 856 857 861 864 867 869 870 872 874 878 879 880 883 885 886 887 889 892 894 897 900 901 903 904 905 912 913 917 920 921 923 925 926 928 934 936 937 938 942 945 948 949 956 960 962 964 965 968 969 970 975 976 977 978 979 980 984 986 988 990 992 993 996 998 +1 3 5 6 9 11 14 19 21 22 28 30 36 37 40 43 44 45 46 50 54 62 63 64 65 66 71 74 76 78 80 82 84 89 90 96 97 99 106 110 113 115 116 117 118 119 128 133 135 136 137 140 141 150 152 153 154 158 164 165 167 168 169 172 173 177 179 183 188 189 192 197 204 205 206 212 213 214 218 222 223 224 225 232 234 235 237 239 240 242 243 244 246 250 251 252 255 260 261 264 266 268 269 272 276 280 281 283 286 287 291 292 295 297 298 300 301 302 310 314 315 316 320 324 325 326 330 333 334 335 338 339 341 343 344 345 346 351 355 359 366 368 370 372 373 374 375 376 378 379 380 381 382 384 385 386 390 391 392 396 398 400 402 405 408 415 422 423 424 427 433 438 440 442 445 446 447 449 451 452 453 454 455 457 459 462 467 468 472 474 475 476 480 481 482 483 485 490 493 498 503 508 514 516 518 519 520 521 523 524 525 526 529 532 537 539 541 542 545 546 548 550 552 560 561 565 571 575 579 583 586 592 593 594 596 599 607 609 626 629 630 631 633 637 641 642 645 649 652 656 657 660 665 669 679 683 684 685 686 689 690 693 695 699 700 706 707 708 710 712 713 714 716 723 728 730 731 735 738 739 740 741 742 745 748 749 758 760 762 764 767 770 773 774 776 780 782 786 789 790 793 794 795 796 803 807 815 816 822 828 830 831 838 839 841 845 846 847 848 849 850 852 854 857 859 863 867 870 877 878 880 881 883 885 886 887 890 894 896 897 899 906 909 912 913 914 915 917 919 922 923 928 929 930 932 933 934 935 936 937 939 940 942 946 947 953 958 966 968 969 971 975 979 980 981 982 983 984 985 986 989 990 992 993 997 +0 5 6 8 9 14 17 21 22 24 27 28 29 30 31 32 33 41 42 44 45 51 52 67 68 69 73 76 77 80 88 89 92 93 94 95 97 102 103 107 108 109 110 111 112 117 122 127 128 131 132 134 135 140 146 153 155 158 159 162 167 170 172 173 176 179 180 184 188 189 191 192 194 197 203 205 209 210 212 214 216 222 226 231 236 249 251 253 254 261 263 265 267 268 270 272 274 275 277 279 283 290 291 293 294 296 299 301 302 306 309 310 313 316 317 321 326 328 332 333 335 336 341 348 350 351 352 355 356 363 364 366 367 369 370 373 382 383 387 389 392 394 398 401 402 404 406 411 415 416 422 423 424 426 427 428 439 442 454 459 460 464 471 472 473 474 476 478 479 482 485 486 490 491 492 498 499 500 501 502 503 505 507 508 509 511 512 513 516 517 518 523 524 526 527 529 531 532 534 536 544 545 546 548 550 557 558 562 563 564 566 568 571 573 575 578 581 582 583 588 591 592 594 596 597 603 605 609 611 616 618 619 625 627 629 632 633 634 637 641 647 648 649 652 653 656 657 658 661 662 665 666 669 670 672 674 675 676 678 680 683 685 686 688 689 690 692 693 694 696 697 698 699 700 701 703 706 708 710 712 713 720 721 723 725 728 731 734 738 742 744 748 751 755 757 760 761 762 769 770 771 776 777 779 781 783 784 787 788 795 797 802 810 811 813 814 815 819 827 831 832 834 837 838 839 842 845 846 847 850 851 855 856 857 859 860 861 866 867 873 875 876 877 879 881 882 885 888 889 890 896 898 904 907 908 909 914 916 917 921 922 925 926 927 928 931 942 945 948 949 951 955 956 957 960 963 964 966 967 969 973 974 975 976 979 985 988 989 990 991 992 994 995 996 997 +0 2 4 6 12 15 19 23 26 39 43 44 48 49 50 51 52 53 62 63 74 89 92 101 103 107 109 110 112 113 115 116 118 122 124 127 129 130 131 133 135 140 142 144 145 147 148 149 150 152 156 157 159 160 163 165 167 168 170 173 179 183 185 186 191 196 199 202 203 204 206 207 209 212 213 215 216 217 219 221 222 224 225 228 229 232 236 239 241 242 243 246 248 250 255 257 258 260 264 265 266 275 276 284 287 290 291 292 296 299 301 302 306 309 310 312 314 315 318 320 321 322 327 328 332 336 341 343 344 345 347 348 352 354 357 359 362 363 364 366 368 369 372 373 374 377 378 384 385 387 389 390 404 408 410 413 415 416 418 420 423 425 426 429 430 431 432 433 437 438 439 442 443 444 447 448 450 451 453 455 457 458 459 465 466 470 471 472 473 488 489 490 494 499 502 506 508 512 515 518 519 521 525 527 530 531 533 535 536 540 544 545 547 548 553 554 557 565 566 568 577 583 584 588 589 591 593 595 598 599 603 605 607 609 611 614 617 620 621 622 623 624 625 627 633 635 639 640 642 645 646 647 649 655 663 667 668 673 674 675 680 681 682 683 688 689 690 691 692 697 702 703 705 706 707 708 711 713 720 721 723 724 726 727 728 731 733 734 744 746 748 749 751 752 754 758 761 766 767 773 775 779 782 783 784 789 790 791 796 800 803 804 806 809 810 812 815 818 820 823 825 828 833 838 839 840 842 843 844 845 846 847 851 854 855 857 861 863 867 869 870 871 872 873 878 880 882 883 889 890 891 894 895 896 901 903 905 907 914 919 923 928 935 937 938 939 945 946 947 950 952 956 959 962 963 964 965 968 970 971 973 976 977 979 981 984 989 993 996 +0 2 5 11 13 14 24 25 27 28 31 32 35 39 41 43 44 48 50 53 57 60 61 62 66 69 71 73 74 75 77 84 86 88 89 94 99 100 104 106 107 108 111 112 113 115 117 118 119 121 122 123 125 130 132 135 136 139 141 143 144 145 146 147 150 152 153 158 159 161 162 165 174 178 180 186 187 191 194 198 200 202 203 205 211 212 216 217 218 219 220 224 225 228 231 232 234 235 237 238 240 243 257 259 260 262 263 265 268 271 278 279 280 283 287 292 293 294 296 297 301 306 311 314 317 318 319 323 326 329 330 332 334 337 338 341 342 350 354 355 360 363 369 380 387 388 392 395 401 406 410 411 418 421 422 423 424 426 430 431 432 433 434 438 440 442 448 450 455 465 468 471 472 474 478 479 480 482 485 486 488 493 500 507 508 509 511 515 516 518 519 521 523 525 526 527 528 529 531 532 541 542 549 550 552 554 555 557 559 562 566 567 568 569 570 572 576 577 581 584 586 587 589 590 591 592 594 595 605 606 607 610 612 613 614 615 616 617 620 623 624 625 626 627 629 632 637 644 648 651 652 653 654 655 657 663 666 669 671 672 673 674 677 679 681 682 683 684 688 692 695 699 703 704 706 708 712 721 723 728 730 734 736 738 739 743 753 755 756 758 762 764 765 767 768 769 774 775 776 778 780 786 789 793 796 798 799 802 808 816 817 819 820 821 823 824 825 832 833 841 842 843 848 849 853 854 858 862 864 865 867 871 876 878 880 884 888 894 895 900 901 903 904 905 907 910 914 918 919 920 921 925 930 932 934 936 940 944 950 952 954 956 967 968 969 970 971 972 973 975 976 980 982 986 988 992 993 994 995 997 +0 2 7 10 11 12 13 15 16 19 24 25 26 28 29 31 32 33 34 40 41 42 45 46 47 48 49 51 53 55 56 57 63 64 69 73 77 78 79 82 83 84 85 88 89 90 91 92 94 95 97 100 101 102 103 104 105 106 107 109 110 112 114 132 133 134 137 138 139 145 151 153 156 157 158 163 164 167 171 173 179 183 184 187 189 190 191 192 194 199 202 204 205 213 214 215 216 217 224 225 229 230 231 232 235 236 239 240 242 244 245 247 248 252 260 262 264 266 267 268 271 276 280 282 284 285 286 289 291 294 298 302 303 307 309 312 316 317 318 327 328 329 330 332 334 335 338 341 343 344 345 347 349 351 353 354 356 357 361 365 367 369 370 371 375 377 378 382 387 389 396 398 399 401 404 409 410 411 412 414 415 421 422 425 426 427 429 430 431 439 440 442 445 446 449 454 455 457 462 463 465 466 468 470 473 477 482 484 489 493 494 499 502 504 505 508 510 511 512 519 523 525 527 529 532 534 535 536 538 540 543 544 545 546 547 551 553 555 557 558 559 560 563 565 566 567 570 571 574 578 584 585 586 589 591 594 595 600 604 606 608 612 613 615 619 624 625 628 631 635 637 639 640 641 642 643 645 646 647 649 651 652 653 655 656 660 664 665 670 671 674 676 677 681 682 685 690 692 695 698 700 702 703 705 706 709 712 714 715 718 720 722 735 737 743 745 746 749 752 753 758 760 767 769 771 773 776 779 780 785 787 788 790 792 794 797 798 804 806 808 809 811 812 814 815 816 820 822 823 826 830 832 833 841 843 844 846 851 857 859 860 862 863 866 869 870 878 883 884 891 892 896 897 898 899 903 906 907 909 910 914 924 927 930 931 932 933 934 941 943 944 946 947 948 950 952 957 962 964 968 971 972 973 976 977 979 980 982 989 994 996 999 +1 2 8 11 12 13 15 17 24 25 26 27 29 30 31 32 33 34 39 41 43 44 49 53 54 55 56 60 61 64 71 73 74 75 76 77 78 79 91 92 93 97 100 101 102 103 107 109 113 116 117 118 119 120 121 122 130 137 142 145 147 148 149 151 152 154 157 165 169 171 172 174 179 180 182 188 189 191 194 196 198 201 203 204 205 207 208 210 211 213 214 216 218 223 225 226 230 232 237 238 241 242 245 249 250 252 253 259 260 261 265 268 269 271 274 276 278 280 281 282 283 284 285 286 288 290 294 296 297 298 302 304 306 313 316 317 320 322 324 327 329 332 334 337 340 345 346 348 352 354 357 359 360 363 366 368 370 371 378 388 389 394 395 397 401 402 403 408 409 411 412 415 416 417 419 422 426 431 433 434 437 438 440 442 443 446 449 451 454 455 456 457 459 461 463 464 466 471 477 478 482 483 484 490 492 493 497 499 500 517 519 521 526 527 528 530 534 535 536 540 545 550 554 556 557 559 561 562 563 564 565 567 570 571 575 582 583 584 585 586 591 592 593 594 595 597 602 609 611 612 618 619 622 629 630 632 633 638 639 642 645 646 647 648 650 655 658 662 663 664 665 670 673 674 678 682 688 690 691 692 695 696 697 698 699 702 703 704 705 706 710 713 715 720 722 729 730 733 734 735 740 741 742 746 751 757 758 759 763 766 770 776 777 778 780 784 786 787 788 792 793 802 803 806 807 811 815 818 819 822 824 828 830 831 837 838 840 842 848 852 853 854 856 858 859 860 862 863 865 867 868 871 872 874 878 879 881 884 887 889 891 894 895 896 899 902 908 909 911 913 914 915 918 920 921 923 924 927 928 929 930 931 933 934 935 937 939 940 947 952 953 956 959 961 964 965 973 977 979 983 985 986 987 992 995 996 999 +1 3 7 12 15 16 17 19 20 25 27 28 29 30 31 38 42 43 44 47 50 51 52 62 66 72 74 76 78 79 80 81 84 89 90 93 94 95 97 98 100 102 104 105 114 115 117 120 121 124 134 135 136 137 138 140 142 147 149 152 153 156 157 161 162 168 173 175 176 177 179 180 181 182 184 187 189 195 196 200 202 209 210 211 214 217 218 221 226 229 231 232 236 239 241 244 247 248 250 251 252 254 257 260 263 270 271 272 273 274 285 286 289 290 294 295 296 297 300 305 307 308 309 312 313 314 315 318 319 320 325 329 330 334 338 339 340 344 345 348 351 352 356 360 363 364 369 370 371 374 380 386 388 390 392 393 397 399 400 405 406 408 420 421 422 424 428 429 430 433 435 436 437 438 439 441 442 449 454 456 461 462 468 475 477 478 481 482 484 485 486 493 495 497 500 503 504 506 507 508 509 510 511 518 521 523 526 527 528 534 538 540 541 543 547 550 552 555 565 567 569 571 574 575 577 578 580 583 584 585 586 588 589 590 598 602 604 605 607 609 610 614 621 623 628 629 631 633 636 644 645 646 647 648 651 653 658 664 665 669 672 678 680 681 684 686 691 694 695 698 699 700 702 707 708 710 713 715 716 718 719 723 724 727 729 730 734 735 738 740 747 748 749 751 755 759 760 761 763 765 766 772 773 777 778 783 785 793 794 796 799 802 805 806 808 810 812 813 814 817 819 822 825 826 827 828 833 835 836 837 840 843 847 851 854 857 861 866 867 874 875 882 883 884 888 890 893 896 897 900 901 903 905 915 916 918 919 926 927 929 930 932 933 935 939 941 943 948 949 950 951 952 957 960 962 964 965 967 968 969 970 972 973 974 976 977 980 982 985 986 991 992 994 995 998 +5 12 14 16 17 18 19 20 24 27 35 36 44 45 46 47 50 53 54 56 57 59 60 61 62 63 65 66 77 79 83 84 86 95 96 98 102 104 106 107 109 111 116 118 119 121 124 126 130 131 132 136 140 141 146 150 151 153 157 162 164 166 167 169 170 172 173 176 178 180 182 184 185 186 189 190 191 195 199 202 204 206 212 213 214 215 228 229 230 231 232 234 238 240 244 245 247 251 254 257 258 259 268 269 272 276 280 283 286 288 290 291 294 297 300 301 305 310 311 312 313 315 316 320 323 324 326 331 332 333 336 341 344 346 348 349 350 351 353 354 357 358 360 361 365 371 373 375 376 380 385 388 393 394 399 401 412 413 417 421 424 427 428 433 434 435 439 441 442 444 453 455 457 462 464 467 468 476 477 478 483 485 486 488 489 492 493 494 496 498 503 506 509 512 513 519 522 526 528 529 532 534 538 550 551 552 558 559 561 563 564 566 567 568 569 570 571 572 574 575 577 578 580 581 582 585 593 594 609 611 612 614 615 617 621 630 632 635 637 642 645 655 662 663 664 665 666 670 672 673 676 678 679 684 686 687 697 698 701 703 704 706 708 712 713 714 719 720 722 724 725 726 731 732 735 738 741 743 745 746 750 751 754 758 760 764 766 767 768 769 773 774 777 779 780 783 785 786 787 789 790 793 797 801 802 811 814 818 823 832 833 840 841 844 847 850 851 854 856 858 859 860 863 865 867 868 874 876 879 882 884 885 886 890 893 894 898 901 904 908 919 926 928 931 932 937 939 940 945 949 952 953 954 955 956 960 964 969 970 973 977 981 984 985 988 989 991 993 996 999 +0 1 3 5 6 7 8 11 13 15 22 23 24 26 28 30 32 36 38 39 43 47 48 49 50 51 55 60 64 66 67 68 69 70 71 77 80 81 82 85 87 88 92 95 96 98 99 103 105 106 110 112 115 116 118 119 120 124 132 135 136 138 140 142 145 146 147 148 149 151 153 154 155 163 166 167 168 174 175 178 179 183 184 186 187 188 191 194 196 197 202 210 211 217 222 223 224 226 229 233 238 239 246 247 249 251 253 255 257 258 259 262 265 266 267 270 271 272 274 275 279 282 285 286 288 289 291 296 297 304 305 312 314 315 319 320 327 328 330 335 340 343 344 345 349 350 353 354 355 356 358 360 361 362 363 369 371 376 377 380 383 388 395 397 400 401 404 410 411 413 415 416 419 420 423 424 425 427 428 430 433 434 436 438 440 445 448 464 467 470 472 473 477 481 482 487 495 500 505 508 510 517 518 519 521 525 526 527 535 538 543 545 546 547 550 553 555 556 558 560 564 565 566 570 571 572 574 576 578 580 583 588 591 598 600 603 606 610 611 612 617 618 620 624 626 627 630 633 635 636 638 639 647 648 655 658 659 661 662 665 667 668 670 671 672 674 675 680 682 683 684 686 688 690 691 694 696 697 701 703 706 712 714 716 717 718 719 721 722 724 727 729 730 731 733 734 736 744 747 749 752 754 756 758 762 763 765 769 770 780 782 783 787 789 791 793 794 796 797 805 807 808 811 813 814 819 821 822 823 827 828 829 834 835 836 841 850 852 856 857 858 859 863 864 868 871 872 875 877 878 881 882 885 888 891 894 899 902 905 908 910 911 912 913 915 916 924 925 926 928 929 930 931 934 937 940 941 943 951 952 953 959 963 965 967 968 969 970 972 974 975 980 981 983 987 993 995 +2 9 10 14 15 16 20 22 25 27 28 29 32 33 34 39 46 49 50 51 61 62 63 64 65 72 73 76 77 78 84 87 92 93 97 98 99 101 103 106 107 122 124 129 130 131 134 137 141 144 145 146 149 156 160 162 163 164 165 166 168 170 171 174 175 176 181 182 186 187 188 189 192 195 198 199 201 202 207 211 214 215 216 219 220 221 223 225 227 232 233 236 237 239 240 242 243 244 247 251 253 258 260 262 266 267 269 271 274 285 286 287 292 294 297 298 300 301 302 305 307 311 312 313 314 316 318 321 323 327 328 331 336 338 340 342 343 347 348 349 354 362 365 366 367 372 376 381 383 385 387 390 394 395 396 397 402 406 412 414 415 417 419 423 425 427 429 431 434 436 437 438 440 446 455 459 460 463 466 467 469 471 476 478 479 480 483 485 487 488 494 497 499 501 507 509 520 521 525 526 527 533 534 535 537 538 544 545 546 548 550 553 554 555 559 561 565 576 579 582 583 586 588 589 591 592 594 595 599 600 602 604 606 607 609 612 613 619 622 624 625 626 627 630 631 632 635 636 638 639 640 650 651 659 664 677 679 682 683 684 685 686 688 689 693 697 704 706 709 711 712 713 714 720 723 726 727 731 732 733 734 739 741 742 744 747 748 750 751 753 754 755 756 760 762 765 767 771 773 775 779 782 787 789 794 796 800 802 809 810 811 812 813 817 819 822 823 831 832 836 838 841 845 848 850 854 856 858 860 865 870 872 874 881 888 894 896 902 903 905 907 909 912 913 914 918 926 927 930 936 937 940 941 943 944 947 949 950 951 953 954 956 957 958 959 962 969 972 975 976 980 983 991 992 996 997 998 +1 3 5 10 12 13 16 20 23 24 26 32 34 43 44 46 47 48 50 55 58 59 60 66 67 68 69 70 71 72 74 75 76 78 79 80 82 83 84 86 88 89 95 97 98 100 101 104 105 108 111 113 114 116 117 119 120 122 123 124 128 131 135 146 147 150 152 155 157 158 159 162 163 166 167 168 169 171 173 176 177 183 185 187 191 195 199 200 201 205 206 208 209 210 213 216 219 222 224 227 228 230 233 234 235 238 239 241 243 248 249 254 258 259 263 266 268 269 270 273 279 282 283 285 286 287 289 294 295 297 299 300 302 304 309 314 315 316 317 318 322 324 325 326 328 331 333 335 338 340 341 343 348 352 353 354 355 360 363 364 368 370 374 378 381 384 385 387 388 391 393 395 396 397 399 401 408 409 411 412 413 415 417 419 422 423 424 426 429 431 432 438 439 444 446 447 451 459 460 463 466 469 472 475 478 479 482 485 487 489 491 493 498 505 506 512 513 514 515 516 519 522 525 527 529 537 539 542 547 548 549 552 553 556 559 560 561 564 565 566 567 568 569 570 571 575 576 580 583 584 585 587 588 589 591 598 599 605 608 609 614 616 617 618 622 623 626 629 630 634 635 636 641 643 649 657 660 661 665 667 671 673 674 676 677 678 679 686 691 696 700 701 703 704 710 713 719 721 723 724 730 731 733 735 736 737 738 740 741 746 747 748 750 751 752 754 756 757 759 761 763 765 766 768 769 770 772 774 777 778 779 780 782 785 788 791 798 799 800 801 804 805 808 810 811 813 816 822 824 829 830 831 832 834 840 846 847 850 852 858 861 862 864 865 870 876 881 884 885 886 887 888 889 891 893 898 899 903 906 908 911 912 914 916 917 920 922 926 927 928 929 931 932 933 935 938 939 940 942 944 945 948 949 950 952 954 959 961 964 966 967 968 970 972 973 974 975 978 984 986 988 989 994 998 +0 1 3 5 6 7 9 10 12 13 14 22 23 25 28 30 32 33 40 43 45 54 55 56 62 63 64 65 67 68 70 71 76 77 78 83 90 92 93 94 100 101 103 105 106 110 113 114 115 119 123 126 129 130 131 134 135 138 139 140 142 144 145 147 148 154 155 157 158 160 165 168 169 170 171 172 173 174 177 178 179 185 187 192 195 198 214 219 227 228 230 232 233 234 235 236 237 238 240 241 244 250 252 253 258 261 263 264 265 271 272 273 274 277 278 279 280 281 292 295 297 300 305 306 307 309 310 316 317 318 320 323 324 325 326 329 330 337 342 346 347 350 352 353 359 367 371 372 373 374 375 378 381 382 384 385 391 392 396 398 399 400 401 404 406 409 411 417 418 422 423 424 427 430 437 439 442 445 446 450 451 452 455 460 464 466 467 471 474 475 478 479 482 483 484 485 486 488 489 494 497 498 500 501 503 505 508 509 510 511 514 515 518 519 522 524 525 529 535 536 537 540 541 542 543 545 546 548 551 554 564 568 569 571 573 574 575 577 578 580 581 584 585 586 589 591 592 594 597 599 600 606 614 615 617 621 624 626 630 634 635 637 638 639 649 650 652 657 658 661 662 669 671 673 678 683 684 688 689 690 694 699 700 707 708 709 711 712 714 717 718 721 725 726 727 731 734 735 736 737 742 744 747 748 751 753 757 758 764 766 770 771 773 776 790 792 794 798 799 801 804 805 806 810 812 815 817 818 824 828 831 832 834 848 849 851 853 856 857 858 860 861 865 868 869 873 874 875 876 879 882 883 886 890 892 894 897 899 908 910 915 917 921 923 927 933 939 943 944 950 951 952 953 956 958 959 960 964 973 979 980 983 985 993 994 995 996 998 +1 2 3 4 7 9 13 17 22 23 24 27 28 29 35 36 37 44 45 46 50 54 55 60 61 62 66 67 68 71 73 74 75 76 79 80 83 85 88 89 91 93 94 95 97 99 100 101 103 104 107 109 115 119 122 125 126 129 132 133 139 140 142 144 159 160 161 163 166 167 172 173 176 177 179 180 182 191 193 194 195 196 199 201 204 205 211 213 221 228 229 230 232 233 234 235 236 242 243 245 250 251 254 257 258 260 262 265 268 275 277 279 284 286 290 293 296 301 305 307 308 309 316 317 318 319 320 321 322 326 327 330 332 333 336 339 342 344 345 347 348 349 351 355 358 359 361 362 369 371 376 379 383 384 387 388 389 390 394 395 397 398 402 406 407 413 414 416 417 418 421 422 431 432 436 441 443 444 450 452 453 456 457 459 466 467 470 474 476 477 481 484 490 494 495 497 500 504 506 510 522 526 528 529 530 531 533 534 536 539 546 547 548 552 553 554 555 557 558 561 562 566 573 575 582 590 591 593 594 597 598 602 603 606 608 609 611 612 613 618 619 621 622 624 625 630 631 633 636 638 642 643 650 652 653 655 657 661 662 668 672 676 677 678 684 687 689 694 696 697 700 701 706 708 712 713 714 715 716 717 720 723 724 726 730 734 735 736 739 740 741 746 747 748 751 752 755 756 758 759 760 761 763 765 767 773 774 776 777 778 779 783 785 787 789 790 793 797 799 800 802 807 808 809 814 816 817 821 824 825 826 827 828 829 830 831 832 833 836 837 838 840 843 846 847 850 851 852 859 863 865 872 875 877 881 883 884 885 886 892 893 894 895 897 899 901 904 906 907 912 914 916 917 918 919 920 924 925 926 930 933 937 938 939 940 942 943 944 947 951 954 955 959 960 962 967 968 969 971 976 979 981 983 984 985 987 988 989 994 997 998 +0 2 6 9 12 13 15 19 20 22 23 26 29 30 34 35 36 37 38 39 42 43 44 45 46 48 51 54 56 59 60 63 71 73 74 75 78 80 81 88 89 90 94 97 98 99 101 102 104 106 110 115 116 117 129 130 131 133 134 135 137 140 141 143 145 150 151 155 158 160 164 165 166 168 169 170 172 173 176 179 182 184 186 187 192 193 198 199 200 201 206 208 214 218 219 220 222 223 224 225 227 230 233 236 237 238 242 243 250 251 252 254 256 257 259 262 263 264 267 269 272 274 275 279 281 283 287 289 291 293 295 296 298 300 305 308 310 311 314 315 318 319 322 323 325 326 327 328 329 341 344 350 358 359 362 364 367 368 369 371 374 376 378 382 387 391 392 394 395 398 401 402 403 408 409 410 411 412 422 428 430 435 436 437 438 441 446 447 456 457 458 463 467 468 469 473 480 484 485 486 487 490 492 495 497 498 499 500 502 503 505 506 508 509 510 517 520 522 525 529 533 535 536 537 538 541 542 543 544 547 549 550 552 557 559 560 562 564 565 566 569 572 573 576 577 578 579 584 585 591 592 594 595 597 603 604 607 610 613 617 620 621 624 627 630 631 633 637 642 643 647 649 650 651 652 653 654 656 657 660 664 665 670 676 679 681 682 686 687 688 689 691 692 695 698 699 701 702 704 706 707 708 709 710 711 712 715 716 717 720 722 723 729 732 735 737 739 742 743 745 748 749 750 751 756 759 760 763 764 765 766 767 772 774 775 776 777 778 779 781 783 784 787 793 794 795 796 799 801 802 803 804 807 812 813 815 816 817 820 822 823 824 837 839 841 847 850 853 854 858 862 866 869 873 875 878 880 884 887 888 889 893 896 900 904 905 906 907 908 911 917 918 920 924 925 928 929 930 935 936 937 938 942 944 946 950 952 956 962 965 967 969 976 978 980 982 985 988 992 994 995 997 998 999 +6 12 17 18 19 20 22 23 25 28 29 31 32 35 36 37 39 43 46 50 53 54 58 60 61 62 63 64 67 70 73 74 75 80 82 83 84 85 86 88 89 96 98 99 101 104 105 107 109 110 112 113 115 124 126 127 130 132 139 142 144 145 146 151 152 156 157 162 168 169 170 171 172 177 179 180 181 183 185 186 189 190 192 198 202 204 207 211 212 213 215 217 219 220 221 223 229 232 234 238 239 240 241 242 244 245 248 249 251 255 256 257 261 262 263 264 268 281 282 284 286 287 290 291 295 296 298 301 303 305 312 314 317 318 319 322 324 326 328 330 331 333 335 336 337 341 345 349 351 352 353 354 356 359 360 361 366 367 371 373 375 377 381 382 385 388 389 393 395 397 398 400 408 409 410 416 417 419 423 425 426 429 436 438 443 448 450 453 454 455 456 459 462 464 465 466 467 468 470 473 475 479 482 485 486 488 495 496 499 502 503 504 505 508 511 512 513 515 517 519 520 524 528 529 532 533 537 539 540 541 542 546 548 551 553 554 556 559 560 561 563 564 566 570 576 579 581 586 590 592 593 594 595 600 602 604 605 613 614 615 616 617 618 620 622 625 627 632 635 638 640 641 654 656 660 661 662 663 665 672 673 674 675 677 679 681 682 683 688 689 690 691 697 698 701 704 706 708 709 710 711 712 722 724 725 726 727 728 734 737 744 745 747 748 751 754 763 764 765 767 774 786 790 794 796 801 802 809 810 811 816 817 818 819 820 821 823 827 828 830 835 836 837 845 846 848 849 850 851 854 855 859 860 862 864 865 866 867 868 874 875 877 880 881 883 884 887 889 900 901 902 905 909 913 918 921 927 929 935 936 940 941 944 945 946 950 952 953 957 958 960 961 962 963 971 972 975 977 978 980 981 983 986 987 988 989 990 995 997 +0 7 12 14 19 20 21 23 30 35 36 37 39 43 47 48 49 54 59 61 64 68 69 71 73 75 76 78 92 95 97 99 105 106 110 112 113 117 119 121 125 131 139 142 143 144 145 148 149 153 154 156 158 160 163 164 167 168 173 174 176 177 181 182 188 194 196 202 204 206 211 212 214 215 222 223 234 236 237 240 241 242 244 247 249 253 258 259 266 271 274 280 281 282 285 286 287 288 292 293 294 296 299 303 305 306 307 308 309 313 314 321 322 329 330 332 333 334 340 341 342 348 351 353 358 359 361 363 368 371 372 376 377 378 380 381 382 383 388 389 391 392 395 397 398 406 408 409 411 412 413 417 419 420 423 427 433 435 438 441 443 444 448 451 453 458 459 460 463 465 466 467 468 469 474 476 482 484 485 488 491 494 496 501 502 505 506 508 513 518 520 524 525 533 536 538 541 544 545 546 548 553 554 556 559 564 566 568 573 577 578 579 580 582 583 586 592 596 597 598 600 601 602 604 606 607 608 609 613 614 615 616 621 623 624 625 627 628 629 630 632 633 635 637 638 640 648 649 651 652 654 655 657 658 659 660 661 665 668 675 678 682 683 689 690 692 698 700 701 704 705 706 707 709 710 713 717 719 720 722 723 724 726 727 728 732 734 735 736 737 738 743 744 746 747 749 750 754 762 768 774 776 779 780 781 782 783 784 787 789 790 791 792 796 797 798 799 800 801 802 803 804 805 809 811 812 814 818 819 821 822 824 825 828 830 834 839 842 848 849 851 853 854 856 864 867 869 870 871 872 875 876 878 880 882 883 886 889 891 894 901 903 905 912 916 917 918 921 922 923 926 928 932 933 936 942 945 946 948 949 953 954 956 962 963 967 968 969 974 975 976 979 980 984 987 988 991 993 996 997 998 +0 2 4 5 6 9 12 13 16 25 26 33 35 37 38 47 50 62 66 67 68 69 75 78 80 82 84 85 86 91 94 95 99 101 105 109 113 127 131 134 146 147 149 151 156 163 164 169 172 173 174 176 177 180 181 183 185 186 187 190 191 192 194 195 196 197 198 200 208 210 213 217 219 222 227 233 234 237 238 240 243 245 247 252 253 258 260 262 264 267 268 270 274 276 277 278 296 297 298 302 306 308 309 311 314 316 322 323 326 328 331 345 347 348 357 358 367 371 372 373 374 377 379 381 387 390 391 392 393 400 414 415 417 421 424 426 427 429 430 431 432 434 435 439 440 442 443 444 445 450 451 454 456 460 463 465 466 467 468 469 470 475 478 482 488 489 491 492 494 499 500 501 502 503 504 509 511 516 518 519 521 522 523 524 526 528 529 531 533 538 540 541 543 544 545 548 549 553 559 563 564 565 566 567 568 570 572 573 574 575 576 577 578 579 581 582 583 588 589 592 596 597 598 599 602 605 607 608 609 611 612 613 615 622 623 625 626 627 630 631 635 641 642 644 647 649 651 656 662 666 667 669 671 672 673 675 678 681 682 683 686 694 697 700 701 702 707 710 711 712 720 724 727 734 735 737 738 741 743 744 746 747 749 750 753 757 759 761 763 766 767 768 770 771 776 779 784 786 787 788 790 794 795 796 799 802 804 805 807 810 813 814 816 817 818 820 822 823 824 828 832 833 836 838 841 842 843 845 847 848 853 857 858 859 862 863 865 873 874 875 876 889 891 893 898 899 905 910 911 913 921 923 928 930 937 942 943 946 948 961 963 965 967 968 970 972 975 978 981 982 986 987 998 999 +2 7 8 10 12 13 14 16 17 18 19 23 25 27 28 32 35 39 40 41 43 44 45 46 50 52 56 57 62 64 71 73 74 78 83 84 86 87 92 95 96 97 99 100 101 102 103 112 113 114 118 119 120 125 126 129 130 131 134 135 137 142 143 144 146 151 152 154 158 159 161 162 165 166 167 169 170 172 176 177 178 179 183 187 189 190 193 195 197 200 202 203 204 207 208 210 211 212 213 215 216 224 225 226 233 234 237 240 241 243 244 246 250 252 253 254 257 258 260 262 266 268 269 272 275 276 279 282 283 285 289 290 292 294 295 297 299 301 310 319 322 324 325 328 332 333 334 337 340 341 342 344 347 351 353 355 356 357 364 367 368 370 371 372 377 378 379 387 391 396 397 398 401 404 406 407 410 411 412 415 422 425 426 430 434 440 442 446 449 451 455 460 461 463 466 467 469 470 473 475 476 488 491 496 498 501 503 507 509 516 524 526 528 529 530 533 535 536 538 540 544 545 546 547 548 549 550 551 552 554 555 560 563 565 567 569 572 575 576 578 579 586 588 591 594 595 598 599 601 604 608 609 614 615 617 624 626 631 633 636 637 639 640 641 643 645 646 647 649 653 656 657 661 665 667 668 669 670 676 679 680 681 682 684 685 686 688 690 691 695 697 698 701 702 706 707 710 711 712 714 715 717 719 722 727 730 731 732 733 735 737 739 741 743 745 748 751 752 754 759 763 765 766 769 772 777 778 779 780 782 783 789 795 796 798 800 801 808 809 810 817 818 821 822 825 827 828 834 835 836 837 839 846 850 851 852 855 857 859 863 865 866 868 871 872 882 884 885 889 891 894 895 898 900 907 909 911 913 915 919 920 921 925 926 927 928 930 937 939 940 944 945 948 949 950 952 953 954 957 959 961 963 966 969 970 972 974 975 976 977 978 979 982 983 984 985 990 995 998 +0 1 6 10 15 16 19 20 22 27 28 36 39 41 44 47 48 49 56 57 58 64 65 66 70 71 73 75 80 83 84 86 87 91 94 95 99 101 103 108 109 115 116 117 118 120 127 130 132 134 136 137 142 146 150 155 158 160 164 167 171 172 178 179 181 184 185 186 191 192 193 197 201 202 204 206 211 213 215 216 217 219 221 222 226 227 228 231 236 238 240 244 245 246 256 260 261 266 269 273 274 275 277 278 279 287 288 289 290 293 296 297 298 302 303 308 310 311 312 315 316 319 322 323 331 333 334 338 339 342 343 346 350 352 357 360 362 363 368 369 378 384 386 387 389 391 394 398 402 404 406 411 412 414 417 420 425 426 431 433 434 437 438 440 441 442 444 445 447 448 449 451 453 455 457 460 462 463 464 470 472 477 478 479 480 483 484 485 491 492 501 504 514 515 517 520 521 525 527 529 531 532 535 539 540 542 545 549 551 552 553 554 557 561 567 577 578 579 583 584 588 590 592 593 594 597 598 602 609 610 611 612 614 620 621 622 625 627 628 630 631 632 633 634 639 640 642 643 647 653 657 663 665 666 667 670 671 672 674 676 679 680 681 682 683 684 688 689 691 692 697 700 702 703 704 707 712 715 716 717 725 726 729 734 736 737 739 742 746 748 755 757 759 763 773 775 777 779 785 786 787 788 789 794 795 796 798 805 810 812 813 815 819 821 824 825 826 828 838 842 845 847 849 851 853 855 861 864 865 867 868 872 873 878 879 881 884 887 888 889 890 892 898 900 907 910 914 916 917 919 921 928 929 930 931 938 940 941 944 949 951 960 962 963 970 971 974 975 976 979 981 982 986 987 988 991 993 994 995 998 +3 5 6 8 9 11 14 17 20 21 23 24 25 31 32 34 35 36 37 39 40 44 46 47 49 50 52 55 58 68 71 76 77 78 82 84 85 88 89 90 91 92 93 95 100 108 109 110 113 115 116 119 121 123 124 127 128 129 131 132 137 139 142 143 144 145 146 153 154 155 158 159 160 161 162 167 169 170 171 175 176 177 178 180 183 186 188 192 195 199 201 207 210 211 212 214 216 217 218 221 225 229 231 234 237 244 245 248 251 255 258 261 264 267 269 271 274 275 280 285 286 287 288 293 297 298 299 300 304 305 316 317 318 321 322 324 325 326 327 329 330 331 335 338 340 342 344 347 349 351 355 357 358 359 360 361 362 364 365 367 368 375 376 377 381 386 387 388 391 399 402 407 408 409 411 412 414 415 417 419 421 424 429 430 435 436 437 439 440 441 443 444 445 446 448 451 452 457 459 461 463 466 467 470 474 477 478 482 487 488 489 492 493 494 495 496 497 501 502 504 506 507 510 512 513 514 516 518 522 523 526 538 539 543 551 552 555 558 559 562 563 564 567 568 575 578 580 581 583 585 587 588 593 594 598 599 602 603 604 609 610 611 616 622 626 628 631 633 638 640 642 643 650 654 656 657 659 663 668 669 670 678 679 682 683 691 693 694 695 697 702 709 714 716 719 720 722 725 729 732 733 735 737 738 739 740 742 744 746 747 748 750 753 757 759 762 769 774 781 782 784 785 788 789 791 793 794 796 800 803 804 806 808 809 812 814 821 822 834 836 837 838 843 845 847 850 853 855 858 860 861 863 869 876 878 880 881 882 889 890 891 894 897 899 905 906 908 909 910 915 916 923 924 925 927 932 933 934 936 938 941 947 949 952 960 961 962 967 973 975 978 979 982 984 986 988 992 995 996 998 999 +0 3 5 12 14 18 20 21 24 28 29 31 32 34 35 38 40 41 43 45 52 59 60 62 63 64 65 67 68 69 71 72 74 75 77 78 80 83 84 85 90 91 96 97 100 101 105 106 111 112 114 115 117 118 120 125 132 134 141 147 149 161 164 165 168 172 174 179 180 181 183 184 186 187 188 189 193 195 197 198 200 203 205 209 210 211 214 218 220 225 227 230 231 233 234 235 245 246 247 248 249 250 253 255 256 257 270 273 274 276 277 279 280 284 287 289 299 305 308 309 310 314 315 316 320 321 324 326 327 328 330 331 332 334 335 336 340 341 342 345 347 352 356 357 359 362 363 365 366 370 373 378 379 381 382 385 386 387 388 391 392 395 397 403 404 406 407 410 411 412 417 422 425 426 428 429 432 433 434 435 436 437 438 440 444 445 448 452 453 457 462 464 466 467 469 470 473 476 478 480 484 491 495 496 501 502 504 506 508 509 511 513 516 517 519 520 527 529 531 532 533 535 536 538 539 547 555 556 560 564 565 571 572 574 576 577 582 585 587 590 591 592 599 600 601 602 604 606 607 611 612 613 614 615 616 618 619 620 621 622 624 634 636 638 639 647 648 650 653 656 658 659 661 663 669 671 673 674 676 678 682 683 685 688 689 691 696 699 701 702 707 709 710 712 717 720 728 729 735 736 740 743 746 751 759 764 765 772 773 774 776 777 779 780 781 783 784 785 787 790 791 794 795 796 797 798 800 803 804 806 807 808 811 813 817 818 822 823 824 825 827 829 831 832 833 836 840 844 846 848 849 857 859 861 864 866 867 869 870 876 879 886 887 889 897 900 903 904 906 909 911 913 914 915 916 917 919 921 924 925 927 929 930 931 932 936 939 940 941 943 945 950 952 953 955 960 961 963 965 966 973 976 977 979 980 983 987 989 991 993 994 995 +2 3 6 11 12 17 20 25 35 37 38 39 40 42 43 44 48 50 52 53 57 58 60 63 65 66 67 70 74 78 82 83 90 101 103 104 105 106 110 112 117 120 124 133 137 139 141 142 144 146 147 148 151 152 153 156 157 159 162 165 166 168 170 173 176 179 184 185 186 188 190 192 198 199 201 204 205 208 209 211 212 213 218 219 221 223 227 231 233 234 236 238 239 241 248 249 250 251 257 258 259 260 263 265 267 271 281 283 291 293 295 299 304 306 308 310 312 317 318 320 323 324 325 340 343 344 351 363 365 367 370 376 379 380 382 384 388 391 392 393 395 401 402 403 405 408 410 411 413 416 420 421 423 426 432 435 439 444 445 446 450 452 455 459 460 461 462 469 472 475 478 479 480 481 485 487 493 495 496 501 503 507 511 512 514 516 518 519 522 526 528 529 531 534 536 537 539 540 541 542 543 548 549 550 551 552 554 555 556 557 559 560 561 567 569 574 578 580 581 583 584 585 593 596 603 607 611 614 616 618 620 622 626 627 630 631 632 633 634 637 641 642 643 645 649 651 652 656 659 663 665 666 667 668 671 674 677 681 682 684 685 687 689 690 691 693 695 697 698 702 704 708 709 711 712 713 715 719 722 725 726 734 741 743 744 747 748 751 752 753 754 755 758 760 765 768 772 774 775 778 780 786 787 788 789 790 796 797 799 801 802 810 817 818 819 826 827 829 831 836 837 840 842 845 850 851 855 856 857 858 860 862 863 866 867 868 872 873 875 876 877 879 883 884 889 892 893 895 897 903 904 911 912 914 917 918 920 925 926 927 929 930 931 934 937 939 944 945 948 953 961 965 967 970 974 975 980 982 983 987 988 990 991 992 999 +2 3 6 8 14 18 24 27 28 30 32 36 39 42 43 48 49 50 53 54 56 58 61 62 67 71 73 75 77 79 82 83 86 88 89 90 91 94 100 102 107 110 111 112 116 118 119 122 123 124 126 135 137 140 141 143 146 147 148 151 152 154 156 157 163 169 170 171 175 176 179 183 184 185 187 188 195 196 201 202 203 207 209 210 211 212 216 217 218 221 224 228 229 231 232 233 235 237 239 241 242 243 246 249 251 253 254 256 261 264 265 267 271 272 275 276 277 278 279 285 288 291 297 300 306 307 308 309 310 313 315 317 321 322 323 324 327 329 333 334 335 339 340 342 349 350 352 353 354 365 370 373 374 375 377 382 388 391 392 394 395 396 398 403 404 406 410 412 413 414 417 419 420 425 427 428 429 430 432 436 442 443 448 449 452 464 466 468 470 476 478 482 483 484 488 489 490 493 494 497 498 499 511 514 520 522 523 524 525 528 529 536 538 540 547 551 553 558 559 562 563 565 566 567 569 570 573 574 582 584 585 586 593 594 596 597 604 606 608 609 610 615 622 624 628 633 639 644 645 646 647 648 653 654 658 660 662 664 669 674 680 681 682 686 689 691 695 698 700 704 707 709 711 712 717 719 722 727 732 734 739 742 745 746 748 749 750 751 752 756 758 761 763 767 769 771 773 775 776 779 781 782 786 790 793 794 795 799 800 804 806 807 808 809 810 812 816 817 822 834 839 841 843 844 845 849 856 864 867 868 870 871 874 876 877 878 879 882 885 886 887 889 892 893 895 896 897 903 908 911 913 917 920 923 925 929 931 933 934 935 936 941 943 949 951 953 954 956 959 961 962 963 968 970 971 972 973 975 977 981 983 984 988 994 997 999 +0 1 5 8 9 12 13 14 18 19 21 22 23 24 27 32 40 44 48 52 53 55 58 62 68 71 73 76 78 80 81 82 84 86 89 93 94 97 98 101 105 106 109 120 126 127 129 134 137 138 139 141 149 151 152 154 157 159 160 162 165 170 171 172 174 175 176 178 181 182 185 187 192 195 199 202 206 207 208 209 214 216 217 221 225 226 227 228 229 231 232 235 238 246 249 251 252 256 259 267 269 270 271 276 278 282 284 288 291 292 295 305 306 316 317 320 323 328 329 330 332 335 337 344 346 347 353 354 355 356 360 361 362 366 368 369 370 373 379 383 388 389 390 392 395 396 397 398 405 406 407 410 412 414 418 423 427 430 434 435 437 438 439 440 442 443 444 446 448 449 454 455 456 459 462 465 466 467 468 470 471 472 473 475 477 478 479 480 482 483 484 491 493 494 499 501 505 509 511 512 515 519 522 526 528 532 535 538 540 545 546 547 549 550 555 556 562 568 569 570 571 580 581 589 590 591 594 595 596 597 599 602 607 608 612 617 618 620 622 623 624 625 626 630 634 635 637 642 643 644 646 647 649 651 652 655 658 660 661 662 663 667 673 674 675 677 678 681 683 685 689 692 693 694 698 699 700 703 706 709 710 713 717 720 721 724 729 732 733 736 737 739 744 750 752 753 755 760 761 771 773 777 779 781 784 785 786 787 789 790 791 793 794 796 798 801 802 804 811 814 818 819 821 822 823 824 828 829 830 832 833 834 836 841 845 846 847 848 852 854 858 859 863 864 867 871 872 873 875 877 878 889 890 894 898 900 901 902 905 906 911 915 916 924 931 933 936 940 941 946 949 950 951 955 956 961 962 964 966 968 971 972 978 980 983 985 986 987 990 991 995 +0 3 4 5 7 12 14 16 19 21 22 24 25 31 35 37 40 42 44 49 50 51 54 60 61 62 63 64 70 71 72 73 76 81 82 83 85 87 88 92 94 96 97 100 101 103 104 107 109 113 116 117 119 122 124 126 133 134 135 136 139 140 144 145 146 147 148 150 152 153 154 159 161 164 165 166 174 175 179 183 184 185 192 199 200 201 204 205 206 207 208 210 211 212 214 217 218 221 224 225 227 229 230 231 232 236 237 244 245 246 247 250 251 254 255 256 260 261 264 267 269 270 279 282 290 292 293 298 299 302 303 304 307 310 320 324 325 326 327 330 335 337 338 345 346 349 350 352 354 355 356 357 358 360 361 362 363 364 367 369 371 372 378 386 387 388 390 392 394 395 397 398 399 400 401 402 403 406 407 408 416 417 418 419 430 432 434 435 439 441 442 445 447 450 451 452 453 454 458 462 466 467 468 470 476 478 479 480 481 483 486 489 493 496 497 501 504 505 510 511 512 513 516 521 523 525 526 527 529 534 537 539 544 545 548 554 555 558 559 562 564 567 568 575 583 585 586 588 591 596 600 601 603 604 605 606 609 610 611 612 617 621 625 627 629 633 635 638 641 651 653 655 657 658 665 670 671 674 679 680 681 682 684 685 688 691 692 693 694 695 699 700 701 703 704 709 710 711 715 716 720 722 727 728 730 731 734 735 742 743 745 748 750 755 756 758 759 761 762 768 769 770 771 774 777 784 785 786 787 788 789 791 792 793 798 799 801 804 805 808 811 815 823 825 827 828 831 832 833 836 837 843 845 846 852 856 858 864 867 868 869 871 872 876 878 881 883 885 887 888 890 891 892 894 895 896 900 901 903 909 911 913 920 925 928 933 938 941 942 943 947 952 953 954 955 957 958 959 965 966 967 969 971 974 975 985 988 992 994 995 997 998 +2 5 8 10 12 14 16 20 24 27 30 37 38 42 43 44 48 49 50 54 61 65 68 70 73 76 79 84 88 89 90 97 99 100 103 106 111 114 115 118 122 123 132 142 150 153 158 159 161 163 164 165 170 171 172 173 174 177 179 181 184 186 188 189 190 191 192 195 198 201 204 209 211 212 213 214 215 221 222 223 226 228 233 234 239 245 248 249 250 252 255 256 258 259 260 261 267 273 276 277 278 280 281 288 291 292 293 297 302 305 308 312 316 317 321 325 326 327 330 341 345 347 358 362 363 364 365 370 371 382 386 387 388 389 393 398 402 404 405 409 414 415 416 419 429 437 439 442 444 445 447 449 457 458 460 461 466 468 469 470 472 473 479 484 486 487 488 490 492 494 496 500 503 504 507 508 512 515 517 520 522 523 526 528 529 530 531 533 536 539 540 541 542 545 549 553 559 562 566 571 581 582 585 587 590 592 595 597 600 601 605 606 607 610 615 616 617 618 619 620 626 630 633 634 637 639 640 641 647 651 659 662 663 665 670 672 675 685 687 689 690 694 700 704 706 708 710 711 716 718 719 721 722 724 726 727 728 729 731 732 734 736 742 743 744 749 750 751 759 761 765 766 768 771 772 773 776 779 781 784 788 789 796 797 800 801 803 806 816 818 821 823 826 827 830 833 837 840 842 843 844 847 849 850 855 856 858 862 863 864 865 869 870 872 873 875 876 878 879 885 886 887 888 892 893 895 900 901 902 904 905 909 913 915 916 917 918 922 923 925 928 929 934 939 941 942 944 945 947 948 955 956 957 960 963 964 966 970 971 975 976 979 981 987 990 991 995 996 997 +3 4 6 10 13 19 23 29 34 38 42 50 51 52 53 55 58 59 62 64 65 69 74 75 79 83 87 88 93 94 95 96 101 102 103 105 107 110 111 117 118 120 123 130 131 133 134 135 141 142 143 145 148 149 152 153 154 157 158 159 161 162 166 168 169 172 177 180 181 184 189 194 196 200 202 204 207 208 210 212 220 223 225 227 230 231 232 233 236 238 243 245 246 248 253 257 261 262 263 265 266 268 270 271 275 277 282 286 288 289 291 295 297 299 300 302 306 309 315 316 318 319 320 322 325 326 327 329 330 332 335 336 337 338 339 340 342 345 347 348 349 350 354 356 357 367 372 376 377 379 381 382 383 385 388 389 393 396 397 398 401 402 404 410 412 419 421 425 427 430 431 432 435 436 440 443 445 447 448 449 450 452 454 455 457 458 459 462 463 465 466 468 469 471 472 473 475 481 485 486 488 490 491 494 498 499 508 510 513 514 515 517 519 528 530 531 534 537 538 542 545 546 549 551 555 560 561 562 563 564 567 571 573 575 578 580 582 583 587 589 592 594 595 596 599 600 602 605 611 614 617 619 627 631 632 633 635 640 641 647 648 650 651 653 655 662 664 668 677 678 680 682 685 687 688 693 695 700 701 704 707 709 711 713 722 723 724 726 728 729 731 732 737 739 741 745 746 758 763 764 765 766 772 773 774 776 777 778 779 781 783 784 788 790 792 795 797 798 801 805 807 809 810 812 814 817 818 823 825 826 830 832 834 836 837 842 844 845 850 851 852 853 854 856 858 859 860 861 862 863 868 869 870 873 877 879 882 885 889 891 892 895 896 903 904 906 909 910 912 913 915 919 922 924 926 927 929 931 935 936 942 943 944 946 950 955 956 957 959 961 968 970 972 974 980 984 988 990 999 +0 4 8 14 15 17 22 24 25 27 29 33 36 37 38 39 41 44 45 46 50 52 53 54 57 60 61 63 64 66 68 70 74 75 77 84 85 86 88 95 98 103 105 107 113 114 115 116 118 120 123 125 132 134 136 140 146 148 149 151 152 156 158 160 164 168 172 177 179 182 184 187 189 190 194 196 197 199 201 203 205 206 210 211 213 218 219 221 223 224 227 232 234 238 239 240 241 242 243 244 245 246 247 249 250 251 252 253 255 257 258 261 263 265 267 268 272 274 275 276 277 280 289 293 294 295 296 297 300 303 304 305 310 315 318 324 325 328 333 337 338 341 343 345 347 348 349 351 352 353 355 356 357 358 360 365 367 369 371 378 380 381 384 386 387 388 389 391 392 394 395 399 400 403 404 407 408 409 410 411 413 415 416 419 420 425 426 428 432 433 434 438 440 448 450 451 452 454 455 459 460 462 464 468 471 472 475 480 483 487 488 492 496 497 498 501 505 507 509 510 513 515 518 524 525 529 530 532 535 544 548 553 554 556 565 568 569 574 575 576 577 579 580 581 585 586 587 589 590 591 594 595 597 600 602 603 606 608 609 612 614 617 622 623 624 626 628 639 640 642 644 645 648 650 652 653 655 658 660 663 665 666 668 670 671 672 673 675 682 684 685 691 695 699 700 702 703 704 707 708 709 712 716 719 728 737 739 740 741 743 750 752 753 754 755 756 760 764 766 773 775 776 777 779 782 785 786 787 790 792 794 800 802 804 807 810 811 813 815 820 822 824 827 834 835 836 837 838 839 840 841 842 843 845 846 849 850 853 854 857 859 864 865 868 872 873 874 876 877 881 883 885 887 888 890 892 895 896 899 900 903 906 907 908 910 911 912 913 915 916 919 922 924 926 927 930 931 933 934 943 945 948 951 953 954 956 963 967 968 971 973 974 975 979 980 981 983 984 985 986 987 988 989 990 992 994 999 +0 2 4 5 6 8 10 12 13 14 19 21 26 27 31 37 39 42 49 57 58 62 64 65 66 67 70 77 79 82 85 89 91 92 93 102 104 109 111 112 114 115 117 119 120 121 123 124 126 128 130 131 137 138 146 147 149 150 153 156 162 164 166 170 171 173 174 182 183 185 187 194 195 196 197 202 203 207 208 211 214 218 220 223 228 239 242 245 246 248 249 253 258 264 266 273 274 275 277 278 279 280 287 288 291 293 296 297 299 306 307 308 311 312 313 314 315 316 317 320 323 324 329 330 331 332 333 335 341 343 345 346 349 350 352 354 357 358 359 361 365 369 373 375 378 381 382 387 390 391 392 396 397 398 400 403 404 405 407 409 411 414 419 420 421 422 424 428 430 431 432 433 434 435 436 438 441 442 446 448 449 451 452 453 455 457 461 466 468 470 472 473 478 484 487 494 496 497 499 504 505 506 507 513 514 515 516 524 527 528 531 537 541 543 547 548 549 553 555 556 557 558 562 563 564 565 569 575 576 578 579 580 582 583 584 587 589 592 596 598 599 606 608 609 611 613 616 617 624 627 629 630 634 639 640 642 643 647 649 653 654 655 657 662 664 667 668 670 674 678 680 681 684 685 687 689 690 693 696 697 698 700 701 702 703 704 712 713 714 716 719 720 721 724 725 729 730 732 735 739 741 746 747 749 750 753 756 757 759 762 764 766 768 771 772 773 775 777 779 782 783 784 786 787 788 791 794 795 796 799 804 807 809 813 814 819 821 822 823 824 825 826 827 837 838 839 840 841 842 843 845 847 851 853 861 864 865 866 868 869 871 873 874 877 879 880 881 885 892 898 902 903 906 907 908 909 915 916 917 918 919 922 925 932 938 940 941 945 948 949 951 952 953 959 960 961 967 970 971 972 973 974 975 977 978 988 989 990 992 994 996 +2 6 13 14 15 16 22 24 28 29 30 31 34 39 41 42 43 44 50 52 53 55 57 61 65 67 70 71 73 74 75 76 77 78 81 83 87 89 92 93 95 96 97 100 102 107 111 114 115 116 117 118 123 124 128 130 132 135 136 137 138 139 143 145 146 148 150 154 157 159 163 165 174 179 180 181 182 183 184 186 187 191 192 198 201 205 207 211 212 215 216 217 221 222 223 226 232 236 237 238 240 241 242 243 250 251 252 254 263 264 265 266 271 276 281 282 285 293 297 298 300 301 303 305 307 311 316 320 321 324 326 327 328 337 339 340 341 346 347 349 353 354 357 358 360 361 362 363 367 368 375 378 381 384 385 386 387 388 389 390 391 392 394 400 401 407 410 415 416 417 418 421 422 423 424 425 428 430 433 434 437 438 439 441 442 445 450 453 454 456 458 460 464 465 470 471 473 474 475 482 485 488 490 493 500 503 505 508 512 513 515 517 521 523 525 527 528 530 531 533 536 537 541 542 543 544 551 554 558 564 570 571 572 576 581 583 585 591 595 596 601 608 609 610 613 617 619 624 625 627 629 631 635 638 640 644 645 647 648 652 656 657 658 659 662 664 665 670 672 676 677 678 680 688 691 692 696 703 706 708 710 711 712 716 717 719 720 722 724 725 726 730 732 733 734 735 736 738 739 742 745 746 750 755 756 757 758 760 762 766 767 773 774 779 781 782 787 788 794 795 798 803 804 807 811 823 826 828 829 831 832 836 837 842 843 846 847 849 851 853 855 856 857 858 860 865 866 867 868 874 876 879 882 883 884 891 893 899 908 909 910 915 916 920 921 924 926 927 928 929 931 935 937 938 941 942 943 947 948 949 952 954 958 961 962 966 970 974 975 976 978 979 980 982 983 984 986 987 991 995 996 999 +0 1 2 4 7 9 12 14 16 17 18 25 26 27 28 29 32 33 34 45 46 48 51 52 53 54 57 58 61 66 68 70 72 76 84 90 92 94 97 103 104 105 110 112 113 116 121 126 129 132 138 142 143 148 149 151 161 162 164 167 168 170 171 173 175 179 180 181 183 184 188 190 191 193 196 204 205 206 210 211 212 213 214 216 217 219 222 223 224 226 229 238 239 242 246 253 254 255 263 264 265 266 271 273 275 276 282 284 290 293 299 300 302 304 309 310 314 315 318 320 322 325 326 327 328 329 330 332 333 337 344 345 347 348 353 359 364 365 368 369 372 374 378 381 382 383 384 394 398 402 405 407 408 409 411 417 419 420 423 424 426 427 434 435 436 441 442 446 447 449 450 452 462 466 468 469 470 478 479 485 487 489 492 495 496 497 501 502 505 508 509 512 515 516 517 518 520 521 528 530 531 533 534 536 538 547 551 552 554 555 557 562 563 564 565 567 569 571 573 574 576 578 583 584 586 588 590 598 600 602 605 606 613 614 615 616 617 618 619 620 622 623 627 629 630 632 633 635 637 638 641 647 648 651 656 657 658 659 660 662 663 666 667 671 674 679 680 681 682 685 687 690 691 692 695 696 698 701 703 706 707 709 711 714 716 719 722 723 727 728 731 736 738 745 746 747 749 751 762 764 765 770 773 775 777 779 781 782 785 788 789 791 793 798 800 804 808 812 813 814 817 822 823 827 829 832 835 836 841 842 843 846 848 850 859 865 866 873 874 879 880 881 882 886 888 889 890 891 892 894 896 898 899 900 901 903 906 908 916 920 921 923 924 925 926 929 935 938 939 942 944 947 948 951 958 962 966 967 969 973 974 975 980 984 985 988 996 +2 3 6 7 10 11 13 14 15 18 19 20 22 24 29 30 34 35 36 37 40 41 44 45 49 56 57 59 62 66 67 68 69 70 72 81 82 87 89 91 92 95 108 110 111 114 115 116 118 119 125 128 129 140 142 143 146 149 152 158 160 161 163 166 167 168 171 173 174 175 176 177 180 182 183 184 185 188 189 190 194 195 197 200 204 205 206 207 213 221 222 225 226 227 228 230 233 235 236 239 241 244 245 251 254 256 257 258 260 261 262 266 268 271 274 275 277 283 284 288 289 291 292 294 295 296 297 298 300 301 306 307 308 310 312 315 317 318 319 320 321 323 324 325 333 336 337 338 341 344 345 348 352 354 355 357 360 361 367 369 373 375 379 381 382 386 387 391 392 394 395 397 400 403 404 409 412 413 414 415 416 418 419 420 425 427 428 429 434 436 437 439 441 442 443 444 446 449 450 456 460 463 467 468 476 477 480 481 482 483 488 490 493 498 500 506 507 508 512 517 518 520 521 523 527 529 530 532 533 536 537 538 542 545 546 549 556 558 559 563 564 565 569 570 572 577 579 581 585 589 591 595 599 600 601 603 604 605 609 610 612 613 617 619 620 629 631 634 635 641 642 644 646 648 651 653 656 657 658 659 660 661 662 663 670 672 679 688 689 690 697 698 702 703 704 705 706 709 711 714 718 719 723 724 731 732 734 739 740 743 745 746 747 754 756 762 766 773 774 775 777 778 780 784 785 786 788 792 793 797 798 799 800 809 810 811 813 814 815 816 819 822 825 836 838 842 843 846 847 852 854 859 860 866 868 870 871 872 873 874 878 879 884 891 895 897 898 899 902 908 914 924 925 930 933 935 938 939 942 943 945 949 951 956 957 960 964 965 967 968 969 970 973 974 978 979 981 982 983 995 996 997 +0 1 2 4 5 6 7 9 11 14 16 21 27 32 33 34 35 38 39 41 42 47 48 49 50 51 53 55 59 61 67 68 69 71 72 74 76 77 83 88 89 90 91 92 103 107 108 109 112 115 116 118 119 120 121 124 126 128 130 136 137 140 141 147 149 153 157 160 162 163 165 167 168 169 170 173 176 179 181 183 186 188 190 195 197 198 200 201 202 204 207 212 214 215 216 217 218 220 221 223 224 226 227 229 230 237 240 243 244 245 246 249 257 258 262 264 265 270 271 273 275 276 281 283 286 291 297 299 300 302 303 305 306 309 316 318 319 322 328 329 334 335 343 346 349 351 352 353 361 363 364 365 367 368 372 376 377 383 385 388 390 391 395 396 398 400 402 403 404 409 410 415 416 420 424 425 426 427 429 432 433 445 447 449 450 451 452 454 455 456 457 461 467 470 474 476 477 479 480 486 488 490 494 499 500 503 508 510 512 513 517 519 521 522 525 527 530 531 532 534 536 542 543 545 548 549 560 561 562 564 568 569 573 580 581 582 585 586 587 590 591 594 604 605 607 609 612 618 620 621 622 624 625 626 627 629 630 633 636 637 638 639 640 644 645 651 652 653 654 655 656 658 659 661 663 666 668 669 673 678 680 682 686 690 692 694 697 698 700 701 703 704 706 707 712 713 714 718 720 723 724 725 727 730 731 734 736 737 741 742 745 748 749 752 753 757 762 765 766 768 772 773 775 778 779 780 781 783 784 786 787 789 790 793 795 797 804 808 810 811 812 813 816 823 824 825 826 838 839 843 844 845 846 850 859 861 863 864 868 871 872 873 874 878 879 881 882 883 885 890 893 897 898 899 905 906 908 909 912 913 916 920 921 923 924 926 936 937 942 945 950 955 956 959 963 971 979 980 982 983 985 988 989 991 992 993 994 996 997 999 +4 5 6 9 10 11 14 15 17 18 21 24 26 28 29 34 38 41 46 49 50 53 56 57 58 68 72 73 77 79 81 84 86 90 91 92 94 96 97 98 99 107 109 112 117 123 125 126 130 131 132 134 136 140 142 143 145 148 149 150 154 161 163 164 171 173 175 177 178 179 181 182 183 184 189 190 191 194 196 197 198 202 208 211 213 214 217 218 226 229 231 233 234 235 239 241 244 252 254 257 258 259 260 263 267 268 273 276 281 286 288 289 290 291 292 294 295 298 299 304 306 308 309 312 314 319 320 321 322 323 325 326 332 333 335 336 341 343 344 349 350 353 355 358 360 363 365 370 376 378 379 382 383 385 387 391 393 398 399 402 404 406 409 410 411 412 413 415 416 419 420 424 425 426 428 429 430 431 434 437 443 444 445 447 450 451 452 453 455 457 459 464 465 466 469 470 473 474 475 478 479 483 485 486 489 490 491 492 493 498 499 501 504 506 510 519 521 526 527 528 529 530 531 534 535 536 539 543 546 548 549 552 554 556 557 559 560 561 562 566 567 570 571 574 576 578 579 580 581 586 592 599 610 612 617 618 621 625 626 627 629 630 634 636 637 639 643 647 650 651 652 654 655 656 657 658 662 664 665 669 672 676 684 686 687 689 691 692 694 696 705 706 711 715 717 718 719 721 723 724 727 729 730 732 735 736 738 740 742 746 747 750 751 754 755 756 757 759 760 761 764 765 767 768 769 771 774 778 784 788 789 791 792 802 804 807 810 813 819 820 824 825 827 828 830 833 836 840 842 843 844 845 846 850 854 857 858 859 860 861 862 863 864 867 869 871 872 879 880 881 884 891 895 900 903 904 909 910 914 918 919 922 923 924 927 928 931 932 940 941 943 944 946 947 948 949 950 952 953 959 962 964 966 968 969 971 972 975 977 979 980 984 985 989 991 +0 1 2 3 7 9 12 18 19 23 24 27 31 35 37 38 39 41 45 47 57 59 61 62 64 66 69 70 71 72 73 76 77 79 82 84 85 87 90 91 94 95 97 99 100 101 106 108 113 114 116 118 124 125 127 128 136 139 152 153 154 157 158 162 165 166 168 175 178 180 181 184 185 189 190 193 196 201 207 208 209 210 215 216 219 221 222 227 232 234 236 237 242 245 246 247 248 253 254 257 260 261 262 265 266 269 270 271 278 279 281 284 285 288 289 290 293 300 307 309 311 313 316 318 319 322 323 327 329 334 336 341 343 346 347 348 349 350 351 353 355 356 359 361 362 363 365 366 368 369 372 374 375 376 377 378 381 382 384 386 388 392 393 397 399 405 406 408 411 414 419 420 422 424 425 428 429 436 438 439 445 447 449 451 452 453 461 465 468 469 473 479 480 482 488 491 492 493 498 500 501 502 503 504 512 513 520 521 523 524 529 536 537 540 545 547 549 550 551 557 558 560 562 563 565 567 572 573 575 576 578 582 583 585 587 593 601 604 607 608 609 612 617 623 630 631 634 635 636 637 639 640 641 643 648 650 653 654 655 658 660 661 662 669 670 671 672 673 675 677 679 680 681 689 690 691 692 693 696 698 703 704 705 708 709 710 712 713 716 721 723 727 729 730 731 732 737 739 744 746 753 760 765 769 774 779 780 783 791 795 797 799 800 806 807 808 810 813 817 820 822 824 825 826 828 829 832 833 834 835 838 839 843 844 845 849 851 855 856 859 863 867 868 871 874 875 876 877 878 882 883 886 888 889 891 899 900 902 903 904 908 909 910 911 913 915 918 920 921 923 924 927 928 930 933 937 938 939 940 942 945 948 951 952 954 956 960 962 963 964 969 970 973 976 977 980 982 984 985 988 989 994 998 999 +4 9 16 21 22 25 28 30 35 38 39 40 41 44 46 49 54 55 56 57 63 66 67 69 70 72 74 77 79 80 81 87 89 91 94 98 99 102 103 105 106 111 112 113 122 124 125 126 128 129 132 139 144 145 148 154 155 156 157 158 159 161 163 164 166 168 170 171 172 173 174 178 179 182 183 187 188 190 192 193 194 196 197 198 201 203 204 205 206 207 209 210 213 215 218 219 220 227 231 232 236 237 239 240 242 243 244 246 248 249 253 255 257 263 265 266 269 271 272 273 274 277 281 284 286 287 288 289 293 295 296 297 300 304 306 307 313 316 317 319 323 324 325 328 330 331 332 335 336 341 342 343 344 345 346 353 354 360 361 362 363 364 366 370 371 372 376 377 378 387 388 391 392 396 397 401 404 406 412 414 416 419 420 421 429 433 434 436 441 443 444 458 462 463 464 467 472 473 488 489 492 495 502 503 506 513 515 518 522 524 526 528 534 535 536 537 538 540 546 547 549 551 553 558 560 561 563 567 568 569 570 572 574 575 577 578 579 583 585 586 590 591 592 595 596 599 605 607 611 613 614 617 621 623 629 630 634 635 637 639 640 641 642 644 645 646 647 650 651 654 659 662 666 667 669 677 680 681 684 686 687 688 697 699 710 720 722 723 724 725 728 732 734 737 739 749 750 753 754 756 757 760 762 765 768 770 772 774 775 779 780 782 783 784 786 791 793 795 800 802 803 805 807 808 809 811 813 815 816 817 819 821 825 828 829 831 836 839 840 844 845 849 856 857 858 859 865 866 870 874 875 877 879 881 882 883 885 888 889 892 893 894 896 900 901 904 907 908 911 912 913 917 919 922 923 929 930 931 932 934 937 939 940 941 943 949 950 953 957 958 959 961 964 965 967 971 972 975 978 981 984 987 991 996 997 +1 4 5 6 8 9 13 14 18 20 22 23 25 26 30 33 34 35 36 37 39 42 43 44 47 49 50 53 55 57 58 59 60 61 62 65 67 68 69 71 79 82 83 84 86 95 96 106 107 108 110 111 114 115 118 119 121 123 126 127 128 129 133 137 140 142 143 144 145 147 148 149 153 155 158 159 163 167 168 175 176 178 182 185 187 188 190 192 194 195 197 198 199 202 209 211 212 214 217 218 219 224 227 230 231 233 236 239 243 246 251 254 255 256 261 263 264 266 269 270 271 278 281 294 295 296 297 298 302 303 307 309 311 312 313 314 319 321 322 324 326 328 331 333 340 343 344 346 347 349 351 355 359 362 363 364 367 368 369 372 373 374 376 377 380 381 386 387 391 393 396 403 408 409 411 416 417 418 419 424 426 428 429 430 431 436 437 441 442 444 448 453 455 456 459 460 462 463 465 471 474 477 478 479 483 485 498 502 507 508 511 513 515 516 518 521 522 523 525 529 531 534 537 538 539 541 546 547 550 553 555 557 559 560 564 568 569 571 572 573 576 578 581 582 583 585 586 587 588 592 594 595 599 600 601 606 621 622 626 627 636 646 648 649 652 654 660 662 663 664 668 674 675 676 677 682 685 688 689 693 694 696 707 708 714 715 718 725 726 729 734 738 739 745 750 751 755 756 757 764 766 767 769 770 772 773 778 779 780 781 782 783 785 786 790 793 796 799 802 804 808 813 815 816 818 820 823 824 830 832 836 837 838 839 841 842 845 849 852 854 855 857 858 865 866 870 874 877 878 879 883 888 890 893 897 898 899 903 904 907 912 914 927 933 939 943 949 951 956 957 965 969 971 972 974 975 976 983 992 994 999 +1 5 6 8 9 13 15 18 20 22 29 30 31 32 33 34 35 36 37 38 43 44 45 47 48 49 55 57 58 60 64 66 69 70 76 80 82 84 87 88 89 91 93 94 95 96 97 98 102 103 104 112 115 120 123 126 128 130 134 135 136 141 142 144 145 146 147 148 150 157 159 160 162 163 165 167 168 170 176 177 178 180 181 184 186 195 196 197 199 203 204 206 207 208 209 214 217 218 219 221 222 225 227 228 230 232 239 241 245 250 252 255 259 266 268 271 272 274 275 278 280 284 285 288 292 293 296 297 300 303 305 307 311 312 318 320 321 324 329 331 332 333 334 337 338 339 340 341 347 348 351 354 356 359 364 366 369 372 375 378 379 381 383 384 386 388 389 390 392 393 394 395 397 401 402 414 415 417 418 423 426 428 429 431 433 435 437 438 442 443 445 447 448 449 450 453 457 458 460 461 467 472 475 477 479 480 482 483 486 488 490 491 492 494 495 500 502 505 514 515 516 517 518 519 520 531 533 535 543 546 548 549 550 553 554 556 558 559 565 566 572 575 579 582 584 588 589 590 594 599 600 602 603 606 607 610 612 613 614 616 618 621 626 629 630 635 637 638 639 640 641 645 646 647 648 649 652 658 659 660 661 666 667 669 670 671 672 673 680 681 683 685 686 693 698 700 702 704 705 709 710 711 713 714 720 721 722 725 729 735 737 738 739 742 745 746 750 751 753 755 757 758 760 765 766 767 768 769 770 772 773 774 776 779 781 783 789 790 791 792 793 795 797 802 803 805 807 809 810 812 814 817 818 819 823 824 826 828 829 831 833 836 839 840 841 845 848 849 851 852 854 857 859 860 861 866 867 869 872 876 877 878 882 885 888 889 891 892 895 899 904 907 909 910 917 919 924 926 927 928 929 930 932 934 935 937 938 939 941 944 945 948 963 964 965 968 969 974 975 976 977 981 982 984 985 987 988 991 992 996 999 +0 2 3 7 9 10 13 15 17 19 22 26 27 28 33 35 36 37 43 57 59 64 66 73 74 76 81 82 84 87 90 92 94 96 98 100 102 106 108 111 113 114 119 121 122 124 127 128 130 131 132 134 136 137 140 147 149 150 151 154 155 156 162 168 169 171 173 175 177 181 182 184 185 186 188 193 195 196 197 198 199 200 202 203 207 209 210 212 215 216 218 222 223 224 229 235 236 243 245 247 248 251 252 253 255 258 259 260 265 266 269 272 275 278 279 283 286 289 290 293 297 298 300 303 306 307 311 313 314 317 319 325 330 334 336 337 339 347 348 349 353 355 358 359 360 361 362 363 365 368 369 370 371 372 375 377 378 379 383 384 388 390 392 393 395 398 400 401 403 404 408 409 413 414 416 417 423 424 425 426 427 428 429 430 433 435 438 440 441 442 443 446 449 450 451 452 454 459 460 461 462 464 466 467 470 473 474 475 478 479 480 482 483 484 485 486 487 493 494 495 500 501 502 506 509 515 517 519 520 532 533 540 541 543 545 548 550 552 554 557 558 564 569 570 571 572 574 575 576 582 583 590 592 595 600 602 606 608 609 610 619 624 625 626 629 630 631 635 636 640 642 643 645 652 653 654 655 658 659 662 663 664 666 667 668 670 673 682 683 685 689 691 693 696 697 699 701 702 703 705 707 708 715 718 719 725 728 733 734 738 739 749 750 753 756 757 765 766 771 773 774 775 779 782 784 786 788 789 793 794 795 796 797 798 799 800 801 803 804 805 807 808 809 812 813 819 820 822 823 825 834 842 843 844 846 847 849 850 851 853 856 857 860 861 862 863 865 867 868 870 874 877 878 879 880 881 886 888 891 893 896 899 907 908 909 912 915 916 918 919 921 922 924 929 934 936 938 941 943 950 955 957 959 961 965 966 968 969 970 971 976 977 988 990 992 993 996 +0 1 2 3 4 10 12 14 15 17 19 21 23 29 31 32 40 43 44 45 48 49 50 51 52 57 58 64 67 68 71 73 77 87 88 89 92 93 94 96 97 101 102 103 110 111 113 119 121 128 132 133 137 138 140 142 143 144 145 147 151 152 153 155 157 158 160 165 167 169 173 174 175 176 178 179 181 182 184 186 188 189 192 193 196 201 202 204 205 208 209 211 214 215 218 225 227 229 234 235 236 237 241 251 252 259 261 266 270 273 274 276 280 283 284 288 289 290 293 295 297 298 300 303 304 306 308 310 312 314 315 316 319 320 321 322 325 326 327 329 334 338 340 341 342 346 348 349 352 353 358 359 362 365 369 372 373 374 375 379 381 382 383 385 388 390 391 393 395 398 399 403 406 410 413 414 418 420 421 422 426 434 443 444 446 447 450 453 454 456 459 460 461 463 464 467 469 470 472 474 475 478 481 482 483 484 486 487 488 489 490 491 492 497 499 500 502 503 504 508 512 513 514 518 522 523 526 530 534 536 537 540 545 546 547 549 550 551 552 554 559 560 561 562 566 567 570 572 573 575 578 580 582 583 584 586 587 588 590 592 594 595 600 601 603 609 611 612 613 615 620 621 623 624 626 628 634 635 636 637 639 640 647 650 657 661 665 674 678 682 686 687 689 691 692 695 696 697 698 700 702 704 705 708 709 710 711 713 716 717 718 719 720 722 723 725 726 728 732 733 737 741 742 745 746 749 757 763 765 766 769 770 774 776 779 784 786 787 789 793 794 798 801 802 805 809 810 811 814 817 818 821 824 827 831 832 836 837 841 842 843 844 846 847 849 854 855 856 857 861 864 865 867 868 869 872 875 881 883 893 894 896 899 903 907 908 909 910 917 918 919 921 923 924 926 928 932 934 942 943 946 947 949 954 958 960 961 967 968 973 975 979 983 984 985 986 988 989 991 993 995 997 +6 7 12 14 15 18 20 24 26 29 31 33 34 38 42 43 45 49 50 51 53 56 57 58 59 60 62 63 65 66 67 71 73 75 82 83 85 86 90 91 92 95 97 99 101 104 107 111 113 115 117 123 124 126 127 133 139 142 143 145 154 162 163 164 168 169 170 174 175 177 182 184 185 188 189 190 193 194 200 202 203 205 207 208 210 212 214 215 219 220 223 225 231 233 236 239 240 241 242 259 261 264 267 268 269 270 271 274 276 278 281 282 283 288 293 295 296 297 300 301 305 310 313 314 316 318 321 322 328 329 331 332 334 335 339 340 342 348 349 354 358 359 360 362 363 365 367 369 371 372 373 374 375 389 390 392 396 398 399 401 402 403 404 405 412 415 418 420 428 429 430 432 435 440 442 443 444 446 447 455 456 460 461 462 466 468 470 471 472 473 474 478 481 482 483 484 486 487 488 490 491 499 500 503 505 506 507 509 511 513 518 519 522 523 529 530 531 534 535 537 539 540 541 542 551 552 554 555 556 559 566 568 573 578 586 590 595 596 600 606 608 611 615 617 619 622 623 630 631 632 637 641 642 646 650 651 653 658 659 662 663 664 665 667 668 669 675 676 679 683 688 689 692 694 695 696 699 700 701 702 704 706 707 715 716 718 733 737 738 740 743 757 758 759 761 762 763 766 767 768 769 773 776 783 785 788 789 792 793 794 795 796 797 798 799 801 802 805 806 807 809 813 817 818 820 824 832 833 835 839 840 843 844 848 851 852 857 859 860 863 865 870 874 875 876 877 881 882 886 887 888 892 894 895 901 902 907 909 910 911 916 919 921 928 934 937 942 943 949 950 951 952 955 958 959 960 963 967 968 970 972 973 975 978 979 980 982 986 991 992 993 996 997 +3 4 5 8 12 13 15 19 23 27 29 30 31 35 38 40 41 42 44 47 48 50 54 55 57 60 66 68 70 71 76 77 80 83 87 91 92 97 99 100 101 102 104 106 109 110 111 112 113 116 118 120 122 123 126 128 132 135 140 142 145 146 147 149 151 155 158 161 168 172 175 177 178 180 182 184 188 189 194 195 202 203 204 206 207 211 213 214 216 219 220 221 222 223 226 229 232 235 236 237 238 239 243 249 253 255 256 262 263 265 267 271 272 281 283 284 285 286 288 291 294 298 300 301 303 305 306 307 309 310 311 312 313 314 315 319 320 321 326 327 330 331 334 335 336 340 341 346 350 351 352 353 358 359 362 365 367 368 377 380 381 383 385 390 395 398 400 402 406 407 409 410 411 413 417 418 419 421 422 425 427 433 434 436 442 444 446 447 449 452 455 456 457 460 464 466 473 475 478 484 485 488 489 491 495 498 500 502 505 508 509 512 513 515 516 519 520 521 525 526 530 531 532 533 538 539 541 543 545 546 550 551 554 557 558 560 566 571 574 576 581 582 584 585 587 589 590 591 594 596 597 598 600 601 602 605 606 609 615 616 619 620 621 627 628 631 636 638 643 644 647 648 651 652 654 656 659 660 661 663 664 665 666 672 674 680 684 686 690 691 692 695 697 700 702 704 705 706 708 709 710 712 714 720 723 725 727 729 734 736 737 740 748 749 751 752 756 757 758 761 768 769 776 779 780 783 786 787 788 792 793 794 798 799 804 811 814 815 816 817 822 824 825 826 827 830 833 834 835 841 842 845 847 856 860 861 863 866 869 870 871 872 875 878 879 881 882 883 884 885 888 889 894 899 903 906 909 912 913 914 915 918 920 922 923 925 926 930 933 934 937 939 940 943 944 945 948 951 953 957 958 963 966 968 971 972 973 975 977 978 982 985 987 989 993 999 +0 1 2 6 7 9 10 12 15 17 20 21 25 26 33 35 36 38 41 44 45 53 55 56 57 62 65 68 69 73 74 78 79 80 81 83 87 89 99 104 105 108 111 112 115 119 121 134 139 143 145 147 150 151 154 156 157 165 167 170 172 173 174 175 178 179 180 183 184 185 187 188 189 190 194 195 200 205 206 211 214 219 220 221 226 228 229 234 235 236 244 245 248 249 251 252 260 262 264 266 268 270 271 274 277 278 283 284 285 286 290 291 293 294 298 300 307 308 309 312 314 315 316 317 318 319 320 321 323 324 327 328 333 338 339 341 342 343 345 346 348 352 358 360 361 365 367 368 369 370 372 375 376 384 387 388 389 393 394 395 396 398 404 406 407 412 413 414 415 419 421 423 427 428 429 431 439 442 445 447 448 449 452 454 458 465 470 472 473 474 476 477 478 480 481 483 484 487 488 490 491 494 496 497 501 505 506 511 514 518 519 520 521 526 529 530 531 533 536 538 546 547 548 556 558 560 561 562 563 566 570 571 572 574 575 578 579 580 584 587 594 595 597 598 601 603 604 608 610 613 616 628 629 630 637 643 645 649 650 653 655 663 664 672 673 679 680 681 682 685 687 688 695 697 701 705 707 710 717 725 726 729 730 731 732 734 735 736 740 742 743 745 746 747 749 751 752 755 756 757 763 766 771 773 774 776 779 781 785 789 790 793 794 796 797 800 802 803 804 805 806 809 811 813 815 820 821 824 825 830 832 834 841 842 843 845 847 848 852 854 856 859 860 861 865 873 874 876 880 885 888 891 893 894 895 896 897 898 899 901 903 904 908 909 910 911 915 929 930 931 933 936 940 941 942 947 948 950 951 952 953 954 955 962 966 968 970 972 973 974 978 981 985 987 995 996 997 998 999 +0 3 8 12 16 18 28 29 32 36 41 47 48 51 52 53 55 56 59 60 61 65 72 76 79 90 93 94 95 98 99 101 105 106 107 108 111 113 115 117 119 120 123 124 125 126 127 128 129 130 132 135 137 139 142 147 150 152 156 158 162 163 166 168 172 174 177 180 186 188 189 191 192 200 204 205 206 208 209 210 211 213 214 216 217 219 222 225 226 227 231 232 233 236 238 239 242 244 245 246 250 251 252 255 256 259 260 266 271 272 273 274 275 277 280 283 285 287 290 291 293 297 298 302 305 306 308 311 315 316 320 323 325 327 328 329 331 334 336 337 338 346 349 352 361 362 363 370 374 381 383 385 389 393 394 397 404 408 409 413 421 422 423 424 425 426 427 428 433 435 437 438 440 442 445 447 448 450 451 452 454 460 461 466 471 474 480 481 486 488 489 490 491 492 493 495 496 499 500 502 507 508 509 516 517 521 522 523 526 531 532 534 536 538 542 544 545 549 559 562 564 565 567 568 574 576 577 582 584 585 587 588 590 591 595 597 599 602 609 610 614 616 617 621 624 625 627 628 629 633 637 641 644 646 648 649 650 652 656 658 659 666 669 672 673 675 678 679 685 686 688 690 692 693 696 699 701 703 704 712 716 719 727 730 733 734 735 737 742 743 748 750 752 753 754 762 764 765 766 767 771 773 775 777 780 781 783 786 790 793 795 799 803 806 810 811 815 816 824 827 829 830 833 842 844 853 859 861 864 871 873 874 876 881 884 886 892 895 899 902 903 907 908 912 913 916 918 921 924 926 927 928 937 943 944 946 947 948 953 964 966 967 968 969 975 980 981 983 988 991 992 994 995 996 +2 4 5 7 8 9 10 12 20 21 23 25 28 30 31 34 35 37 39 42 44 46 48 49 54 55 59 62 65 68 72 74 75 76 77 79 81 82 91 92 93 94 96 98 99 100 101 102 105 107 108 110 111 112 121 124 126 127 128 131 132 133 136 139 140 147 148 150 152 157 159 160 165 167 171 183 184 185 189 192 199 203 204 205 207 208 210 215 216 219 220 221 222 223 229 234 244 245 248 251 260 262 265 270 271 277 279 281 285 286 288 289 291 293 294 295 296 298 301 302 305 307 308 309 311 313 315 316 317 319 320 322 325 326 330 331 333 336 337 339 343 345 348 349 360 361 363 366 367 368 370 371 374 376 378 381 383 384 385 387 388 391 400 401 402 405 409 412 413 415 422 425 429 432 435 436 440 444 445 446 447 450 457 458 463 467 470 471 474 479 483 488 489 490 491 496 504 510 512 513 519 521 523 526 528 531 532 533 535 542 549 550 552 561 562 564 566 567 574 578 585 586 587 594 596 597 598 599 603 606 609 612 614 615 616 617 621 622 624 628 630 634 635 636 641 644 648 649 656 660 661 665 666 668 669 670 680 682 683 684 685 689 691 694 697 699 700 706 707 711 715 717 721 722 723 724 725 726 734 737 738 739 740 742 746 747 748 751 753 754 763 768 773 775 776 777 782 783 787 790 793 797 801 802 804 807 810 819 820 822 827 834 837 842 843 848 852 858 860 864 866 867 869 871 872 875 876 877 880 881 884 888 889 890 891 894 897 899 900 901 902 907 908 910 913 914 915 917 920 922 923 924 925 927 929 930 931 932 933 939 943 944 945 947 949 950 951 955 959 960 961 962 966 968 970 971 980 981 988 990 996 998 999 +5 9 10 14 16 18 22 25 26 32 39 41 42 43 46 47 50 52 53 56 57 58 59 61 63 64 68 71 74 75 90 95 97 99 101 102 105 111 112 113 116 117 124 125 126 127 129 133 135 137 138 139 143 147 153 154 155 157 158 160 163 175 178 179 183 184 185 187 189 190 193 207 208 209 210 211 212 213 216 217 219 222 223 226 228 233 236 239 240 241 242 245 246 252 253 254 257 258 265 266 267 268 274 275 279 280 285 291 294 295 297 300 302 303 305 316 319 320 321 322 324 325 326 329 330 331 335 337 339 341 342 343 345 346 348 351 353 355 356 359 364 365 367 368 369 370 371 376 377 380 381 385 387 389 394 395 397 398 399 401 407 409 412 414 415 416 419 421 423 426 431 432 433 434 435 440 442 447 448 449 453 454 456 458 463 465 467 471 475 477 478 481 482 493 494 498 500 501 502 504 505 508 509 511 512 513 514 515 516 521 523 526 527 529 530 531 532 533 536 542 543 545 549 554 557 559 561 562 568 569 572 574 575 579 581 582 589 594 596 598 599 600 604 607 611 614 616 617 618 621 624 626 628 629 630 631 638 643 645 651 653 654 656 659 663 665 668 669 671 680 685 688 692 695 696 697 698 701 705 708 713 715 717 718 720 721 722 723 724 726 731 732 733 734 738 740 745 750 751 752 753 754 755 756 757 758 759 762 765 768 769 770 772 775 778 782 788 790 791 793 794 795 798 801 804 806 809 813 814 817 818 819 821 822 826 828 831 833 835 837 838 840 841 845 848 851 855 857 864 866 867 869 871 880 883 888 889 890 891 893 894 895 897 900 902 903 907 909 910 914 917 918 923 924 925 927 928 929 930 934 936 945 949 952 954 955 956 961 964 965 966 972 973 974 978 979 980 982 983 984 985 987 989 996 997 998 +0 1 3 6 7 8 9 11 13 15 20 25 26 27 28 30 34 35 36 39 46 47 49 52 55 57 58 60 62 63 64 66 73 75 79 80 86 88 89 90 91 93 98 100 102 104 105 106 109 111 114 115 118 121 123 128 133 137 140 142 144 145 148 152 154 155 158 160 161 162 168 171 175 177 178 179 182 185 186 192 193 194 196 197 201 202 206 207 208 212 213 214 217 218 220 224 225 234 236 238 241 243 244 246 247 248 249 255 256 261 262 266 268 269 272 273 274 275 276 280 282 285 288 289 290 293 298 301 302 303 304 311 315 317 318 321 322 327 335 336 337 342 344 348 350 359 360 362 363 365 369 370 374 376 381 383 385 386 387 388 392 394 400 402 404 406 407 410 416 418 419 422 425 426 432 434 438 442 444 446 447 449 452 457 458 460 461 462 465 467 469 470 473 476 477 478 479 480 481 483 484 486 488 493 495 496 498 499 504 506 512 517 521 522 523 524 528 532 533 535 537 538 540 541 543 544 546 547 551 552 553 566 567 569 570 571 572 575 577 580 581 582 585 588 589 593 604 609 612 613 615 618 619 621 623 624 631 635 636 637 639 643 644 647 648 649 650 651 652 655 656 660 666 668 669 672 673 674 676 678 679 680 683 690 692 694 696 699 701 702 704 706 712 713 714 719 729 730 733 737 738 740 741 746 750 754 758 767 768 770 773 779 780 784 786 787 791 792 797 799 804 808 810 812 816 818 819 820 821 825 828 830 834 835 839 840 843 845 850 854 858 862 864 866 870 872 873 876 880 882 891 892 894 897 902 905 907 908 910 917 920 923 927 929 931 932 933 934 935 936 937 938 940 944 946 948 951 953 962 965 966 968 969 970 971 973 975 976 983 985 989 991 993 994 997 998 999 +0 1 6 8 11 13 16 18 20 24 25 31 33 35 38 39 40 46 47 48 50 52 55 58 59 63 64 68 71 72 73 76 78 81 84 85 90 94 96 97 100 104 106 114 117 120 128 130 131 137 138 139 143 144 145 149 150 152 153 159 160 162 164 165 166 167 169 172 173 174 179 180 184 185 187 194 197 198 202 204 205 206 207 209 213 223 225 230 231 235 236 238 239 241 242 245 250 251 253 254 257 258 260 261 263 265 266 269 271 274 275 276 280 284 285 291 292 294 295 296 297 298 302 303 306 310 312 313 315 317 320 321 326 329 331 332 336 337 340 341 342 347 348 349 351 352 353 355 358 363 365 368 370 372 373 377 380 385 386 389 393 394 398 399 402 405 409 413 418 421 423 425 427 431 432 433 438 439 440 443 445 448 451 452 453 454 456 458 460 463 466 467 468 470 473 475 481 487 490 494 496 498 499 504 507 511 512 513 516 522 524 527 530 532 537 541 542 543 544 546 548 549 551 554 559 560 562 563 566 568 571 574 575 577 578 580 582 583 584 587 591 593 594 595 602 605 610 611 615 617 619 620 622 624 626 631 634 637 639 640 644 645 647 650 656 659 661 665 666 670 671 672 674 684 687 690 693 696 699 701 703 704 708 715 722 723 728 732 734 737 738 744 745 746 747 752 755 757 758 759 762 766 771 772 773 774 777 786 788 791 792 793 794 796 797 800 801 802 803 804 805 807 810 811 814 818 823 825 826 827 829 831 836 838 839 841 849 850 851 852 854 859 867 873 875 876 880 882 886 888 889 891 892 893 894 897 898 900 904 905 908 909 910 912 917 918 921 923 924 926 927 928 930 940 941 944 948 949 952 953 954 956 958 959 960 962 964 966 967 972 974 975 976 978 985 986 987 990 992 995 996 999 +0 2 3 7 10 16 20 22 24 25 27 30 31 32 35 37 41 44 45 49 54 55 63 64 66 68 71 73 77 80 82 83 89 101 102 104 112 114 128 132 133 135 137 138 139 140 145 149 153 158 159 161 167 169 173 175 177 180 182 183 189 191 192 194 195 196 199 200 203 204 206 207 208 209 212 214 216 218 219 220 229 232 233 234 238 240 246 252 254 256 258 262 264 265 266 276 285 288 292 294 295 296 299 301 302 305 306 307 308 310 312 317 324 325 326 331 333 339 340 345 346 347 348 350 351 353 361 366 369 372 375 376 378 380 381 382 385 389 391 393 394 398 401 403 405 406 408 409 416 417 418 419 424 425 426 430 432 436 437 438 440 441 442 443 445 447 450 451 453 454 456 459 460 465 468 469 471 472 474 477 479 481 483 487 493 495 500 502 503 505 506 507 508 513 515 523 524 530 532 533 535 536 538 540 541 542 543 547 548 550 554 555 565 568 572 573 574 576 577 579 582 583 585 586 587 591 592 593 599 603 607 609 610 612 614 615 617 620 623 630 633 636 639 641 642 643 649 651 655 656 657 663 669 671 672 673 674 677 682 683 684 687 688 689 690 692 694 695 697 700 703 707 710 712 713 717 723 725 726 727 729 732 734 735 737 738 742 743 744 746 748 752 753 754 756 757 758 760 762 764 766 768 769 770 771 773 777 778 781 787 789 791 796 797 798 802 804 805 807 808 814 815 817 819 823 824 830 831 837 841 843 844 854 855 856 858 859 860 864 869 870 872 874 875 876 877 878 881 882 885 896 897 898 899 900 904 906 910 912 913 914 916 917 919 921 923 924 925 928 929 930 935 936 941 944 950 951 953 956 957 962 964 966 967 972 975 979 980 982 987 991 992 993 994 997 999 +3 4 7 9 15 17 23 25 30 31 33 51 54 56 63 67 68 76 77 78 79 80 82 85 88 89 90 91 92 100 101 104 107 108 109 110 111 112 113 116 122 124 129 131 140 142 146 150 154 155 157 159 161 162 164 168 169 171 176 181 186 190 191 192 193 201 203 207 208 210 211 212 213 214 215 222 228 230 233 234 237 238 244 246 247 248 249 250 251 261 262 264 265 268 269 272 274 275 281 283 284 286 288 289 292 294 300 301 303 306 307 308 313 314 319 321 323 324 325 327 328 332 335 345 349 354 356 358 359 360 366 371 374 375 379 382 384 385 386 391 394 395 402 403 404 408 410 411 413 418 423 425 426 427 429 431 432 437 444 446 449 451 452 455 456 457 458 461 465 467 470 473 477 479 480 482 484 485 487 488 489 490 492 497 499 500 501 505 506 507 508 509 511 517 518 519 522 525 528 529 531 532 536 537 538 539 540 543 545 548 555 556 558 564 566 571 573 578 585 590 591 592 596 603 606 607 609 611 613 615 621 625 626 628 634 635 636 638 642 649 650 652 653 654 663 668 669 672 673 675 680 683 684 688 690 691 692 695 696 697 700 705 706 708 709 711 713 716 717 719 727 732 734 737 741 743 744 746 747 749 753 758 761 762 763 766 768 769 774 775 779 784 788 791 793 795 800 801 807 808 812 815 821 822 823 827 829 830 835 836 839 842 844 847 848 851 853 855 859 862 863 865 868 869 877 878 883 884 885 889 890 893 898 900 905 906 910 911 917 922 924 927 928 932 935 937 938 942 945 947 950 951 952 956 958 965 967 968 970 973 981 983 985 988 993 994 997 998 999 +0 1 3 6 8 10 13 15 18 19 20 23 24 25 30 31 33 35 36 44 45 46 47 48 49 51 53 54 70 72 74 77 78 79 81 83 85 89 90 93 94 97 98 99 100 102 106 109 110 114 115 116 117 119 122 123 125 127 128 131 132 133 140 142 150 152 154 155 157 163 167 168 172 173 174 175 177 179 184 186 188 191 196 198 199 200 203 204 208 209 210 211 212 214 220 221 223 224 230 234 235 237 240 243 251 253 254 256 260 261 266 270 272 274 277 279 280 285 286 289 292 293 296 297 298 299 302 304 307 310 311 314 315 319 321 324 330 334 335 336 338 340 342 344 345 347 349 350 351 352 354 355 361 362 363 365 371 373 375 377 383 385 391 392 395 396 397 399 403 405 406 408 412 415 418 419 428 430 432 434 436 438 439 441 442 445 446 447 449 454 456 457 461 463 465 467 469 476 477 479 482 487 488 491 495 501 503 508 509 512 513 515 518 521 522 525 527 528 529 531 532 534 535 538 541 544 545 547 549 553 555 556 560 564 565 566 570 572 574 575 576 579 581 582 584 590 591 593 595 598 602 605 606 608 609 612 614 617 620 621 624 628 631 633 635 637 640 643 644 648 650 653 655 659 660 662 663 665 669 671 672 673 674 675 676 677 678 680 682 683 686 689 690 693 694 695 697 698 702 704 707 708 710 714 715 716 717 718 722 723 724 725 727 729 730 731 732 733 734 736 738 744 747 750 753 759 763 769 771 773 774 778 780 782 784 790 796 798 799 801 802 803 808 814 816 819 820 824 826 828 829 832 845 854 855 856 857 858 859 863 864 865 867 874 875 876 878 881 883 887 890 892 898 901 903 906 908 910 912 913 914 918 922 923 924 927 931 932 938 939 942 944 945 946 947 949 951 952 953 954 955 956 961 962 967 968 970 972 973 974 976 977 978 980 984 990 991 993 995 996 997 999 +3 6 7 8 11 13 19 20 21 22 23 32 33 35 38 39 40 42 43 45 47 48 50 53 54 56 57 58 63 64 65 69 72 75 78 79 80 83 84 85 86 87 89 92 93 98 99 102 103 106 107 109 117 120 121 122 123 125 126 127 131 134 140 141 143 145 149 151 152 153 155 156 158 160 161 162 164 167 168 171 172 174 175 177 178 184 186 188 198 203 204 205 206 208 209 210 211 215 218 222 224 225 226 232 233 238 239 240 242 245 247 248 250 254 255 256 257 259 260 261 266 268 285 290 294 300 302 305 306 308 311 321 326 327 329 333 336 337 344 346 348 349 350 353 356 358 364 367 374 379 384 390 393 394 397 398 402 406 416 420 425 428 429 430 431 432 433 434 440 442 443 444 445 447 449 451 453 455 457 461 464 465 469 475 480 483 489 490 491 498 505 508 512 516 518 521 525 526 532 537 540 546 547 548 550 551 553 555 557 560 562 566 567 568 570 571 572 573 574 578 579 581 582 583 586 587 588 589 593 594 596 598 602 603 605 606 609 610 611 612 614 618 619 620 622 628 629 631 632 633 634 635 639 640 642 647 648 655 656 657 658 661 663 664 669 670 671 676 679 680 681 683 684 687 689 697 698 699 702 704 705 706 707 712 713 715 717 720 721 724 729 736 737 738 744 749 750 755 756 761 765 766 773 774 776 777 782 784 785 787 790 791 792 793 797 803 806 808 809 817 819 820 827 828 830 834 836 839 840 841 847 848 850 859 860 862 864 866 867 868 869 870 872 873 876 877 881 882 892 897 900 904 906 907 909 911 912 913 917 919 920 921 922 928 929 930 932 933 934 935 938 941 944 945 947 948 949 953 954 965 967 970 971 978 982 985 991 992 995 999 +0 1 3 9 18 19 21 24 25 26 27 29 30 34 35 37 38 39 40 41 43 44 45 47 48 49 53 58 59 60 62 65 68 69 71 73 83 87 88 97 100 101 105 106 107 108 113 122 123 124 128 130 132 138 140 147 150 153 158 159 161 164 165 168 169 170 174 177 178 180 181 182 183 184 185 186 191 194 197 202 203 209 214 215 216 217 218 222 226 227 228 237 238 240 242 246 247 248 255 257 258 259 261 264 266 267 271 273 274 275 278 279 282 284 286 295 299 310 311 318 320 322 323 325 326 328 330 332 334 336 339 340 342 343 352 353 354 356 361 362 365 369 370 373 380 383 392 396 399 404 406 408 411 412 413 414 426 429 431 434 438 441 443 444 446 447 448 451 452 453 454 455 462 465 467 472 474 475 477 482 484 485 486 494 497 498 499 501 502 508 509 510 514 517 520 523 524 531 532 533 534 535 549 550 551 553 554 556 559 560 561 564 565 566 572 575 577 580 584 585 587 588 592 593 595 602 603 606 609 614 615 617 620 624 625 626 628 633 634 637 638 645 646 647 648 651 652 657 661 664 666 669 671 673 675 679 682 685 690 695 703 704 705 706 708 711 712 713 716 720 721 726 727 729 730 731 732 735 737 738 740 741 745 748 751 752 754 756 758 761 766 767 772 773 774 775 777 778 785 786 787 789 791 794 795 801 802 804 805 806 807 808 815 819 820 828 833 834 835 836 841 842 843 849 853 857 861 862 866 868 869 870 871 872 873 874 876 877 879 884 886 892 897 900 902 907 909 910 911 915 916 918 919 922 927 930 931 933 935 936 937 940 941 942 945 946 947 948 950 954 957 958 959 961 962 967 970 972 974 975 977 979 980 982 987 995 997 999 +0 3 4 6 8 10 11 12 14 15 16 18 19 20 22 25 26 27 29 30 31 33 37 40 41 42 44 45 46 47 48 50 52 53 54 56 57 58 60 63 65 73 74 76 83 84 86 88 89 92 95 96 98 99 105 106 108 114 118 119 121 122 124 125 126 128 131 134 135 136 137 139 141 142 143 146 149 150 151 153 159 163 166 167 170 172 173 174 175 179 181 182 183 184 190 192 196 200 204 209 210 212 215 217 219 220 224 226 231 233 241 242 244 246 250 251 253 258 259 260 261 267 271 273 274 279 280 285 287 290 291 292 295 298 299 301 304 310 315 317 320 322 325 329 330 331 332 333 334 336 337 340 342 343 347 348 351 352 353 355 360 363 365 367 369 370 374 375 376 380 381 383 385 388 392 394 395 396 400 401 403 414 415 416 417 418 423 426 428 430 431 432 435 436 440 441 442 443 448 453 456 459 461 462 465 469 470 474 477 478 479 481 483 484 485 493 494 497 499 500 502 504 507 508 510 511 513 517 518 519 524 526 529 534 535 536 540 542 543 544 545 546 550 552 554 555 560 565 572 577 578 579 583 585 586 587 588 594 595 596 598 600 602 605 606 608 609 611 613 614 617 618 619 621 623 624 625 629 634 635 636 639 647 650 651 654 655 656 657 660 662 667 669 671 674 675 681 685 686 689 690 691 692 693 694 695 698 699 703 707 711 712 713 716 719 726 731 732 734 735 736 741 742 748 750 751 753 754 756 757 758 759 760 762 764 765 767 768 771 773 774 775 777 779 781 786 795 799 800 801 810 811 812 813 814 816 817 822 824 825 826 828 834 836 840 841 844 845 847 849 855 857 862 867 868 869 872 879 880 883 886 888 891 892 893 894 895 896 899 902 903 905 918 923 925 931 932 933 935 937 938 942 943 944 959 960 961 963 965 969 973 974 978 980 983 985 987 990 993 994 997 +0 2 5 6 9 12 24 27 28 30 33 37 38 39 43 44 45 51 52 54 56 57 58 59 62 63 72 78 79 81 82 92 93 95 96 99 100 102 105 106 107 113 114 116 117 118 123 130 136 142 149 154 156 159 164 169 171 175 176 180 182 183 184 188 189 190 192 195 196 197 198 201 202 203 204 205 208 210 213 214 215 218 220 224 227 231 234 236 237 238 240 241 243 245 247 248 249 250 255 263 266 268 271 272 280 281 283 285 286 287 289 292 295 298 304 306 307 313 317 318 326 328 333 336 339 340 346 351 354 355 357 360 362 363 367 370 372 374 378 381 382 383 385 387 389 390 392 393 396 397 401 404 409 410 411 415 416 418 419 422 425 427 428 429 436 438 439 440 441 444 446 453 454 455 459 460 461 463 467 468 469 474 475 481 486 488 490 491 492 493 494 497 498 500 501 507 508 509 510 512 514 515 517 518 519 522 523 524 527 535 537 538 539 540 541 542 544 547 549 552 553 556 560 562 563 565 566 567 572 573 574 575 578 579 580 582 584 585 586 587 596 598 599 600 603 604 613 614 615 617 620 621 622 624 626 627 628 633 640 646 648 656 659 660 661 665 667 669 671 675 677 679 683 684 685 689 691 696 698 699 700 706 709 710 712 713 716 717 719 720 722 724 729 732 733 735 736 737 739 742 744 745 746 748 749 750 751 752 753 756 758 763 766 770 772 773 775 778 781 784 785 787 789 791 793 799 802 803 807 808 810 816 819 822 824 826 827 828 830 831 840 844 845 846 848 849 857 863 865 867 869 870 873 878 880 881 886 890 891 892 896 902 904 905 906 911 919 924 925 929 932 933 934 939 941 942 946 948 950 951 957 960 961 964 967 968 969 971 976 978 981 983 985 987 988 989 990 991 993 994 995 998 999 +1 3 6 9 10 15 21 30 33 35 36 38 40 43 44 47 48 50 53 54 56 57 58 59 64 66 68 69 75 77 78 80 86 87 90 95 97 98 102 109 113 116 117 118 119 121 122 123 125 127 128 133 134 136 137 139 140 143 144 145 146 147 148 150 151 153 154 156 157 159 162 163 164 166 169 170 171 182 189 192 193 195 196 197 202 204 205 207 209 214 216 217 218 219 221 222 226 232 235 238 246 247 251 256 257 258 259 263 264 268 269 272 277 278 280 281 284 287 289 290 296 298 299 300 302 303 304 306 307 313 315 317 319 321 322 328 330 331 333 334 339 340 345 350 351 353 355 356 357 358 362 368 369 370 371 372 375 376 378 379 380 388 389 390 397 402 407 408 409 410 412 416 421 422 423 424 425 426 428 430 431 432 434 437 441 442 443 445 448 449 451 452 453 456 460 462 463 466 467 471 473 478 482 487 489 492 493 494 495 498 500 501 503 510 512 519 520 523 526 528 529 535 536 537 538 539 540 543 545 546 549 550 556 557 559 563 564 565 568 570 573 574 577 578 580 581 584 585 587 588 590 591 594 595 597 598 609 611 613 614 621 623 631 634 637 640 641 642 645 648 650 651 652 654 655 657 659 660 661 663 669 670 676 681 682 685 690 691 695 696 697 699 702 703 708 712 713 717 723 725 730 731 734 735 738 739 741 743 744 745 753 755 757 758 760 763 766 769 771 773 774 777 780 783 784 785 789 791 793 797 800 810 811 813 815 819 820 822 824 826 828 829 830 833 841 842 844 847 849 851 855 857 860 863 867 868 869 878 879 881 882 883 886 887 889 891 896 901 902 904 908 910 911 914 918 919 922 924 925 926 927 929 935 939 941 942 946 948 950 955 956 957 961 966 968 970 975 982 986 988 989 990 996 998 999 +0 1 2 3 4 5 9 11 12 13 15 17 18 23 26 27 28 29 35 38 39 40 41 43 44 45 47 48 49 50 52 53 56 57 58 61 62 63 71 72 74 75 77 78 83 84 86 87 88 90 91 92 97 99 108 119 121 122 123 125 126 130 131 132 133 136 141 142 143 145 149 151 155 156 158 159 164 168 169 170 171 173 177 178 179 180 183 184 192 193 199 204 206 208 211 214 215 223 226 228 229 230 231 233 238 240 241 247 250 251 252 253 255 259 261 267 268 269 270 271 274 275 278 283 287 288 290 291 292 294 296 297 298 299 301 302 303 310 312 313 319 321 322 323 324 325 328 333 337 340 341 342 343 347 348 349 352 353 356 360 364 365 367 368 370 372 376 380 385 388 389 390 391 392 394 396 399 406 411 412 416 417 420 421 423 424 425 426 429 433 434 436 439 441 446 447 451 453 458 459 460 461 465 467 471 472 473 474 480 482 483 486 487 489 494 497 504 506 507 511 513 515 517 522 523 525 527 528 529 530 535 541 542 543 544 545 547 556 557 566 567 568 574 579 582 584 585 587 594 595 599 601 605 606 609 610 611 612 613 615 619 620 624 625 626 628 629 630 632 635 637 639 640 642 643 646 651 652 653 656 657 658 660 661 664 665 670 671 673 676 679 683 686 688 693 695 698 699 701 702 704 705 706 710 711 715 717 718 719 720 721 723 728 732 736 737 744 745 746 747 748 751 757 763 767 769 772 773 774 776 779 781 784 791 794 795 796 802 803 805 808 815 818 822 824 825 828 833 840 842 843 849 850 851 852 853 855 856 857 859 862 863 865 874 875 877 879 881 885 889 890 892 893 894 895 897 898 900 904 906 908 913 916 919 920 921 924 925 930 931 932 933 934 935 937 938 945 952 953 954 957 968 975 978 979 981 985 986 989 990 994 995 +1 2 3 4 6 8 12 14 18 22 24 27 28 29 31 36 38 41 46 47 48 54 61 64 72 74 80 84 88 90 91 93 94 97 99 100 101 102 104 105 106 108 109 110 112 117 118 119 121 122 123 124 125 126 127 130 131 132 133 134 135 139 142 143 144 149 151 154 160 162 163 168 170 171 172 174 175 176 177 181 186 187 191 193 202 203 206 209 213 221 223 224 228 229 231 233 238 239 240 241 248 258 259 260 261 264 265 270 276 277 278 279 281 282 284 286 292 293 299 303 304 305 308 309 310 311 312 314 315 316 319 320 325 327 328 331 332 333 334 340 348 354 357 358 363 367 369 371 372 374 377 378 383 384 390 391 392 393 395 399 403 408 409 414 417 423 425 427 429 430 431 432 433 440 442 446 448 452 456 458 462 464 466 471 472 474 475 479 480 482 483 486 488 494 495 496 499 505 507 509 513 514 515 518 521 522 528 530 531 533 537 539 540 544 545 547 551 552 554 555 556 557 561 562 563 564 567 568 569 570 575 577 578 580 581 582 583 586 587 588 589 590 592 593 594 596 597 602 603 605 607 609 611 613 615 618 621 623 624 625 628 630 631 633 634 635 637 638 641 644 645 648 652 654 656 657 658 661 662 665 670 672 677 679 681 685 686 689 692 693 695 700 703 704 709 711 713 714 717 722 723 725 726 729 732 733 737 740 741 743 744 747 748 752 753 754 758 760 761 762 765 766 767 770 771 773 775 783 785 786 787 790 793 795 796 798 803 808 809 810 811 812 814 816 819 820 822 825 827 829 835 840 841 846 847 848 849 860 864 875 876 878 879 883 884 887 895 897 898 899 900 901 903 904 906 910 915 916 917 919 922 924 925 929 930 933 934 937 938 939 943 948 949 956 957 959 961 964 966 967 968 970 971 973 976 980 985 986 992 998 +3 5 7 13 16 17 19 20 21 25 28 31 32 37 46 47 51 56 57 65 67 68 69 71 74 78 81 84 86 89 92 97 98 103 104 105 106 107 108 110 111 114 115 116 118 121 122 127 129 130 131 140 144 151 153 154 155 159 161 162 166 170 171 175 176 179 180 185 186 187 189 192 193 194 198 200 201 203 204 206 207 212 213 214 218 222 223 225 227 228 230 232 233 239 240 241 242 248 253 254 255 259 260 261 263 272 277 281 284 285 290 292 300 301 304 314 316 317 318 319 323 325 326 328 330 333 339 342 344 346 347 348 351 360 362 365 366 369 370 372 377 379 386 388 392 393 394 395 396 399 402 403 405 407 408 409 413 414 415 417 419 422 427 430 431 434 437 438 439 440 441 447 451 455 457 459 463 464 470 472 475 477 478 479 483 484 485 488 489 490 492 496 497 498 502 503 508 509 510 518 521 524 525 527 528 531 535 537 539 540 543 546 549 551 555 557 562 564 567 568 570 574 577 578 579 580 588 590 596 604 608 609 610 611 612 613 614 617 620 621 624 626 627 628 630 633 634 636 637 639 645 648 649 651 652 653 655 661 662 663 664 665 667 668 670 671 672 673 676 678 682 685 694 698 700 701 702 704 710 715 716 721 723 724 734 735 737 739 740 743 745 747 751 763 765 767 769 772 773 774 775 782 783 788 790 792 793 796 800 801 807 809 811 812 815 819 825 828 829 830 831 838 840 842 845 846 847 848 857 859 860 861 862 865 867 868 874 875 879 880 881 884 885 886 889 891 893 895 903 904 907 909 916 917 919 922 924 925 926 927 928 929 938 940 943 947 948 949 951 954 955 957 959 960 962 966 968 972 973 975 977 979 981 982 983 984 986 987 988 991 993 994 995 996 998 +5 7 11 15 17 20 22 23 25 26 27 28 31 32 33 34 35 37 40 41 52 54 56 57 58 62 63 64 65 66 67 72 73 76 79 80 81 82 85 86 88 90 92 103 106 110 114 117 119 122 128 133 134 135 138 139 147 148 150 154 156 157 158 159 163 178 180 182 183 185 193 199 200 218 220 223 224 226 227 228 229 232 233 234 240 241 242 248 249 256 258 261 268 271 276 279 280 285 286 287 291 295 298 301 302 304 305 307 308 310 312 318 319 322 326 330 332 340 342 343 346 348 349 352 353 355 359 360 363 364 369 377 379 380 384 385 389 394 398 399 400 404 405 409 414 419 422 423 427 433 434 435 436 437 438 441 443 445 449 452 453 457 459 461 462 469 472 475 476 477 479 480 481 482 486 488 494 495 497 500 504 506 508 511 512 515 516 519 523 524 526 530 531 533 541 542 546 547 549 551 555 556 558 560 561 562 563 566 569 576 586 588 589 590 591 592 595 596 598 599 602 603 606 608 610 611 614 616 617 628 629 630 636 647 653 654 655 660 661 662 664 665 666 668 670 671 673 688 692 694 697 704 709 710 711 713 714 716 717 719 723 725 726 728 729 730 733 735 739 740 742 743 745 747 749 752 755 761 768 770 775 776 777 779 781 782 787 788 789 793 794 801 802 804 805 806 809 811 813 814 817 822 823 824 831 832 835 836 837 838 839 840 844 852 853 854 855 858 859 862 863 865 866 877 878 879 881 883 892 894 896 899 903 908 911 916 918 919 925 926 927 929 930 934 935 937 941 942 944 945 946 948 951 954 959 961 964 966 969 978 979 980 981 982 985 987 990 993 994 996 +1 4 8 10 12 22 23 24 26 27 29 31 32 33 34 40 42 44 46 50 52 63 65 66 69 72 73 74 76 82 87 89 96 97 99 101 102 103 105 106 107 111 113 115 123 125 128 129 130 132 134 135 136 140 142 145 146 148 151 153 154 155 157 163 165 168 169 171 172 175 176 180 181 183 187 188 194 195 196 197 200 202 205 208 210 212 213 218 220 234 241 242 243 245 247 252 257 259 260 262 263 266 267 268 270 273 274 275 283 287 289 291 293 295 298 299 300 301 302 303 304 307 311 314 318 323 324 328 329 335 336 337 339 340 341 343 345 348 349 350 351 353 355 358 359 360 361 368 370 372 374 376 377 379 380 388 389 390 392 399 404 406 410 412 415 416 417 418 424 425 426 430 434 435 436 437 444 447 449 451 452 456 457 460 463 464 465 467 470 471 475 477 478 480 484 491 495 498 501 502 503 505 506 507 509 517 519 520 521 523 528 530 531 532 537 539 541 542 546 549 550 552 554 557 560 564 569 571 573 574 577 580 581 587 592 593 596 599 601 603 604 608 609 610 611 616 619 621 624 629 631 632 641 645 647 648 651 658 659 664 670 679 680 681 693 695 696 697 702 703 704 710 712 715 721 722 725 726 727 728 729 730 732 733 735 736 739 740 742 745 747 753 757 759 761 762 769 770 772 775 776 778 780 781 783 791 792 794 795 797 799 803 804 805 809 811 812 815 816 823 825 826 827 828 829 835 838 839 844 846 847 848 851 853 854 861 869 870 872 873 877 880 882 884 888 891 893 894 901 902 903 904 906 907 912 913 916 917 918 920 921 924 926 927 929 934 935 936 938 939 941 943 944 950 954 955 956 957 959 962 963 964 965 967 968 971 975 976 980 981 982 984 988 990 993 994 997 +2 4 5 10 12 13 15 16 17 20 21 22 25 26 27 34 40 44 50 51 52 54 56 57 59 60 61 62 66 68 69 71 72 73 78 79 80 87 88 90 92 93 95 98 103 105 111 112 122 124 126 130 131 133 136 138 143 146 149 152 157 158 159 165 166 170 174 175 178 179 180 182 183 187 190 192 193 196 201 202 203 204 205 207 214 216 218 224 226 227 229 230 233 236 238 239 240 241 242 244 248 250 253 255 256 257 260 264 265 267 268 272 273 276 279 281 282 283 284 285 290 292 294 298 299 302 306 307 311 313 316 320 321 322 327 330 334 337 340 341 343 344 345 346 349 350 352 353 360 362 370 371 373 374 375 377 380 381 385 387 389 391 392 394 396 398 401 404 405 411 412 413 414 421 425 427 435 446 448 449 450 451 455 456 461 465 469 472 474 475 477 486 487 489 490 494 496 498 499 501 504 506 507 513 515 517 524 530 534 537 538 540 542 545 546 550 553 554 555 556 557 565 567 568 569 570 571 575 578 579 582 584 586 587 588 591 597 599 606 607 608 609 610 612 613 616 617 618 619 625 628 629 630 634 642 643 646 648 654 656 663 666 671 674 679 680 682 684 685 687 690 691 692 696 698 699 706 707 708 712 714 715 716 717 725 731 732 733 738 739 740 743 746 747 749 750 753 754 757 758 761 762 763 764 769 772 773 774 775 776 779 780 783 784 785 786 789 790 791 796 798 802 807 808 810 811 812 813 814 816 817 818 819 820 821 827 831 832 835 837 838 842 846 855 858 859 862 866 869 871 877 879 880 882 883 885 886 888 890 891 892 894 897 900 904 911 912 913 914 915 917 918 920 925 927 935 937 938 941 944 946 947 951 953 954 955 956 958 959 962 963 964 968 970 975 976 979 981 982 985 986 987 988 990 992 994 996 998 +0 1 3 4 10 12 13 14 18 20 23 24 26 34 35 39 42 43 46 48 49 52 54 55 56 62 64 65 66 67 68 69 70 71 72 73 82 84 85 86 90 91 92 93 97 102 103 104 105 108 109 110 111 113 114 116 117 119 121 123 124 125 126 128 129 132 133 135 140 144 149 153 154 155 159 161 162 166 168 170 174 175 176 186 192 193 194 196 201 203 207 208 215 216 219 221 224 228 230 236 237 239 245 248 252 253 257 260 266 267 268 269 270 272 274 277 279 280 281 282 284 285 286 288 294 295 296 297 299 300 303 306 316 318 324 326 328 330 332 337 339 344 347 351 352 353 354 356 359 361 362 364 368 369 370 371 373 374 376 382 383 384 386 388 393 397 398 400 401 403 405 410 412 415 418 422 423 427 428 429 432 436 437 440 443 447 449 450 451 453 459 460 462 463 464 465 467 468 469 471 472 476 477 484 490 495 497 498 500 501 502 503 511 516 517 518 520 523 525 526 529 532 534 536 538 540 542 543 547 554 555 562 563 566 569 570 572 573 576 579 580 583 589 594 600 601 602 603 605 610 611 614 615 616 619 624 627 632 634 639 640 642 643 647 653 654 660 661 664 665 669 670 673 675 677 678 679 680 682 685 686 687 688 691 695 697 701 705 706 707 709 713 714 715 716 717 720 721 722 724 732 733 736 738 743 744 746 748 749 754 755 756 759 760 761 762 764 770 773 774 775 776 785 786 789 791 795 797 804 805 810 811 814 815 818 819 822 823 825 827 833 834 835 841 842 845 846 847 852 855 856 858 860 861 864 866 868 870 871 878 882 884 885 886 892 894 895 896 899 900 902 905 907 909 913 915 916 917 918 919 920 922 923 928 930 937 939 940 942 947 949 953 956 957 961 963 965 968 973 974 976 977 979 980 981 983 988 990 991 994 995 996 998 +1 3 4 5 6 7 13 14 15 16 17 18 23 24 27 35 37 40 42 44 45 50 53 56 61 63 65 66 68 69 71 74 76 93 94 95 96 101 104 105 106 107 108 111 112 117 121 128 129 134 135 137 139 149 152 153 158 159 160 161 163 164 165 167 168 169 171 173 174 175 178 180 181 182 183 184 185 186 187 188 190 191 193 195 196 197 198 200 204 206 210 211 212 218 219 221 222 223 224 227 228 232 235 236 239 241 242 243 244 248 250 252 254 255 257 259 260 263 266 267 268 269 270 273 276 278 280 284 288 291 293 297 299 300 301 302 304 305 306 308 318 319 320 322 324 328 333 337 347 349 355 358 360 361 364 369 371 383 388 390 393 397 403 405 406 410 411 418 425 427 428 429 432 434 436 437 440 441 444 445 446 448 449 450 453 455 459 462 463 464 465 468 470 471 475 478 479 481 482 485 486 487 488 489 492 493 494 496 499 500 502 504 507 509 511 513 514 518 519 521 528 531 532 534 538 541 547 548 550 552 553 555 557 558 559 560 563 564 566 571 573 574 575 576 577 581 584 587 588 593 594 598 603 611 613 614 615 616 617 619 620 624 626 627 628 629 632 635 638 639 651 652 654 657 661 662 667 668 671 673 677 678 682 683 684 695 696 698 704 708 712 715 717 718 719 721 723 725 726 729 732 736 737 738 739 740 741 742 743 744 751 755 756 758 759 768 770 773 775 777 779 781 784 787 790 791 792 794 795 798 800 801 802 803 804 805 807 810 812 813 814 815 821 823 824 826 828 830 833 834 836 839 840 841 842 847 848 850 852 855 861 865 866 870 872 873 875 876 877 878 880 881 885 888 889 890 893 897 900 903 906 908 909 911 915 922 928 931 933 934 938 940 941 942 948 951 960 961 962 963 964 965 966 969 974 982 983 994 998 999 +1 2 3 10 12 15 19 21 22 25 26 27 30 31 33 34 35 36 37 39 40 43 45 46 47 48 50 51 52 53 54 56 57 58 60 61 63 65 66 71 76 77 83 86 88 93 96 97 98 99 102 103 104 106 107 109 111 116 118 119 120 125 126 132 136 137 139 141 145 149 158 159 160 162 169 171 175 176 177 178 180 185 188 189 191 192 198 199 201 202 204 205 207 209 213 216 217 219 220 222 224 225 227 230 232 233 235 236 239 245 248 249 251 254 257 258 263 265 266 269 271 273 276 277 279 282 283 286 290 294 296 299 300 301 304 308 310 312 314 317 318 332 336 341 342 343 348 349 350 353 355 357 358 359 362 365 368 369 370 374 377 378 380 381 383 387 388 391 393 396 400 403 405 408 410 412 415 417 418 421 422 423 424 425 428 430 431 432 434 436 443 445 446 447 457 458 459 462 463 464 467 468 469 470 471 472 473 478 480 485 486 488 490 493 496 498 499 504 505 506 508 509 511 512 513 515 516 517 519 520 522 524 529 530 532 535 536 537 542 544 547 548 549 550 551 555 557 558 559 560 564 565 569 576 579 585 588 589 590 593 595 598 601 602 604 609 610 612 613 614 617 618 619 620 623 626 630 631 632 634 637 638 640 641 643 646 647 649 650 651 654 656 657 658 659 663 665 666 667 669 670 671 672 674 677 678 679 686 689 690 691 694 696 697 699 705 707 708 710 712 713 719 723 724 726 727 730 732 733 734 741 742 750 755 758 759 761 762 766 770 771 773 777 778 784 785 787 795 796 798 800 801 803 805 806 807 811 814 816 817 821 826 827 840 845 846 847 848 850 853 854 857 866 867 869 872 876 877 879 880 881 882 883 885 887 888 891 892 904 906 907 911 912 915 917 922 927 928 929 930 931 934 935 936 938 940 948 949 951 952 953 960 962 963 964 966 968 969 972 973 975 978 982 984 985 988 991 993 999 +0 1 3 4 5 11 13 16 19 20 21 24 28 29 32 33 34 35 38 42 44 47 50 51 52 53 54 55 56 57 58 60 64 65 68 69 70 72 74 76 77 79 82 83 85 86 87 89 91 92 93 101 102 104 106 111 116 119 120 123 126 128 133 136 138 142 144 146 149 154 155 157 159 161 164 166 167 171 172 174 175 177 179 180 181 182 184 185 192 193 196 197 198 201 204 206 215 219 220 223 224 227 228 232 233 234 236 239 242 245 251 252 259 264 265 266 268 270 273 274 279 283 284 286 287 290 291 292 294 301 308 309 311 312 318 319 320 321 326 329 330 331 333 336 337 340 342 344 345 349 351 353 354 355 360 364 365 370 378 379 382 383 386 387 388 392 394 395 396 397 401 402 404 408 413 415 419 422 423 426 430 431 432 435 437 440 441 442 446 448 449 450 451 452 457 458 459 462 464 465 466 468 469 470 471 474 476 477 480 481 483 484 491 495 500 503 506 509 510 514 515 516 518 528 531 535 537 539 540 542 543 546 549 550 552 554 561 564 565 570 571 575 576 582 584 586 587 588 591 595 604 606 607 608 610 611 612 614 616 618 620 627 629 630 632 633 634 637 638 641 643 645 652 654 656 657 658 660 666 667 668 671 672 673 677 679 680 683 684 685 686 688 689 692 693 698 699 701 702 703 705 706 709 710 726 728 732 734 738 741 743 745 746 748 749 757 760 761 763 767 769 770 773 784 785 788 791 792 797 798 799 800 803 804 808 812 813 814 815 816 819 821 822 828 833 834 841 843 848 850 853 855 862 863 864 866 871 872 873 877 881 883 884 887 888 889 892 894 895 900 901 907 910 911 913 915 916 918 922 923 924 925 927 932 934 935 936 937 940 941 942 944 948 949 950 953 964 966 975 976 980 982 984 986 987 991 997 998 999 +2 3 4 9 10 11 13 16 17 20 21 24 27 30 34 35 36 37 39 40 41 43 47 51 54 56 57 60 63 65 69 72 73 78 79 86 89 95 102 103 105 108 109 111 112 113 114 119 122 125 127 128 130 131 132 134 136 140 146 149 150 152 153 156 157 159 161 162 163 165 173 175 176 177 178 179 182 183 185 194 196 197 198 199 200 201 202 203 204 205 208 211 212 214 215 216 217 220 221 228 231 233 239 254 255 257 258 259 260 261 264 265 267 268 275 279 280 281 284 286 289 293 295 300 303 304 306 309 310 311 314 319 321 322 324 325 329 330 331 332 333 340 341 343 344 347 354 355 357 360 361 362 364 367 368 374 379 381 383 388 389 390 391 392 395 396 398 403 404 406 407 408 409 410 412 415 416 419 425 432 433 436 439 442 443 450 453 458 460 461 462 464 470 472 473 480 484 485 489 492 497 500 502 505 508 509 512 515 516 518 521 522 524 525 526 527 530 532 539 544 545 546 549 551 552 555 557 560 561 563 569 570 572 574 580 584 585 587 591 592 593 594 596 602 603 609 611 614 615 616 617 618 619 620 621 623 624 628 629 631 632 633 635 639 641 644 647 651 655 656 660 664 665 669 670 672 674 675 678 681 687 688 692 694 695 696 699 701 704 710 711 714 718 720 723 729 731 733 740 741 742 743 749 753 754 759 760 762 763 766 769 771 777 778 779 787 791 793 799 803 804 807 808 810 813 815 817 818 824 825 826 827 830 831 832 833 834 835 839 843 844 846 847 848 850 852 853 856 858 860 861 864 865 868 869 875 876 877 879 885 887 888 891 892 893 894 897 899 900 901 902 908 909 911 913 915 917 918 921 923 925 926 928 930 931 933 934 935 936 937 940 941 944 945 946 949 950 955 957 958 964 965 968 969 970 971 973 979 981 983 987 995 997 998 +1 3 14 15 17 18 20 23 24 26 27 31 36 38 40 41 43 44 46 48 50 52 55 63 66 69 71 73 75 76 77 80 84 87 88 89 90 91 99 100 101 105 109 112 114 118 119 127 130 134 135 136 137 139 141 143 144 149 151 152 153 154 155 156 166 167 171 173 178 182 183 186 189 192 199 203 204 205 207 208 209 210 213 217 218 223 225 227 229 234 237 240 243 244 247 253 258 259 267 270 271 274 276 277 281 282 290 291 292 294 295 300 304 307 310 313 315 316 317 318 320 321 324 327 328 330 331 332 336 338 341 342 344 345 347 349 350 353 356 357 359 366 367 369 371 376 379 380 383 387 388 395 398 399 405 406 409 411 413 417 419 420 422 424 425 427 432 433 436 437 439 441 443 449 450 451 454 457 458 463 467 470 477 479 485 486 488 492 493 495 500 510 514 515 517 520 524 526 527 528 530 531 532 534 536 538 540 542 545 549 554 555 556 557 558 559 561 562 568 572 573 575 579 580 582 587 588 594 598 600 605 606 610 612 614 616 617 618 622 623 624 625 627 628 630 631 633 635 636 640 641 645 647 648 654 659 663 664 666 668 670 673 677 680 681 683 686 688 690 692 693 697 699 703 704 710 712 713 718 724 726 728 732 733 734 741 742 744 745 747 751 752 755 759 760 761 762 765 766 767 769 772 773 776 781 782 783 793 794 795 799 800 803 807 811 824 826 828 831 837 841 842 843 844 845 849 851 858 859 860 862 863 866 867 868 871 872 876 877 878 881 883 886 889 898 900 901 903 904 908 909 911 912 914 923 924 927 929 930 932 933 934 936 937 938 941 943 944 945 946 947 948 949 951 952 954 956 960 962 964 968 970 975 978 980 982 983 988 990 996 997 999 +2 5 7 12 13 14 15 18 19 24 25 26 28 30 32 33 35 37 38 39 44 49 52 55 58 60 63 74 76 77 78 81 83 87 90 92 94 95 96 97 99 100 102 104 107 111 112 113 114 115 117 119 120 125 127 131 132 135 136 139 141 142 143 144 146 147 152 154 163 168 170 171 173 180 183 184 189 190 191 195 200 202 205 208 211 212 214 215 216 217 218 222 226 227 231 234 238 239 240 246 251 256 257 258 259 263 267 269 270 273 275 277 278 279 280 285 287 291 292 294 296 297 301 303 305 307 309 310 313 317 321 322 323 326 329 334 335 336 337 343 345 347 350 352 353 356 358 359 361 371 372 374 376 379 380 386 387 388 389 390 392 393 394 395 396 397 404 405 407 409 415 416 422 429 430 434 437 441 442 443 444 447 451 452 454 457 459 464 466 467 470 472 475 477 479 481 482 483 484 485 487 490 491 501 502 503 505 506 507 510 520 521 522 524 526 527 531 532 533 536 537 539 544 545 554 556 559 560 562 563 568 569 570 572 577 578 582 583 584 589 591 592 595 596 597 599 600 603 606 609 611 616 621 624 625 629 630 631 632 635 640 644 655 656 657 659 661 662 664 669 676 679 680 686 691 696 700 703 706 708 709 710 711 712 716 717 719 727 731 735 739 747 748 749 751 754 757 760 761 765 766 768 770 771 776 777 782 783 787 788 789 792 794 797 806 807 811 815 819 820 823 826 828 829 831 832 834 837 839 840 845 846 848 851 852 853 855 857 859 860 862 872 876 879 881 887 888 898 901 902 903 904 905 907 909 910 914 923 924 925 929 934 935 936 938 944 945 947 949 950 951 955 960 962 963 965 968 971 973 974 976 977 983 984 987 988 991 992 994 999 +1 4 7 9 10 14 15 16 17 18 20 26 28 29 35 36 42 44 47 51 58 59 61 64 66 71 76 77 80 81 89 90 92 97 99 102 105 106 108 111 113 115 116 119 121 122 123 124 126 127 128 132 133 134 135 141 144 147 148 149 150 152 153 155 156 157 162 164 173 183 187 192 194 196 200 201 202 204 214 217 218 222 223 224 227 229 231 237 240 242 243 245 247 249 251 253 254 255 256 258 260 261 271 273 274 275 276 278 280 281 286 291 298 304 308 313 314 320 321 326 327 328 330 331 333 334 335 337 338 341 349 351 355 356 358 367 371 376 377 384 387 388 391 392 399 405 406 408 409 410 412 418 422 423 429 442 444 452 455 456 461 463 464 467 469 473 477 478 480 483 488 496 499 501 502 503 505 509 511 514 516 519 520 522 525 529 535 536 537 540 546 551 552 561 563 569 570 572 573 574 577 579 580 582 583 584 586 588 591 592 593 594 600 602 603 606 607 608 609 612 614 616 617 618 625 631 636 639 643 645 648 650 652 653 655 656 657 658 660 661 662 663 664 665 667 668 669 670 673 676 679 680 681 682 685 688 689 694 695 700 705 706 708 709 711 713 714 716 717 719 720 723 726 731 734 735 740 746 747 750 753 756 757 765 766 769 774 776 778 784 785 788 789 792 794 795 796 799 800 802 803 804 805 806 810 811 813 814 815 818 819 823 826 827 828 830 833 836 837 838 841 848 852 855 856 859 862 865 867 869 870 871 874 879 881 884 885 887 888 894 897 901 907 908 909 911 912 913 917 919 920 929 932 935 936 942 943 944 945 948 953 954 955 956 958 959 961 962 965 967 970 976 980 983 986 +1 4 5 13 17 18 21 23 26 28 29 36 37 39 41 42 45 49 50 51 52 55 57 61 62 64 65 68 73 74 76 79 80 82 83 84 85 86 95 96 101 103 105 107 112 114 117 120 123 125 128 129 130 132 133 135 137 138 142 146 148 151 153 164 169 171 172 173 179 180 186 189 190 191 193 194 195 196 199 203 206 211 214 215 216 218 221 224 225 226 227 228 231 232 235 237 243 244 245 246 248 249 254 256 258 260 261 267 268 269 271 273 275 282 284 286 290 291 292 296 300 308 309 313 314 315 318 319 321 322 324 330 331 333 335 336 338 339 344 345 346 349 352 354 355 357 369 370 371 373 374 375 376 377 378 381 382 383 387 389 390 391 394 399 403 407 408 411 413 416 417 419 421 427 432 433 442 443 445 446 449 452 455 458 459 463 466 467 468 470 471 486 487 493 495 499 501 503 505 506 507 510 518 519 526 531 534 543 549 552 557 559 562 569 571 573 574 575 576 577 580 582 584 591 594 597 598 601 604 607 608 611 613 614 618 619 621 626 630 631 632 633 634 640 643 647 648 651 652 656 657 659 661 667 670 671 674 676 677 679 681 684 685 688 689 690 691 694 695 697 704 707 708 712 713 717 718 720 721 723 727 729 731 736 737 738 740 743 744 748 750 755 756 758 759 760 763 764 765 769 771 778 780 782 784 785 786 792 793 794 797 798 799 801 802 803 804 806 807 808 809 811 817 819 820 822 823 828 829 831 837 841 842 843 845 848 850 851 853 867 868 870 872 875 876 881 882 883 886 888 892 893 894 895 896 899 907 909 911 913 914 915 916 920 924 931 932 933 934 936 937 938 942 943 944 946 947 948 951 952 955 956 963 968 969 974 976 977 978 980 981 984 986 988 990 992 995 997 999 +0 1 12 13 15 16 21 28 34 37 39 40 43 44 45 47 49 51 53 54 55 56 59 62 63 65 66 67 71 72 75 77 79 80 81 85 90 91 93 94 98 101 102 103 104 105 111 113 114 115 117 121 125 126 128 131 133 137 138 140 142 143 145 147 148 154 161 162 169 170 172 178 179 180 182 183 184 188 189 193 194 198 199 200 203 204 205 208 209 211 216 217 218 219 220 228 238 241 243 244 246 248 249 250 254 257 259 262 264 266 268 270 276 278 279 282 283 287 289 292 297 299 301 305 308 309 312 318 322 323 324 327 330 332 333 336 338 339 340 344 345 350 357 358 362 364 366 367 370 372 374 375 378 379 380 381 387 388 389 392 393 401 403 404 405 406 410 412 414 415 417 419 420 422 426 427 428 432 434 439 446 449 452 454 456 457 459 461 463 464 467 470 471 476 484 486 489 491 493 497 498 499 500 501 505 508 509 510 511 512 514 515 516 517 520 521 526 527 528 529 531 532 535 536 538 542 543 546 547 548 549 550 553 554 555 559 562 563 565 570 571 572 577 578 580 585 586 587 589 593 595 598 600 604 605 609 611 613 614 615 617 618 623 625 627 632 633 635 639 644 645 646 651 655 658 659 663 667 671 674 675 680 682 686 687 688 691 697 700 701 705 707 708 709 710 711 718 723 724 726 727 729 736 737 741 744 746 747 751 752 753 754 756 758 760 761 762 763 764 765 768 770 772 776 779 782 784 785 788 789 790 791 793 796 797 802 803 805 807 809 810 811 814 817 823 824 833 834 837 838 839 840 841 844 847 850 854 855 857 862 867 868 870 871 872 878 879 881 882 883 889 890 892 900 901 903 905 906 907 909 910 912 914 918 919 924 925 927 931 932 937 938 943 951 952 954 955 959 960 967 972 973 975 978 985 986 987 988 990 991 996 998 +4 6 13 14 15 18 19 21 30 31 32 35 39 40 41 42 44 47 48 50 51 56 57 61 62 64 66 69 72 75 76 78 82 84 86 88 89 90 91 92 93 95 99 101 102 103 106 112 116 121 126 128 130 131 133 134 136 139 140 143 144 145 146 148 158 161 164 165 167 169 171 173 175 177 179 182 184 185 188 189 192 194 196 197 198 199 203 204 205 206 207 208 211 212 213 215 216 218 220 223 224 232 235 239 240 241 242 245 247 254 255 259 262 263 266 272 274 275 278 281 285 286 287 288 289 291 292 297 298 301 308 313 317 319 320 321 323 325 333 335 336 338 342 344 346 350 356 358 363 364 365 366 368 369 375 377 378 379 380 381 382 389 390 391 392 396 400 401 405 407 408 409 411 412 421 425 426 430 432 433 434 436 438 442 444 446 453 454 456 458 459 463 465 472 480 483 486 488 491 494 496 498 500 504 505 507 512 514 517 522 525 527 529 530 534 535 538 541 542 548 562 567 575 576 581 582 583 584 596 597 598 600 602 617 618 619 621 622 623 624 626 634 638 639 642 648 649 653 655 657 664 668 670 671 673 674 675 677 679 682 689 692 693 695 698 699 700 702 705 706 707 708 711 714 720 721 723 724 726 727 730 735 736 737 738 741 744 746 747 753 754 755 756 757 765 770 771 773 774 777 780 786 788 789 790 792 797 802 804 807 808 809 812 815 816 817 823 833 834 836 838 841 842 848 851 855 857 865 868 873 875 876 877 878 880 882 883 888 889 890 894 900 901 904 905 912 918 919 920 924 930 931 933 942 943 945 946 949 950 951 952 953 955 958 964 965 974 978 981 982 983 984 985 989 994 995 998 +3 16 17 18 19 20 23 25 31 32 35 36 37 40 41 42 43 46 47 48 51 53 57 59 61 64 66 67 77 78 83 85 89 93 94 95 97 98 102 103 104 106 110 112 115 118 121 123 124 127 146 148 151 153 155 157 159 160 168 170 171 173 174 178 179 180 188 196 197 200 201 207 212 213 221 232 234 235 237 240 241 243 246 248 250 251 254 255 256 258 261 262 265 273 275 279 284 285 286 287 288 290 292 293 294 297 302 303 304 306 308 311 314 315 319 322 323 330 336 337 339 344 345 353 354 355 357 358 366 367 370 373 375 377 378 380 381 383 386 387 388 393 394 396 397 404 406 407 408 412 413 417 418 419 423 426 427 428 429 430 433 435 440 441 446 450 455 458 467 468 471 472 473 479 484 486 491 493 494 499 510 517 520 521 522 524 525 528 531 532 534 536 541 543 544 546 548 549 550 553 557 558 560 561 562 565 568 569 571 572 573 581 582 585 586 587 588 589 591 593 598 602 603 604 605 606 607 608 609 610 612 615 616 617 624 628 631 632 634 638 639 642 643 644 645 649 651 653 656 658 661 662 665 667 668 670 672 677 679 683 688 690 691 693 694 696 698 699 704 705 708 710 712 713 714 719 720 728 729 733 736 740 742 743 744 747 752 754 755 759 764 769 771 773 779 780 787 790 794 799 800 803 806 810 812 814 820 821 822 823 829 830 835 838 840 843 846 848 849 850 851 854 857 858 860 863 865 868 869 871 873 877 884 885 888 893 895 899 901 903 904 905 907 910 912 919 924 931 932 934 935 938 939 940 945 946 947 948 953 954 956 957 961 962 964 966 967 968 972 974 976 977 979 981 982 987 989 990 992 994 999 +1 3 4 6 9 11 15 17 18 21 23 27 28 30 31 33 35 37 38 39 46 53 55 56 58 59 62 63 67 73 75 76 77 84 85 87 88 91 93 95 96 101 103 104 109 116 117 120 121 123 124 125 128 129 139 143 144 146 150 152 158 160 162 165 168 169 171 173 174 176 183 184 190 193 196 197 199 204 205 207 209 211 213 216 222 224 225 226 227 230 232 236 238 239 240 242 243 248 253 254 256 259 263 266 279 280 281 292 295 296 297 298 299 302 306 307 310 311 316 317 318 319 320 322 323 324 326 329 331 334 335 339 341 345 346 348 352 353 354 360 364 365 367 371 372 375 376 378 379 380 382 386 389 390 393 401 402 404 406 408 412 413 415 417 418 421 423 425 427 433 435 436 437 438 439 440 441 443 445 447 450 451 452 453 454 458 466 467 469 472 474 475 477 478 480 482 483 484 485 487 488 489 497 499 501 502 503 506 515 516 519 520 521 525 534 535 538 541 542 544 549 552 555 557 560 561 562 564 567 568 570 572 577 580 582 586 587 589 590 591 592 593 597 606 608 609 611 613 615 618 620 621 622 623 628 631 633 637 639 640 644 646 648 650 652 653 655 659 668 669 671 674 675 677 679 681 682 684 687 689 690 694 696 697 701 703 704 707 709 715 719 723 724 725 727 728 734 736 740 741 743 746 748 755 759 760 761 762 763 773 776 778 779 782 784 787 788 789 790 794 796 798 803 804 807 810 815 816 817 826 827 828 829 834 835 836 838 843 844 847 848 850 853 854 857 858 859 860 862 865 866 867 868 871 872 873 878 880 881 882 883 885 888 891 897 900 901 902 907 908 909 912 913 915 917 918 922 925 927 928 935 937 939 941 944 946 949 950 952 954 958 963 964 965 968 969 970 971 973 974 976 977 981 985 986 987 999 +1 9 12 16 20 21 27 29 31 32 38 51 54 58 61 62 65 66 68 77 78 79 82 83 85 87 88 89 92 96 97 101 102 103 106 107 108 110 111 116 119 121 124 129 131 132 136 137 138 141 144 145 146 147 149 150 157 158 161 166 167 168 170 171 173 174 176 178 184 186 200 201 207 208 213 214 216 217 219 223 225 230 235 237 239 242 243 244 246 247 248 249 260 262 265 269 271 272 280 282 284 286 290 291 293 294 295 296 297 300 301 303 306 308 309 310 315 316 319 320 321 323 324 325 328 329 331 332 333 342 343 344 346 347 348 349 350 352 354 355 356 357 361 362 365 366 367 373 378 380 385 387 388 393 397 398 399 400 403 405 406 407 409 411 414 424 425 427 430 431 438 440 441 450 452 456 460 462 468 474 475 479 482 484 485 487 488 489 493 494 495 496 497 498 500 501 506 507 508 514 515 518 519 520 521 523 526 527 529 530 531 532 533 534 537 540 541 545 546 548 552 553 554 556 558 559 560 563 565 567 569 571 577 580 582 592 594 595 601 602 606 609 610 611 612 615 619 624 625 627 629 632 633 638 639 647 649 650 656 657 666 668 670 671 672 675 676 681 682 689 693 694 696 697 699 700 701 702 703 706 707 708 710 711 717 720 721 722 728 731 733 734 735 737 739 740 742 743 744 745 746 749 754 755 757 759 760 763 765 768 770 771 772 773 775 776 777 779 781 782 784 785 791 792 793 794 795 798 801 804 806 808 810 811 814 815 817 819 821 823 825 826 827 835 840 843 847 851 852 854 857 859 860 861 863 865 871 873 888 890 892 899 900 904 905 910 911 912 914 915 916 918 922 924 926 927 928 932 933 934 935 938 939 942 944 946 949 952 957 968 970 971 972 973 978 979 985 989 991 994 997 998 diff --git a/in_class/SetCover/test_set-200.sc b/in_class/SetCover/test_set-200.sc new file mode 100644 index 00000000..0a7e8937 --- /dev/null +++ b/in_class/SetCover/test_set-200.sc @@ -0,0 +1,201 @@ +100 200 +63 +54 69 +15 47 +16 26 37 51 +63 +34 40 88 +14 46 72 +62 +87 95 +33 67 93 + +4 6 16 79 +33 99 +38 83 +38 81 94 +41 +68 +47 84 +19 71 95 +44 +4 88 +48 +53 83 +37 77 90 94 +25 92 +47 +46 48 + +27 42 +35 59 90 +83 +9 +56 +6 48 +75 +48 62 64 + +80 +64 +71 +31 40 50 +36 52 + +87 +73 81 + +19 +55 58 82 +12 32 55 + +48 +32 57 + +63 74 89 91 +65 + +40 78 +73 87 +12 41 68 + +50 79 97 +95 + + + +26 70 + +68 91 +18 89 +17 31 41 67 +24 35 +30 46 62 +43 46 +3 76 +32 34 51 95 +20 57 +55 +15 52 77 95 + +90 +15 + +28 37 43 +7 9 71 90 +99 +26 61 +14 58 +74 89 +19 22 +17 88 97 +20 78 +39 55 99 +12 + +29 78 + + +72 +5 43 55 +0 74 93 +23 27 +13 + +84 +99 +3 + +85 +23 91 +21 63 +1 31 33 +18 36 46 +19 +11 +43 53 +2 9 13 58 68 69 +20 49 +15 47 68 +12 71 +8 9 49 +9 84 98 +53 56 67 +5 27 82 +32 54 +50 + +76 +4 6 10 14 25 +49 61 +88 +16 20 28 +49 +18 26 +80 +13 + +11 26 54 71 87 + +24 27 +16 37 44 99 +31 49 +38 76 91 +8 71 +5 14 58 66 77 +45 + +34 68 85 +51 75 +77 +19 52 63 +94 +38 88 97 + +27 64 73 +47 99 +55 88 93 +30 65 83 +64 +24 57 +13 46 87 +23 +0 31 96 +28 35 +90 97 +69 +73 +93 +25 27 46 74 +99 +61 +80 + +11 21 97 +19 + +34 40 41 60 80 93 +4 49 +1 8 80 +55 +16 57 + +55 +22 61 78 +93 +87 +6 60 76 +5 41 42 98 +0 3 7 38 85 +51 +29 44 + +4 34 89 +0 10 +45 +38 86 91 + +1 7 46 55 88 97 +66 93 +10 98 +39 52 diff --git a/in_class/SetCover/test_set.sc b/in_class/SetCover/test_set.sc new file mode 100644 index 00000000..359615c4 --- /dev/null +++ b/in_class/SetCover/test_set.sc @@ -0,0 +1,21 @@ +20 20 +1 8 16 +5 13 18 +6 8 +0 4 15 19 +12 +1 10 12 +2 6 8 12 13 +2 4 15 +12 +0 13 +3 7 12 13 +7 8 15 19 +0 18 +9 11 15 +3 5 12 17 19 +2 6 10 16 18 19 +0 11 +7 9 15 +7 10 14 17 18 +2 4 diff --git a/in_class/SetCover/test_set2.sc b/in_class/SetCover/test_set2.sc new file mode 100644 index 00000000..507fa133 --- /dev/null +++ b/in_class/SetCover/test_set2.sc @@ -0,0 +1,6 @@ +5 5 +1 2 4 +0 1 2 4 +1 4 +0 3 4 +4 diff --git a/in_class/emscripten/Hello.cpp b/in_class/emscripten/Hello.cpp new file mode 100644 index 00000000..93700a2e --- /dev/null +++ b/in_class/emscripten/Hello.cpp @@ -0,0 +1,11 @@ +#include +#include + +int main() { + std::cout << "Hello World" << std::endl; + + std::string text; + std::cin >> text; + + std::cout << "You Entered: " << text << std::endl; +} diff --git a/in_class/emscripten/build-drawSquare.sh b/in_class/emscripten/build-drawSquare.sh new file mode 100644 index 00000000..caa64274 --- /dev/null +++ b/in_class/emscripten/build-drawSquare.sh @@ -0,0 +1 @@ +emcc drawSquare.cpp -o drawSquare.js -s "EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" diff --git a/in_class/emscripten/build-factorial.sh b/in_class/emscripten/build-factorial.sh new file mode 100644 index 00000000..1653cade --- /dev/null +++ b/in_class/emscripten/build-factorial.sh @@ -0,0 +1 @@ +emcc factorial.cpp -s WASM=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']" -o factorial.js diff --git a/in_class/emscripten/drawSquare.cpp b/in_class/emscripten/drawSquare.cpp new file mode 100644 index 00000000..1254bd73 --- /dev/null +++ b/in_class/emscripten/drawSquare.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +int X_pos=50, Y_pos=50; + +extern "C" { + // Function to be called from JavaScript + EMSCRIPTEN_KEEPALIVE + void drawSquare() { + EM_ASM_({ + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + ctx.fillStyle = 'red'; + ctx.fillRect($0, $1, 100, 100); // Draw a 100x100 red square + } + }, X_pos, Y_pos); + X_pos += 10; + Y_pos += 10; + } +} + +int main() { + // Use EM_ASM to inject HTML for the button + EM_ASM({ + var button = document.createElement('button'); + button.innerHTML = 'Draw Square'; + button.onclick = function() { + // Call the C++ function drawSquare() + _drawSquare(); + }; + document.body.appendChild(button); + + // Create a canvas element + var canvas = document.createElement('canvas'); + canvas.id = 'canvas'; + canvas.width = 300; + canvas.height = 300; + canvas.style.border = '1px solid black'; + document.body.appendChild(canvas); + }); + + return 0; +} diff --git a/in_class/emscripten/drawSquare.html b/in_class/emscripten/drawSquare.html new file mode 100644 index 00000000..61e223aa --- /dev/null +++ b/in_class/emscripten/drawSquare.html @@ -0,0 +1,9 @@ + + + + Draw Squares with Emscripten + + + + + diff --git a/in_class/emscripten/factorial.cpp b/in_class/emscripten/factorial.cpp new file mode 100644 index 00000000..95d0f90d --- /dev/null +++ b/in_class/emscripten/factorial.cpp @@ -0,0 +1,10 @@ +#include +#include + +extern "C" { + EMSCRIPTEN_KEEPALIVE + int factorial(int n) { + if (n == 0) return 1; + return n * factorial(n - 1); + } +} diff --git a/in_class/emscripten/factorial.html b/in_class/emscripten/factorial.html new file mode 100644 index 00000000..80ef6498 --- /dev/null +++ b/in_class/emscripten/factorial.html @@ -0,0 +1,23 @@ + + + + Factorial Calculator + + +

Factorial Calculator

+ Enter a number: + +
+ + + + + + + diff --git a/in_class/emscripten/power.cpp b/in_class/emscripten/power.cpp new file mode 100644 index 00000000..71220f0b --- /dev/null +++ b/in_class/emscripten/power.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +extern "C" { + EMSCRIPTEN_KEEPALIVE + double power(double base, double exponent) { + return std::pow(base, exponent); + } +} diff --git a/in_class/emscripten/power.html b/in_class/emscripten/power.html new file mode 100644 index 00000000..f87f4513 --- /dev/null +++ b/in_class/emscripten/power.html @@ -0,0 +1,25 @@ + + + + Power Calculator + + +

Power Calculator

+ Enter a base: + Enter an exponent: + +
+ + + + + + + diff --git a/in_class/emscripten/start-server.sh b/in_class/emscripten/start-server.sh new file mode 100644 index 00000000..846e5104 --- /dev/null +++ b/in_class/emscripten/start-server.sh @@ -0,0 +1 @@ +python3 -m http.server diff --git a/in_class/meta/meta.cpp b/in_class/meta/meta.cpp new file mode 100644 index 00000000..319af905 --- /dev/null +++ b/in_class/meta/meta.cpp @@ -0,0 +1,67 @@ +#include +#include +//#include + +// static size_t NextID() { +// static size_t next_id = 0; +// return ++next_id; +// } + +// template +// static size_t ToID() { +// static size_t this_id = NextID(); +// return this_id; +// } + +template +constexpr bool SameType(T1, T2) { + return false; +} + +template +constexpr bool SameType(T1, T1) { + return true; +} + +template +constexpr bool SameType(T1) { + return true; +} + +template +constexpr bool SameType(T1 v1, T2 v2, extraTs... extra_values) { + return SameType(v1,v2) && SameType(v1, extra_values...); +} + +void TestFun(int) { std::cout << "int version!" << std::endl; } +void TestFun(bool) { std::cout << "bool version!" << std::endl; } +void TestFun(...) { std::cout << "extra version!" << std::endl; } + +int main() +{ + int u = 5, v = 11, w = 22, x = 10, y = 1; + double z = 3.14159265358979; + std::string s("test"); + + std::cout << "SameType(x,y) = " << SameType(x,y) << std::endl; + std::cout << "SameType(x,z) = " << SameType(x,z) << std::endl; + std::cout << "SameType(x,s) = " << SameType(x,s) << std::endl; + std::cout << "SameType(x,1) = " << SameType(x,1) << std::endl; + std::cout << "SameType(x) = " << SameType(x) << std::endl; + std::cout << "SameType(u,v,w,x,y) = " << SameType(u,v,w,x,y) << std::endl; + std::cout << "SameType(u,v,w,x,y,z) = " << SameType(u,v,w,x,y,z) << std::endl; + + // TestFun(5); + // TestFun(true); + // std::string str("Hello."); + // TestFun(str); + // TestFun("what will this do?"); + // TestFun('a'); + + // std::cout << "int: " << ToID() << std::endl; + // std::cout << "int: " << ToID() << std::endl; + // std::cout << "double: " << ToID() << std::endl; + // std::cout << "std::string: " << ToID() << std::endl; + // std::cout << "char: " << ToID() << std::endl; + // std::cout << "int: " << ToID() << std::endl; +} \ No newline at end of file diff --git a/in_class/meta/meta2.cpp b/in_class/meta/meta2.cpp new file mode 100644 index 00000000..18126701 --- /dev/null +++ b/in_class/meta/meta2.cpp @@ -0,0 +1,68 @@ +#include +#include + +struct Animal { + std::string name; + void PrintName() const { std::cout << name << std::endl; }; +}; + +struct Dog : Animal { + void Herd() { } + void Hunt() { } + int GetStrength() { return 10; } +}; +struct Sheep : Animal { + void Graze() { } + int GetStrength() { return 5; } +}; +struct Lion : Animal { + void Roar() { } + int Hunt() { return 1; } + int GetStrength() { return 100; } +}; + +template +concept CanHunt = requires(T animal) { + { animal.Hunt() } -> std::same_as; +}; + +template +void ManageHunt(T & hunter) { + hunter.Hunt(); +} + +template +void PrintNames(Ts &... animals) { + (std::cout << ... << animals.name) << std::endl; + // (..., animals.PrintName()); +} + +template +int TotalStrength(Ts &... animals) { + return (animals.GetStrength() + ...); +} + +template +auto Multiply(Ts... values) { + return (... * values); +} + +template +int MultStrength(Ts &... animals) { + return Multiply(animals.GetStrength() ...); +} + +int main() +{ + Lion l; l.name = "Oscar"; + Dog d; d.name = "Spot"; + Sheep s; s.name = "Baaaa"; + + PrintNames(l, d, s, l, l); + std::cout << "Total = " << TotalStrength(l, d, s, l, l) << std::endl; + std::cout << "Product = " << MultStrength(l, d, s, l, l) << std::endl; + + ManageHunt(l); + // ManageHunt(d); + // ManageHunt(s); +} \ No newline at end of file diff --git a/in_class/other/adl.cpp b/in_class/other/adl.cpp new file mode 100644 index 00000000..cd6ecd4a --- /dev/null +++ b/in_class/other/adl.cpp @@ -0,0 +1,22 @@ +#include +#include + +namespace mynamespace { + struct MyClass { int x = 5; }; + + template + int fun(T in) { return in.x; } +} + +struct MyClass2 { int x = 10; }; + + template + int fun(T in) { return in.x + 1; } + +int main() +{ + mynamespace::MyClass obj; + MyClass2 obj2; + + std::cout << fun(obj) << std::endl; +} \ No newline at end of file diff --git a/in_class/other/crtp.cpp b/in_class/other/crtp.cpp new file mode 100644 index 00000000..5456c661 --- /dev/null +++ b/in_class/other/crtp.cpp @@ -0,0 +1,30 @@ +#include +#include + +struct VehicleBase { + +}; + +template +struct Vehicle : public VehicleBase { + std::string name; + std::string owner; + virtual double GetSpeed() const { return 0; } + DERIVED_T & Derived() { return *static_cast(this); } + + DERIVED_T & SetName(std::string in) { name = in; return Derived(); } + DERIVED_T & SetOwner(std::string in) { owner = in; return Derived(); } +}; + +struct Quinjet : public Vehicle { + int num_missiles = 100; + double GetSpeed() const override { return 1000000.0; } + + Quinjet & SetNumMissiles(int in) { num_missiles = in; return *this; } +}; + +int main() +{ + Quinjet q1; + q1.SetName("q1").SetOwner("Avengers").SetNumMissiles(2000); +} \ No newline at end of file diff --git a/in_class/other/downto.cpp b/in_class/other/downto.cpp new file mode 100644 index 00000000..2051a2d0 --- /dev/null +++ b/in_class/other/downto.cpp @@ -0,0 +1,9 @@ +#include + +int main() +{ + int x = 10; + while (x --> 0) { + std::cout << x << std::endl; + } +} diff --git a/in_class/other/multitype.cpp b/in_class/other/multitype.cpp new file mode 100644 index 00000000..d44e3ffb --- /dev/null +++ b/in_class/other/multitype.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +struct BaseNode { + virtual void Print() = 0; +}; + +template +struct Node : public BaseNode { + T value; + + Node(T value) : value(value) { } + + void Print() override { + std::cout << value << std::endl; + } +}; + +struct Container { + std::vector values; + + template + void AddValue(T in) { + values.push_back( new Node(in) ); + } + + void Print() { + for (auto ptr : values) ptr->Print(); + } +}; + + +int main() +{ + Container c; + c.AddValue(10); + c.AddValue("Test"); + c.AddValue('x'); + c.Print(); +} \ No newline at end of file diff --git a/in_class/other/template-template.cpp b/in_class/other/template-template.cpp new file mode 100644 index 00000000..2a7329b0 --- /dev/null +++ b/in_class/other/template-template.cpp @@ -0,0 +1,22 @@ +#include +#include +#include + +template typename CONTAINER_T=std::vector> +struct String { + CONTAINER_T str; + + size_t size() { return str.size(); } +}; + +int main() +{ + String str1; + String str2; + + str1.str.resize(10,' '); + str2.str.resize(15,'x'); + + std::cout << str1.size() << std::endl; + std::cout << str2.size() << std::endl; +} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..362e93f8 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,34 @@ +site_name: "CSE 491 Documentation" +site_description: "Documentation for CSE 491 Group 7 GP Agent" + +theme: + name: material + palette: + primary: green + accent: green + +plugins: + - search + - mkdoxy: + projects: + Core Project: # name of project must be alphanumeric + numbers (without spaces) + src-dirs: ./source/core # path to source code (support multiple paths separated by space) => INPUT + full-doc: True # if you want to generate full documentation + + doxy-cfg: # standard doxygen configuration (key: value) + FILE_PATTERNS: "*.cpp *.h*" # specify file patterns to filter out + RECURSIVE: True # recursive search in source directories + HIDE_UNDOC_MEMBERS: YES + HIDE_SCOPE_NAMES: YES + EXTRACT_ALL: NO + + GP Agents: + src-dirs: ./source/Agents/GP + full-doc: True + + doxy-cfg: + FILE_PATTERNS: "*.cpp *.h*" + RECURSIVE: True + HIDE_UNDOC_MEMBERS: YES + HIDE_SCOPE_NAMES: YES + EXTRACT_ALL: NO diff --git a/savedata/GPAgent/Z_gp_folder_save.push b/savedata/GPAgent/Z_gp_folder_save.push new file mode 100644 index 00000000..0b90e2b8 --- /dev/null +++ b/savedata/GPAgent/Z_gp_folder_save.push @@ -0,0 +1 @@ +sup \ No newline at end of file diff --git a/source/Agents/AStarAgent.hpp b/source/Agents/AStarAgent.hpp index b58ba7eb..771a88b9 100644 --- a/source/Agents/AStarAgent.hpp +++ b/source/Agents/AStarAgent.hpp @@ -1,94 +1,133 @@ /** - * @file AStarAgent.h + * This file is part of the Fall 2023, CSE 491 course project. + * @file AStarAgent.hpp + * @brief AStar Agent Class + * @note Status: PROPOSAL * @author Matt Kight - */ + **/ + #pragma once -#include #include "../core/AgentBase.hpp" #include "AgentLibary.hpp" +#include namespace walle { -/** - * Class that describes a AStarAgent class - */ -class AStarAgent : public cse491::AgentBase { - private: - std::vector path; ///< Path this agent is taking - cse491::GridPosition goal_position; ///< Where the agent wants to end up - int recalculate_after_x_turns = 100; ///< How often agent recalculates moves - int current_move_num = 0; ///< What move # we are currently on - - public: - AStarAgent(size_t id, const std::string &name) : AgentBase(id, name) { - } - - ~AStarAgent() = default; - - /// @brief This agent needs a specific set of actions to function. - /// @return Success. - bool Initialize() override { - return HasAction("up") && HasAction("down") && HasAction("left") && HasAction("right"); - } - - /** - * @brief Set where the agent should head towards - * @param x x-coordinate of the goal position - * @param y y-coordinate of the goal position - */ - void SetGoalPosition(const double x, const double y) { - goal_position = cse491::GridPosition(x, y); - } - - /** - * @brief Set where the agent should head towards - * @param gp position agent should go towards - */ - void SetGoalPosition(const cse491::GridPosition gp) { - goal_position = gp; - } - /** - * @brief Set how many moves should occur before recalculating path - * A lower number will react faster to updates in the world but will call A* search more often - * @param recalculate How often path should be recalculated - */ - void SetRecalculate(const int recalculate) { - recalculate_after_x_turns = recalculate; - } - - /** - * @brief Update the path to go to goal position - */ - void RecalculatePath() { - path = GetShortestPath(GetPosition(), goal_position, GetWorld(), *this); - current_move_num = 0; - } - /// Choose the action to take a step in the appropriate direction. - size_t SelectAction(const cse491::WorldGrid & /*grid*/, - const cse491::type_options_t & /* type_options*/, - const cse491::item_map_t & /* item_map*/, - const cse491::agent_map_t & /* agent_map*/) override { - // We are taking an action so another turn has passed - ++current_move_num; - // If the last step failed, or we need a new path the then regenerate the path - if (action_result == 0 || path.empty() || current_move_num > recalculate_after_x_turns) { - RecalculatePath(); - } - // Return whatever action gets us closer to our goal - if (!path.empty()) { - auto pos = path.back(); - path.pop_back(); - if (pos == position.Above()) - return action_map["up"]; - if (pos == position.Below()) - return action_map["down"]; - if (pos == position.ToLeft()) - return action_map["left"]; - if (pos == position.ToRight()) - return action_map["right"]; - } - return 0; // If no path then do not do anything - } -}; -}; + + /** + * Class that describes a AStarAgent class + */ + class AStarAgent : public cse491::AgentBase { + private: + std::vector path; ///< Path this agent is taking + cse491::GridPosition goal_position; ///< Where the agent wants to end up + int recalculate_after_x_turns = 100; ///< How often agent recalculates moves + int current_move_num = 0; ///< What move # we are currently on + + public: + /// @brief Constructor for creating a new AStarAgent object + /// @param id id of the agent + /// @param name name of the agent + AStarAgent(size_t id, const std::string &name) : AgentBase(id, name) {} + + ~AStarAgent() = default; + + /// @brief This agent needs a specific set of actions to function. + /// @return Success. + bool Initialize() override { + return HasAction("up") && HasAction("down") && HasAction("left") && + HasAction("right"); + } + + /** + * @brief Set where the agent should head towards + * @param x x-coordinate of the goal position + * @param y y-coordinate of the goal position + */ + void SetGoalPosition(const double x, const double y) { + goal_position = cse491::GridPosition(x, y); + } + + /** + * @brief Set where the agent should head towards + * @param gp position agent should go towards + */ + + void SetGoalPosition(const cse491::GridPosition gp) { + goal_position = gp; + } + + /** + * @brief gets the goal position and returns it + * @return goal_position member variable + */ + cse491::GridPosition GetGoalPosition() const {return goal_position; } + + /** + * Returns the recalculate value + * @return recalculated value + */ + int GetRecalculateValue() const {return recalculate_after_x_turns; } + + /** + * Gets the size of the current path + * @return length of path + */ + int GetPathLength() const {return path.size(); } + + + /** + * @brief Set how many moves should occur before recalculating path + * A lower number will react faster to updates in the world but will call A* + * search more often + * @param recalculate How often path should be recalculated + */ + void SetRecalculate(const int recalculate) { + recalculate_after_x_turns = recalculate; + } + + /** + * @brief Update the path to go to goal position + */ + void RecalculatePath() { + path = GetShortestPath(GetPosition(), goal_position, GetWorld(), *this); + if (!path.empty()){path.pop_back();} // Remove the val that we are currently at + current_move_num = 0; + } + + /// @brief Get the next position to move to + /// @return GridPosition to move to + [[nodiscard]] cse491::GridPosition GetNextPosition() override { + return !path.empty() ? path.back() : GetPosition(); + } + /// Choose the action to take a step in the appropriate direction. + size_t SelectAction(const cse491::WorldGrid & /*grid*/, + const cse491::type_options_t & /* type_options*/, + const cse491::item_map_t & /* item_map*/, + const cse491::agent_map_t & /* agent_map*/) override { + // We are taking an action so another turn has passed + ++current_move_num; + // If the last step failed, or we need a new path the then regenerate the + // path + if (action_result == 0 || path.empty() || + current_move_num > recalculate_after_x_turns) { + RecalculatePath(); + } + // Return whatever action gets us closer to our goal + if (!path.empty()) { + auto pos = path.back(); + path.pop_back(); + if (pos == position.Above()) + return action_map["up"]; + if (pos == position.Below()) + return action_map["down"]; + if (pos == position.ToLeft()) + return action_map["left"]; + if (pos == position.ToRight()) + return action_map["right"]; + } + return 0; // If no path then do not do anything + } + }; +}; // namespace walle diff --git a/source/Agents/AgentFactory.hpp b/source/Agents/AgentFactory.hpp new file mode 100644 index 00000000..c3610d3b --- /dev/null +++ b/source/Agents/AgentFactory.hpp @@ -0,0 +1,219 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @file AgentFactory.hpp + * @brief A factory class that abstracts away the initialization of adding an agent to a world + * @note Status: PROPOSAL + * @author Matt Kight + * @author David Rackerby + **/ + +#pragma once + +#include "../core/AgentBase.hpp" +#include "AStarAgent.hpp" +#include "PacingAgent.hpp" +#include "PathAgent.hpp" +#include "TrackingAgent.hpp" +#include "AgentLibary.hpp" + +#include "../core/Entity.hpp" +#include "../core/WorldBase.hpp" + +namespace walle { + +// Forward-declare since it's easier to understand how AddXAgent works +// when the structs are defined nearby +struct PacingAgentData; +struct PathAgentData; +struct AStarAgentData; +struct TrackingAgentData; + +class AgentFactory { +private: + cse491::WorldBase &world; /// The world to create Agents in + +public: + AgentFactory() = delete; + + /** + * Constructor for AgentFactory + * @param world we are adding agents too + */ + explicit AgentFactory(cse491::WorldBase &world) : world(world) {} + + AStarAgent &AddAStarAgent(const AStarAgentData &agent_data); + cse491::PacingAgent &AddPacingAgent(const PacingAgentData &agent_data); + TrackingAgent &AddTrackingAgent(const TrackingAgentData &agent_data); + PathAgent &AddPathAgent(const PathAgentData &agent_data); + +}; // class AgentFactory + +/** + * Stores data for AgentBase + */ +struct BaseAgentData { + /// Name of the agent + std::string name; + + /// Agent's position + cse491::GridPosition position; + + /// Agent's representation + char symbol = '*'; +}; + +/** + * Stores data for a PacingAgent + */ +struct PacingAgentData : public BaseAgentData { + /// Whether the PacingAgent is moving up and down (vertical) or left and right(!vertical) + bool vertical = false; +}; + +/** + * Add a PacingAgent to the world + * @param agent_data data for agent we want to create + * @return self + */ +cse491::PacingAgent &AgentFactory::AddPacingAgent(const PacingAgentData &agent_data) { + auto &entity = world.AddAgent(agent_data.name).SetPosition(agent_data.position).SetProperty( + "symbol", + agent_data.symbol); + auto &agent = DownCastAgent(entity); + agent.SetVertical(agent_data.vertical); + return agent; +} + +/** + * Stores data for a PathAgent + */ +struct PathAgentData : public BaseAgentData { + /// Starting index into the vector of GridPositions + int index; + + /// String representation of the path traveled (e.g. "n s e w" for north south east west) + std::string string_path; + + /// Set of grid positions that are applied to the agent's position during one step (constructed from string_path) + std::vector vector_path; +}; + +/** +* Add a PathAgent to the world +* @param agent_data data for agent we want to create +* @return self +*/ +PathAgent &AgentFactory::AddPathAgent(const PathAgentData &agent_data) { + auto &entity = world.AddAgent(agent_data.name).SetPosition(agent_data.position).SetProperty( + "symbol", + agent_data.symbol); + auto &agent = DownCastAgent(entity); + if (!agent_data.string_path.empty()) { + agent.SetProperty>("path", + agent_data.string_path); // TODO add another option to provide grid point + } else { + agent.SetPath(agent_data.vector_path); + } + agent.Initialize(); + return agent; +} + +/** + * Stores data for an AStarAgent + */ +struct AStarAgentData : public BaseAgentData { + /// Number of steps after which the shortest path is recalculated + int recalculate_after_x_turns = 5; + + /// The final position in the world that the AStarAgent is travelling to + cse491::GridPosition goal_pos; +}; + +/** + * Add an AStarAgent to the world + * @param agent_data data for agent we want to create + * @return self + */ +AStarAgent &AgentFactory::AddAStarAgent(const AStarAgentData &agent_data) { + auto &entity = world.AddAgent(agent_data.name).SetPosition(agent_data.position).SetProperty( + "symbol", + agent_data.symbol); + auto &agent = DownCastAgent(entity); + agent.SetGoalPosition(agent_data.goal_pos); + agent.SetRecalculate(agent_data.recalculate_after_x_turns); + return agent; +} + +/** + * Stores data for a TrackingAgent + */ +struct TrackingAgentData : public BaseAgentData { + /// Set of grid positions that are applied to the agent's position during one step (constructed from string_path) like in PathAgent + std::vector vector_path; + + /// String representation of the path traveled (e.g. "n s e w" for north south east west) like in PathAgent + std::string string_path; + + /// Goal Entity being tracked (must not be null or else the agent simply behaves like a PathAgent) + cse491::Entity *target; + + /// Distance that the TrackingAgent can "see" such that when the target enters that range, it begins tracking + int tracking_distance = 5; + + /// Where the TrackingAgent begins from patrolling from and returns two after the target moves out of range + cse491::GridPosition start_pos; + + /// Shared reference to an Alerter, which is non-null if the agent should be able to tell other agents to immediately + /// focus on their targets + /// @remark You should be using the **same** shared pointer across multiple instances of TrackingAgentData in order + /// to make the TrackingAgents part of the same network. This means you need to copy around this shared pointer + /// when using the factory + std::shared_ptr alerter = nullptr; + + /// Use initial values + TrackingAgentData() = default; + + /// Set all values + TrackingAgentData(std::string name, + cse491::GridPosition curr_pos, + char symbol, + std::string path, + cse491::Entity * target, + int tracking_dist, + cse491::GridPosition start_pos, + std::shared_ptr alerter) + : BaseAgentData({std::move(name), curr_pos, symbol}), + vector_path(StrToOffsets(path)), + string_path(std::move(path)), + target(target), + tracking_distance(tracking_dist), + start_pos(start_pos), + alerter(alerter) {} +}; + +/** +* Add a TrackingAgent to the world +* @param agent_data data for agent we want to create +* @return self +*/ +TrackingAgent &AgentFactory::AddTrackingAgent(const TrackingAgentData &agent_data) { + auto &entity = world.AddAgent(agent_data.name).SetPosition(agent_data.position).SetProperty( + "symbol", + agent_data.symbol); + auto &agent = DownCastAgent(entity); + if (!agent_data.string_path.empty()) { + agent.SetProperty>("path", agent_data.string_path); + } else { + agent.SetPath(agent_data.vector_path); + } + agent.SetTarget(agent_data.target); + agent.SetTrackingDistance(agent_data.tracking_distance); + agent.SetStartPosition(agent_data.start_pos); + if (agent_data.alerter != nullptr) { + agent.SetProperty("alerter", agent_data.alerter); + } + agent.Initialize(); + return agent; +} + +} // namespace walle diff --git a/source/Agents/AgentLibary.hpp b/source/Agents/AgentLibary.hpp index fe281887..8efcd44f 100644 --- a/source/Agents/AgentLibary.hpp +++ b/source/Agents/AgentLibary.hpp @@ -1,124 +1,271 @@ -// -// Created by Matthew Kight on 9/24/23. -// +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @file AgentLibrary.hpp + * @brief Structs and functions to aid in Agent creation + * @note Status: PROPOSAL + * @author Matt Kight + **/ + #pragma once -#include "../core/AgentBase.hpp" -#include "../core/WorldBase.hpp" -#include #include #include +#include +#include #include +#include + +#include "../core/AgentBase.hpp" +#include "../core/WorldBase.hpp" namespace walle { -/** - * @brief Node class to hold information about positions for A* search - */ -struct Node { - cse491::GridPosition position; ///< Where node is located - double g; ///< Cost from start to current node - double h; ///< Heuristic (estimated cost from current node to goal) - std::shared_ptr parent; ///< How we got to this node (Used to construct final path) - - /** - * Constructor for a node - * @param position location on grid of this node - * @param g actual distance to get from start to this node - * @param h heuristic guess for distance from this node to end location - * @param parent Used to construct path back at end - */ - Node(const cse491::GridPosition &position, double g, double h, std::shared_ptr parent) - : position(position), g(g), h(h), parent(std::move(parent)) {} - - /** - * @brief Calculate the total cost (f) of the node - * @return sum of actual distance and heuristic distance - */ - [[nodiscard]] double f() const { - return g + h; - } -}; + /** + * @brief Node class to hold information about positions for A* search + */ + struct Node { + cse491::GridPosition position; ///< Where node is located + double g; ///< Cost from start to current node + double h; ///< Heuristic (estimated cost from current node to goal) + std::shared_ptr + parent; ///< How we got to this node (Used to construct final path) -/** - * @brief Custom comparison function for priority queue - * @return if a has a greater total cost than b - */ -struct CompareNodes { - bool operator()(const std::shared_ptr &a, const std::shared_ptr &b) const { - return a->f() > b->f(); - } -}; - -/// @brief Uses A* to return a list of grid positions -/// @author @mdkdoc15 -/// @param start Starting position for search -/// @param end Ending position for the search -/// @return vector of A* path from start to end, empty vector if no path -/// exist -std::vector GetShortestPath(const cse491::GridPosition &start, - const cse491::GridPosition &end, - const cse491::WorldBase &world, - const cse491::AgentBase &agent) { - // Generated with the help of chat.openai.com - const size_t rows = world.GetGrid().GetWidth(); - const size_t cols = world.GetGrid().GetHeight(); - std::vector path; - // If the start or end is not valid then return empty list - if (!(world.GetGrid().IsValid(start) && world.GetGrid().IsValid(end))) - return path; + /** + * Constructor for a node + * @param position location on grid of this node + * @param g actual distance to get from start to this node + * @param h heuristic guess for distance from this node to end location + * @param parent Used to construct path back at end + */ + Node(const cse491::GridPosition &position, double g, double h, + std::shared_ptr parent) + : position(position), g(g), h(h), parent(std::move(parent)) {} + + /** + * @brief Calculate the total cost (f) of the node + * @return sum of actual distance and heuristic distance + */ + [[nodiscard]] double f() const { return g + h; } + }; + + /** + * @brief Custom comparison function for priority queue + * @return if a has a greater total cost than b + */ + struct CompareNodes { + bool operator()(const std::shared_ptr &a, + const std::shared_ptr &b) const { + return a->f() > b->f(); + } + }; - // Define possible movements (up, down, left, right) - const int dx[] = {-1, 1, 0, 0}; - const int dy[] = {0, 0, -1, 1}; + /// @brief Uses A* to return a list of grid positions + /// @author @mdkdoc15 + /// @param start Starting position for search + /// @param end Ending position for the search + /// @return vector of A* path from start to end, empty vector if no path exists + inline std::vector + GetShortestPath(const cse491::GridPosition &start, + const cse491::GridPosition &end, const cse491::WorldBase &world, + const cse491::AgentBase &agent) { + // Generated with the help of chat.openai.com + const size_t rows = world.GetGrid().GetWidth(); + const size_t cols = world.GetGrid().GetHeight(); + std::vector path; + // If the start or end is not valid then return empty list + if (!(world.GetGrid().IsValid(start) && world.GetGrid().IsValid(end))) + return path; - // Create a 2D vector to store the cost to reach each cell - std::vector> cost(rows, std::vector(cols, INT_MAX)); + // Define possible movements (up, down, left, right) + const int dx[] = {-1, 1, 0, 0}; + const int dy[] = {0, 0, -1, 1}; - // Create an open list as a priority queue - std::priority_queue, std::vector>, walle::CompareNodes> - openList; + // Create a 2D vector to store the cost to reach each cell + std::vector> cost(rows, + std::vector(cols, INT_MAX)); - // Create the start and end nodes - auto startNode = std::make_shared(start, 0, 0, nullptr); - auto endNode = std::make_shared(end, 0, 0, nullptr); + // Create an open list as a priority queue + std::priority_queue, + std::vector>, + walle::CompareNodes> + openList; - openList.push(startNode); - cost[start.CellX()][start.CellY()] = 0; + // Create the start and end nodes + auto startNode = std::make_shared(start, 0, 0, nullptr); + auto endNode = std::make_shared(end, 0, 0, nullptr); - while (!openList.empty()) { - auto current = openList.top(); - openList.pop(); + openList.push(startNode); + cost[start.CellX()][start.CellY()] = 0; - if (current->position == endNode->position) { + while (!openList.empty()) { + auto current = openList.top(); + openList.pop(); + + if (current->position == endNode->position) { + + // Reached the goal, reconstruct the path + while (current != nullptr) { + path.push_back(current->position); + current = current->parent; + } + break; + } - // Reached the goal, reconstruct the path - while (current != nullptr) { - path.push_back(current->position); - current = current->parent; - } - break; + // Explore the neighbors + for (int i = 0; i < 4; ++i) { + cse491::GridPosition newPos(current->position.GetX() + dx[i], + current->position.GetY() + dy[i]); + // Check if the neighbor is within bounds and is a valid move + if (world.GetGrid().IsValid(newPos) && + world.IsTraversable(agent, newPos)) { + double newG = + current->g + 1; // Assuming a cost of 1 to move to a neighbor + double newH = std::abs(newPos.GetX() - endNode->position.GetX()) + + std::abs(newPos.GetY() - + endNode->position.GetY()); // Manhattan distance + + if (newG + newH < cost[newPos.CellX()][newPos.CellY()]) { + auto neighbor = + std::make_shared(newPos, newG, newH, current); + openList.push(neighbor); + cost[newPos.CellX()][newPos.CellY()] = newG + newH; + } + } + } } + return path; + } + + /** + * Converts a string to a sequence of offsets + * + * This convenience method takes a string with a special formatting that allows + * one to specify a sequence of whitespace-separated inputs in linear + * directions. The format is [steps[*]] where `steps` is a positive + * integer and optional (assumed to be 1 by default) star `*` represents scaling + * the movement by `steps`. Optional, but cannot be used if `steps` is not + * provided if the star is not present, then `steps` individual offsets are + * created in the direction `direction` `direction` is a cardinal direction with + * the following logical mapping: n: north s: south e: east w: west x: stay put + * Example: "n w 3e 10*s 5*w x" should create the sequence of offsets + * {0, -1}, {-1, 0}, {1, 0}, {1, 0}, {1, 0}, {0, 10}, {-5, 0}, {0, 0} + * @param commands string in a format of sequential directions + * @note throws an `std::invalid_argument` when input string is poorly formatted + * @note this includes when a negative integer is passed as `steps`. If a zero + * is used, treated as the default (one) + */ + inline std::vector + StrToOffsets(std::string_view commands) { + std::vector positions; + + // Regex capturing groups logically mean the following: + // Group 0: whole regex + // Group 1: `steps` and `*` pair (optional)(unused) + // Group 2: `steps` (optional) + // Group 3: `*` (optional, only matches when Group 2 matches) + // Group 4: direction + std::regex pattern("(([1-9]\\d*)(\\*?))?([nswex])"); + std::istringstream iss{std::string(commands)}; + iss >> std::skipws; + + std::string single_command; + while (iss >> single_command) { + std::smatch pattern_match; + if (std::regex_match(single_command, pattern_match, pattern)) { + int steps = 1; + + if (pattern_match[2].length() > 0) { + std::istringstream step_val(pattern_match[1].str()); + step_val >> steps; + } + + bool multiply = pattern_match[3].length() > 0; - // Explore the neighbors - for (int i = 0; i < 4; ++i) { - cse491::GridPosition newPos(current->position.GetX() + dx[i], current->position.GetY() + dy[i]); - // Check if the neighbor is within bounds and is a valid move - if (world.GetGrid().IsValid(newPos) && world.IsTraversable(agent, newPos)) { - double newG = current->g + 1; // Assuming a cost of 1 to move to a neighbor - double newH = std::abs(newPos.GetX() - endNode->position.GetX()) + - std::abs(newPos.GetY() - endNode->position.GetY()); // Manhattan distance - - if (newG + newH < cost[newPos.CellX()][newPos.CellY()]) { - auto neighbor = std::make_shared(newPos, newG, newH, current); - openList.push(neighbor); - cost[newPos.CellX()][newPos.CellY()] = newG + newH; + char direction = pattern_match[4].str()[0]; + + cse491::GridPosition base_pos; + switch (direction) { + // Move up + case 'n': { + if (multiply) { + positions.push_back(base_pos.Above(steps)); + } else { + for (int i = 0; i < steps; ++i) { + positions.push_back(base_pos.Above()); + } + } + break; + } + + // Move down + case 's': { + if (multiply) { + positions.push_back(base_pos.Below(steps)); + } else { + for (int i = 0; i < steps; ++i) { + positions.push_back(base_pos.Below()); + } + } + break; + } + + // Move left + case 'w': { + if (multiply) { + positions.push_back(base_pos.ToLeft(steps)); + } else { + for (int i = 0; i < steps; ++i) { + positions.push_back(base_pos.ToLeft()); + } + } + break; + } + + // Move right + case 'e': { + if (multiply) { + positions.push_back(base_pos.ToRight(steps)); + } else { + for (int i = 0; i < steps; ++i) { + positions.push_back(base_pos.ToRight()); + } + } + break; + } + + // Stay + case 'x': { + // Using the `*` does nothing to scale the offset since it's scaling {0, + // 0} + steps = multiply ? 1 : steps; + + for (int i = 0; i < steps; ++i) { + positions.push_back(base_pos); + } + } + } + } else { + std::ostringstream what; + what << "Incorrectly formatted argument: " << single_command; + throw std::invalid_argument(what.str()); + } + + iss >> std::skipws; } - } + return positions; } - } - return path; -} + template + concept Agent_Type = std::is_base_of_v; + + /** + * @brief Helper function for simplifying downcasting entities that + * have been added to the world + */ + template + T &DownCastAgent(cse491::Entity &entity) requires(Agent_Type) { + assert(dynamic_cast(&entity)!=nullptr); + return static_cast(entity); + } -} +} // namespace walle diff --git a/source/Agents/GP/CGPAgent.hpp b/source/Agents/GP/CGPAgent.hpp new file mode 100644 index 00000000..dc2ea3fa --- /dev/null +++ b/source/Agents/GP/CGPAgent.hpp @@ -0,0 +1,145 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @brief An Agent based on genetic programming. + **/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "GPAgentBase.hpp" +#include "GraphBuilder.hpp" + +namespace cowboys { + /// Don't know the maximum size a state can be, arbitrary large number + constexpr size_t INPUT_SIZE = 9; + + /// Number of computational layers for each agent + constexpr size_t NUM_LAYERS = 3; + + /// The number of nodes in each layer + constexpr size_t NUM_NODES_PER_LAYER = 2; + + /// The number of layers preceding a node's layer that the node can reference + constexpr size_t LAYERS_BACK = 2; + + /// @brief An agent based on cartesian genetic programming. + class CGPAgent : public GPAgentBase { + protected: + /// The genotype for this agent. + CGPGenotype genotype; + + /// The decision graph for this agent. + std::unique_ptr decision_graph; + + + + public: + CGPAgent(size_t id, const std::string &name) : GPAgentBase(id, name) {} + CGPAgent(size_t id, const std::string &name, const CGPGenotype &genotype) + : GPAgentBase(id, name), genotype(genotype) {} + + + void PrintAgent() override { + std::cout << "Genotype: " << genotype.Export() << std::endl; + } + + void MutateAgent(double mutation = 0.8) override { + auto graph_builder = GraphBuilder(); + + genotype.MutateDefault(mutation, *this); + + decision_graph = graph_builder.CartesianGraph(genotype, FUNCTION_SET, this); + } + /// @brief Setup graph. + /// @return Success. + bool Initialize() override { + + // Create a default genotype if none was provided in the constructor + if (genotype.GetNumFunctionalNodes() == 0) { + genotype = CGPGenotype({INPUT_SIZE, action_map.size(), NUM_LAYERS, NUM_NODES_PER_LAYER, LAYERS_BACK}); + } + + // Mutate the beginning genotype, might not want this. + MutateAgent(0.2); + + return true; + } + + size_t GetAction(const cse491::WorldGrid &grid, const cse491::type_options_t &type_options, + const cse491::item_map_t &item_set, const cse491::agent_map_t &agent_set) override { + auto inputs = EncodeState(grid, type_options, item_set, agent_set, this, extra_state); + size_t action_to_take = decision_graph->MakeDecision(inputs, EncodeActions(action_map)); + return action_to_take; + } + + /// @brief Serialize this agent to XML. + /// @param doc The XML document to serialize to. + /// @param parentElem The parent element to serialize to. + /// @param fitness The fitness of this agent to write to the XML. + void SerializeGP(tinyxml2::XMLDocument &doc, tinyxml2::XMLElement *parentElem, double fitness = -1) override { + auto agentElem = doc.NewElement("CGPAgent"); + parentElem->InsertEndChild(agentElem); + + auto genotypeElem = doc.NewElement("genotype"); + genotypeElem->SetText(genotype.Export().c_str()); + if (fitness != -1) + genotypeElem->SetAttribute("fitness", fitness); + + genotypeElem->SetAttribute("seed" , seed); + + agentElem->InsertEndChild(genotypeElem); + + } + + /// @brief Export the genotype for this agent. + /// @return The string representation of the genotype for this agent. + std::string Export() override { return genotype.Export(); } + + /// @brief Load in the string representation of a genotype and configure this agent based on it. + /// @param genotype The string representation of a genotype. + void Import(const std::string &genotype) override { + this->genotype.Configure(genotype); + decision_graph = GraphBuilder().CartesianGraph(this->genotype, FUNCTION_SET, this); + } + + /// @brief Get the genotype for this agent. + /// @return A const reference to the genotype for this agent. + const CGPGenotype &GetGenotype() const { return genotype; } + + + /// @brief Copies the genotype and behavior of another CGPAgent into this agent. + /// @param other The CGPAgent to copy. + void Configure(const CGPAgent &other) { + genotype = other.GetGenotype(); + decision_graph = GraphBuilder().CartesianGraph(genotype, FUNCTION_SET, this); + } + + /// @brief Copy the behavior of another agent into this agent. + /// @param other The agent to copy. + void Copy(const GPAgentBase &other) override { + assert(dynamic_cast(&other) != nullptr); + Configure(dynamic_cast(other)); + } + + /// @brief The complexity of this agent. Used for fitness. + /// @return The complexity of this agent. + double GetComplexity() const { + double connection_complexity = + static_cast(genotype.GetNumConnections()) / genotype.GetNumPossibleConnections(); + + double functional_nodes = genotype.GetNumFunctionalNodes(); + + // Just needed some function such that connection_complexity + node_complexity grows as the number of nodes grows, this function makes the increase more gradual. + double node_complexity = std::log(functional_nodes) / 5; + + double complexity = connection_complexity + node_complexity; + return complexity; + } + }; + +} // End of namespace cowboys diff --git a/source/Agents/GP/CGPGenotype.hpp b/source/Agents/GP/CGPGenotype.hpp new file mode 100644 index 00000000..99d786ec --- /dev/null +++ b/source/Agents/GP/CGPGenotype.hpp @@ -0,0 +1,773 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../core/WorldBase.hpp" +#include "GPAgentBase.hpp" +#include "GraphNode.hpp" + +namespace cowboys { + + /// The separator between each parameter in the header, defining the cartesian graph. + constexpr char HEADER_SEP = ','; + /// The separator between the header and the genotype. + constexpr char HEADER_END = ';'; + /// The separator between each attribute in a node. + constexpr char NODE_GENE_SEP = '.'; + /// The separator between each node in the genotype. + constexpr char NODE_SEP = ':'; + + /// @brief A namespace for base64 encoding and decoding. Does not convert to and from base64 in the typical way. Only + /// guarantees that x == b64_inv(b64(x)), aside from doubles which have problems with precision, + /// so x ~= b64_inv(b64(x)). + namespace base64 { + /// The characters used to represent digits in base64. + static constexpr char CHARS[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"; + static constexpr size_t MAX_CHAR = *std::max_element(CHARS, CHARS + 64); + static constexpr std::array CHAR_TO_IDX = []() { + std::array indices{}; + for (size_t i = 0; i < 64; ++i) { + indices[CHARS[i]] = i; + } + return indices; + }(); + + /// @brief Converts a number in base10 to base64. + /// @param ull The number to convert. + /// @return The number in base64 as a string. + static std::string ULLToB64(size_t ull) { + if (ull == 0) + return "0"; + // Range of numbers represented by n digits of base b excluding 0: b^(n-1) <= x <= b^n - 1 + // -> n-1 <= log_b(x) -> n-1 = floor(log_b(x)) -> n = 1 + floor(log_b(x)) + // Or x + 1 <= b^n -> log_b(x + 1) <= n -> ceil(log_b(x + 1)) = n; But this can cause an overflow when adding 1 to + // the max value of size_t + size_t n = 1 + std::floor(std::log(ull) / std::log(64)); + std::string result(n, ' '); + for (size_t i = 0; ull > 0; ++i) { + result[n - 1 - i] = CHARS[ull % 64]; + ull /= 64; + } + return result; + } + + /// @brief Converts a number in base64 to base10. + /// @param num_base64 The number in base64 as a string. + /// @return The number in base10. + static size_t B64ToULL(std::string num_base64) { + size_t result = 0; + for (size_t i = 0; i < num_base64.size(); ++i) { + const char ch = num_base64[i]; + const size_t coeff = std::pow(64, num_base64.size() - i - 1); + result += CHAR_TO_IDX[ch] * coeff; + } + return result; + } + + /// @brief Converts a binary string to a base64 string. + /// @param binary A string of 1s and 0s representing binary. + /// @return The binary string in base64. + static std::string B2ToB64(const std::string &binary) { + // 2^6 = 64, so we can encode 6 bits at a time + + size_t remainder = binary.size() % 6; + if (remainder != 0) { + // Pad the binary string with 0s to make it divisible by 6 + return B2ToB64(std::string(6 - remainder, '0') + binary); + } + + std::string result; + result.reserve(binary.size() / 6); + bool all_zeros = true; + for (size_t i = 0; i < binary.size(); i += 6) { + std::string buffer = binary.substr(i, 6); + size_t ull = std::bitset<6>(buffer).to_ulong(); + result += CHARS[ull]; + if (ull != 0) + all_zeros = false; + } + if (all_zeros) // If all 0s, compress to 1 character + return std::string(1, CHARS[0]); + return result; + } + + /// @brief Converts a base64 string to a binary string. + /// @param base64 A string of base64 characters. + /// @return The base64 string in binary. + static std::string B64ToB2(std::string base64) { + std::string result = ""; + for (size_t i = 0; i < base64.size(); ++i) { + const char ch = base64[i]; + const size_t ull = CHAR_TO_IDX[ch]; + result += std::bitset<6>(ull).to_string(); + } + // Remove leading 0s and return result: https://stackoverflow.com/a/31226728/13430191 + return result.erase(0, std::min(result.find_first_not_of(CHARS[0]), result.size() - 1)); + } + + /// @brief Converts a double to a base64 string. Assumes that the stoull(to_string(value)) is possible. Only + /// guarantees that x ~= b64_inv(b64(x)) due to precision errors. Empirically accurate up to 3 decimal places, e.g. + /// round(x, 3) = round(b64_inv(b64(x)), 3). + /// @param value The double to convert. + /// @return The double in base64. + static std::string DoubleToB64(double value) { + std::string double_str = std::to_string(value); + + // Sign + // Store if it is positive or negative using the first base64 character or the second + char sign_b64 = CHARS[0]; + if (value < 0) { + sign_b64 = CHARS[1]; + // Remove the negative sign + double_str.erase(0, 1); + } + + // Decimal point + size_t decimal_loc = std::min(double_str.find('.'), double_str.size()); + // Remove the decimal point (does nothing if decimal_loc == double_str.size()) + double_str.erase(decimal_loc, 1); + // Location of the decimal from the right end of the string, so that leading 0s that are dropped can be recovered + size_t decimal_loc_from_right = double_str.size() - decimal_loc; + // Store decimal location using 1 base64 character (arbitrary choice, assumes decimal_loc < 64) + char decimal_loc_b64 = CHARS[decimal_loc_from_right]; + + // ULL + // Take the rest of the string as a ULL + size_t ull = std::stoull(double_str); + // Convert to base64 + std::string ull_b64 = ULLToB64(ull); + // Return decimal location and ULL + return std::string({decimal_loc_b64, sign_b64}) + ull_b64; + } + + /// @brief Converts a base64 string to a double. See @ref DoubleToB64 for precision issues. + /// @param value The base64 string to convert. + /// @return The base64 string as a double. + static double B64ToDouble(const std::string &value) { + assert(value.size() > 0); + // Get decimal location + size_t decimal_loc_from_right = CHAR_TO_IDX[value[0]]; + // Get sign + double sign = value[1] == CHARS[0] ? 1 : -1; + // Get ULL + std::string ull = std::to_string(B64ToULL(value.substr(2))); + if (ull.size() < decimal_loc_from_right) + ull = std::string(decimal_loc_from_right - ull.size() + 1, CHARS[0]) + ull; + // Insert decimal point + ull.insert(ull.size() - decimal_loc_from_right, "."); + // Return double + return sign * std::stod(ull); + } + } // namespace base64 + + /// @brief Holds the representation of a cartesian graph node. + struct CGPNodeGene { + /// The input connections of this node. '1' means connected, '0' means not connected. + std::vector input_connections{}; + + /// The index of the function the node uses. + size_t function_idx{0}; + + /// The default output of the node. + double default_output{0}; + + /// @brief Compare two CGPNodeGenes for equality. + /// @param other The other CGPNodeGene to compare to. + /// @return True if the two CGPNodeGenes are equal, false otherwise. + inline bool operator==(const CGPNodeGene &other) const { + return input_connections == other.input_connections && function_idx == other.function_idx && + default_output == other.default_output; + } + }; + + /// @brief Holds the parameters that define the structure of a cartesian graph. + struct CGPParameters { + /// The number of inputs to the graph. + size_t num_inputs{0}; + /// The number of outputs from the graph. + size_t num_outputs{0}; + /// The number of middle layers in the graph. + size_t num_layers{0}; + /// The number of nodes per middle layer. + size_t num_nodes_per_layer{0}; + /// The number of layers backward that a node can connect to. + size_t layers_back{0}; + + CGPParameters() = default; + + /// Constructor for the cartesian graph parameters. + CGPParameters(size_t num_inputs, size_t num_outputs, size_t num_layers, size_t num_nodes_per_layer, + size_t layers_back) + : num_inputs(num_inputs), num_outputs(num_outputs), num_layers(num_layers), + num_nodes_per_layer(num_nodes_per_layer), layers_back(layers_back) {} + + /// @brief Returns the number of functional nodes in the graph. + /// @return The number of functional nodes in the graph. + size_t GetFunctionalNodeCount() const { return num_layers * num_nodes_per_layer + num_outputs; } + + /// @brief Check if two CGPParameters are equal. + /// @param other The other CGPParameters to compare to. + /// @return True if the two CGPParameters are equal, false otherwise. + inline bool operator==(const CGPParameters &other) const { + return num_inputs == other.num_inputs && num_outputs == other.num_outputs && num_layers == other.num_layers && + num_nodes_per_layer == other.num_nodes_per_layer && layers_back == other.layers_back; + } + }; + + /// @brief Holds all the information that uniquely defines a cartesian graph. + class CGPGenotype { + protected: + /// The parameters of the cartesian graph. + CGPParameters params; + + /// The node configurations. + std::vector nodes; + + private: + /// @brief Encodes the header into a string. + /// @return The encoded header. + + std::string EncodeHeader() const { + std::string header; + header += std::to_string(params.num_inputs); + header += HEADER_SEP; + header += std::to_string(params.num_outputs); + header += HEADER_SEP; + header += std::to_string(params.num_layers); + header += HEADER_SEP; + header += std::to_string(params.num_nodes_per_layer); + header += HEADER_SEP; + header += std::to_string(params.layers_back); + return header; + } + + /// @brief Decodes the header of the genotype. + void DecodeHeader(const std::string &header) { + // Parse header and save to member variables + std::vector header_parts; + size_t start_pos = 0; + size_t comma_pos = header.find(HEADER_SEP, start_pos); + while (comma_pos != std::string::npos) { + header_parts.push_back(std::stoull(header.substr(start_pos, comma_pos - start_pos))); + start_pos = comma_pos + 1; + comma_pos = header.find(HEADER_SEP, start_pos); + } + header_parts.push_back(std::stoull(header.substr(start_pos))); + + if (header_parts.size() != 5) { + std::string message; + message += "Invalid genotype: Header should have 5 parameters but found "; + message += std::to_string(header_parts.size()); + message += "."; + throw std::runtime_error(message); + } + params.num_inputs = header_parts.at(0); + params.num_outputs = header_parts.at(1); + params.num_layers = header_parts.at(2); + params.num_nodes_per_layer = header_parts.at(3); + params.layers_back = header_parts.at(4); + } + + /// @brief Encodes the genotype into a string. + /// @return The encoded genotype. + std::string EncodeGenotype() const { + std::string genotype = ""; + for (const CGPNodeGene &node : nodes) { + // Input Connections + genotype += base64::B2ToB64(std::string(node.input_connections.cbegin(), node.input_connections.cend())); + genotype += NODE_GENE_SEP; + // Function index + genotype += base64::ULLToB64(node.function_idx); + genotype += NODE_GENE_SEP; + // Default output + genotype += base64::DoubleToB64(node.default_output); + // End of node + genotype += NODE_SEP; + } + return genotype; + } + + /// @brief Encodes the genotype into a string. + /// @return The encoded genotype. + std::string EncodeGenotypeRaw() const { + std::string genotype = ""; + for (const CGPNodeGene &node : nodes) { + // Input Connections + genotype += std::string(node.input_connections.cbegin(), node.input_connections.cend()); + genotype += NODE_GENE_SEP; + // Function index + genotype += std::to_string(node.function_idx); + genotype += NODE_GENE_SEP; + // Default output + genotype += std::to_string(node.default_output); + // End of node + genotype += NODE_SEP; + } + return genotype; + } + + /// @brief Decodes the genotype string and configures the node genes. Node gene vector should be initialized + /// before calling this. + void DecodeGenotype(const std::string &genotype) { + size_t node_gene_start = 0; + size_t node_gene_end = genotype.find(NODE_SEP, node_gene_start); + size_t node_idx = 0; + while (node_gene_end != std::string::npos) { + // Parse the node gene + std::string node_gene = genotype.substr(node_gene_start, node_gene_end - node_gene_start); + assert(node_idx < nodes.size()); + auto ¤t_node = nodes[node_idx]; + + // + // Input Connections + // + size_t sep_pos = node_gene.find(NODE_GENE_SEP); + assert(sep_pos != std::string::npos); + std::string input_connections_b64 = node_gene.substr(0, sep_pos); + std::string input_connections_b2 = base64::B64ToB2(input_connections_b64); + auto &input_connections = current_node.input_connections; + // If there were leading bits that were 0 when converted to base 64, they were dropped. Add them back. + std::string input_connections_str = std::string(input_connections.cbegin(), input_connections.cend()); + assert(input_connections.size() >= input_connections_b2.size()); // Invalid genotype if this fails + input_connections_b2 = + std::string(input_connections.size() - input_connections_b2.size(), '0') + input_connections_b2; + assert(input_connections.size() == input_connections_b2.size()); + for (size_t i = 0; i < input_connections_b2.size(); ++i) { + input_connections[i] = input_connections_b2[i]; + } + node_gene = node_gene.substr(sep_pos + 1); + + // + // Function index + // + sep_pos = node_gene.find(NODE_GENE_SEP); + std::string function_idx_str = node_gene.substr(0, std::min(sep_pos, node_gene.size())); + current_node.function_idx = base64::B64ToULL(function_idx_str); + node_gene = node_gene.substr(sep_pos + 1); + + // + // Default output + // + sep_pos = node_gene.find(NODE_GENE_SEP); + assert(sep_pos == std::string::npos); // Should be the last attribute + std::string default_output_str = node_gene.substr(0, std::min(sep_pos, node_gene.size())); + current_node.default_output = base64::B64ToDouble(default_output_str); + + // Move to next node gene + node_gene_start = node_gene_end + 1; + node_gene_end = genotype.find(NODE_SEP, node_gene_start); + ++node_idx; + } + } + + public: + /// @brief Default constructor for the cartesian graph genotype. Will have 0 functional nodes + CGPGenotype() = default; + /// @brief Constructor for the cartesian graph genotype. Initializes the genotype with the given parameters and + /// leaves everything default (nodes will be unconnected). + /// @param parameters The parameters of the cartesian graph. + CGPGenotype(const CGPParameters ¶meters) : params(parameters) { InitGenotype(); } + + // Rule of 5 + ~CGPGenotype() = default; + /// @brief Copy constructor for the cartesian graph genotype. + /// @param other The other cartesian graph genotype to copy from. + CGPGenotype(const CGPGenotype &other) { Configure(other.Export()); } + /// @brief Copy assignment operator for the cartesian graph genotype. + /// @param other The other cartesian graph genotype to copy from. + /// @return This cartesian graph genotype. + CGPGenotype &operator=(const CGPGenotype &other) { + Configure(other.Export()); + return *this; + } + /// @brief Move constructor for the cartesian graph genotype. + /// @param other The other cartesian graph genotype to move from. + CGPGenotype(CGPGenotype &&other) noexcept { + params = other.params; + nodes = std::move(other.nodes); + } + /// @brief Move assignment operator for the cartesian graph genotype. + /// @param other The other cartesian graph genotype to move from. + /// @return This cartesian graph genotype. + CGPGenotype &operator=(CGPGenotype &&other) noexcept { + params = other.params; + nodes = std::move(other.nodes); + return *this; + } + + /// @brief Configures this genotype from an encoded string. + /// @param encoded_genotype The encoded genotype. + /// @return This genotype. + CGPGenotype &Configure(const std::string &encoded_genotype) { + // Separate header and genotype + size_t newline_pos = encoded_genotype.find(HEADER_END); + if (newline_pos == std::string::npos) + throw std::runtime_error("Invalid genotype: No newline character found."); + std::string header = encoded_genotype.substr(0, newline_pos); + std::string genotype = encoded_genotype.substr(newline_pos + 1); + + // Parse header and save to member variables + DecodeHeader(header); + + // Initialize the genotype + InitGenotype(); + + // Decode genotype + DecodeGenotype(genotype); + + // Check if the number of functional nodes is correct + assert(nodes.size() == params.GetFunctionalNodeCount()); + + return *this; + } + + /// @brief Returns the iterator to the beginning of the node configurations. + /// @return The iterator to the beginning of the node configurations. + std::vector::iterator begin() { return nodes.begin(); } + + /// @brief Returns the iterator to the end of the node configurations. + /// @return The iterator to the end of the node configurations. + std::vector::iterator end() { return nodes.end(); } + + /// @brief Returns the const iterator to the beginning of the node configurations. + /// @return The const iterator to the beginning of the node configurations. + std::vector::const_iterator begin() const { return nodes.begin(); } + + /// @brief Returns the const iterator to the end of the node configurations. + /// @return The const iterator to the end of the node configurations. + std::vector::const_iterator end() const { return nodes.end(); } + + /// @brief Returns the const iterator to the beginning of the node configurations. + /// @return The const iterator to the beginning of the node configurations. + std::vector::const_iterator cbegin() const { return nodes.cbegin(); } + + /// @brief Returns the const iterator to the end of the node configurations. + /// @return The const iterator to the end of the node configurations. + std::vector::const_iterator cend() const { return nodes.cend(); } + + /// @brief Returns the number of possible connections in the graph. + /// @return The number of possible connections in the graph. + size_t GetNumPossibleConnections() const { + size_t num_connections = 0; + for (const CGPNodeGene &node : nodes) { + num_connections += node.input_connections.size(); + } + return num_connections; + } + + /// @brief Returns the number of connected connections in the graph. + /// @return The number of connected connections in the graph. + size_t GetNumConnections() const { + size_t num_connections = 0; + for (const CGPNodeGene &node : nodes) { + for (char con : node.input_connections) { + if (con == '1') + ++num_connections; + } + } + return num_connections; + } + + /// @brief Set the parameters of the cartesian graph. + /// @param params The parameters of the cartesian graph. Basically a 5-tuple. + void SetParameters(const CGPParameters ¶ms) { this->params = params; } + + /// @brief Returns the number of inputs to the graph. + /// @return The number of inputs to the graph. + size_t GetNumInputs() const { return params.num_inputs; } + + /// @brief Returns the number of outputs from the graph. + /// @return The number of outputs from the graph. + size_t GetNumOutputs() const { return params.num_outputs; } + + /// @brief Returns the number of middle layers in the graph. + /// @return The number of middle layers in the graph. + size_t GetNumLayers() const { return params.num_layers; } + + /// @brief Returns the number of nodes per middle layer. + /// @return The number of nodes per middle layer. + size_t GetNumNodesPerLayer() const { return params.num_nodes_per_layer; } + + /// @brief Returns the number of layers backward that a node can connect to. + /// @return The number of layers backward that a node can connect to. + size_t GetLayersBack() const { return params.layers_back; } + + /// @brief Returns the number of functional (non-input) nodes in the graph. + /// @return The number of functional (non-input) nodes in the graph. + size_t GetNumFunctionalNodes() const { return nodes.size(); } + + /// @brief Identify if the genome has any non-zero input connections in it. + /// @return Bool value to indicate if any input connections non-zero. + bool HasInputConnections() const { + for (auto it = begin(); it != end(); ++it) { + if (std::any_of(it->input_connections.begin(), it->input_connections.end(), [](char c) { return c != '0'; })) + return true; + } + return false; + } + + /// @brief Initializes an empty genotype with the cartesian graph parameters. + void InitGenotype() { + // Clear node configurations + nodes.clear(); + + // Input nodes won't have any inputs and no function, so they are skipped + + // Start at 1 to account for the input layer + for (size_t i = 1; i <= params.num_layers + 1; ++i) { + size_t layer_size = i == params.num_layers + 1 ? params.num_outputs : params.num_nodes_per_layer; + for (size_t j = 0; j < layer_size; ++j) { + // Count up possible input connections from each layer backwards + size_t valid_layers_back = std::min(params.layers_back, i); + size_t num_input_connections = valid_layers_back * params.num_nodes_per_layer; + if (i <= params.layers_back) { + num_input_connections -= params.num_nodes_per_layer; + num_input_connections += params.num_inputs; + } + // Create node gene using empty connections + std::vector input_connections(num_input_connections, '0'); + // Add the node configuration. With default values + nodes.push_back({input_connections}); + } + } + } + + /// @brief Exports this genotype into a string representation. + /// @return The string representation of this genotype. + std::string Export() const { + std::string header = EncodeHeader(); + std::string genotype = EncodeGenotype(); + return header + HEADER_END + genotype; + } + + /// @brief Exports this genotype into a string representation. + /// @return The string representation of this genotype. + std::string ExportRaw() const { + std::string header = EncodeHeader(); + std::string genotype = EncodeGenotypeRaw(); + return header + HEADER_END + genotype; + } + + /// @brief Mutates the genotype. + /// @param mutation_rate Value between 0 and 1 representing the probability of mutating a value. + /// @param mutation The function to use for mutating the output. The function will receive the node gene as a + /// parameter. + /// @return This genotype. + CGPGenotype &Mutate(double mutation_rate, GPAgentBase &agent, std::function mutation) { + assert(mutation_rate >= 0.0 && mutation_rate <= 1.0); + for (CGPNodeGene &node : nodes) + if (agent.GetRandom() < mutation_rate) + mutation(node); + return *this; + } + + /// @brief Mutates the input connections of the genotype. + /// @param mutation_rate The probability of mutating a connection. For a given connection, if it is chosen to be + /// mutated, there is a 50% chance it will stay the same. + /// @param agent The agent to use for random number generation. + /// @return This genotype. + CGPGenotype &MutateConnections(double mutation_rate, GPAgentBase &agent) { + std::uniform_int_distribution dist(0, 1); + Mutate(mutation_rate, agent, [&agent](CGPNodeGene &node) { + for (char &con : node.input_connections) { + con = agent.GetRandomULL(2) == 0 ? '0' : '1'; + } + }); + return *this; + } + + /// @brief Mutates the genotype by changing the function of each node with a given probability between 0 and 1. + /// @param mutation_rate The probability of changing the function of a node. + /// @param num_functions The number of functions available to the nodes. + /// @return This genotype. + CGPGenotype &MutateFunctions(double mutation_rate, size_t num_functions, GPAgentBase &agent) { + Mutate(mutation_rate, agent, + [num_functions, &agent](CGPNodeGene &node) { node.function_idx = agent.GetRandomULL(num_functions); }); + return *this; + } + + /// @brief Mutates the genotype, changing the default output of nodes with probability between 0 and 1. + /// @param mutation_rate Value between 0 and 1 representing the probability of mutating each value. + /// @param min The minimum value to generate for mutation. + /// @param max The maximum value to generate for mutation. + /// @return This genotype. + CGPGenotype &MutateOutputs(double mutation_rate, double mean, double std, GPAgentBase &agent, + bool additive = true) { + Mutate(mutation_rate, agent, [mean, std, &agent, additive](CGPNodeGene &node) { + double mutation = agent.GetRandomNormal(mean, std); + if (additive) { + node.default_output += mutation; + // Clamp to prevent overflow during genotype export + double min = std::numeric_limits::lowest(); + double max = std::numeric_limits::max(); + // Wrap random double in stod(to_string(.)) to reliably export and import genotype from string. + node.default_output = std::stod(std::to_string(std::clamp(node.default_output, min, max))); + } else { + node.default_output = std::stod(std::to_string(mutation)); + } + }); + return *this; + } + + /// @brief Mutates the header of the genotype. + /// @param mutation_rate Value between 0 and 1 representing the probability of mutating each value. + /// @param agent The agent to use for random number generation. + /// @return This genotype. + CGPGenotype &MutateHeader(double mutation_rate, GPAgentBase &agent) { + + // Must expand the genotype in a way so that the behavior is preserved + + // Can mutate number of inputs and outputs to adapt to changing state and action spaces, but not doing it for + // now + + // Mutate layers back + if (agent.GetRandom() < mutation_rate) { + // Update params + params.layers_back += 1; + // Add empty connections to each node at the front + // Start at 1 to account for the input layer + for (size_t i = 1; i <= params.num_layers + 1; ++i) { + size_t layer_size = i == params.num_layers + 1 ? params.num_outputs : params.num_nodes_per_layer; + for (size_t j = 0; j < layer_size; ++j) { + + // Get the old number of input connections + auto &curr_connections = nodes[(i - 1) * params.num_nodes_per_layer + j].input_connections; + size_t old_num_input_connections = curr_connections.size(); + + // Get the new number of input connections + size_t valid_layers_back = std::min(params.layers_back, i); + size_t num_input_connections = valid_layers_back * params.num_nodes_per_layer; + if (i <= params.layers_back) { + num_input_connections -= params.num_nodes_per_layer; + num_input_connections += params.num_inputs; + } + + // Push empty connections to the front of the vector of input connections + size_t num_needed = num_input_connections - old_num_input_connections; + if (num_needed > 0) { + // Create empty connections + std::vector input_connections(num_needed, '0'); + // Insert the empty connections into the front of the vector + curr_connections.insert(curr_connections.cbegin(), input_connections.cbegin(), input_connections.cend()); + } + } + } + } + + // Mutate number of nodes in each layer + if (agent.GetRandom() < mutation_rate) { + // Add a node to each middle layer and update connections for middle and output layers + std::vector new_nodes; + for (size_t i = 1; i <= params.num_layers + 1; ++i) { + // Add the nodes in this layer to the new node vector + size_t layer_start = (i - 1) * params.num_nodes_per_layer; + size_t layer_size = i == params.num_layers + 1 ? params.num_outputs : params.num_nodes_per_layer; + size_t layer_end = layer_start + layer_size; + size_t valid_layers_back = std::min(params.layers_back, i); + + // Get the number of connections for the new node + size_t new_num_connections = valid_layers_back * (params.num_nodes_per_layer + 1); + if (i <= params.layers_back) { + new_num_connections -= params.num_nodes_per_layer + 1; + new_num_connections += params.num_inputs; + } + size_t num_needed = new_num_connections - nodes[layer_start].input_connections.size(); + new_nodes.insert(new_nodes.cend(), nodes.cbegin() + layer_start, nodes.cbegin() + layer_end); + + // For middle layers, add a new node + if (i != params.num_layers + 1) { + auto newNode = std::vector(new_num_connections, '0'); + new_nodes.push_back({newNode}); + } + + // Add the extra connections for each node in this layer + if (i == 1) + // First layer doesn't have any connections to add because the input layer is unchanged + continue; + + size_t new_layer_start = (i - 1) * (params.num_nodes_per_layer + 1); + for (size_t j = 0; j < layer_size; ++j) { + // Add an empty connection at the end of each layer of connections in the valid layers back + assert(new_layer_start + j < new_nodes.size()); + auto &connections = new_nodes[new_layer_start + j].input_connections; + // Only iterate over the valid layers back that are middle layers, not including the input layer + for (size_t k = 0; k < num_needed; ++k) { + // Insert in reverse order to keep indices correct + size_t insert_pos = params.num_nodes_per_layer * (num_needed - k); + connections.insert(connections.cbegin() + insert_pos, '0'); + assert(*(connections.cbegin() + insert_pos) == '0'); + } + } + } + // Update params + params.num_nodes_per_layer += 1; + nodes = std::move(new_nodes); + // Check if everything is correct + assert(nodes.size() == params.GetFunctionalNodeCount()); + for (size_t i = 1; i < params.num_layers + 1; ++i) { + [[maybe_unused]] size_t layer_start = (i - 1) * params.num_nodes_per_layer; + size_t layer_size = i == params.num_layers + 1 ? params.num_outputs : params.num_nodes_per_layer; + size_t valid_layers_back = std::min(params.layers_back, i); + for (size_t j = 0; j < layer_size; ++j) { + // Check that the number of connections is correct + [[maybe_unused]] size_t num_connections = + valid_layers_back * params.num_nodes_per_layer; + if (i <= params.layers_back) { + num_connections -= params.num_nodes_per_layer; + num_connections += params.num_inputs; + } + assert(nodes[layer_start + j].input_connections.size() == num_connections); + } + } + } + + return *this; + } + + /// @brief Performs a mutation on the genotype with default parameters. + /// @param mutation_rate Value between 0 and 1 representing the probability of mutating each value. + /// @param agent The agent to use for random number generation. + /// @param num_functions The number of functions available to the nodes. + /// @return This genotype. + CGPGenotype &MutateDefault(double mutation_rate, GPAgentBase &agent, size_t num_functions = FUNCTION_SET.size()) { + MutateHeader(mutation_rate, agent); + MutateConnections(mutation_rate, agent); + MutateFunctions(mutation_rate, num_functions, agent); + MutateOutputs(mutation_rate, 0, 1, agent); + return *this; + } + + /// @brief Check if two CGPGenotypes are equal. CGPParameters and CGPNodeGenes should be equal. + /// @param other The other CGPGenotype to compare to. + /// @return True if the two CGPGenotypes are equal, false otherwise. + inline bool operator==(const CGPGenotype &other) const { + if (params != other.params) // Compare CGPParameters for equality + return false; + if (nodes.size() != other.nodes.size()) // # of genes should be equal + return false; + bool all_same = true; + for (auto it = cbegin(), it2 = other.cbegin(); it != cend(); ++it, ++it2) { + all_same = all_same && (*it == *it2); // Compare CGPNodeGenes for equality + } + return all_same; + } + + /// @brief Write the genotype representation to an output stream. + /// @param os The output stream to write to. + /// @param genotype The genotype to write. + /// @return The output stream. + friend std::ostream &operator<<(std::ostream &os, const CGPGenotype &genotype) { + os << genotype.ExportRaw(); + return os; + } + }; +} // namespace cowboys \ No newline at end of file diff --git a/source/Agents/GP/GPAgent.hpp b/source/Agents/GP/GPAgent.hpp index 3a332138..e4152d61 100644 --- a/source/Agents/GP/GPAgent.hpp +++ b/source/Agents/GP/GPAgent.hpp @@ -21,7 +21,7 @@ #include "./GPAgentSensors.hpp" /** - * @brief Namespace for GPagent and its related classes + * @brief Namespace for GPAgent and its related classes * * @note yeeeeeeeehaaaaaaaaa 🤠 */ diff --git a/source/Agents/GP/GPAgentAnalyze.h b/source/Agents/GP/GPAgentAnalyze.h new file mode 100644 index 00000000..d485bae5 --- /dev/null +++ b/source/Agents/GP/GPAgentAnalyze.h @@ -0,0 +1,104 @@ +// +// A class that analyzes the data of the best agent in the GP algorithm +// and saves it to a csv file +// + +#pragma once + +#include +#include +#include +#include + +namespace cowboys { + + class GPAgentAnalyzer { + private: + /// The average fitness of the best agent + std::vector average_fitness; + + /// The max fitness of the best agent + std::vector max_fitness; + + /// The weighted score of the best agent + std::vector elite_score; + + /// The average score of the best agent + std::vector average_score; + + /// The number of agents with the max fitness + std::vector max_agents; + + public: + /** + * @brief Construct a new GP Agent Analyzer object + */ + GPAgentAnalyzer() = default; + + /** + * @brief Destroy the GP Agent Analyzer object + */ + ~GPAgentAnalyzer() = default; + + /** + * @brief Adds the average fitness of the best agent + * @param fitness + */ + void addAverageFitness(double fitness) { + average_fitness.push_back(fitness); + } + + /** + * @brief Adds the max fitness of the best agent + * @param fitness + */ + void addMaxFitness(double fitness) { + max_fitness.push_back(fitness); + } + + /** + * @brief Adds the weighted score of the best agent + * @param score + */ + void addEliteScore(double score) { + elite_score.push_back(score); + } + + /** + * @brief Adds the average score of the best agent + * @param score + */ + void addAverageScore(double score) { + average_score.push_back(score); + } + + /** + * @brief Adds the number of agents with the max fitness + * @param num_agents + */ + void addNumAgentsWithMaxFitness(double num_agents) { + max_agents.push_back(num_agents); + } + + /** + * @brief Saves the data to a csv file + */ + void saveToFile() { + // create a new file + std::ofstream file("gp_agent_analyzer.csv"); + + // write the data to the file + file << "average_fitness,max_fitness,average_elite_score,best_agent_weighted_score,agents_with_max_fitness\n"; + + for (size_t i = 0; i < average_fitness.size(); i++) { + file << average_fitness[i] << "," << max_fitness[i] << "," << elite_score[i] << "," << average_score[i] << "," << max_agents[i] << "\n"; + } + std::cout << "Saved GP Agent Analyzer data to gp_agent_analyzer.csv" << std::endl; + + // close the file + file.close(); + } + }; + +} // namespace cowboys + diff --git a/source/Agents/GP/GPAgentBase.hpp b/source/Agents/GP/GPAgentBase.hpp new file mode 100644 index 00000000..16e192b7 --- /dev/null +++ b/source/Agents/GP/GPAgentBase.hpp @@ -0,0 +1,124 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @brief An Agent based on genetic programming. + * @note Status: PROPOSAL + **/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "tinyxml2.h" + +#include "../../core/AgentBase.hpp" + +namespace cowboys { + class GPAgentBase : public cse491::AgentBase { + protected: + std::unordered_map extra_state; ///< A map of extra state information. + unsigned int seed = 0; ///< Seed for the random number generator. + std::mt19937 rng{seed}; ///< Random number generator. + std::uniform_real_distribution uni_dist; ///< Uniform distribution. + std::normal_distribution norm_dist; ///< Normal distribution. + + public: + GPAgentBase(size_t id, const std::string &name) : AgentBase(id, name) { + Reset(); + } + ~GPAgentBase() = default; + + /// @brief Setup graph. + /// @return Success. + bool Initialize() override { return true; } + + /// Choose the action to take a step in the appropriate direction. + size_t SelectAction(const cse491::WorldGrid &grid, const cse491::type_options_t &type_options, + const cse491::item_map_t &item_set, const cse491::agent_map_t &agent_set) override { + // Update extra state information before action + if (extra_state["starting_x"] == std::numeric_limits::max()) { + auto pos = GetPosition(); + extra_state["starting_x"] = pos.GetX(); + extra_state["starting_y"] = pos.GetY(); + } + + size_t action = GetAction(grid, type_options, item_set, agent_set); + + // Update extra state information after action + extra_state["previous_action"] = action; + + return action; + } + + virtual size_t GetAction(const cse491::WorldGrid &grid, const cse491::type_options_t &type_options, + const cse491::item_map_t &item_set, const cse491::agent_map_t &agent_set) = 0; + + /// @brief Get a map of extra state information + /// @return Map of extra state information + const std::unordered_map GetExtraState() const { return extra_state; } + + /// @brief Mutate this agent. + /// @param mutation_rate The mutation rate. Between 0 and 1. + virtual void MutateAgent(double mutation_rate = 0.8) = 0; + + /// @brief Copy the behavior of another agent into this agent. + /// @param other The agent to copy. Should be the same type. + virtual void Copy(const GPAgentBase &other) = 0; + + virtual void PrintAgent(){ + + }; + + virtual void SerializeGP(tinyxml2::XMLDocument &doc, tinyxml2::XMLElement *parentElem, double fitness = -1) = 0; + + virtual std::string Export() { return ""; } + + virtual void Reset(bool /*hard*/ = false) { + extra_state["previous_action"] = 0; + extra_state["starting_x"] = std::numeric_limits::max(); + extra_state["starting_y"] = std::numeric_limits::max(); + }; + + // virtual void crossover(const GPAgentBase &other) {}; + virtual void Import(const std::string &genotype) = 0; + + // -- Random Number Generation -- + + /// @brief Set the seed used to initialize this RNG + void SetSeed(unsigned int seed) { + this->seed = seed; + rng.seed(seed); + } + + /// @brief Get the seed used to initialize this RNG + unsigned int GetSeed() const { return seed; } + + /// @brief Return a uniform random value between 0.0 and 1.0 + double GetRandom() { return uni_dist(rng); } + + /// @brief Return a uniform random value between 0.0 and max + double GetRandom(double max) { return GetRandom() * max; } + + /// @brief Return a uniform random value between min and max + double GetRandom(double min, double max) { + assert(max > min); + return min + GetRandom(max - min); + } + + /// @brief Return a uniform random unsigned long long between 0 (inclusive) and max (exclusive) + size_t GetRandomULL(size_t max) { return static_cast(GetRandom(max)); } + + /// @brief Return a gaussian random value with mean 0.0 and sd 1.0 + double GetRandomNormal() { return norm_dist(rng); } + + /// @brief Return a gaussian random value with provided mean and sd. + double GetRandomNormal(double mean, double sd = 1.0) { + assert(sd > 0); + return mean + norm_dist(rng) * sd; + } + }; + +} // End of namespace cowboys diff --git a/source/Agents/GP/GPAgentSensors.hpp b/source/Agents/GP/GPAgentSensors.hpp index 1a7ef861..095cd4dc 100644 --- a/source/Agents/GP/GPAgentSensors.hpp +++ b/source/Agents/GP/GPAgentSensors.hpp @@ -10,8 +10,6 @@ * * @static currently a static class * - * @note TODO: might have to move this over to core of the project - * @note TODO: might have to refactor to make it one function??? * * @author @amantham20 * @details currenly supports only wall distance sensors for left, right, top @@ -32,9 +30,9 @@ class Sensors { * @brief print the positions of the agent only during debug mode * @param printstring */ - [[maybe_unused]] static void debugPosition(const std::string &printstring) { + [[maybe_unused]] static void debugPosition(const std::string &/*printstring*/) { #ifndef NDEBUG - std::cout << printstring << std::endl; +// std::cout << printstring << std::endl; #endif } @@ -105,4 +103,4 @@ class Sensors { return SensorDirection::LEFT; } }; -} // namespace cowboys +} // namespace cowboys \ No newline at end of file diff --git a/source/Agents/GP/GPAgentsRegisters.hpp b/source/Agents/GP/GPAgentsRegisters.hpp index 84a5779f..e151ea8d 100644 --- a/source/Agents/GP/GPAgentsRegisters.hpp +++ b/source/Agents/GP/GPAgentsRegisters.hpp @@ -64,9 +64,9 @@ class GPAgentRegisters { * @brief Get the number of registers * @return size of the registers */ - int getNumRegisters() { return registers.size(); } + size_t getNumRegisters() { return registers.size(); } - int size() { return registers.size(); } + size_t size() { return registers.size(); } /** * @brief Iterator class for GPAgentRegisters diff --git a/source/Agents/GP/GPTrainingLoop.hpp b/source/Agents/GP/GPTrainingLoop.hpp new file mode 100644 index 00000000..ff4ea8ab --- /dev/null +++ b/source/Agents/GP/GPTrainingLoop.hpp @@ -0,0 +1,1085 @@ + +#pragma once + +#include "../../core/AgentBase.hpp" +#include "../../core/WorldBase.hpp" +//#include "GPAgent.hpp" +#include "GPAgentBase.hpp" + + +#include "CGPAgent.hpp" +#include "LGPAgent.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "tinyxml2.h" +#include "GPAgentAnalyze.h" + + +namespace cowboys { + + constexpr unsigned int TRAINING_SEED = 0; ///< If this is 0, then a random seed will be used + + template + class GPTrainingLoop { + private: + + std::vector> environments; + std::vector> agents; + std::vector> TEMPAgentFitness; + + GPAgentAnalyzer analyzer; + + tinyxml2::XMLDocument topAgentsDoc; + tinyxml2::XMLDocument lastGenerationsTopAgentsDoc; // <- Saves the last 5 generations + tinyxml2::XMLDocument allOfLastGeneration; + tinyxml2::XMLDocument metaData; + + + tinyxml2::XMLElement *rootTopAllGenerations = topAgentsDoc.NewElement("GPLoopTopOfAllGeneration"); + tinyxml2::XMLElement *rootTopLastGenerations = lastGenerationsTopAgentsDoc.NewElement("GPLoopLastNGeneration"); + tinyxml2::XMLElement *rootAllOfLastGeneration = allOfLastGeneration.NewElement("GPLoopAllOfLastGeneration"); + tinyxml2::XMLElement *rootMetaData = metaData.NewElement("GPLoopMetaData"); + + + std::vector> sortedAgents = std::vector>(); + + /** + * Default Grid + */ + const std::vector STARTPOSITIONS = {cse491::GridPosition(0,0), cse491::GridPosition(22,5) , cse491::GridPosition(22,1) , cse491::GridPosition(0,8), cse491::GridPosition(22,8)}; +// const std::vector STARTPOSITIONS = {cse491::GridPosition(0,0), cse491::GridPosition(22,5) }; +// const std::vector STARTPOSITIONS = {cse491::GridPosition(22,5) }; +// const std::vector STARTPOSITIONS = {cse491::GridPosition(0,0)}; + + +/** + * Group 8 Grid + */ +// const std::vector STARTPOSITIONS = {cse491::GridPosition(0,2), cse491::GridPosition(49,2) , cse491::GridPosition(49,19) , cse491::GridPosition(4,19), cse491::GridPosition(28,10)}; + + +/** + * Default Grid 2 + */ +// const std::vector STARTPOSITIONS = {cse491::GridPosition(0,0), cse491::GridPosition(50,0) , cse491::GridPosition(0,28) , cse491::GridPosition(50,28)}; + + /// ArenaIDX, AgentIDX, EndPosition + std::vector>> endPositions = std::vector>>(); + std::vector>> independentAgentFitness = std::vector>>(); + + int global_max_threads = std::thread::hardware_concurrency(); + int rollingRandomSeed = 0; + + double ELITE_POPULATION_PERCENT = 0.1; + double UNFIT_POPULATION_PERCENT = 0.2; + + public: + bool ScavengerQueuing = false; + + /** + * @brief: constructor + */ + GPTrainingLoop(const bool scavengerQueuing = false) : ScavengerQueuing(scavengerQueuing) { + + topAgentsDoc.InsertFirstChild(rootTopAllGenerations); + + rootMetaData = metaData.NewElement("GPLoopMetaData"); + metaData.InsertFirstChild(rootMetaData); + srand(TRAINING_SEED); + ResetMainTagLastGenerations(); + } + + /** + * Resets the xml for data that needs to be overwritten + */ + void ResetMainTagLastGenerations() { + rootTopLastGenerations = lastGenerationsTopAgentsDoc.NewElement("GPLoop"); + lastGenerationsTopAgentsDoc.InsertFirstChild(rootTopLastGenerations); + + rootAllOfLastGeneration = allOfLastGeneration.NewElement("GPLoopAllOfLastGeneration"); + allOfLastGeneration.InsertFirstChild(rootAllOfLastGeneration); + } + + /** + * @brief Initialize the training loop with a number of environments and agents per environment. + * @param numArenas + * @param NumAgentsForArena + */ + void Initialize(size_t numArenas = 5, size_t NumAgentsForArena = 100) { + + unsigned int seed = TRAINING_SEED; + if (seed == 0) { + seed = std::random_device()(); + } + std::cout << "Using seed: " << seed << std::endl; + + + for (size_t i = 0; i < numArenas; ++i) { + // instantiate a new environment + environments.emplace_back(std::make_unique(seed)); + + + agents.push_back(std::vector()); + + endPositions.push_back(std::vector>()); + independentAgentFitness.push_back(std::vector>()); + + for (size_t j = 0; j < NumAgentsForArena; ++j) { + + endPositions[i].push_back(std::vector()); + independentAgentFitness[i].push_back(std::vector()); + + for (size_t k = 0; k < STARTPOSITIONS.size(); ++k) { + endPositions[i][j].push_back(cse491::GridPosition(0, 0)); + independentAgentFitness[i][j].push_back(0); + } + + cowboys::GPAgentBase &addedAgent = static_cast(environments[i]->template AddAgent( + "Agent " + std::to_string(j))); + addedAgent.SetPosition(0, 0); + addedAgent.SetSeed(seed); + + agents[i].emplace_back(&addedAgent); + + } + + } + + loadLastGeneration(); + + Printgrid(STARTPOSITIONS); + + + const size_t numAgents = numArenas * NumAgentsForArena; + + std::stringstream ss; + // ss.imbue(std::locale("")); + ss << std::fixed << numAgents; + + std::cout << "number of agents " << std::fixed << ss.str() << std::endl; + + } + + + void loadLastGeneration() { + if (ScavengerQueuing) + { + + auto lastFile = FullLoadGrabLatestGeneration(); + + if (lastFile == "NOTTAFILE") + { + std::cout << "No last file found" << std::endl; + return; + } + + allOfLastGeneration.LoadFile(lastFile.string().c_str()); + rootAllOfLastGeneration = allOfLastGeneration.FirstChildElement("GPLoopAllOfLastGeneration"); + + std::cout << "Loaded last file" << std::endl; + +// if (auto agentType = dynamic_cast(&agents[0][0])) { +// std::cout << "Agent Type is CGPAgent" << std::endl; +// agentType->Import(lastFile.string()); +// } +// else if (auto agentType = dynamic_cast(&agents[0][0])) { +// std::cout << "Agent Type is LGPAgent" << std::endl; +// agentType->Import(lastFile.string()); +// } +// else { +// std::cout << "Agent Type is not CGPAgent or LGPAgent" << std::endl; +// } +// use typetraits to check the type of the agent + if (std::is_same::value) { + std::cout << "Agent Type is CGPAgent" << std::endl; + } + else if (std::is_same::value) { + std::cout << "Agent Type is LGPAgent" << std::endl; + assert(false); //TODO: Agent not implemented for import + } + else { + std::cout << "Agent Type is not CGPAgent or LGPAgent" << std::endl; + } + + + auto *latestGenerationElem = rootAllOfLastGeneration->FirstChildElement(); + std::cout << latestGenerationElem->Name() << std::endl; + auto *agentElem = latestGenerationElem->FirstChildElement(); + tinyxml2::XMLElement* generationElem = nullptr; + + std::cout << agentElem->Name() << std::endl; + size_t numArenas = agents.size(); + size_t NumAgentsForArena = agents.at(0).size(); + for (size_t i = 0; i < numArenas; ++i) { + for (size_t j = 0; j < NumAgentsForArena; ++j) { + + generationElem = agentElem->FirstChildElement(); + const char *genotypeData = generationElem->GetText(); + agents.at(i).at(j)->Import(genotypeData); + agentElem = agentElem->NextSiblingElement(); + } + } + + std::cout << "Agents LoadComplete" << std::endl; + + } + } + + std::filesystem::path FullLoadGrabLatestGeneration() { + std::filesystem::path normalizedAbsolutePath = getSystemPath(); + + std::string lastGenerationsPrefix = "allAgentData_"; + std::string lastGenerationsFilenameExtension = ".xml"; + + std::vector matchingFiles; + for (const auto & entry : std::filesystem::directory_iterator(normalizedAbsolutePath)) + { + if (entry.path().extension() == lastGenerationsFilenameExtension && entry.path().filename().string().find(lastGenerationsPrefix) != std::string::npos) + { + matchingFiles.push_back(entry.path()); + } + } + std::sort(matchingFiles.begin(), matchingFiles.end()); + + if (matchingFiles.empty()) + { + return "NOTTAFILE"; + } + + std::filesystem::path lastFile = matchingFiles.back(); + + std::cout << "Last File: " << lastFile << std::endl; + + return lastFile; + } + + + /** + * Simple and temporary fitness function + * @param agent + * @param startPosition + * @return + */ + double SimpleFitnessFunction(cse491::AgentBase &agent, cse491::GridPosition startPosition) { + double fitness = 0; + + // Euclidean distance + cse491::GridPosition currentPosition = agent.GetPosition(); + double distance = std::sqrt(std::pow(currentPosition.GetX() - startPosition.GetX(), 2) + + std::pow(currentPosition.GetY() - startPosition.GetY(), 2)); + + double score = distance; + + fitness += score; + + // Agent complexity, temporarily doing this in a bad way + if (auto *cgp = dynamic_cast(&agent)) { + fitness -= cgp->GetComplexity(); + } + + return fitness; + } + +// STARTPOSITIONS[startPos_idx], agents[arena][a]->GetPosition(), arena, a + double AStarFitnessFunction(const cse491::GridPosition & startpos, const cse491::GridPosition & endpos, int arena, int a) + { + double fitness = 0; + + // Euclidean distance + cse491::GridPosition currentPosition = endpos; + double distance = static_cast( + Get_A_StarDistance(startpos, currentPosition, arena, a) + ); + + + double score = distance; + + fitness += score; + + cse491::AgentBase &agent = *agents[arena][a]; + // Agent complexity, temporarily doing this in a bad way + if (auto *cgp = dynamic_cast(&agent)){ + fitness -= cgp->GetComplexity(); + } + + return fitness; + } + + /** + * Gets the path of the save location + * @return + */ + static std::filesystem::path getSystemPath() { + /// XML save filename data + std::string relativePath = "../../savedata/GPAgent/"; + std::filesystem::path absolutePath = std::filesystem::absolute(relativePath); + std::filesystem::path normalizedAbsolutePath = std::filesystem::canonical(absolutePath); + return normalizedAbsolutePath; + } + + /** + * Gets the date and time as a string + * @return + */ + static std::string getDateStr() { + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + + // Format the date and time as a string (hour-minute-second) + std::tm tm_time = *std::localtime(&now_time); + std::ostringstream oss; + oss << std::put_time(&tm_time, "%Y-%m-%d__%H_%M_%S"); + std::string dateTimeStr = oss.str(); + + return dateTimeStr; + } + + /** + * + * @param maxThreads + * @param numberOfTurns + */ + void ThreadTrainLoop(size_t maxThreads = 1, int numberOfTurns = 100) { + std::vector threads; + + size_t threadsComplete = 0; + + + + + for (size_t arena = 0; arena < environments.size(); ++arena) { + if (maxThreads == 0 || threads.size() < maxThreads) { + threads.emplace_back(&GPTrainingLoop::RunArena, this, arena, numberOfTurns); + + } else { + // Wait for one of the existing threads to finish + threads[0].join(); + threads.erase(threads.begin()); + threadsComplete++; + threads.emplace_back(&GPTrainingLoop::RunArena, this, arena, numberOfTurns); + } + + + size_t barWidth = 64; + float progress = (float) (arena+1) / environments.size(); + size_t pos = barWidth * progress; + std::cout << "["; + for (size_t i = 0; i < barWidth; ++i) { + if (i < pos) std::cout << "="; + else if (i == pos) std::cout << ">"; + else std::cout << " "; + } + std::cout << "] " << int(progress * 100.0) << " % - " << threadsComplete << " threads done\r"; + std::cout.flush(); + } + + // Wait for all threads to finish + for (auto &thread: threads) { + if (thread.joinable()) { + thread.join(); + threadsComplete+=maxThreads; + } + } + + std::cout << std::endl; + std::cout << "All threads done" << std::endl; + + + } + + + + /** + * @brief: runs the Genetic Programming training loop for a number of generations to evolve the agents + * + * @param numGenerations + * @param numberOfTurns + * @param maxThreads + */ + void Run(size_t numGenerations, + size_t numberOfTurns = 100, + size_t maxThreads = 0, bool saveData = false) { + + auto startTime = std::chrono::high_resolution_clock::now(); + + global_max_threads = maxThreads; + + + SaveDataParams saveDataParams(0); + saveDataParams.save = saveData; + saveDataParams.saveMetaData = true; + saveDataParams.saveAllAgentData = true; +// +// saveDataParams.saveTopAgents = true; +// saveDataParams.saveLastGenerations = true; + + + +// check to see if meta data exists + std::filesystem::path normalizedAbsolutePath = getSystemPath(); + std::string metaDataFilename = "metaData.xml"; +// check to see if the file exists + std::filesystem::path metaDataFullPath = normalizedAbsolutePath / metaDataFilename; + + + size_t generation = 0; // <- the generation to start at + + if (std::filesystem::exists(metaDataFullPath) && ScavengerQueuing) { + std::cout << "MetaData file exists" << std::endl; + metaData.LoadFile(metaDataFullPath.string().c_str()); + rootMetaData = metaData.FirstChildElement("GPLoopMetaData"); + auto *generationTag = rootMetaData->FirstChildElement(); + generation = generationTag->UnsignedAttribute("generation") + 1; + rollingRandomSeed = generationTag->UnsignedAttribute("randSeed"); + std::cout << "Starting at generation " << generation << std::endl; + + } else { + if (ScavengerQueuing) + { + std::cout << "MetaData file does not exist Starting a new Scavenger Queue" << std::endl; + } + rollingRandomSeed = TRAINING_SEED; + rootMetaData = metaData.NewElement("GPLoopMetaData"); + metaData.InsertFirstChild(rootMetaData); + } + + for (; generation < numGenerations; ++generation) { + srand(rollingRandomSeed); + rollingRandomSeed = rand(); + + auto generationStartTime = std::chrono::high_resolution_clock::now(); + saveDataParams.updateGeneration(generation); + + InitTEMPAgentFitness(); + ThreadTrainLoop(maxThreads, numberOfTurns); + + std::cout << std::endl; + + sortedAgents.clear(); + SortThemAgents(); + + int countMaxAgents = AgentsAnalysisComputationsAndPrint(generation); + + saveDataParams.countMaxAgents = countMaxAgents; + SaveDataCheckPoint(saveDataParams); + + + GpLoopMutateHelper(); + resetEnvironments(); + + auto generationEndTime = std::chrono::high_resolution_clock::now(); + auto generationDuration = std::chrono::duration_cast( + generationEndTime - generationStartTime); + std::cout << "Generation " << generation << " took " << generationDuration.count() / 1000000.0 << " seconds" + << std::endl; + analyzer.saveToFile(); + + } + + auto endTime = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(endTime - startTime); + std::cout << "Time taken by run: " << duration.count() / 1000000.0 << " seconds" << std::endl; + + if (saveData) { + + } + + MemGOBYE(); + } + + /** + * SaveDataParams for saving data in checkpoints + */ + struct SaveDataParams { + size_t generation; + bool save = false; + bool saveAllAgentData = false; + bool saveMetaData = true; + bool saveTopAgents = false; + bool saveLastGenerations = false; + + size_t countMaxAgents = 0; + + std::string dateTimeStr = getDateStr(); + std::filesystem::path normalizedAbsolutePath = getSystemPath(); + + size_t checkPointEvery = 5; + + SaveDataParams(size_t gen) : generation(gen) {} + + void updateGeneration(size_t gen) { generation = gen; } + }; + + + /** + * Saves checkpoint data to XML files everyso often + * @param params + */ + void SaveDataCheckPoint(const SaveDataParams ¶ms) { + if (!params.save) { + return; + } + + allOfLastGeneration.Clear(); + rootAllOfLastGeneration = allOfLastGeneration.NewElement("GPLoopAllOfLastGeneration"); + allOfLastGeneration.InsertFirstChild(rootAllOfLastGeneration); + + size_t totalNumberOfAgents = agents.size() * agents[0].size(); + + SerializeAgents(params.generation, rootAllOfLastGeneration, allOfLastGeneration, totalNumberOfAgents); + + if (params.saveTopAgents) { + SerializeAgents(params.generation, rootTopAllGenerations, topAgentsDoc); + } + + if (params.saveLastGenerations){ + SerializeAgents(params.generation, rootTopLastGenerations, lastGenerationsTopAgentsDoc, 5); + } + + std::string dateTimeStr = params.dateTimeStr; + std::filesystem::path normalizedAbsolutePath = params.normalizedAbsolutePath; + + + if (params.generation % params.checkPointEvery != 0) { + return; + } + + + if (params.saveMetaData) { + const std::string metaDataFilename = "metaData_" + dateTimeStr + ".xml"; + auto metaDataFullPath = normalizedAbsolutePath / metaDataFilename; + saveXMLDoc(metaData, metaDataFullPath.string()); + } + + if (params.saveAllAgentData) { + const std::string allAgentDataFilename = "allAgentData_" + dateTimeStr + ".xml"; + auto allAgentDataFullPath = normalizedAbsolutePath / allAgentDataFilename; + saveXMLDoc(allOfLastGeneration, allAgentDataFullPath.string()); + } + + + + if (params.saveTopAgents) { + const std::string filename = "AgentData_" + dateTimeStr + ".xml"; + auto fullPath = normalizedAbsolutePath / filename; + + saveXMLDoc(topAgentsDoc, fullPath.string()); + } + + if (params.saveLastGenerations) { + const std::string lastGenerationsFilename = "lastGenerations_" + dateTimeStr + ".xml"; + auto lastGenerationsFullPath = normalizedAbsolutePath / lastGenerationsFilename; + saveXMLDoc(lastGenerationsTopAgentsDoc, lastGenerationsFullPath.string()); + } + + + std::cout << "@@@@@@@@@@@@@@@@@@@@@@ " << "DataSaved" << " @@@@@@@@@@@@@@@@@@@@@@" << std::endl; + +// analyzer.saveToFile(getSystemPath() / "fitness.csv"); + lastGenerationsTopAgentsDoc.Clear(); + ResetMainTagLastGenerations(); + } + + + /** + * Helper function to format the data analysis + * @param pos + * @param precision + * @return + */ + std::string FormatPosition(const cse491::GridPosition & pos, int precision = 0) { + std::stringstream ss; + ss << std::fixed << std::setprecision(precision) << "[" << pos.GetX() << "," << pos.GetY() << "]"; + return ss.str(); + } + + size_t Get_A_StarDistance(const cse491::GridPosition & startpos, const cse491::GridPosition & endpos, int arenaIDX, int agentIDX) { + auto& agent = agents[arenaIDX][agentIDX]; + auto& world = environments[arenaIDX]; + + + auto distance = walle::GetShortestPath(startpos, endpos, *world, *agent).size() - 1; + assert(distance >= 0); + return distance; + } + + + /** + * Computes agents analysis metrics + * + * @param generation + * @return + */ + int AgentsAnalysisComputationsAndPrint(int generation, double deltaForMaxFitness = 0.1) { + // print average fitness + double averageFitness = 0; + double maxFitness = -10000; + + + std::pair bestAgent = std::make_pair(-1, -1); + + int countMaxAgents = 0; + for (size_t arena = 0; arena < environments.size(); ++arena) { + for (size_t a = 0; a < agents[arena].size(); ++a) { + averageFitness += TEMPAgentFitness[arena][a]; + + + if (abs(TEMPAgentFitness[arena][a] - maxFitness) > deltaForMaxFitness && + TEMPAgentFitness[arena][a] > maxFitness) { + maxFitness = TEMPAgentFitness[arena][a]; + bestAgent = std::make_pair(arena, a); + countMaxAgents = 1; + } + + if (abs(TEMPAgentFitness[arena][a] - maxFitness) < deltaForMaxFitness) { + countMaxAgents++; + } + } + } + + averageFitness /= (environments.size() * agents[0].size()); + + + std::cout << "Generation " << generation << " complete" << std::endl; + std::cout << "Average fitness: " << averageFitness << " "; + analyzer.addAverageFitness(averageFitness); + + std::cout << "Max fitness: " << maxFitness << std::endl; + analyzer.addMaxFitness(maxFitness); + + + + std::string tagName = "generation_" + std::to_string(generation); + auto *generationTag = metaData.NewElement(tagName.c_str()); + generationTag->SetAttribute("generation", generation); + + generationTag->SetAttribute("averageFitness", averageFitness); + generationTag->SetAttribute("maxFitness", maxFitness); + generationTag->SetAttribute("bestAgentIDX", bestAgent.second); + + generationTag->SetAttribute("Rand", rollingRandomSeed); + + rootMetaData->InsertFirstChild(generationTag); + + + + + std::cout << "Best agent: AGENT[" << bestAgent.first << "," << bestAgent.second << "] " << std::endl; + + std::cout << "Best Agent Final Positions" << std::endl; + + Printgrid(endPositions[bestAgent.first][bestAgent.second], 'A'); + + // auto& agent = agents[bestAgent.first][bestAgent.second]; + auto& startPosition = STARTPOSITIONS; + auto& endPosition = endPositions[bestAgent.first][bestAgent.second]; + + // auto& world = environments[bestAgent.first]; + + + auto calculateDistance = [](const cse491::GridPosition& startPosition, const cse491::GridPosition & currentPosition) { + return std::sqrt(std::pow(currentPosition.GetX() - startPosition.GetX(), 2) + + std::pow(currentPosition.GetY() - startPosition.GetY(), 2)); + }; + + int columnWidth = 10; // Adjust as needed + + std::cout << std::left << std::setw(columnWidth) << "Start" + << std::setw(columnWidth) << "Final" + << std::setw(columnWidth) << "Distance" + << "A* Distance\n"; + for (size_t i = 0; i < STARTPOSITIONS.size(); ++i) { + std::cout << std::setw(columnWidth) << FormatPosition(STARTPOSITIONS[i]) + << std::setw(columnWidth) << FormatPosition(endPositions[bestAgent.first][bestAgent.second][i]); + + + // Calculate and print Euclidean distance + double distance = calculateDistance(STARTPOSITIONS[i], endPositions[bestAgent.first][bestAgent.second][i]); + std::cout << std::fixed << std::setprecision(2) << std::setw(12) << distance; + + + // Calculate and print A* distance + size_t astarDistance = Get_A_StarDistance(startPosition[i], endPosition[i], bestAgent.first, bestAgent.second); + std::cout << std::setw(12) << astarDistance; + + + std::cout << std::endl; + } + + std::cout << "with best agent weighted score of " << TEMPAgentFitness[bestAgent.first][bestAgent.second] << std::endl; + std::cout << std::endl; + analyzer.addAverageScore(TEMPAgentFitness[bestAgent.first][bestAgent.second]); + + std::cout << "Number of agents with max fitness: " << countMaxAgents << std::endl; + std::cout << "------------------------------------------------------------------" << std::endl; + analyzer.addNumAgentsWithMaxFitness(countMaxAgents); + return countMaxAgents; + } + + /** + * @brief: sort the agents based on their fitness + */ + void SortThemAgents() { + for (size_t arena = 0; arena < environments.size(); ++arena) { + for (size_t a = 0; a < agents[arena].size(); ++a) { + sortedAgents.push_back(std::make_pair(arena, a)); + } + } + + std::sort(sortedAgents.begin(), sortedAgents.end(), + [&](const std::pair &a, const std::pair &b) { + return TEMPAgentFitness[a.first][a.second] > TEMPAgentFitness[b.first][b.second]; + }); + } + + + void saveXMLDoc(tinyxml2::XMLDocument ¶mdoc, std::string fullPath) { + if (paramdoc.SaveFile(fullPath.c_str()) == tinyxml2::XML_SUCCESS) { + // std::filesystem::path fullPath = std::filesystem::absolute("example.xml"); + std::cout << "XML file saved successfully to: " << fullPath << std::endl; + } else { + std::cout << "Error saving XML file." << std::endl; +// std::cout << "Error ID: " << paramdoc.ErrorID() << std::endl; + std::cout << "Error for path" << fullPath << std::endl; + } + } + + + /** + * @brief: Serializes the agents to an XML file. + * + * @param countMaxAgents + * @param generation + * @param topN + */ + void SerializeAgents(int generation, tinyxml2::XMLElement *rootElement, tinyxml2::XMLDocument ¶mDocument, + size_t topN = 5) { + + std::string tagName = "generation_" + std::to_string(generation); + auto *generationTag = paramDocument.NewElement(tagName.c_str()); + + + rootElement->InsertFirstChild(generationTag); + + for (size_t i = 0; i < std::min(sortedAgents.size(), topN); ++i) { + auto [arenaIDX, agentIDX] = sortedAgents[i]; + agents[arenaIDX][agentIDX]->SerializeGP(paramDocument, generationTag, TEMPAgentFitness[arenaIDX][agentIDX]); + } + + + } + + /** + * @brief: initialize the TEMP agent fitness vector + */ + void InitTEMPAgentFitness() { + for (size_t arena = 0; arena < environments.size(); ++arena) { + TEMPAgentFitness.push_back(std::vector(agents[arena].size(), 0)); + } + } + + + /** + * @brief Helper function for the GP loop mutate function. + * This function mutates the agents. + * This function is called in a thread. + * + * @param start : The start index of the agents to mutate. + * @param end : The end index of the agents to mutate. + * @param sortedAgents : The sorted agents' index vector. + * @param agents : The agents vector. + * @param mutationRate: The mutation rate. + */ + void MutateAgents(int start, int end, const std::vector> &sortedAgents, + std::vector> &agents, double mutationRate) { + for (int i = start; i < end; i++) { + auto [arenaIDX, agentIDX] = sortedAgents[i]; + agents[arenaIDX][agentIDX]->MutateAgent(mutationRate); + + if (i % (sortedAgents.size() / 10) == 0) { + std::cout << " --- mutation complete " << (i * 1.0 / sortedAgents.size()) << std::endl; + } + } + } + + /** + * @brief Helper function for the GP loop mutate function. + * This function copies the elite agents and mutates them. + * This function is called in a thread. + * for th + * @param start + * @param end + * @param sortedAgents + * @param agents + * @param elitePopulationSize + */ + void MutateAndCopyAgents(int start, int end, const std::vector> &sortedAgents, + std::vector> &agents, int elitePopulationSize) { + for (int i = start; i < end; i++) { + auto [arenaIDX, agentIDX] = sortedAgents[i]; + auto eliteINDEX = rand() % elitePopulationSize; + auto [eliteArenaIDX, eliteAgentIDX] = sortedAgents[eliteINDEX]; + + agents[arenaIDX][agentIDX]->Copy(*agents[eliteArenaIDX][eliteAgentIDX]); + agents[arenaIDX][agentIDX]->MutateAgent(0.01); + + if (i % (sortedAgents.size() / 10) == 0) { + std::cout << " --- mutation complete " << (i * 1.0 / sortedAgents.size()) << std::endl; + } + } + } + + /** + * @brief Helper function for the GP loop mutate function. + * + */ + void GpLoopMutateHelper() { + +// constexpr double ELITE_POPULATION_PERCENT = 0.1; +// constexpr double UNFIT_POPULATION_PERCENT = 0.2; + + + const int ELITE_POPULATION_SIZE = int(ELITE_POPULATION_PERCENT * sortedAgents.size()); + + + double averageEliteFitness = 0; + for (int i = 0; i < ELITE_POPULATION_SIZE; i++) { + auto [arenaIDX, agentIDX] = sortedAgents[i]; + averageEliteFitness += TEMPAgentFitness[arenaIDX][agentIDX]; + } + averageEliteFitness /= ELITE_POPULATION_SIZE; + + std::cout << " --- average elite score " << averageEliteFitness << "------ " << std::endl; + analyzer.addEliteScore(averageEliteFitness); + + const int MIDDLE_MUTATE_ENDBOUND = int(sortedAgents.size() * (1 - UNFIT_POPULATION_PERCENT)); + const int MIDDLE_MUTATE_STARTBOUND = int(ELITE_POPULATION_PERCENT * sortedAgents.size()); + + // Determine the number of threads to use + const int num_threads = global_max_threads; +// const int num_threads = std::min(static_cast(std::thread::hardware_concurrency()), global_max_threads); + + std::vector threads; + + // Calculate the number of agents per thread + int agents_per_thread = (MIDDLE_MUTATE_ENDBOUND - MIDDLE_MUTATE_STARTBOUND) / num_threads; + + // Launch threads for the first loop + for (int i = 0; i < num_threads; ++i) { + int start = MIDDLE_MUTATE_STARTBOUND + i * agents_per_thread; + int end = (i == num_threads - 1) ? MIDDLE_MUTATE_ENDBOUND : start + agents_per_thread; + threads.push_back(std::thread([this, start, end] { + this->MutateAgents(start, end, sortedAgents, agents, 0.05); + })); + } + + // Join the threads + for (auto &t: threads) { + t.join(); + } + + threads.clear(); + + // Second loop - copy and mutate agents + // int unfitAgents = int(sortedAgents.size() * UNFIT_POPULATION_PERCENT); + agents_per_thread = (sortedAgents.size() - MIDDLE_MUTATE_ENDBOUND) / num_threads; + for (int i = 0; i < num_threads; ++i) { + int start = MIDDLE_MUTATE_ENDBOUND + i * agents_per_thread; + int end = (i == num_threads - 1) ? sortedAgents.size() : start + agents_per_thread; + + threads.push_back(std::thread([this, start, end, ELITE_POPULATION_SIZE] { + this->MutateAndCopyAgents(start, end, sortedAgents, agents, ELITE_POPULATION_SIZE); + })); + } + + for (auto &t: threads) { + t.join(); + } + + + } + + /** + * @brief Prints the grid for a single arena. + * @param arenaId + * @author: @amantham20 + */ + void Printgrid(const std::vector &positions, char symbol = 'S') { + + if (environments.empty()) { + std::cout << "No environments to print" << std::endl; + return; + } + + size_t arena = 0; + auto &grid = environments[arena]->GetGrid(); + std::vector symbol_grid(grid.GetHeight()); + + + const auto &type_options = environments[arena]->GetCellTypes(); + // Load the world into the symbol_grid; + for (size_t y = 0; y < grid.GetHeight(); ++y) { + symbol_grid[y].resize(grid.GetWidth()); + for (size_t x = 0; x < grid.GetWidth(); ++x) { + symbol_grid[y][x] = type_options[grid.At(x, y)].symbol; + } + } + + + + for (size_t pos_idx = 0; pos_idx < positions.size(); ++pos_idx) { + + assert(positions[pos_idx].CellY() < symbol_grid.size()); + assert(positions[pos_idx].CellX() < symbol_grid[positions[pos_idx].CellY()].size()); + symbol_grid[positions[pos_idx].CellY()][positions[pos_idx].CellX()] = symbol; + } + + +// const auto &agent_set = agents[arena]; +// for (const auto &agent_ptr: agent_set) { +// cse491::GridPosition pos = agent_ptr->GetPosition(); +// char c = '*'; +// if (agent_ptr->HasProperty("symbol")) { +// c = agent_ptr->template GetProperty("symbol"); +// } +// symbol_grid[pos.CellY()][pos.CellX()] = c; +// } + + std::cout << " "; + for (size_t x = 0; x < grid.GetWidth(); ++x) { + if (x % 10 == 0 && x != 0) { + std::cout << x / 10; // Print the ten's place of the column number + } else { + std::cout << " "; // Space for non-marker columns + } + } + std::cout << "\n"; + + // Print column numbers + std::cout << " "; // Space for row numbers + for (size_t x = 0; x < grid.GetWidth(); ++x) { + std::cout << x % 10; // Print only the last digit of the column number + } + std::cout << "\n"; + + // Print out the symbol_grid with a box around it. + std::cout << " +" << std::string(grid.GetWidth(), '-') << "+\n"; + for (size_t y = 0; y < grid.GetHeight(); ++y) { + + if (y % 10 == 0 && y != 0) { + std::cout << y / 10 << " "; // Print the ten's place of the row number + } else { + std::cout << " "; // Space for non-marker rows + } + + // Print row number + std::cout << y % 10 << "|"; // Print only the last digit of the row number + for (char cell: symbol_grid[y]) { + std::cout << cell; + } + std::cout << "|\n"; + } + + std::cout << " +" << std::string(grid.GetWidth(), '-') << "+\n"; + std::cout << std::endl; + } + + + + /** + * @brief Resets the environments to their initial state. + * This function is called after each generation. + * This function currently only soft resets the environments. + */ + void resetEnvironments() { + + for (size_t arena = 0; arena < environments.size(); ++arena) { + for (size_t a = 0; a < agents[arena].size(); ++a) { + agents[arena][a]->Reset(); + } + } + + TEMPAgentFitness.clear(); + } + + /** + * @brief Runs the training loop for a single arena. + * This function is called in a thread. + * Each arena is run in a separate thread. + * + * @author: @amantham20 + * @param arena : The arena to run. + * @param numberOfTurns : The number of turns to run the arena for. + */ + void RunArena(size_t arena, size_t numberOfTurns) { + for (size_t startPos_idx = 0; startPos_idx < STARTPOSITIONS.size(); ++startPos_idx) { + for(size_t a = 0; a < agents[arena].size(); ++a) { + // Reset the agent before each run + agents[arena][a]->Reset(); + // Set the starting position + agents[arena][a]->SetPosition(STARTPOSITIONS[startPos_idx]); + } + + for (size_t turn = 0; turn < numberOfTurns; turn++) { + environments[arena]->RunAgents(); + environments[arena]->UpdateWorld(); + } + for (size_t a = 0; a < agents[arena].size(); ++a) { +// double tempscore = SimpleFitnessFunction(*agents[arena][a], STARTPOSITIONS[startPos_idx]); + double tempscore = AStarFitnessFunction(STARTPOSITIONS[startPos_idx], agents[arena][a]->GetPosition(), arena, a); + auto tempEndPosition = agents[arena][a]->GetPosition(); + endPositions[arena][a][startPos_idx] = tempEndPosition; + independentAgentFitness[arena][a][startPos_idx] = tempscore; + TEMPAgentFitness[arena][a] += tempscore; + + } + + } + + for (size_t a = 0; a < agents[arena].size(); ++a) { + std::vector scores = independentAgentFitness[arena][a]; + // auto computeMedian = [&scores]() -> double { + // std::vector temp(scores); // Copy the data + // std::sort(temp.begin(), temp.end()); + + // size_t n = temp.size(); + // return n % 2 ? temp[n / 2] : (temp[n / 2 - 1] + temp[n / 2]) / 2.0; + // }; + + +// TEMPAgentFitness[arena][a] /= STARTPOSITIONS.size(); +// TEMPAgentFitness[arena][a] += computeMedian(); +// double min = *std::min_element(scores.begin(), scores.end()); + [[maybe_unused]] double avg = TEMPAgentFitness[arena][a] / STARTPOSITIONS.size(); + // TEMPAgentFitness[arena][a] = 0.7 * min + 0.3 * avg; + // TEMPAgentFitness[arena][a] = min; + TEMPAgentFitness[arena][a] = avg; + } + + } + + /** + * @brief Clears the memory of the training loop. + */ + void MemGOBYE() { + + TEMPAgentFitness.clear(); + environments.clear(); + agents.clear(); + sortedAgents.clear(); + + } + + ~GPTrainingLoop() = default; + }; +} diff --git a/source/Agents/GP/Graph.hpp b/source/Agents/GP/Graph.hpp new file mode 100644 index 00000000..4580ab7f --- /dev/null +++ b/source/Agents/GP/Graph.hpp @@ -0,0 +1,144 @@ + +#pragma once + +#include +#include +#include +#include +#include + +#include "../../core/AgentBase.hpp" +#include "../AgentLibary.hpp" +#include "GraphNode.hpp" + +namespace cowboys { + using GraphLayer = std::vector>; + + /// @brief A graph of nodes that can be used to make decisions. + class Graph { + protected: + /// Layers of nodes in the graph. + std::vector layers; + + public: + Graph() = default; + ~Graph() = default; + + /// @brief Get the number of nodes in the graph. + /// @return The number of nodes in the graph. + size_t GetNodeCount() const { + return std::accumulate(layers.cbegin(), layers.cend(), 0, + [](size_t sum, const auto &layer) { return sum + layer.size(); }); + } + + /// @brief Get the number of layers in the graph. + /// @return The number of layers in the graph. + size_t GetLayerCount() const { return layers.size(); } + + /// @brief Makes a decision based on the inputs and the action vector. + /// @param inputs The inputs to the graph. + /// @param action_vec The action vector. + /// @return The action to take. + size_t MakeDecision(const std::vector &inputs, const std::vector &actions) { + if (layers.size() == 0) + return actions.at(0); + + // Set inputs of input layer + size_t i = 0; + for (auto &node : layers[0]) { + double input = 0; + if (i < inputs.size()) + input = inputs.at(i); + node->SetDefaultOutput(input); + ++i; + } + + // Get output of last layer + std::vector outputs; + for (auto &node : layers.back()) { + outputs.push_back(node->GetOutput()); + } + + // Choose the action with the highest output + auto max_output = std::max_element(outputs.cbegin(), outputs.cend()); + size_t index = std::distance(outputs.cbegin(), max_output); + + // If index is out of bounds, return the last action + size_t action = 0; + if (index >= actions.size()) + action = actions.back(); + else // Otherwise, return the action at the index + action = actions.at(index); + return action; + } + + /// @brief Add a layer to the graph. Purely organizational, but important for CGP for determining the "layers back" + /// parameter. + /// @param layer The layer of nodes to add. + void AddLayer(const GraphLayer &layer) { layers.push_back(layer); } + + /// @brief Returns a vector of functional (non-input) nodes in the graph. + /// @return A vector of functional nodes in the graph. + std::vector> GetFunctionalNodes() const { + std::vector> functional_nodes; + for (size_t i = 1; i < layers.size(); ++i) { + functional_nodes.insert(functional_nodes.cend(), layers.at(i).cbegin(), layers.at(i).cend()); + } + return functional_nodes; + } + + /// @brief Returns a vector of all nodes in the graph. + /// @return A vector of all nodes in the graph. + std::vector> GetNodes() const { + std::vector> all_nodes; + for (auto &layer : layers) { + all_nodes.insert(all_nodes.cend(), layer.cbegin(), layer.cend()); + } + return all_nodes; + } + }; + + /// @brief Encodes the actions from an agent's action map into a vector of + /// size_t, representing action IDs. + /// @param action_map The action map from the agent. + /// @return A vector of size_t, representing action IDs. + std::vector EncodeActions(const std::unordered_map &action_map) { + std::vector actions; + for (const auto &[action_name, action_id] : action_map) { + actions.push_back(action_id); + } + // Sort the actions so that they are in a consistent order. + std::sort(actions.begin(), actions.end()); + return actions; + } + + /// @brief Translates state into nodes for the decision graph. + /// @return A vector of doubles for the decision graph. + std::vector EncodeState(const cse491::WorldGrid &grid, const cse491::type_options_t & /*type_options*/, + const cse491::item_map_t & /*item_set*/, const cse491::agent_map_t & /*agent_set*/, + const cse491::AgentBase *agent, + const std::unordered_map &extra_agent_state) { + /// TODO: Implement this function properly. + std::vector inputs; + + auto current_position = agent->GetPosition(); + + double current_state = grid.At(current_position); + double above_state = grid.IsValid(current_position.Above()) ? grid.At(current_position.Above()) : 0.; + double below_state = grid.IsValid(current_position.Below()) ? grid.At(current_position.Below()) : 0.; + double left_state = grid.IsValid(current_position.ToLeft()) ? grid.At(current_position.ToLeft()) : 0.; + double right_state = grid.IsValid(current_position.ToRight()) ? grid.At(current_position.ToRight()) : 0.; + + double prev_action = extra_agent_state.at("previous_action"); + double starting_x = extra_agent_state.at("starting_x"); + double starting_y = extra_agent_state.at("starting_y"); + auto starting_pos = cse491::GridPosition(starting_x, starting_y); + auto path = walle::GetShortestPath(agent->GetPosition(), starting_pos, agent->GetWorld(), *agent); + double distance_from_start = path.size(); + + inputs.insert(inputs.end(), {prev_action, starting_x, starting_y, distance_from_start, current_state, above_state, below_state, left_state, right_state}); + + return inputs; + } + +} // namespace cowboys diff --git a/source/Agents/GP/GraphBuilder.hpp b/source/Agents/GP/GraphBuilder.hpp new file mode 100644 index 00000000..28c1df22 --- /dev/null +++ b/source/Agents/GP/GraphBuilder.hpp @@ -0,0 +1,163 @@ +#pragma once + +#include "CGPGenotype.hpp" +#include "Graph.hpp" + +namespace cowboys { + + /// @brief A class for building graphs. Graphs are a generic representation, so this class is used to build the + /// specific format of a Cartesian Graph, and also preset graphs. + class GraphBuilder { + public: + GraphBuilder() = default; + ~GraphBuilder() = default; + + /// @brief Creates a decision graph from a CGP genotype. + /// @param genotype The genotype to create the decision graph from. + /// @param function_set The set of functions available to the decision graph. + /// @param agent The agent that will be using the decision graph. + /// @return The decision graph. + std::unique_ptr CartesianGraph(const CGPGenotype &genotype, const std::vector &function_set, + const cse491::AgentBase *agent = nullptr) { + auto decision_graph = std::make_unique(); + + // + // Add all the nodes + // + // Input layer + GraphLayer input_layer; + for (size_t i = 0; i < genotype.GetNumInputs(); ++i) { + input_layer.emplace_back(std::make_shared(0)); + } + decision_graph->AddLayer(input_layer); + + // Middle Layers + for (size_t i = 0; i < genotype.GetNumLayers(); ++i) { + GraphLayer layer; + for (size_t j = 0; j < genotype.GetNumNodesPerLayer(); ++j) { + layer.emplace_back(std::make_shared(0)); + } + decision_graph->AddLayer(layer); + } + + // Action layer + GraphLayer output_layer; + for (size_t i = 0; i < genotype.GetNumOutputs(); ++i) { + output_layer.emplace_back(std::make_shared(0)); + } + decision_graph->AddLayer(output_layer); + + // + // Configure graph based on genotype + // + + auto functional_nodes = decision_graph->GetFunctionalNodes(); + auto all_nodes = decision_graph->GetNodes(); + auto nodes_it = functional_nodes.cbegin(); + auto genes_it = genotype.cbegin(); + // Iterator distances should be the same + assert(std::distance(functional_nodes.cend(), functional_nodes.cbegin()) == + std::distance(genotype.cend(), genotype.cbegin())); + // Get the iterator of all nodes and move it to the start of the first functional node + auto all_nodes_it = all_nodes.cbegin() + genotype.GetNumInputs(); + for (; nodes_it != functional_nodes.end() && genes_it != genotype.cend(); ++nodes_it, ++genes_it) { + // Advance the all nodes iterator if we are at the start of a new layer + auto dist = std::distance(functional_nodes.cbegin(), nodes_it); + if (dist != 0 && dist % genotype.GetNumNodesPerLayer() == 0) { + std::advance(all_nodes_it, genotype.GetNumNodesPerLayer()); + } + + auto &[connections, function_idx, output] = *genes_it; + (*nodes_it)->SetFunctionPointer(NodeFunction{function_set.at(function_idx), agent}); + (*nodes_it)->SetDefaultOutput(output); + + // Copy the all nodes iterator and move it backwards by the number of connections + auto nodes_it_copy = all_nodes_it; + std::advance(nodes_it_copy, -connections.size()); + // Add the inputs to the node + for (auto &connection : connections) { + if (connection != '0') { + (*nodes_it)->AddInput(*nodes_it_copy); + } + ++nodes_it_copy; + } + } + + return decision_graph; + } + + /// @brief Creates a decision graph for pacing up and down in a + /// MazeWorld. Assumes that the inputs are in the format: prev_action, + /// current_state, above_state, below_state, left_state, right_state + /// @param action_vec Assumes that the action outputs are in the format: + /// up, down, left, right + /// @return The decision graph for a vertical pacer. + std::unique_ptr VerticalPacer() { + auto decision_graph = std::make_unique(); + + GraphLayer input_layer; + std::shared_ptr prev_action = std::make_shared(0); + std::shared_ptr current_state = std::make_shared(0); + std::shared_ptr above_state = std::make_shared(0); + std::shared_ptr below_state = std::make_shared(0); + std::shared_ptr left_state = std::make_shared(0); + std::shared_ptr right_state = std::make_shared(0); + input_layer.insert(input_layer.end(), + {prev_action, current_state, above_state, below_state, left_state, right_state}); + decision_graph->AddLayer(input_layer); + + // state == 1 => floor which is walkable + GraphLayer obstruction_layer; + std::shared_ptr up_not_blocked = std::make_shared(AnyEq); + up_not_blocked->AddInputs(GraphLayer{above_state, std::make_shared(1)}); + std::shared_ptr down_not_blocked = std::make_shared(AnyEq); + down_not_blocked->AddInputs(GraphLayer{below_state, std::make_shared(1)}); + obstruction_layer.insert(obstruction_layer.end(), {up_not_blocked, down_not_blocked}); + decision_graph->AddLayer(obstruction_layer); + + // Separate previous action into up and down nodes + GraphLayer prev_action_layer; + std::shared_ptr up_prev_action = std::make_shared(AnyEq); + up_prev_action->AddInputs(GraphLayer{prev_action, std::make_shared(1)}); + std::shared_ptr down_prev_action = std::make_shared(AnyEq); + down_prev_action->AddInputs(GraphLayer{prev_action, std::make_shared(2)}); + prev_action_layer.insert(prev_action_layer.end(), {up_prev_action, down_prev_action}); + decision_graph->AddLayer(prev_action_layer); + + GraphLayer moving_layer; + // If up_not_blocked and up_prev_action ? return 1 : return 0 + // If down_not_blocked and down_prev_action ? return 1 : return 0 + std::shared_ptr keep_up = std::make_shared(And); + keep_up->AddInputs(GraphLayer{up_not_blocked, up_prev_action}); + std::shared_ptr keep_down = std::make_shared(And); + keep_down->AddInputs(GraphLayer{down_not_blocked, down_prev_action}); + moving_layer.insert(moving_layer.end(), {keep_up, keep_down}); + decision_graph->AddLayer(moving_layer); + + // If down_blocked, turn_up + // If up_blocked, turn_down + GraphLayer turn_layer; + std::shared_ptr turn_up = std::make_shared(Not); + turn_up->AddInputs(GraphLayer{down_not_blocked}); + std::shared_ptr turn_down = std::make_shared(Not); + turn_down->AddInputs(GraphLayer{up_not_blocked}); + turn_layer.insert(turn_layer.end(), {turn_up, turn_down}); + decision_graph->AddLayer(turn_layer); + + // Output layer, up, down, left, right + GraphLayer action_layer; + // move up = keep_up + turn_up, + // move down = keep_down + turn_down, + std::shared_ptr up = std::make_shared(Sum); + up->AddInputs(GraphLayer{keep_up, turn_up}); + std::shared_ptr down = std::make_shared(Sum); + down->AddInputs(GraphLayer{keep_down, turn_down}); + std::shared_ptr left = std::make_shared(0); + std::shared_ptr right = std::make_shared(0); + action_layer.insert(action_layer.end(), {up, down, left, right}); + decision_graph->AddLayer(action_layer); + + return decision_graph; + } + }; +} // namespace cowboys \ No newline at end of file diff --git a/source/Agents/GP/GraphNode.hpp b/source/Agents/GP/GraphNode.hpp new file mode 100644 index 00000000..93327dac --- /dev/null +++ b/source/Agents/GP/GraphNode.hpp @@ -0,0 +1,423 @@ +#pragma once + +// Macro for parallel execution, add -DPARALLEL flag to CMAKE_CXX_FLAGS when building to enable +#if PARALLEL +#include +#define PAR std::execution::par, +#else +#define PAR +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../core/AgentBase.hpp" +#include "../../core/WorldBase.hpp" +#include "../AgentLibary.hpp" +#include "GPAgentSensors.hpp" + +namespace cowboys { + class GraphNode; ///< Forward declaration of GraphNode + /// Function pointer for a node function. + using InnerFunction = double (*)(const GraphNode &, const cse491::AgentBase &); + /// @brief A function pointer wrapper that holds extra arguments for the function pointer. + struct NodeFunction { + InnerFunction function{nullptr}; + const cse491::AgentBase *agent{nullptr}; + double operator()(const GraphNode &node) const { return function(node, *agent); } + bool IsNull() const { return function == nullptr; } + }; + + /// @brief A node in a decision graph. + /// @note This should always be a shared pointer. Caching will not work otherwise. + class GraphNode : public std::enable_shared_from_this { + protected: + /// The input nodes to this node. + std::vector> inputs; + + /// The function that operates on the outputs from a node's input nodes. + NodeFunction function_pointer; + + /// The default output of this node. + double default_output{0}; + + /// The nodes connected to this node's output. + std::vector outputs; + + /// The cached output of this node. + mutable double cached_output{0}; + + /// Flag indicating whether the cached output is valid. + mutable bool cached_output_valid{false}; + + /// @brief Add an output node to this node. Used for cache invalidation. + /// @param node The node to add as an output. + void AddOutput(GraphNode *node) { outputs.push_back(node); } + + /// @brief Invalidates this node's cache and the caches of all nodes that depend on this node. + void RecursiveInvalidateCache() const { + cached_output_valid = false; + for (auto &output : outputs) { + output->RecursiveInvalidateCache(); + } + } + + public: + GraphNode() = default; + ~GraphNode() = default; + + /// TODO: Check guidelines for this + GraphNode(double default_value) : default_output{default_value} {} + GraphNode(NodeFunction function) : function_pointer{function} {} + GraphNode(InnerFunction function) : function_pointer{function} {} + + /// @brief Get the output of this node. Performs caching. + /// @return The output of this node. + double GetOutput() const { + if (cached_output_valid) + return cached_output; + + double result = default_output; + // Invoke function pointer if it exists + if (!function_pointer.IsNull()) { + result = function_pointer(*this); + } + + // Cache the output + cached_output = result; + cached_output_valid = true; + + return result; + } + + /// @brief Get the output values of the inputs of this node. + /// @return A vector of doubles representing the input values. + std::vector GetInputValues() const { + std::vector values; + values.reserve(inputs.size()); + std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(values), + [](const auto &node) { return node->GetOutput(); }); + return values; + } + + /// @brief Get the output values of the inputs of this node given an array of indices. + /// @tparam N The size of the indices array. + /// @param indices The indices of the inputs to get the output values of. + /// @return A vector of doubles representing the input values in the same order of the indices. + template std::optional> GetInputValues(const std::array &indices) const { + size_t max_index = *std::max_element(indices.cbegin(), indices.cend()); + if (max_index >= inputs.size()) + return std::nullopt; + std::vector values; + values.reserve(N); + std::transform(indices.cbegin(), indices.cend(), std::back_inserter(values), + [this](const auto &index) { return inputs.at(index)->GetOutput(); }); + return values; + } + + /// @brief Set the function pointer of this node. + /// @param function The function for this node to use. + void SetFunctionPointer(NodeFunction function) { + function_pointer = function; + RecursiveInvalidateCache(); + } + + /// @brief Set the function pointer of this node. + /// @param inner_function The inner function for this node to use. Will be wrapped in a NodeFunction. + void SetFunctionPointer(InnerFunction inner_function) { + function_pointer = NodeFunction{inner_function}; + RecursiveInvalidateCache(); + } + + /// @brief Add an input node to this node. + /// @param node The node to add as an input. + void AddInput(std::shared_ptr node) { + inputs.push_back(node); + // Add a weak pointer to this node to the input node's outputs + node->AddOutput(this); + RecursiveInvalidateCache(); + } + + /// @brief Append nodes in a vector to this node's list of inputs. + /// @param nodes The nodes to add as inputs. + void AddInputs(const std::vector> &nodes) { + inputs.insert(inputs.cend(), nodes.cbegin(), nodes.cend()); + RecursiveInvalidateCache(); + } + + /// @brief Set the input nodes of this node. + /// @param nodes + void SetInputs(std::vector> nodes) { + inputs = nodes; + RecursiveInvalidateCache(); + } + + /// @brief Set the default output of this node. + /// @param value The new default output. + void SetDefaultOutput(double value) { + if (default_output != value) { + default_output = value; + RecursiveInvalidateCache(); + } + } + + /// @brief Get the default output of this node. + /// @return The default output. + double GetDefaultOutput() const { return default_output; } + + /// @brief Check if the cached output is valid. + /// @return True if the cached output is valid, false otherwise. + bool IsCacheValid() const { return cached_output_valid; } + }; + + /// @brief Returns the sum all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Sum(const GraphNode &node, const cse491::AgentBase &) { + auto vals = node.GetInputValues(); + return std::reduce(PAR vals.cbegin(), vals.cend(), 0.); + } + + /// @brief Returns 1 if all inputs are not equal to 0, 0 otherwise. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double And(const GraphNode &node, const cse491::AgentBase &) { + auto vals = node.GetInputValues(); + return std::any_of(vals.cbegin(), vals.cend(), [](const double val) { return val == 0.; }) ? 0. : 1.; + } + + /// @brief Returns 1 if any of the inputs besides the first are equal to the first + /// input, 0 otherwise. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double AnyEq(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + if (vals.size() == 0) + return node.GetDefaultOutput(); + for (size_t i = 1; i < vals.size(); ++i) { + if (vals.at(0) == vals.at(i)) + return 1.; + } + return 0.; + } + + /// @brief Returns 1 if the first input is equal to 0 or there are no inputs, 0 otherwise. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Not(const GraphNode &node, const cse491::AgentBase &) { + auto vals = node.GetInputValues<1>(std::array{0}); + if (!vals.has_value()) + return node.GetDefaultOutput(); + return (*vals)[0] == 0. ? 1. : 0.; + } + + /// @brief Returns the input with index 0 if the condition (input with index + /// 1) is not 0. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Gate(const GraphNode &node, const cse491::AgentBase &) { + auto vals = node.GetInputValues<2>(std::array{0, 1}); + if (!vals.has_value()) + return node.GetDefaultOutput(); + return (*vals)[1] != 0. ? (*vals)[0] : 0.; + } + + /// @brief Sums the sin(x) of all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Sin(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return std::sin(val); }); + } + + /// @brief Sums the cos(x) of all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Cos(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return std::cos(val); }); + } + + /// @brief Returns the product of all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Product(const GraphNode &node, const cse491::AgentBase &) { + auto vals = node.GetInputValues(); + return std::reduce(PAR vals.cbegin(), vals.cend(), 1., std::multiplies{}); + } + + /// @brief Returns the sum of the reciprocal of all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Reciprocal(const GraphNode &node, const cse491::AgentBase &) { + auto vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return 1. / (val + std::numeric_limits::epsilon()); }); + } + + /// @brief Returns the sum of the exp(x) of all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Exp(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return std::exp(val); }); + } + + /// @brief Returns 1 if all inputs are in ascending, 0 otherwise. If only one input, then defaults to 1. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double LessThan(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::is_sorted(vals.begin(), vals.end(), std::less{}); + } + + /// @brief Returns 1 if all inputs are in ascending, 0 otherwise. If only one input, then defaults to 1. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double GreaterThan(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::is_sorted(vals.begin(), vals.end(), std::greater{}); + } + + /// @brief Returns the maximum value of all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Max(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + if (vals.empty()) + return node.GetDefaultOutput(); + return *std::max_element(vals.cbegin(), vals.cend()); + } + + /// @brief Returns the minimum value of all inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Min(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + if (vals.empty()) + return node.GetDefaultOutput(); + return *std::min_element(vals.cbegin(), vals.cend()); + } + + /// @brief Returns the sum of negated inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double NegSum(const GraphNode &node, const cse491::AgentBase &agent) { return -Sum(node, agent); } + + /// @brief Returns the sum of squared inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Square(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return val * val; }); + } + + /// @brief Returns the sum of positively clamped inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double PosClamp(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return std::max(0., val); }); + } + + /// @brief Returns the sum of negatively clamped inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double NegClamp(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return std::min(0., val); }); + } + + /// @brief Returns the sum of square root of positively clamped inputs. + /// @param node The node to get the inputs from. + /// @return The function result as a double. + double Sqrt(const GraphNode &node, const cse491::AgentBase &) { + std::vector vals = node.GetInputValues(); + return std::transform_reduce(PAR vals.cbegin(), vals.cend(), 0., std::plus{}, + [](const double val) { return std::sqrt(std::max(0., val)); }); + } + + /// @brief Returns the distance to the nearest obstruction upwards from the agent. + /// @param agent The agent that the node belongs to. + /// @return The distance to the nearest obstruction upwards. + double WallDistanceUp(const GraphNode &, const cse491::AgentBase &agent) { + return Sensors::wallDistance(agent.GetWorld().GetGrid(), agent, SensorDirection::ABOVE); + } + + /// @brief Returns the distance to the nearest obstruction downwards from the agent. + /// @param agent The agent that the node belongs to. + /// @return The distance to the nearest obstruction downwards. + double WallDistanceDown(const GraphNode &, const cse491::AgentBase &agent) { + return Sensors::wallDistance(agent.GetWorld().GetGrid(), agent, SensorDirection::BELOW); + } + + /// @brief Returns the distance to the nearest obstruction to the left of the agent. + /// @param agent The agent that the node belongs to. + /// @return The distance to the nearest obstruction to the left. + double WallDistanceLeft(const GraphNode &, const cse491::AgentBase &agent) { + return Sensors::wallDistance(agent.GetWorld().GetGrid(), agent, SensorDirection::LEFT); + } + + /// @brief Returns the distance to the nearest obstruction to the right of the agent. + /// @param agent The agent that the node belongs to. + /// @return The distance to the nearest obstruction to the right. + double WallDistanceRight(const GraphNode &, const cse491::AgentBase &agent) { + return Sensors::wallDistance(agent.GetWorld().GetGrid(), agent, SensorDirection::RIGHT); + } + + /// @brief Returns the distance to the grid position represented by the first two inputs using A*. + /// @param node The node to get the inputs from. + /// @param agent The agent that the node belongs to. + /// @return The distance to the grid position using A* + double AStarDistance(const GraphNode &node, const cse491::AgentBase &agent) { + // + // The outputs of the first two connections are the x and y coordinates of the goal position. It'd probably be rare + // for agents to randomly use it in a useful way. Most of the time when it IS used, there is no input connections + // and thus the default output is used, so it isn't REALLY being used. Other times when it does have input + // connections, the agent has a lower fitness, so it probably wasn't making good use of it. + // + // Decided to make an easier way A* can be used by agents by giving the A* distance from the agent's start position + // as an input. This can still be used in the off chance it is useful. + auto vals = node.GetInputValues<2>(std::array{0, 1}); + if (!vals.has_value()) + return node.GetDefaultOutput(); + auto vals2 = *vals; + auto goal_position = cse491::GridPosition(vals2[0], vals2[1]); + auto path = walle::GetShortestPath(agent.GetPosition(), goal_position, agent.GetWorld(), agent); + return path.size(); + } + + /// A vector of all the node functions + static const std::vector NODE_FUNCTION_SET{ + nullptr, Sum, And, AnyEq, Not, Gate, Sin, Cos, Product, Exp, + LessThan, GreaterThan, Max, Min, NegSum, Square, PosClamp, NegClamp, Sqrt}; + /// A vector of all the sensor functions + static const std::vector SENSOR_FUNCTION_SET{WallDistanceUp, WallDistanceDown, WallDistanceLeft, + WallDistanceRight, AStarDistance}; + + /// A vector of all the node functions and sensors + static const std::vector FUNCTION_SET = []() { + std::vector functions; + functions.reserve(NODE_FUNCTION_SET.size() + SENSOR_FUNCTION_SET.size()); + functions.insert(functions.cend(), NODE_FUNCTION_SET.cbegin(), NODE_FUNCTION_SET.cend()); + functions.insert(functions.cend(), SENSOR_FUNCTION_SET.cbegin(), SENSOR_FUNCTION_SET.cend()); + return functions; + }(); +} // namespace cowboys \ No newline at end of file diff --git a/source/Agents/GP/Group7_GPA.md b/source/Agents/GP/Group7_GPA.md index 511fd42c..710503ed 100644 --- a/source/Agents/GP/Group7_GPA.md +++ b/source/Agents/GP/Group7_GPA.md @@ -1,5 +1,43 @@ # Group 7 GP Agent +# Release Freeze Update: + +Here is our plan @mercere99 + +Things to get done ( Group 7) + +- Implement better fitness functions ** Undecided** + - implementing A* as another sensor + +- Saving the state of the best agents overall: **Rajmeet** + +- CGPA: **Simon** + - Crossover: Graph (goes in the base GP class) + +- HPCC: **Aman** + - Serialization? just of the genotype + - adding in multithreading for mutation + - multiple start positions + +- Integration testing? + +- Crossover for LGPA + - Generate a new list using two parents. + +- Export (waiting on the worlds) + +- LGPA agent: **Jason** + - get the current pure virtual functions working + - tests + + +Things to ask +- Ask world groups: what agents do they want (attack, chase, etc) with a decent description of the world. +- Data collection team (we're getting data from them) + +Goals to achieve by the end: +- End up with agents that exhibit semi intelligent behavior (they can chase the player around, attack, do whatever the world wants them to do) + # Demo October 18th ## Current progress: diff --git a/source/Agents/GP/LGPAgent.hpp b/source/Agents/GP/LGPAgent.hpp index 9a013a33..16085cf3 100644 --- a/source/Agents/GP/LGPAgent.hpp +++ b/source/Agents/GP/LGPAgent.hpp @@ -1,181 +1,370 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @brief An Agent based on linear genetic programming. + **/ #pragma once -#include +#include +#include #include #include -#include -#include - +#include #include "../../core/AgentBase.hpp" #include "GPAgentSensors.hpp" -/// Generated by CHATGPT - -namespace cowboys { -const int LISTSIZE = 100; - -EXPERIMENTAL_CLASS class LGPAgent : public cse491::AgentBase { - protected: - // A dictionary of actions and a dictionary of sensors - // A sensor is a function that takes in a grid and returns a value (e.g. - // distance to nearest agent) - - // For example group 1 has a function for the shortest path - - std::vector possibleInstructionsList = {}; - std::vector actionsList = {"up", "down", "left", "right"}; - std::vector operationsList = {"lessthan", "greaterthan", - "equals"}; - std::vector resultsList = std::vector(LISTSIZE); - - std::vector> instructionsList = {}; - size_t currentInstructionIndex = 0; - - std::vector sensorsList; - std::vector sensorsNamesList = {"getLeft", "getRight", "getUp", - "getDown"}; - - std::random_device rd; - std::mt19937 gen; - - public: - EXPERIMENTAL_FUNCTION LGPAgent(size_t id, const std::string &name) - : AgentBase(id, name) { - gen = std::mt19937(rd()); - } - - ~LGPAgent() override = default; - - /// @brief This agent needs a specific set of actions to function. - /// @return Success. - EXPERIMENTAL_FUNCTION bool Initialize() override { - possibleInstructionsList = EncodeActions(action_map, sensorsNamesList); - GenerateRandomActionList(); - return true; - } - - EXPERIMENTAL_FUNCTION void GenerateRandomActionList() { - // generate a random list of actions - std::uniform_int_distribution dist( - 0, possibleInstructionsList.size() - 1); - std::uniform_int_distribution dist2(0, resultsList.size() - 1); - for (int i = 0; i < LISTSIZE; i++) { - instructionsList.push_back(std::make_tuple( - possibleInstructionsList[dist(gen)], dist2(gen), dist2(gen))); - } - -#ifndef NDEBUG - for (auto i = 0; i < LISTSIZE; i++) { - std::cout << get<0>(instructionsList[i]) << " "; - } - - std::cout << std::endl; -#endif - } - - /// @brief Encodes the actions from an agent's action map into a vector of - /// string, representing action names. - /// @param action_map The action map from the agent. - /// @return A vector of strings, representing action names. - EXPERIMENTAL_FUNCTION static std::vector EncodeActions( - const std::unordered_map &action_map, - const std::vector &sensorsNamesList) { - std::vector instructions; - for (const auto &[action_name, action_id] : action_map) { - instructions.push_back(action_name); - } - instructions.push_back("lessthan"); - instructions.push_back("greaterthan"); - instructions.push_back("equals"); - - for (const auto &sensor : sensorsNamesList) { - instructions.push_back(sensor); - } - - return instructions; - } - - EXPERIMENTAL_FUNCTION size_t - SelectAction([[maybe_unused]] const cse491::WorldGrid &grid, - [[maybe_unused]] const cse491::type_options_t &type_options, - [[maybe_unused]] const cse491::item_map_t &item_map, - [[maybe_unused]] const cse491::agent_map_t &agent_map) override { - std::string action; - std::string sensor; - std::string operation; - auto instruction = instructionsList[currentInstructionIndex]; - int i = 0; - -#ifndef NDEBUG - std::cout << "=========================================" << std::endl; - - Sensors::wallDistance(grid, *this, SensorDirection::LEFT); - Sensors::wallDistance(grid, *this, SensorDirection::RIGHT); - Sensors::wallDistance(grid, *this, SensorDirection::ABOVE); - Sensors::wallDistance(grid, *this, SensorDirection::BELOW); -#endif - - if (currentInstructionIndex != 0) { - resultsList[currentInstructionIndex - 1] = action_result; - } else { - resultsList[LISTSIZE - 1] = action_result; - } - - while (i < LISTSIZE && action.empty()) { - if (std::find(actionsList.begin(), actionsList.end(), - get<0>(instruction)) != actionsList.end()) { - action = get<0>(instruction); - } else if (std::find(sensorsNamesList.begin(), sensorsNamesList.end(), - get<0>(instruction)) != sensorsNamesList.end()) { - // the instruction is in the sensor list (getLeft, getRight, getUp, - // getDown) - sensor = get<0>(instruction); - - SensorDirection direction = Sensors::getSensorDirectionEnum(sensor); - int distance = Sensors::wallDistance(grid, *this, direction); - resultsList[currentInstructionIndex] = distance; - } - - else { - // the instruction is an operation (lessthan, greaterthan, equals) - operation = get<0>(instruction); - if (operation == "lessthan") { - if (get<1>(instruction) < get<2>(instruction)) { - resultsList[currentInstructionIndex] = 1; - ++currentInstructionIndex; - } else { - resultsList[currentInstructionIndex] = 0; - } - } else if (operation == "greaterthan") { - if (get<1>(instruction) > get<2>(instruction)) { - resultsList[currentInstructionIndex] = 1; - ++currentInstructionIndex; - } else { - resultsList[currentInstructionIndex] = 0; - } - } else if (operation == "equals") { - if (get<1>(instruction) == get<2>(instruction)) { - resultsList[currentInstructionIndex] = 1; - ++currentInstructionIndex; - } else { - resultsList[currentInstructionIndex] = 0; - } +#include "./GPAgentBase.hpp" + +namespace cowboys +{ + const int LISTSIZE = 100; + + class LGPAgent : public GPAgentBase + { + protected: + // A dictionary of actions and a dictionary of sensors + // A sensor is a function that takes in a grid and returns a value (e.g. distance to left wall) + + std::vector possibleInstructionsList = {}; + std::vector actionsList = {}; + std::vector operationsList = {"lessthan", "greaterthan", "equals"}; + std::vector sensorsNamesList = {"getLeft", "getRight", "getUp", "getDown"}; + + // A list that stores the results of executed instructions + std::vector resultsList; + + std::vector> instructionsList = {}; + size_t currentInstructionIndex = 0; + + std::random_device rd; + std::mt19937 gen; + + public: + LGPAgent(size_t id, const std::string &name) : GPAgentBase(id, name) + { + gen = std::mt19937(rd()); + + for (auto i = 0; i < LISTSIZE; i++) + { + resultsList.push_back(0); + } + } + + /// @brief Initialize the agent after being given an action map + /// @return Success. + bool Initialize() override + { + possibleInstructionsList = EncodeActions(action_map, sensorsNamesList, operationsList, actionsList); + GenerateRandomActionList(); + return true; + } + + /// @brief Generate a random list of instructions from a list of possible instructions + /// @return Success. + void GenerateRandomActionList() + { + std::uniform_int_distribution dist(0, possibleInstructionsList.size() - 1); + std::uniform_int_distribution dist2(0, LISTSIZE - 1); + for (int i = 0; i < LISTSIZE; i++) + { + instructionsList.push_back(std::make_tuple(possibleInstructionsList[dist(gen)], dist2(gen), dist2(gen))); + } + + } + + /// @brief Encodes the actions from an agent's action map into a vector of string, representing action names. + /// @param action_map The action map from the agent. + /// @param sensorsNamesList The list of sensors from the agent. + /// @param operationsList The list of operations from the agent. + /// @param actionsList The list of actions from the agent. + /// @return A vector of strings, representing action names. + static std::vector EncodeActions(const std::unordered_map &action_map, const std::vector &sensorsNamesList, + const std::vector &operationsList, std::vector &actionsList) + { + std::vector instructions; + for (const auto &[action_name, action_id] : action_map) + { + instructions.push_back(action_name); + actionsList.push_back(action_name); + } + for (const auto &sensor : operationsList) + { + instructions.push_back(sensor); + } + + for (const auto &sensor : sensorsNamesList) + { + instructions.push_back(sensor); + } + + return instructions; + } + + /// @brief Mutate this agent. + /// @param mutation_rate The probability of any instruction being changed + void MutateAgent(double mutation_rate = 0.01) override + { + std::uniform_int_distribution rnd_mutate(1, 100); + std::uniform_int_distribution dist(0, possibleInstructionsList.size() - 1); + std::uniform_int_distribution dist2(0, LISTSIZE - 1); + + for (auto i = 0; i < LISTSIZE; i++) + { + if (rnd_mutate(gen) / 100.0 <= mutation_rate) + { + instructionsList[i] = std::make_tuple(possibleInstructionsList[dist(gen)], dist2(gen), dist2(gen)); + } + } + + resultsList.clear(); + resultsList.resize(LISTSIZE); + currentInstructionIndex = 0; + } + + /// @brief Get the instruction list for this agent. + /// @return A const reference to the instruction list for this agent. + const std::vector> &GetInstructionsList(){ return instructionsList; } + + /// @brief Copies the behavior of another LGPAgent into this agent. + /// @param other The LGPAgent to copy. + void Configure(const LGPAgent &other) { + instructionsList = other.instructionsList; + possibleInstructionsList = other.possibleInstructionsList; + actionsList = other.actionsList; + operationsList = other.operationsList; + sensorsNamesList = other.sensorsNamesList; + resultsList = other.resultsList; + currentInstructionIndex = other.currentInstructionIndex; + } + + /// @brief Copy the behavior of another agent into this agent. + /// @param other The agent to copy. + void Copy(const GPAgentBase &other) override + { + assert(dynamic_cast(&other) != nullptr); + Configure(dynamic_cast(other)); + } + + + /// @brief Get the action to take. + /// @param grid The world grid. + /// @param type_options The available types of cells in the grid. + /// @param item_set The set of items in the world. + /// @param agent_set The set of agents in the world. + /// @return A size_t corresponding to the action chosen + size_t GetAction([[maybe_unused]] const cse491::WorldGrid &grid, + [[maybe_unused]] const cse491::type_options_t &type_options, + [[maybe_unused]] const cse491::item_map_t &item_set, + [[maybe_unused]] const cse491::agent_map_t &agent_set) override + { + std::string action; + std::string sensor; + std::string operation; + auto instruction = instructionsList[currentInstructionIndex]; + int i = 0; + + if (currentInstructionIndex != 0) + { + resultsList[currentInstructionIndex - 1] = action_result; + } + else + { + resultsList[LISTSIZE - 1] = action_result; + } + + while (i < LISTSIZE * 2 && action.empty()) + { + if (std::find(actionsList.begin(), actionsList.end(), std::get<0>(instruction)) != actionsList.end()) + { + // the instruction is in the action list (provided by the world) + action = std::get<0>(instruction); + } + else if (std::find(sensorsNamesList.begin(), sensorsNamesList.end(), std::get<0>(instruction)) != sensorsNamesList.end()) + { + // the instruction is in the sensor list (getLeft, getRight, getUp, getDown) + sensor = std::get<0>(instruction); + + SensorDirection direction = Sensors::getSensorDirectionEnum(sensor); + int distance = Sensors::wallDistance(grid, *this, direction); + + + resultsList[currentInstructionIndex] = distance; + + + } + else + { + // the instruction is an operation (lessthan, greaterthan, equals) + operation = std::get<0>(instruction); + if (operation == "lessthan") + { + if (std::get<1>(instruction) < std::get<2>(instruction)) + { + resultsList[currentInstructionIndex] = 1; + } + else + { + resultsList[currentInstructionIndex] = 0; + ++currentInstructionIndex; + } + } + else if (operation == "greaterthan") + { + if (std::get<1>(instruction) > std::get<2>(instruction)) + { + resultsList[currentInstructionIndex] = 1; + } + else + { + resultsList[currentInstructionIndex] = 0; + ++currentInstructionIndex; + } + } + else if (operation == "equals") + { + if (std::get<1>(instruction) == std::get<2>(instruction)) + { + resultsList[currentInstructionIndex] = 1; + } + else + { + resultsList[currentInstructionIndex] = 0; + ++currentInstructionIndex; + } + } + } + + ++currentInstructionIndex; + if (currentInstructionIndex >= LISTSIZE) + { + currentInstructionIndex = 0; + } + ++i; + instruction = instructionsList[currentInstructionIndex]; + } + if (!action.empty()) + { + return action_map[action]; + } + + return 0; + } + + + /// @brief Export the agent to a string + /// @return The string representation of the agent + std::string Export() override { + std::string encodedLists = ""; + + for (auto instruction : instructionsList) + { + encodedLists += std::get<0>(instruction); + encodedLists += "."; + encodedLists += std::to_string(std::get<1>(instruction)); + encodedLists += "."; + encodedLists += std::to_string(std::get<2>(instruction)); + encodedLists += ","; + } + + encodedLists += ";"; + + for (auto possInstruction : possibleInstructionsList) + { + encodedLists += possInstruction; + encodedLists += "."; + } + + encodedLists += ";"; + + for (auto action : actionsList) + { + encodedLists += action; + encodedLists += "."; + } + + return encodedLists; + } + + /// @brief Serialize this agent to XML. + /// @param doc The XML document to serialize to. + /// @param parentElem The parent element to serialize to. + /// @param fitness The fitness of this agent to write to the XML. + void SerializeGP(tinyxml2::XMLDocument & doc, tinyxml2::XMLElement* parentElem, double fitness = -1) override + { + auto agentElem = doc.NewElement("LGPAgent"); + parentElem->InsertEndChild(agentElem); + + auto listElem = doc.NewElement("instruction list"); + listElem->SetText(Export().c_str()); + if (fitness != -1) + listElem->SetAttribute("fitness", fitness); + agentElem->InsertEndChild(listElem); + } + + /// @brief Load in the string representation of an LGP agent and configure this agent based on it. + /// @param genotype The string representation of an LGP agent. + void Import(const std::string & encodedLists) override { + std::vector> decodedInstructionsList = {}; + std::string decodedInstruction; + size_t start_pos = 0; + size_t first_period_pos; + size_t second_period_pos; + size_t comma_pos = encodedLists.find(","); + + // Load the instruction list + while (comma_pos != std::string::npos) { + decodedInstruction = encodedLists.substr(start_pos, comma_pos - start_pos); + first_period_pos = decodedInstruction.find("."); + second_period_pos = decodedInstruction.find(".", first_period_pos + 1); + decodedInstructionsList.push_back(std::make_tuple(decodedInstruction.substr(0, first_period_pos), + std::stoi(decodedInstruction.substr(first_period_pos+1, second_period_pos-first_period_pos+1)), std::stoi(decodedInstruction.substr(second_period_pos+1)))); + + start_pos = comma_pos + 1; + comma_pos = encodedLists.find(",", start_pos); + } + + std::vector decodedPossInstructionsList = {}; + std::vector decodedActionsList = {}; + size_t first_semicolon_pos = encodedLists.find(";"); + size_t second_semicolon_pos = encodedLists.find(";", first_semicolon_pos+1); + std::string unseparated_instruction_list = encodedLists.substr(first_semicolon_pos+1, second_semicolon_pos-first_semicolon_pos+1); + std::string unseparated_action_list = encodedLists.substr(second_semicolon_pos+1); + + // Load the list of possible instructions + size_t period_pos = unseparated_instruction_list.find("."); + start_pos = 0; + while (period_pos != std::string::npos) { + decodedPossInstructionsList.push_back(unseparated_instruction_list.substr(start_pos, period_pos)); + + start_pos = period_pos + 1; + period_pos = encodedLists.find(".", start_pos); + } + + // Load the list of actions + period_pos = unseparated_action_list.find("."); + start_pos = 0; + while (period_pos != std::string::npos) { + decodedActionsList.push_back(unseparated_action_list.substr(start_pos, period_pos)); + + start_pos = period_pos + 1; + period_pos = encodedLists.find(".", start_pos); + } + + instructionsList = decodedInstructionsList; + possibleInstructionsList = decodedPossInstructionsList; + actionsList = decodedActionsList; + resultsList.clear(); + resultsList.resize(LISTSIZE); + currentInstructionIndex = 0; + } + + /// @brief Print the agent + void PrintAgent() override { + for (auto i = 0; i < LISTSIZE; i++) + { + std::cout << std::get<0>(instructionsList[i]) << " "; + } + std::cout << std::endl; } - } - - ++currentInstructionIndex; - if (currentInstructionIndex >= instructionsList.size()) { - currentInstructionIndex = 0; - } - ++i; - instruction = instructionsList[currentInstructionIndex]; - } - if (!action.empty()) { - return action_map[action]; - } - - return 0; - } -}; -}; // namespace cowboys + }; +} diff --git a/source/Agents/PacingAgent.hpp b/source/Agents/PacingAgent.hpp index b38314ce..8e6f6bbd 100644 --- a/source/Agents/PacingAgent.hpp +++ b/source/Agents/PacingAgent.hpp @@ -12,42 +12,54 @@ namespace cse491 { - class PacingAgent : public AgentBase { - protected: - bool vertical=true; ///< Is this agent moving down&up? False = right&left. - bool reverse=false; ///< Is this agent on their way back? (up/left?) +class PacingAgent : public AgentBase { + protected: + bool vertical = true; ///< Is this agent moving down&up? False = right&left. + bool reverse = false; ///< Is this agent on their way back? (up/left?) - public: - PacingAgent(size_t id, const std::string & name) : AgentBase(id, name) { } + public: + PacingAgent(size_t id, const std::string &name) : AgentBase(id, name) {} ~PacingAgent() = default; /// @brief This agent needs a specific set of actions to function. /// @return Success. bool Initialize() override { - return HasAction("up") && HasAction("down") && HasAction("left") && HasAction("right"); + return HasAction("up") && HasAction("down") && HasAction("left") && HasAction("right"); } /// Choose the action to take a step in the appropriate direction. size_t SelectAction(const WorldGrid & /* grid*/, const type_options_t & /* type_options*/, const item_map_t & /* item_map*/, - const agent_map_t & /* agent_map*/) override - { - // If the last step failed, try going in the other direction. - if (action_result == 0) { - reverse = !reverse; - } - // Take as tep in the direction we are trying to go in. - if (vertical) { - if (reverse) return action_map["up"]; - else return action_map["down"]; - } else { - if (reverse) return action_map["left"]; - else return action_map["right"]; - } - return 0; // Should never actually get here... + const agent_map_t & /* agent_map*/) override { + // If the last step failed, try going in the other direction. + if (action_result == 0) { + reverse = !reverse; + } + // Take as tep in the direction we are trying to go in. + if (vertical) { + if (reverse) return action_map["up"]; + else return action_map["down"]; + } else { + if (reverse) return action_map["left"]; + else return action_map["right"]; + } + return 0; // Should never actually get here... } - }; + /** + * Setter for vertical param + * @param vert what vertical should be + * @return self + */ + PacingAgent &SetVertical(bool vert) { + vertical = vert; + return *this; + } + + /// Returns the vertical member variable + bool GetVertical() const { return vertical; } + +}; } // End of namespace cse491 diff --git a/source/Agents/PathAgent.cpp b/source/Agents/PathAgent.cpp index 6d67cb5d..4675cba6 100644 --- a/source/Agents/PathAgent.cpp +++ b/source/Agents/PathAgent.cpp @@ -1,284 +1,189 @@ /** + * This file is part of the Fall 2023, CSE 491 course project. * @file PathAgent.cpp + * @brief Path Agent Class + * @note Status: PROPOSAL * @author David Rackerby - */ + **/ #include "PathAgent.hpp" -#include -#include #include +#include #include #include #include -#include "../core/AgentBase.hpp" -#include "../core/GridPosition.hpp" - namespace walle { -/** - * Constructor (vector) - * @param id unique agent id - * @param name name of path agent - * @param offsets collection of offsets to move the agent - * @attention The sequence of offsets must not be empty - */ -PathAgent::PathAgent(size_t id, std::string const& name, - std::vector && offsets) : cse491::AgentBase(id, name), offsets_(offsets) { - if (offsets_.empty()) { - throw std::invalid_argument("Sequence of input offsets must not be empty"); - } -} - -/** - * Constructor (string) - * @param id unique agent id - * @param name name of path agent - * @param commands sequence of commands to be interpreted as offsets - * @attention The sequence of offsets must not be empty - */ -PathAgent::PathAgent(size_t id, std::string const& name, - std::string_view commands) : cse491::AgentBase(id, name), offsets_(StrToOffsets(commands)) { - if (offsets_.empty()) { - throw std::invalid_argument("Sequence of input offsets must not be empty"); - } -} - -/** - * Checks that the agent is able to move arbitrarily - * Verifies that it can currently index into a valid offset - * @return true if so; false otherwise - */ -bool PathAgent::Initialize() { - return HasAction("move_arbitrary") && index_ >= 0 && static_cast(index_) < offsets_.size(); -} - -/** - * Increments the index into the offsets sequence - */ - void PathAgent::IncrementIndex() { - ++index_; - - // Wrap-around to front of offsets - if (index_ >= static_cast(offsets_.size())) { - index_ = 0; - } - } - - /** - * Decrements the index into the offsets sequence - */ - void PathAgent::DecrementIndex() { - --index_; - - // Wrap-around to back of offsets - if (index_ < 0) { - index_ = static_cast(offsets_.size()) - 1; - } - } - - /** - * Retrieves the position of the agent after applying the current offset - * @return next position of the agent - */ -cse491::GridPosition PathAgent::GetNextPos() const { - return offsets_[index_] + GetPosition(); -} - -/** - * Convenience method - * Applies the current offset to calculate the next position and then adjusts the index - * @param increment decides whether to move in the forward or backward direction to allow for complex pathing - * @return - */ -cse491::GridPosition PathAgent::UpdateAndGetNextPos(bool increment) { - auto next_pos = GetNextPos(); - if (increment) { - IncrementIndex(); - } - else { - DecrementIndex(); - } - return next_pos; -} - -/** - * Tells world to - * @return whether the update succeeded - */ -size_t PathAgent::SelectAction(cse491::WorldGrid const& /* grid*/, - cse491::type_options_t const& /* type_options*/, - cse491::item_map_t const& /* item_map*/, - cse491::agent_map_t const& /* agent_map*/) { - assert(HasAction("move_arbitrary")); - return action_map["move_arbitrary"]; -} - -/** - * Assigns the offsets_member to a new series of offsets - * @param offsets collection of grid positions used as the new offsets - * @param start_index which offset to start indexing into (beginning by default) - * @return self - * @attention throws an `std::invalid_argument` when an invalid start index is provided - */ -PathAgent& PathAgent::SetPath(std::vector && offsets, size_t start_index) { - offsets_ = offsets; - index_ = static_cast(start_index); - if (static_cast(index_) >= offsets_.size()) { - std::ostringstream what; - what << "Out of bounds offset index to begin from: " << index_ << ", number of offsets: " << offsets_.size(); - throw std::invalid_argument(what.str()); - } - return *this; -} - -/** - * Assigns the offsets_ member to a new series of offsets, taking a command string - * @param commands formatted string of commands used as offsets - * @param start_index which command to begin indexing into (first command by default) - * @return self - * @attention throws an `std::invalid_argument` when mis-formatted commands an invalid index is provided - */ -PathAgent& PathAgent::SetPath(std::string_view commands, size_t start_index) { - offsets_.clear(); - return SetPath(StrToOffsets(commands), start_index); -} - -/** - * Retrieves which step the agent is on - * @return the current index into the offsets - */ -int PathAgent::GetIndex() const { - return index_; -} - -/** - * Returns an immutable reference to this agent's current path - * @return sequence of offsets - */ -std::vector const& PathAgent::GetPath() const { - return offsets_; -} + /** + * Constructor (agent default) + * @param id unique agent id + * @param name name of path agent + * @note When this constructor is called, the agent must still be assigned a + * path before a call to Initialize + */ + PathAgent::PathAgent(size_t id, std::string const &name) + : cse491::AgentBase(id, name) {} + + /** + * Constructor (vector) + * @param id unique agent id + * @param name name of path agent + * @param offsets collection of offsets to move the agent + * @attention The sequence of offsets must not be empty + */ + PathAgent::PathAgent(size_t id, std::string const &name, std::vector offsets) + : cse491::AgentBase(id, name), offsets_(std::move(offsets)) { + if (offsets_.empty()) { + throw std::invalid_argument("Sequence of input offsets must not be empty"); + } + } -/** - * Converts a string to a sequence of offsets - * - * This convenience method takes a string with a special formatting that allows one to specify - * a sequence of whitespace-separated inputs in linear directions. - * The format is [steps[*]] where - * `steps` is a positive integer and optional (assumed to be 1 by default) - * star `*` represents scaling the movement by `steps`. Optional, but cannot be used if `steps` is not provided - * if the star is not present, then `steps` individual offsets are created in the direction `direction` - * `direction` is a cardinal direction with the following logical mapping: - * n: north - * s: south - * e: east - * w: west - * x: stay put - * Example: "n w 3e 10*s 5*w x" should create the sequence of offsets - * {0, -1}, {-1, 0}, {1, 0}, {1, 0}, {1, 0}, {0, 10}, {-5, 0}, {0, 0} - * @param commands string in a format of sequential directions - * @note throws an `std::invalid_argument` when input string is poorly formatted - * @note this includes when a negative integer is passed as `steps`. If a zero is used, treated as the default (one) - */ -std::vector StrToOffsets(std::string_view commands) { - std::vector positions; + /** + * Constructor (string) + * @param id unique agent id + * @param name name of path agent + * @param commands sequence of commands to be interpreted as offsets + * @attention The sequence of offsets must not be empty + */ + PathAgent::PathAgent(size_t id, std::string const &name, std::string_view commands) + : cse491::AgentBase(id, name), offsets_(StrToOffsets(commands)) { + if (offsets_.empty()) { + throw std::invalid_argument("Sequence of input offsets must not be empty"); + } + } - // Regex capturing groups logically mean the following: - // Group 0: whole regex - // Group 1: `steps` and `*` pair (optional)(unused) - // Group 2: `steps` (optional) - // Group 3: `*` (optional, only matches when Group 2 matches) - // Group 4: direction - std::regex pattern ("(([1-9]\\d*)(\\*?))?([nswex])"); - std::istringstream iss{std::string(commands)}; - iss >> std::skipws; + /** + * Checks that the agent is able to move arbitrarily + * Verifies that it can currently index into a valid offset + * @return true if so; false otherwise + */ + bool PathAgent::Initialize() { + if (property_map.contains("path")) { + offsets_ = StrToOffsets(GetProperty>("path")); + } else { + return false; + } + return HasAction("move_arbitrary") && index_ >= 0 && + static_cast(index_) < offsets_.size(); + } - std::string single_command; - while (iss >> single_command) { - std::smatch pattern_match; - if (std::regex_match(single_command, pattern_match, pattern)) { - int steps = 1; + /** + * Increments the index into the offsets sequence + */ + void PathAgent::IncrementIndex() { + ++index_; - if (pattern_match[2].length() > 0) { - std::istringstream step_val(pattern_match[1].str()); - step_val >> steps; + // Wrap-around to front of offsets + if (index_ >= static_cast(offsets_.size())) { + index_ = 0; } + } - bool multiply = pattern_match[3].length() > 0; - - char direction = pattern_match[4].str()[0]; + /** + * Decrements the index into the offsets sequence + */ + void PathAgent::DecrementIndex() { + --index_; - cse491::GridPosition base_pos; - switch (direction) { - // Move up - case 'n': { - if (multiply) { - positions.push_back(base_pos.Above(steps)); - } else { - for (int i = 0; i < steps; ++i) { - positions.push_back(base_pos.Above()); - } - } - break; - } + // Wrap-around to back of offsets + if (index_ < 0) { + index_ = static_cast(offsets_.size()) - 1; + } + } - // Move down - case 's': { - if (multiply) { - positions.push_back(base_pos.Below(steps)); - } else { - for (int i = 0; i < steps; ++i) { - positions.push_back(base_pos.Below()); - } - } - break; - } + /** + * Retrieves the position of the agent after applying the current offset + * @return next position of the agent + */ + cse491::GridPosition PathAgent::CalcNextPos() const { + return offsets_[index_] + GetPosition(); + } - // Move left - case 'w': { - if (multiply) { - positions.push_back(base_pos.ToLeft(steps)); - } else { - for (int i = 0; i < steps; ++i) { - positions.push_back(base_pos.ToLeft()); - } - } - break; - } + /** + * Convenience method + * Applies the current offset to calculate the next position and then adjusts + * the index + * @param increment decides whether to move in the forward or backward direction + * to allow for complex pathing + * @return + */ + cse491::GridPosition PathAgent::UpdateAndGetNextPos(bool increment) { + auto next_pos = CalcNextPos(); + if (increment) { + IncrementIndex(); + } else { + DecrementIndex(); + } + return next_pos; + } - // Move right - case 'e': { - if (multiply) { - positions.push_back(base_pos.ToRight(steps)); - } else { - for (int i = 0; i < steps; ++i) { - positions.push_back(base_pos.ToRight()); - } - } - break; - } + /** + * Overrides AgentBase GetNextPosition to retrieve the calculated next position + * @return next position to move the path agent in + */ + cse491::GridPosition PathAgent::GetNextPosition() { + return UpdateAndGetNextPos(true); + } - // Stay - case 'x': { - // Using the `*` does nothing to scale the offset since it's scaling {0, 0} - steps = multiply ? 1 : steps; + /** + * Tells world to + * @return whether the update succeeded + */ + size_t PathAgent::SelectAction(cse491::WorldGrid const & /* grid*/, + cse491::type_options_t const & /* type_options*/, + cse491::item_map_t const & /* item_map*/, + cse491::agent_map_t const & /* agent_map*/) { + assert(HasAction("move_arbitrary")); + return action_map["move_arbitrary"]; + } - for (int i = 0; i < steps; ++i) { - positions.push_back(base_pos); - } - } + /** + * Assigns the offsets_member to a new series of offsets + * @param offsets collection of grid positions used as the new offsets + * @param start_index which offset to start indexing into (beginning by default) + * @return self + * @attention throws an `std::invalid_argument` when an invalid start index is + * provided + */ + PathAgent &PathAgent::SetPath(std::vector offsets, size_t start_index) { + offsets_ = offsets; + index_ = static_cast(start_index); + if (static_cast(index_) >= offsets_.size()) { + std::ostringstream what; + what << "Out of bounds offset index to begin from: " << index_ + << ", number of offsets: " << offsets_.size(); + throw std::invalid_argument(what.str()); } - } else { - std::ostringstream what; - what << "Incorrectly formatted argument: " << single_command; - throw std::invalid_argument(what.str()); - } + return *this; + } - iss >> std::skipws; + /** + * Assigns the offsets_ member to a new series of offsets, taking a command + * string + * @param commands formatted string of commands used as offsets + * @param start_index which command to begin indexing into (first command by + * default) + * @return self + * @attention throws an `std::invalid_argument` when mis-formatted commands an + * invalid index is provided + */ + PathAgent &PathAgent::SetPath(std::string_view commands, size_t start_index) { + offsets_.clear(); + return SetPath(StrToOffsets(commands), start_index); } - return positions; -} + + /** + * Retrieves which step the agent is on + * @return the current index into the offsets + */ + int PathAgent::GetIndex() const { return index_; } + + /** + * Returns an immutable reference to this agent's current path + * @return sequence of offsets + */ + std::vector const &PathAgent::GetPath() const { return offsets_; } } // namespace walle \ No newline at end of file diff --git a/source/Agents/PathAgent.hpp b/source/Agents/PathAgent.hpp index 259b7ab5..01b47350 100644 --- a/source/Agents/PathAgent.hpp +++ b/source/Agents/PathAgent.hpp @@ -1,9 +1,10 @@ /** - * @file PathAgent.h + * This file is part of the Fall 2023, CSE 491 course project. + * @file PathAgent.cpp + * @brief Path Agent Class: Agent to move in a predefined path + * @note Status: PROPOSAL * @author David Rackerby - * - * Agent to move in predefined path - */ + **/ #ifndef GROUP_1_PROJECT_SOURCE_AGENTS_PATHAGENT_H_ #define GROUP_1_PROJECT_SOURCE_AGENTS_PATHAGENT_H_ @@ -14,49 +15,66 @@ #include "../core/AgentBase.hpp" #include "../core/GridPosition.hpp" +#include "AgentLibary.hpp" namespace walle { -/** - * Agent that has a user-defined custom movement pattern - * Passed a sequence of to be sequentially applied as the agent is updated - */ -class PathAgent : public cse491::AgentBase { - protected: - /// Collection of ways to offset the Agent's position - /// @attention This is a *not* a sequence of direct coordinates on the WorldGrid, but a series of offsets - std::vector offsets_; + /** + * Agent that has a user-defined custom movement pattern + * Passed a sequence of to be sequentially applied as the agent is updated + */ + class PathAgent : public cse491::AgentBase { + protected: + /// Collection of ways to offset the Agent's position + /// @attention This is a *not* a sequence of direct coordinates on the + /// WorldGrid, but a series of offsets + std::vector offsets_; + + /// Current index into offsets_ + int index_ = 0; + + public: + PathAgent() = delete; + PathAgent(size_t id, std::string const &name); + PathAgent(size_t id, std::string const &name, + std::vector offsets); + PathAgent(size_t id, std::string const &name, std::string_view commands); + ~PathAgent() override = default; - /// Current index into offsets_ - int index_ = 0; + bool Initialize() override; - public: - PathAgent() = delete; - PathAgent(size_t id, std::string const& name, std::vector && offsets); - PathAgent(size_t id, std::string const& name, std::string_view commands); - ~PathAgent() override = default; + void IncrementIndex(); + void DecrementIndex(); - bool Initialize() override; + [[nodiscard]] cse491::GridPosition CalcNextPos() const; - void IncrementIndex(); - void DecrementIndex(); - [[nodiscard]] cse491::GridPosition GetNextPos() const; + virtual cse491::GridPosition UpdateAndGetNextPos(bool increment); - cse491::GridPosition UpdateAndGetNextPos(bool increment = true); + size_t SelectAction(cse491::WorldGrid const &, cse491::type_options_t const &, + cse491::item_map_t const &, cse491::agent_map_t const &) override; - size_t SelectAction(cse491::WorldGrid const&, cse491::type_options_t const&, - cse491::item_map_t const&, cse491::agent_map_t const&) override; + [[nodiscard]] cse491::GridPosition GetNextPosition() override; - PathAgent& SetPath(std::vector && offsets, size_t start_index = 0); - PathAgent& SetPath(std::string_view commands, size_t start_index = 0); + PathAgent &SetPath(std::vector offsets, + size_t start_index = 0); + PathAgent &SetPath(std::string_view commands, size_t start_index = 0); - [[nodiscard]] int GetIndex() const; - [[nodiscard]] std::vector const& GetPath() const; + /// @brief Get the index + /// @return int index + [[nodiscard]] int GetIndex() const; -}; + /// @brief Get the Path + /// @return vector of GridPositions + [[nodiscard]] std::vector const &GetPath() const; -std::vector StrToOffsets(std::string_view commands); + /// @brief Reset the index to 0 + /// @return self + PathAgent &ResetIndex() { + index_ = 0; + return *this; + } + }; } // namespace walle -#endif //GROUP_1_PROJECT_SOURCE_AGENTS_PATHAGENT_H_ +#endif // GROUP_1_PROJECT_SOURCE_AGENTS_PATHAGENT_H_ diff --git a/source/Agents/RandomAgent.hpp b/source/Agents/RandomAgent.hpp new file mode 100644 index 00000000..1b808d03 --- /dev/null +++ b/source/Agents/RandomAgent.hpp @@ -0,0 +1,110 @@ +/** + * This file is part of the Fall 2023, CSE 491 Course Project + * @file RandomAgent.hpp + * @brief An Agent that will move around using random actions + * @note Status: PROPOSAL + * @author Yousif Murrani + **/ + +#pragma once + +#include +#include "../core/AgentBase.hpp" +#include "../core/GridPosition.hpp" +#include "../core/WorldBase.hpp" + +namespace walle { + + /** + * Class for the Random Agent + */ + class RandomAgent : public cse491::AgentBase { + + private: + + double random_val = 4.0; /// Random value used to determine direction + + bool moving = true; /// Is the agent moving? + + public: + /** + * @brief Construct a new Random Agent object + * @param id id of the agent + * @param name name of the agent + */ + RandomAgent(size_t id, const std::string &name) : AgentBase(id, name) { + } + + ~RandomAgent() = default; + + /** + * @brief This agent needs a specific set of actions to function. + * @return Success. + */ + bool Initialize() override { + return HasAction("up") && HasAction("down") && HasAction("left") && HasAction("right"); + } + + /** + * @brief Choose the action to take a step in the random direction + */ + size_t SelectAction(const cse491::WorldGrid & /*grid*/, + const cse491::type_options_t & /* type_options*/, + const cse491::item_map_t & /* item_map*/, + const cse491::agent_map_t & /* agent_map*/) override { + // We are taking an action so another turn has passed + + CalculateRandom(random_val); + + if(moving){ + if(random_val < 1.0){ + return action_map["up"]; + } + else if(random_val < 2.0){ + return action_map["down"]; + } + else if(random_val < 3.0){ + return action_map["left"]; + } + else{ + return action_map["right"]; + } + } + + return 0; // should not reach this point + } + + /** + * @brief Function to calculate the random direction + * @param multiplier double: random multiplier + */ + void CalculateRandom(double multiplier){ + random_val = GetWorld().GetRandom(multiplier); + } + + /** + * @brief Set the Direction object + * @param direction direction to set + */ + void SetDirection(double direction) { random_val = direction; } + + /** + * @brief Set the Moving object + * @param move move to set + */ + void SetMoving(bool move) { moving = move; } + + /** + * @brief Get the Random object + * @return double random member variable + */ + double GetRandom() const { return random_val; } + + /** + * @brief Get the Moving object + * @return true + * @return false + */ + bool GetMoving() const { return moving; } + }; +} \ No newline at end of file diff --git a/source/Agents/TrackingAgent.hpp b/source/Agents/TrackingAgent.hpp new file mode 100644 index 00000000..bbdcb057 --- /dev/null +++ b/source/Agents/TrackingAgent.hpp @@ -0,0 +1,512 @@ +/** + * This file is part of the Fall 2023, CSE 491 Course Project + * @file TrackingAgent.hpp + * @brief Agent that switches between user-defined custom movement pattern and + * tracking a given agent + * @note Status: PROPOSAL + * @author David Rackerby + * @author Matt Kight + **/ + +#pragma once + +#include "../core/AgentBase.hpp" +#include "../core/GridPosition.hpp" +#include "AStarAgent.hpp" +#include "PathAgent.hpp" +#include "AgentLibary.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace walle { + +/** + * A single Alerter is responsible for forcefully changing the state of all trackers in its network + * to TrackingState::TRACKING when a single TrackingAgent in the set of trackers + * comes into range of its goal_pos + */ +class Alerter { + private: + /// World the agents in the agent network are a part of + cse491::WorldBase *world_ptr_; + + /// Set of all agents in a single network + std::unordered_set agent_network_set_; + + public: + // Must be constructed with an associated world + Alerter() = delete; + explicit Alerter(cse491::WorldBase *world_ptr); + Alerter(cse491::WorldBase *world_ptr, size_t id); + void AddAgent(size_t id); + void RemoveAgent(size_t id); + void AlertAllTrackingAgents(size_t caller_id); + + /// Returns an immutable reference to the Alerter's set of agents it knows about + std::unordered_set const &GetNetworkSet() const { return agent_network_set_; } +}; // Alerter + +/** + * Used to keep track of what action we are currently taking + */ +enum class TrackingState { RETURNING_TO_START, TRACKING, PATROLLING }; + +/** + * Constrain possible inner types to only PathAgent and AStarAgent to avoid errors + * @tparam T either PathAgent or AStarAgent + */ +template +concept TrackingAgentInner_Type = std::is_same_v || std::is_same_v; + +/** + * Agent that switches between user-defined custom movement pattern and + * tracking a given agent + */ +class TrackingAgent : public cse491::AgentBase { + private: + /// Internal agent whose type depends on the state of the agent + std::variant inner_; + + /// Internal state of the agent + TrackingState state_ = TrackingState::PATROLLING; + + /// Patrol path when not tracking + std::vector offsets_; + + /// Starting position + cse491::GridPosition start_pos_; + + /// Entity that the agent tracks and moves towards + Entity *target_ = nullptr; + + /// How close the goal_pos needs to be to begin tracking + double tracking_distance_ = 50; + + /// Alerter that this tracking agent belongs to; Null implies that it's not associated with an alerter + std::shared_ptr alerter_ = nullptr; + + public: + /** + * Delete default constructor + */ + TrackingAgent() = delete; + + /** + * Constructor (default) + * @param id unique agent id + * @param name name of path agent + */ + TrackingAgent(size_t id, std::string const &name) + : cse491::AgentBase(id, name), + inner_(std::in_place_type, id, name) {} + + /** + * Constructor (vector) + * @param id unique agent id + * @param name name of path agent + * @param offsets collection of offsets to move the agent + * @param alerter alerter network to add agent to + * @attention The sequence of offsets must not be empty + * @attention alerter should be a nullptr if this tracker is not part of any group of tracking agents + */ + TrackingAgent(size_t id, + std::string const &name, + std::vector &&offsets, + std::shared_ptr &&alerter = nullptr) + : cse491::AgentBase(id, name), + inner_(std::in_place_type, id, name, offsets), + offsets_(offsets), + alerter_(alerter) {} + + /** + * Constructor (string view) + * @param id unique agent id + * @param name name of path agent + * @param commands sequence of commands to be interpreted as offsets + * @param alerter alerter network to add agent to + * @attention The sequence of offsets must not be empty + * @attention alerter should be a nullptr if this tracker is not part of any group of tracking agents + */ + TrackingAgent(size_t id, + std::string const &name, + std::string_view commands, + std::shared_ptr &&alerter = nullptr) + : cse491::AgentBase(id, name), + inner_(std::in_place_type, id, name, commands), + offsets_(StrToOffsets(commands)), + alerter_(alerter) {} + + /** + * Destructor + */ + ~TrackingAgent() override { + RemoveFromAlerter(); + } + + /** + * Ensure that the TrackingAgent's internal PathAgent is correctly initialized + * Verifies that it can currently index into a valid offset + * @return true if so; false otherwise + */ + bool Initialize() override { + SetStartPosition(GetPosition()); + if (property_map.contains("path")) { + auto view = GetProperty>("path"); + offsets_ = StrToOffsets(view); + std::get(inner_).SetProperty("path", view); + std::get(inner_).SetWorld(GetWorld()); + std::get(inner_).SetPosition(GetPosition()); + + if (property_map.contains("alerter")) { + auto alerter_property = GetProperty>("alerter"); + AddToAlerter(alerter_property); + } + return std::get(inner_).Initialize(); + } + return false; + } + + /// Creates an alerter network and adds this tracking agent to it + void MakeAlerter() { + alerter_ = std::make_shared(&GetWorld(), id); + } + + /** + * Adds this tracking agent to an already-existing alerter network + * @param alerter alerter that this agent should be associated with + * @note alerter must not be null + */ + void AddToAlerter(std::shared_ptr alerter) { + assert(alerter != nullptr); + alerter->AddAgent(id); + alerter_ = alerter; + } + + /** + * Removes this tracking agent from it's own tracking network + * @note called from the TrackingAgent destructor + */ + void RemoveFromAlerter() { + if (alerter_ != nullptr) { + alerter_->RemoveAgent(id); + alerter_ = nullptr; + } + } + + /** + * Used to expand the alerter network by adding other tracking agents to it + * @return a copy of this tracking agent's alerter + * @note it's expected that this function is used when calling AddToAlerter on a different tracking agent + * @note may be null + */ + [[nodiscard]] std::shared_ptr GetAlerter() const { + return alerter_; + } + + /// Tells the alerter to notify all other tracking agents in network + void CallAlerter(size_t agent_id) { + if (alerter_ != nullptr) { + alerter_->AlertAllTrackingAgents(agent_id); + } + } + + /** + * Handles focusing the agent onto a goal_pos, returning it to its original location, and patrolling + * @param alerting determines whether this agent should alert all other TrackingAgents in its network when its + * goal_pos comes into range + * @note the inner variant type will be AStarAgent when tracking OR returning to a location, but PathAgent when patrolling + */ + void UpdateState(bool alerting = true) { + SetPosition(std::visit([](TrackingAgentInner_Type auto const &agent) { return agent.GetPosition(); }, inner_)); + switch (state_) { + // Tracking can transition only to Returning + case TrackingState::TRACKING: { + // Reached goal position + if (GetPosition() == std::get(inner_).GetGoalPosition()) { + if (target_ != nullptr && GetPosition().Distance(target_->GetPosition()) < tracking_distance_) { + // Target is still in range of goal position so + std::get(inner_).SetGoalPosition(target_->GetPosition()); + + // Alert all trackers + if (alerting) { + CallAlerter(id); + } + } else { + state_ = TrackingState::RETURNING_TO_START; + std::get(inner_).SetGoalPosition(start_pos_); + } + std::get(inner_).RecalculatePath(); + std::get(inner_).SetActionResult(1); + } + break; + } + + // Returning can transition to either Patrolling or Tracking + case TrackingState::RETURNING_TO_START: { + // Within tracking range, start tracking again + if (target_ != nullptr && GetPosition().Distance(target_->GetPosition()) < tracking_distance_) { + state_ = TrackingState::TRACKING; + std::get(inner_).SetGoalPosition(target_->GetPosition()); + std::get(inner_).RecalculatePath(); + std::get(inner_).SetActionResult(1); + + // Alert other trackers + if (alerting) { + CallAlerter(id); + } + } + + // Returned to the beginning, start patrolling again + else if (GetPosition() == start_pos_) { + state_ = TrackingState::PATROLLING; + inner_.emplace(id, name); + std::get(inner_).SetPosition(GetPosition()); + std::get(inner_).SetPath(std::vector(offsets_)); + + // Inner world_ptr needs to be reset + SetWorld(GetWorld()); + } + break; + } + + // Patrolling can transition only to Tracking + case TrackingState::PATROLLING: { + // Within tracking range, needs internal object replacement + if (target_ != nullptr && GetPosition().Distance(target_->GetPosition()) < tracking_distance_) { + state_ = TrackingState::TRACKING; + inner_.emplace(id, name); + // Set internal AStarAgent's position to the outer position + std::get(inner_).SetPosition(GetPosition()); + std::get(inner_).SetGoalPosition(target_->GetPosition()); + + // Inner world_ptr needs to be set + SetWorld(GetWorld()); + + std::get(inner_).RecalculatePath(); + std::get(inner_).SetActionResult(1); + + // Alert all other trackers + if (alerting) { + CallAlerter(id); + } + } + break; + } + } + } + + /** + * Overrides the AgentBase getter to retrieve the next calculated position + * @return inner PathAgent's next position + */ + [[nodiscard]] cse491::GridPosition GetNextPosition() override { + auto pos = std::get(inner_).GetNextPosition(); + std::get(inner_).SetPosition(pos); + return pos; + } + + /// Select action for PathAgent inner type + size_t SelectInnerAction(PathAgent &agent, + cse491::WorldGrid const &grid, + cse491::type_options_t const &type, + cse491::item_map_t const &item_set, + cse491::agent_map_t const &agent_set) { + return agent.SelectAction(grid, type, item_set, agent_set); + } + + /// Select action for AStarAgent inner type + size_t SelectInnerAction(AStarAgent &agent, + cse491::WorldGrid const &grid, + cse491::type_options_t const &type, + cse491::item_map_t const &item_set, + cse491::agent_map_t const &agent_set) { + auto next_pos = agent.GetNextPosition(); + auto res = agent.SelectAction(grid, type, item_set, agent_set); + agent.SetPosition(next_pos); + return res; + } + + /// Updates the internal state of the TrackingAgent and calls the internal agent's select action method + size_t SelectAction(cse491::WorldGrid const &grid, + cse491::type_options_t const &type, + cse491::item_map_t const &item_set, + cse491::agent_map_t const &agent_set) override { + UpdateState(); + return std::visit([&](TrackingAgentInner_Type auto &agent) { + return SelectInnerAction(agent, grid, type, item_set, agent_set); + }, + inner_); + } + + /** + * Set where this agent "patrol area" starts + * @param gp grid position of position + * @return self + */ + TrackingAgent &SetStartPosition(cse491::GridPosition pos) { + start_pos_ = pos; + return *this; + } + + /** + * Set where this agent "patrol area" starts + * @param x x-coordinate of start pos + * @param y y-coordinate of start pos + * @return self + */ + TrackingAgent &SetStartPosition(double x, double y) { + start_pos_ = cse491::GridPosition(x, y); + return *this; + } + + /** + * Set which agent we are following + * @param agent we want to track + * @return self + */ + TrackingAgent &SetTarget(Entity *agent) { + target_ = agent; + return *this; + } + + /** + * Get the distance around this tracker that it surveys + * @return tracking distance + */ + [[nodiscard]] double GetTrackingDistance() const { return tracking_distance_; } + + /** + * Set how close goal_pos has to be to start tracking + * @param dist to start tracking at + * @return calling object + */ + TrackingAgent &SetTrackingDistance(double dist) { + tracking_distance_ = dist; + return *this; + } + + /** + * Set both the world for the current agent and the agents it is a part of + * @param in_world new world to associate the agent with + * @return calling agent + */ + TrackingAgent &SetWorld(cse491::WorldBase &in_world) override { + Entity::SetWorld(in_world); + std::visit([&in_world](TrackingAgentInner_Type auto &agent) { + agent.SetWorld(in_world); + std::as_const(in_world).ConfigAgent(agent); + }, inner_); + return *this; + } + + /** + * Retrieves the current internal state of the Tracking Agent + * @return current state + */ + TrackingState GetState() { + return state_; + } + + /** + * Sets the patrolling path of the TrackingAgent + * @param offsets grid position offsets creating the path + * @return + */ + TrackingAgent &SetPath(std::vector offsets) { + offsets_ = std::move(offsets); + if (offsets_.empty()) { + std::ostringstream what; + what << "TrackingAgent cannot have empty path. If you meant to make the agent stay still, use \"x\""; + throw std::invalid_argument(what.str()); + } + return *this; + } + + /** + * Sets the patrolling path of the TrackingAgent + * @param offsets grid position offsets creating the path + * @return + */ + TrackingAgent &SetPath(std::string_view offsets) { + return SetPath(StrToOffsets(offsets)); + } + + /** + * Returns an immutable reference to this agent's current path + * @return sequence of offsets + */ + std::vector const &GetPath() const { return offsets_; } + + /** + * Returns an immutable pointer to this agent's target + * @return ptr to entity + */ + cse491::Entity const *GetTarget() const { return target_; } + +}; // TrackingAgent + +/** + * Alerter constructor (only knows its world and has no agents in its network) + * @param world_ptr the world this alerter is associated with + */ +Alerter::Alerter(cse491::WorldBase *world_ptr) : world_ptr_(world_ptr) { assert(world_ptr != nullptr); } + +/** + * Alerter constructor (adds the TrackingAgent with that id to the alerter network) + * @param id id of agent to be added + * @param world_ptr the world this alerter is associated with + */ +Alerter::Alerter(cse491::WorldBase *world_ptr, size_t id) : world_ptr_(world_ptr) { + assert(world_ptr != nullptr); + AddAgent(id); +} + +/** + * Adds a TrackingAgent to the network + * @param id id of agent to be added + */ +void Alerter::AddAgent(size_t id) { + // Note: GetAgent already handles checking that the agent exists, but we must type-check + assert(dynamic_cast(&(world_ptr_->GetAgent(id))) != nullptr); + agent_network_set_.insert(id); +} + +/** + * Removes a TrackingAgent to the network + * @param id id of agent to be removed + * @note no assertions here since we may want to allow the TrackingAgent to join another network later if it's not being destructed + */ +void Alerter::RemoveAgent(size_t id) { + agent_network_set_.erase(id); +} + +/** + * Uses UpdateState to focus all trackers onto their goal_pos regardless of the distance away + * @param caller_id the original id of the agent that came into range of its goal_pos; does not need to be updated + */ +void Alerter::AlertAllTrackingAgents(size_t caller_id) { + for (auto id : agent_network_set_) { + // Do not update the caller who gave the alert + if (caller_id == id) { + continue; + } + auto &tracking_agent = DownCastAgent(world_ptr_->GetAgent(id)); + // UpdateState sets an agent's TrackingState to TRACKING if it is within some distance of the goal_pos + // if this distance is positive infinity, then the state will always be reset (given that there IS a goal_pos) + // Important: UpdateState must be called with alerting == false in order to + // avoid infinite recursion from recursively calling AlertAllTrackingAgents + double old_tracking_dist = tracking_agent.GetTrackingDistance(); + tracking_agent.SetTrackingDistance(std::numeric_limits::infinity()); + tracking_agent.UpdateState(false); + tracking_agent.SetTrackingDistance(old_tracking_dist); + } +} + +} // namespace walle diff --git a/source/DataCollection/AgentData.hpp b/source/DataCollection/AgentData.hpp index 0d92bbd2..b4ebd9fd 100644 --- a/source/DataCollection/AgentData.hpp +++ b/source/DataCollection/AgentData.hpp @@ -94,5 +94,9 @@ namespace DataCollection std::string GetName() const { return name; } + + std::vector GetPositions() const { + return position; + } }; } // namespace DataCollection \ No newline at end of file diff --git a/source/DataCollection/AgentInteractionCollector.hpp b/source/DataCollection/AgentInteractionCollector.hpp new file mode 100644 index 00000000..2f990bc7 --- /dev/null +++ b/source/DataCollection/AgentInteractionCollector.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include "JsonBuilder.hpp" + +namespace DataCollection { + + /** + * @brief A data collector class to quantify agent interactions. + * + * Useful for setting up graphs for common interactions. + */ + class AgentInteractionCollector { + private: + std::unordered_map interactionData; /// Data storage map of agent name to interactions. + public: + /** + * Default constructor for AgentInteractionCollector + */ + AgentInteractionCollector() = default; + + /** + * Getter for interaction data + * @return Const reference to the interaction data storage. + */ + const std::unordered_map& GetInteractionData() { return interactionData; } + + /** + * Get the amount of unique agents that occured + * @return int amount of agent occurances + */ + size_t GetUniqueInteractions() { return interactionData.size(); } + + /** + * Increment occurance amount for a certain agent. + * @param agentName Agent name to record new interaction with + */ + void RecordInteraction(const std::string& agentName) { interactionData[agentName]++; } + + void WriteToInteractionFile(const std::string filename){ + JsonBuilder json_builder; + std::ofstream jsonfilestream(filename); + json_builder.StartArray("agentInteractions"); + for (auto& [agentName, interactionCount] : interactionData) { + json_builder.AddName(agentName); + json_builder.AddInt("interactionCount", interactionCount); + json_builder.InputToArray("agentInteractions", json_builder.GetJSON()); + json_builder.ClearJSON(); + } + json_builder.WriteToFile(jsonfilestream, json_builder.GetJSONArray()); + jsonfilestream.close(); + } + + }; +} \ No newline at end of file diff --git a/source/DataCollection/AgentReciever.hpp b/source/DataCollection/AgentReciever.hpp index a0bdb37b..b75edeae 100644 --- a/source/DataCollection/AgentReciever.hpp +++ b/source/DataCollection/AgentReciever.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include "DataReceiver.hpp" #include "AgentData.hpp" +#include "JsonBuilder.hpp" namespace DataCollection { @@ -29,9 +31,19 @@ namespace DataCollection { StoreIntoStorage(*agent); } +// void StoreIntoStorage(AgentData obj) override { +// storage.push_back(obj); +// } + + /** + * @brief Stores agent data into the storage and writes to a json file + * + * @param name the name of the agent + */ void AddAgent(const std::string& name) { AgentData agent(name); agent_map[name] = std::make_shared(agent); + } std::shared_ptr GetAgent(const std::string& name) @@ -48,5 +60,26 @@ namespace DataCollection { AgentData GetAgentData(const std::string& name) { return *agent_map[name]; } + + /** + * @brief Writes the stored AgentData Positions to a JSON file. + * + * @param agent The AgentData Position to be stored. + */ + void WriteToPositionFile(std::string path) { + std::ofstream jsonfilestream(path); + JsonBuilder json_builder; + json_builder.StartArray("AgentPositions"); + for (auto& agent : agent_map) { + json_builder.Addagentname(agent.first); + for (auto& pos: agent.second->GetPositions()) { + json_builder.AddPosition(pos); + } + json_builder.InputToArray("AgentPositions", json_builder.GetJSON()); + json_builder.ClearJSON(); + } + json_builder.WriteToFile(jsonfilestream, json_builder.GetJSONArray()); + jsonfilestream.close(); + } }; } // namespace DataCollection \ No newline at end of file diff --git a/source/DataCollection/DamageCollector.hpp b/source/DataCollection/DamageCollector.hpp new file mode 100644 index 00000000..f0fefee3 --- /dev/null +++ b/source/DataCollection/DamageCollector.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "JsonBuilder.hpp" + +namespace DataCollection { + + /** + * @brief A data collector class for damage of game items. + * + * Useful for setting up graphs for analysis of item balancing. + */ + class DamageCollector { + private: + std::unordered_map> damageData; // Damage storage map of item name to damage amounts + public: + /** + * @brief Default constructor for DamageCollector. + */ + DamageCollector() = default; + + /** + * Store a damage amount for a certain item. + * @param itemName Name of the item to store the damage for + * @param damageAmt Amount of damage this item did + */ + void RecordDamageResult(const std::string& itemName, double damageAmt) { + damageData[itemName].push_back(damageAmt); + } + + /** + * Get the damage amounts for a certain item. + * @param itemName Name of the item to get damage amounts for + * @return Reference to the vector of damage amounts + */ + std::vector& GetDamageAmounts(std::string itemName) { + if (damageData.contains(itemName)) { + return damageData[itemName]; + } else { + // Created only once, subsequent calls will reference this + static std::vector empty; + return empty; + } + } + + /** + * Calculate average damage for a certain item + * @param itemName Item name to calculate average for + * @return The average damage as a double, -1 if the item does not exist + */ + double CalculateAverageDamage(const std::string& itemName) { + if (damageData.contains(itemName)) { + std::vector& damages = damageData[itemName]; + return std::accumulate(damages.begin(), damages.end(), 0.0) / damages.size(); + } + + return -1.0; + } + + void WriteToDamageFile(std::string path) { + std::ofstream jsonfilestream(path); + JsonBuilder json_builder; + for (auto& damage : damageData) { + json_builder.AddName(damage.first); + for (auto& damageAmt : damage.second) { + json_builder.AddDamage(damageAmt); + } + } + } + }; +} \ No newline at end of file diff --git a/source/DataCollection/DamageData.hpp b/source/DataCollection/DamageData.hpp new file mode 100644 index 00000000..c03dc7d6 --- /dev/null +++ b/source/DataCollection/DamageData.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "../core/Entity.hpp" +#include "../core/AgentBase.hpp" + +namespace DataCollection { + + /** + * @brief Represents damage related data between an agent and other entities (agents, items, grids, etc) + */ + class DamageData { + private: + std::shared_ptr agent; /// The agent that took damage + std::shared_ptr source; /// The source entity that inflicted the damage + int amount; /// The amount of damage taken from this source + + public: + /** + * @brief Default constructor for a DamageData + * @param src Damage source entity + * @param amt Amount of damage taken + */ + DamageData(std::shared_ptr agnt, + std::shared_ptr src, + int amt) : agent(std::move(agnt)), source(std::move(src)), amount(amt) {} + + /** + * @brief Destructor for DamageData class. + */ + ~DamageData() = default; + }; +} diff --git a/source/DataCollection/DamageReceiver.hpp b/source/DataCollection/DamageReceiver.hpp new file mode 100644 index 00000000..a93c766e --- /dev/null +++ b/source/DataCollection/DamageReceiver.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "DataReceiver.hpp" +#include "DamageData.hpp" + +namespace DataCollection { + + /** + * @brief Data receiver class specialized for storing DamageData objects. + * + * This class extends DataReceiver class and provides specific functionality + * for storing DamageData objects along with damage sources and amounts. + */ + class DamageReceiver : public DataReceiver { + + }; +} diff --git a/source/DataCollection/DataManager.hpp b/source/DataCollection/DataManager.hpp new file mode 100644 index 00000000..15884f66 --- /dev/null +++ b/source/DataCollection/DataManager.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include "AgentReciever.hpp" +#include "GameReceiver.hpp" +#include "DamageCollector.hpp" +#include "ItemUseCollector.hpp" +#include "AgentInteractionCollector.hpp" + +namespace DataCollection { + + /** + * @brief Represents a data control system to hold all related receivers and collectors. + * + * World should report back relevant data here and it will be stored appropriately. + * Also manages graphing utilities. + */ + class DataManager { + private: + AgentReceiver agentReceiver; /// Receiver for agent based data + GameReceiver gameReceiver; /// Receiver for game based data + DamageCollector damageCollector; /// Collector for item damage data + ItemUseCollector itemUseCollector; /// Collector for item usage data + AgentInteractionCollector agentInteractionCollector; /// Collector for agent interaction data + DataManager() {} + + DataManager(const DataManager&) = delete; + DataManager& operator=(const DataManager&) = delete; + public: + /** + * Destructor + */ + ~DataManager() = default; + + static DataManager& GetInstance() { + static DataManager instance; + return instance; + } + + /** + * Get a handle to the agent receiver + * @return Reference to the agent receiver + */ + AgentReceiver& GetAgentReceiver() { + return agentReceiver; + } + + /** + * Get a handle to the agent interaction collector + * @return Reference to the agent interaction collector + */ + AgentInteractionCollector& GetAgentInteractionCollector() { + return agentInteractionCollector; + } + + /** + * Get a handle to the item use collector + * @return Reference to the item use collector + */ + ItemUseCollector& GetItemUseCollector() { + return itemUseCollector; + } + + /** + * Get a handle to the game receiver + * @return Const reference to the game receiver + */ + const GameReceiver& GetGameReceiver() { + return gameReceiver; + } + + /** + * Get a handle to the damage collector + * @return Const reference to the damage collector + */ + const DamageCollector& GetDamageCollector() { + return damageCollector; + } + + void WriteToJson() { + std::filesystem::path currentPath = std::filesystem::current_path().parent_path().parent_path(); + currentPath = currentPath / "source" / "DataCollection" / "GRAPH"; + // Construct the full path to the data directory and the damage_data.json file + std::filesystem::path DamagefilePath = currentPath / "damage_data.json"; + std::filesystem::path ItemUsefilePath = currentPath / "itemUsage.json"; + std::filesystem::path ItemdamagefilePath = currentPath / "itemDamage.json"; + std::filesystem::path PositionfilePath = currentPath / "gridPositions.json"; + std::filesystem::path InteractionfilePath = currentPath / "agentInteractions.json"; + agentReceiver.WriteToPositionFile(PositionfilePath.string()); + itemUseCollector.WriteToItemUseFile(ItemUsefilePath.string()); + agentInteractionCollector.WriteToInteractionFile(InteractionfilePath.string()); + } + }; +} diff --git a/source/DataCollection/GRAPH/.gitignore b/source/DataCollection/GRAPH/.gitignore new file mode 100644 index 00000000..a6c57f5f --- /dev/null +++ b/source/DataCollection/GRAPH/.gitignore @@ -0,0 +1 @@ +*.json diff --git a/source/DataCollection/GRAPH/ItemGraphPlotter.py b/source/DataCollection/GRAPH/ItemGraphPlotter.py new file mode 100644 index 00000000..0d5212f9 --- /dev/null +++ b/source/DataCollection/GRAPH/ItemGraphPlotter.py @@ -0,0 +1,153 @@ +import sys +import pandas as pd +import json +import matplotlib.pyplot as plt +import numpy as np + +class ItemGraphPlotter: + def __init__(self, json_file): + with open(json_file, 'r') as file: + json_data = json.load(file, parse_float=self._parse_float) + self.json_data = json_data + + @staticmethod + def _parse_float(obj): + try: + if obj == 'Infinity': + return float('inf') + return float(obj) + except (ValueError, TypeError): + return obj + + def plot_item_usage_bar_graph(self): + items = self.json_data.get("items", []) + if not items: + print("No 'items' key found in the JSON data.") + return + + names = [item.get("name", "") for item in items] + uses = [item.get("amountOfUses", 0) for item in items] + + plt.bar(names, uses, color='skyblue') + plt.title("Item Usage Bar Graph") + plt.xlabel("Items") + plt.ylabel("Amount of Uses") + plt.show() + + def plot_item_damage_line_graph(self): + items = self.json_data.get("items", []) + if not items: + print("No 'items' key found in the JSON data.") + return + + for item in items: + name = item.get("name", "") + damages = item.get("damages", []) + + plt.plot(damages, label=name) + + plt.title("Item Damage Line Graph") + plt.xlabel("Damage Instances") + plt.ylabel("Damage") + plt.legend() + plt.show() + + def plot_agent_line_path(self): + agents = self.json_data.get("AgentPositions", []) + if not agents: + print("No 'agents' key found in the JSON data.") + return + + for agent in agents: + agent_name = agent.get("agentname", "") + agent_positions = agent.get("positions", []) + if not agent_positions: + print(f"No 'positions' data found for agent '{agent_name}'.") + continue + + df = pd.DataFrame(agent_positions) + + plt.plot(df["x"], df["y"], label=agent_name) + + plt.title(f"Agent Path") + plt.xlabel("X") + plt.ylabel("Y") + plt.legend() + plt.grid(True) + plt.gca().invert_yaxis() # This line flips the y-axis + plt.show() + + return + + print(f"Agent with name '{agent_name}' not found in the JSON data.") + + def plot_agent_path(self, agent_name): + agents = self.json_data.get("AgentPositions", []) + if not agents: + print("No 'agents' key found in the JSON data.") + return + + for agent in agents: + if agent.get("agentname") == agent_name: + agent_positions = agent.get("positions", []) + if not agent_positions: + print(f"No 'positions' data found for agent '{agent_name}'.") + return + + df = pd.DataFrame(agent_positions) + + heatmap, xedges, yedges = np.histogram2d(df["x"], df["y"], bins=(75, 75)) + extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] + plt.imshow(heatmap.T, extent=extent, origin='lower', cmap='viridis') + plt.title(f"Heatmap - Agent: {agent_name}") + plt.colorbar(label='Frequency') + plt.xlabel("X") + plt.ylabel("Y") + plt.grid(True) + plt.show() + + return + + print(f"Agent with name '{agent_name}' not found in the JSON data.") + + def plot_agent_interaction_bar_graph(self): + interactions = self.json_data.get("agentInteractions", []) + if not interactions: + print("No 'agentInteractions' key found in the JSON data.") + return + + names = [interaction.get("name", "") for interaction in interactions] + uses = [interaction.get("interactionCount", 0) for interaction in interactions] + + plt.bar(names, uses, color='skyblue') + plt.title("Agent Interactions") + plt.xlabel("Agents") + plt.ylabel("Amount of Interactions") + plt.show() + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python ItemGraphPlotter.py ") + sys.exit(1) + + json_file = sys.argv[1] + try: + item_graph_plotter = ItemGraphPlotter(json_file) + + # Determine which graph to plot based on the file name + if "AgentPositions" in item_graph_plotter.json_data: + item_graph_plotter.plot_agent_line_path() + if "agentInteractions" in item_graph_plotter.json_data: + item_graph_plotter.plot_agent_interaction_bar_graph() + # Determine which graph to plot based on the file content + elif "amountOfUses" in item_graph_plotter.json_data.get("items", [])[0]: + item_graph_plotter.plot_item_usage_bar_graph() + elif "damages" in item_graph_plotter.json_data.get("items", [])[0]: + item_graph_plotter.plot_item_damage_line_graph() + else: + print("Invalid JSON file format for graphing.") + + except FileNotFoundError: + print(f"Error: File '{json_file}' not found.") + except Exception as e: + print(f"An error occurred: {e}") \ No newline at end of file diff --git a/source/DataCollection/GRAPH/README.md b/source/DataCollection/GRAPH/README.md new file mode 100644 index 00000000..7761d95d --- /dev/null +++ b/source/DataCollection/GRAPH/README.md @@ -0,0 +1,67 @@ + +# Graphing in Python + +Using Python with Pandas for data visualization has several advantages over C++. +One key advantage is the simplicity and readability of Python code, +making it more accessible for data analysts and scientists who may not have a strong +programming background. Pandas provides a high-level interface to data manipulation +and integrates seamlessly with popular plotting libraries like Matplotlib and Seaborn. +The ease of syntax and the extensive documentation of Python and Pandas enable quicker +development and iteration. Additionally, Python has a vibrant and active community, +leading to a wealth of third-party packages and resources for data analysis and +visualization. In contrast, C++ is a lower-level language, and while it offers high +performance, it typically involves more verbose code and a steeper learning curve. +For data-centric tasks, Python and Pandas provide a more efficient and user-friendly +environment, allowing developers to focus on insights rather than wrestling with complex +syntax and memory management. + +## Installation + +To use this project, you need to install the following Python packages: + +### 1. Pandas + +[Pandas](https://pandas.pydata.org/) is a powerful data manipulation and analysis library. + +To install Pandas, run the following command: + +```bash +pip install pandas +``` + +### 2. Matplotlib + +[Matplotlib](https://matplotlib.org/) is a plotting library for the Python programming language. + +To install Matplotlib, run the following command: + +```bash +pip install matplotlib +``` + +### 3. NumPy + +[NumPy](https://numpy.org/) is the fundamental package for scientific computing with Python. + +To install NumPy, run the following command: + + +pip install numpy + + +## How to Use + +1. Clone the repository to your local machine: + +```bash +git clone https://github.com/dradcl/cse_491_fall_2023_group2 +cd source/DataCollection/GRAPH +``` + +2. Run the Python script `ItemGraphPlotter.py` using the following command: + +```bash +python ItemGraphPlotter.py gridPositions.json +``` + +Replace `gridPositions.json` with the path to your JSON file containing grid positions data. diff --git a/source/DataCollection/GRAPH/agentInteractions.json b/source/DataCollection/GRAPH/agentInteractions.json new file mode 100644 index 00000000..83c91b7b --- /dev/null +++ b/source/DataCollection/GRAPH/agentInteractions.json @@ -0,0 +1,3 @@ +{ + "agentInteractions": [] +} \ No newline at end of file diff --git a/source/DataCollection/GRAPH/damage_data.json b/source/DataCollection/GRAPH/damage_data.json new file mode 100644 index 00000000..e69de29b diff --git a/source/DataCollection/GRAPH/gridPositions.json b/source/DataCollection/GRAPH/gridPositions.json new file mode 100644 index 00000000..bdad9c44 --- /dev/null +++ b/source/DataCollection/GRAPH/gridPositions.json @@ -0,0 +1,3 @@ +{ + "AgentPositions": [] +} \ No newline at end of file diff --git a/source/DataCollection/GRAPH/itemDamage.json b/source/DataCollection/GRAPH/itemDamage.json new file mode 100644 index 00000000..07a9b3dc --- /dev/null +++ b/source/DataCollection/GRAPH/itemDamage.json @@ -0,0 +1,20 @@ +{ + "items": [ + { + "name": "Sword", + "damages": [23, 20, 18, 23, 19] + }, + { + "name": "Stick", + "damages": [5, 8, 7, 4, 9, 8] + }, + { + "name": "Axe", + "damages": [14,18,18,15,13] + }, + { + "name": "Staff", + "damages": [20,25,17,26] + } + ] +} \ No newline at end of file diff --git a/source/DataCollection/GRAPH/itemUsage.json b/source/DataCollection/GRAPH/itemUsage.json new file mode 100644 index 00000000..3b9e4745 --- /dev/null +++ b/source/DataCollection/GRAPH/itemUsage.json @@ -0,0 +1,3 @@ +{ + "items": [] +} \ No newline at end of file diff --git a/source/DataCollection/GRAPH/requirements.txt b/source/DataCollection/GRAPH/requirements.txt new file mode 100644 index 00000000..99fd36a2 --- /dev/null +++ b/source/DataCollection/GRAPH/requirements.txt @@ -0,0 +1,3 @@ +pandas +matplotlib +numpy \ No newline at end of file diff --git a/source/DataCollection/GameReceiver.hpp b/source/DataCollection/GameReceiver.hpp index 23baf36a..c6b69ecb 100644 --- a/source/DataCollection/GameReceiver.hpp +++ b/source/DataCollection/GameReceiver.hpp @@ -5,6 +5,9 @@ #include "DataReceiver.hpp" #include "../core/GridPosition.hpp" #include +#include +#include "JsonBuilder.hpp" + namespace DataCollection { /** diff --git a/source/DataCollection/ItemUseCollector.hpp b/source/DataCollection/ItemUseCollector.hpp new file mode 100644 index 00000000..a167d07e --- /dev/null +++ b/source/DataCollection/ItemUseCollector.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include +#include "JsonBuilder.hpp" + +namespace DataCollection { + + /** + * @brief A data collector class for usage amount of game items. + * + * Useful for setting up graphs for analysis of item balancing. + */ + class ItemUseCollector { + private: + std::unordered_map usageData; /// Damage storage map of item name to amount of uses. + public: + /** + * Default constructor for ItemUseCollector + */ + ItemUseCollector() = default; + + /** + * Getter for item usage data + * @return Const reference to the usage data storage. + */ + const std::unordered_map& GetUsageData() { + return usageData; + } + + /** + * Get the amount of unique items that are collected + * @return int amount of unique items + */ + int GetNumberOfItems() { + return usageData.size(); + } + + /** + * Increment usage amount for a certain item. + * @param itemName Item name to record new usage of + */ + void IncrementItemUsage(const std::string& itemName) { + usageData[itemName]++; + } + + /** + * Get the most frequently used item in the game. + * @return Name of the most frequent item as a string, empty string if no data + */ + std::string GetMostFrequent() { + if (!usageData.empty()) { + auto maxItr = std::max_element(usageData.begin(), usageData.end(), + [](const auto& firstItem, const auto& secondItem) { + return firstItem.second < secondItem.second; + } + ); + + return maxItr->first; + } + + return ""; + } + + /** + * Get the least frequently used item in the game. + * @return Name of the least item as a string, empty string if no data + */ + std::string GetLeastFrequent() { + if (!usageData.empty()) { + auto maxItr = std::min_element(usageData.begin(), usageData.end(), + [](const auto& firstItem, const auto& secondItem) { + return firstItem.second < secondItem.second; + } + ); + + return maxItr->first; + } + + return ""; + } + + void WriteToItemUseFile(std::string path) + { + JsonBuilder json_builder; + std::ofstream jsonfilestream(path); + json_builder.StartArray("items"); + for (auto& usage: usageData) { + json_builder.AddName(usage.first); + json_builder.AddInt("amountOfUses", usage.second); + json_builder.InputToArray("items", json_builder.GetJSON()); + json_builder.ClearJSON(); + } + json_builder.WriteToFile(jsonfilestream, json_builder.GetJSONArray()); + jsonfilestream.close(); + } + }; +} \ No newline at end of file diff --git a/source/DataCollection/JsonBuilder.hpp b/source/DataCollection/JsonBuilder.hpp new file mode 100644 index 00000000..7568fb9e --- /dev/null +++ b/source/DataCollection/JsonBuilder.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include +#include +#include +#include "../core/GridPosition.hpp" +#include + +namespace DataCollection{ + /** + * @brief Builds a JSON object from the data collected for an agent. + */ + class JsonBuilder { + private: + nlohmann::json json; ///< The JSON object to be built. + nlohmann::json json_array; + public: + /** + * @brief Default constructor for JSONBuilder class. + */ + JsonBuilder() = default; + + /** + * @brief Destructor for JSONBuilder class. + */ + ~JsonBuilder() = default; + + void StartArray(std::string title) { + json_array[title] = nlohmann::json::array(); + } + + void InputToArray(std::string title, nlohmann::json input) { + json_array[title].push_back(input); + } + + /** + * @brief Adds the agent's name to the JSON object. + * @param name The agent's name. + */ + void AddName(std::string name) { + json["name"] = name; + } + + void Addagentname(std::string name) { + json["agentname"] = name; + } + + /** + * @brief Adds a grid position to the JSON object. + * @param pos The grid position to be added. + */ + void AddPosition(cse491::GridPosition pos) { + json["positions"].push_back({{"x", pos.GetX()}, {"y", pos.GetY()}}); + } + + void AddDamage(double damage) { + json["damage"].push_back(damage); + } + + /** + * @brief Retrieves the JSON object. + * @return The JSON object. + */ + nlohmann::json GetJSON() { + return json; + } + + void ClearJSON() { + json.clear(); + } + + nlohmann::json GetJSONArray() { + return json_array; + } + + void AddInt(std::string title, int usage) { + json[title] = usage; + } + + /** + * @brief Writes the JSON object to a file. + */ + void WriteToFile(std::ofstream &jsonfilestream, nlohmann::json Json) + { + jsonfilestream << Json.dump(4); + } + }; +} // namespace DataCollection \ No newline at end of file diff --git a/source/Doxyfile.doxy b/source/Doxyfile.doxy new file mode 100644 index 00000000..21eedbe5 --- /dev/null +++ b/source/Doxyfile.doxy @@ -0,0 +1,2519 @@ +# Doxyfile 1.9.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "CSE 335 Project" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = CSE335 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = NO + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 15 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, +# *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = pch.h + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = */Testing \ + */cmake-* \ + */Test \ + */Tests \ + */pch.h \ + */*Tests + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = wxIMPLEMENT_APP + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: +# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /