diff --git a/s2ga.hpp b/s2ga.hpp index 67de92e..2f2d3b2 100644 --- a/s2ga.hpp +++ b/s2ga.hpp @@ -231,6 +231,7 @@ namespace s2ga auto state = initial_state; int valid_actions = 0; + int useless_actions = 0; int d = 99999; @@ -248,7 +249,15 @@ namespace s2ga continue; } - state = actions[aid].apply(state); + auto new_state = actions[aid].apply(state); + + if(state == new_state) + { + useless_actions++; + } + + state = new_state; + d = final_goal.distance(state); cost += actions[aid].cost; valid_actions++; @@ -265,7 +274,12 @@ namespace s2ga return; } - g.fitness = 9999.0f * d * float(valid_actions) + cost; + constexpr float DISTANCE_WEIGHT = 100.0f; + constexpr float USELESS_ACTION_WEIGHT = DISTANCE_WEIGHT * 0.5f; + constexpr float COST_WEIGHT = 1.0f; + + g.fitness = DISTANCE_WEIGHT * d + + USELESS_ACTION_WEIGHT * useless_actions + COST_WEIGHT * cost; //std::cout << std::format("{}({})", g.fitness, cost) << std::endl; } @@ -405,10 +419,15 @@ namespace s2ga return result; } - void mutate(genotype& g) + void mutate(genotype& g, int max_m = 3) { - int index = rng.random(0, MaxDepth - 1); - g.action_ids[index] = rng.random(-1, int(actions.size() - 1)); + int mutations = rng.random(1, max_m); + + for(int i = 0; i < mutations; ++i) + { + int index = rng.random(0, MaxDepth - 1); + g.action_ids[index] = rng.random(-1, int(actions.size() - 1)); + } } public: action_list plan(int population_size, int max_attempts) @@ -417,7 +436,6 @@ namespace s2ga int attempts = 0; - float last_f = 9999999.0f; while(attempts < max_attempts) diff --git a/tests/test.cpp b/tests/test.cpp index ee44b12..03921a9 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -118,8 +118,8 @@ TEST_CASE("(dummy)", "[test]") BENCHMARK("GOAPERS") { goal goal; - goal.negative_goals = bm(HUNGRY); - goal.positive_goals = bm(HAS_HOUSE); + goal.negative_goals = bm(HUNGRY, IS_WET); + goal.positive_goals = bm(HAS_HOUSE, HAS_CLOTHES); genetic_goap goap; goap.set_initial_state(bm(HUNGRY, IS_WET, IS_RAINING)); @@ -128,20 +128,22 @@ TEST_CASE("(dummy)", "[test]") for(int i = 0; i < 32; ++i) { - auto plan = goap.plan(100, 5); + auto plan = goap.plan(100, 4); (void)plan; } }; goal goal; - goal.negative_goals = bm(HUNGRY); - goal.positive_goals = bm(HAS_HOUSE); + goal.negative_goals = bm(HUNGRY, IS_WET); + goal.positive_goals = bm(HAS_HOUSE, HAS_CLOTHES); genetic_goap goap; goap.set_initial_state(bm(HUNGRY, IS_WET, IS_RAINING)); goap.set_possible_actions(actions); goap.set_goal(goal); - auto plan = goap.plan(100, 5); + auto plan = goap.plan(100, 4); + + std::cout << "\n" << std::endl; float cost = 0.0f; for(auto& i: plan) @@ -152,10 +154,76 @@ TEST_CASE("(dummy)", "[test]") std::cout << std::format("[Total Cost: {}]", cost) << std::endl; - if(plan.size() == 0) + if(plan.empty()) { std::cout << "SAD" << std::endl; } + + /* + [WAIT OUT RAIN, 5] + Effects: + -IS_RAINING + Preconditions: + +IS_RAINING + [COLLECT WOOD, 2] + Effects: + +HAS_WOOD + Preconditions: + -IS_RAINING + [CRAFT TOOLS, 5] + Effects: + -HAS_WOOD + +HAS_TOOLS + Preconditions: + +HAS_WOOD + [COLLECT WOOD, 2] + Effects: + +HAS_WOOD + Preconditions: + -IS_RAINING + [HUNT ANIMAL, 6] + Effects: + +HAS_ANIMAL_SKIN + +HAS_RAW_FOOD + Preconditions: + +HAS_TOOLS + -IS_RAINING + [PROCESS ANIMAL SKIN, 6] + Effects: + +HAS_FABRIC + -HAS_ANIMAL_SKIN + Preconditions: + +HAS_ANIMAL_SKIN + [BUILD HOUSE, 8] + Effects: + +HAS_HOUSE + -HAS_WOOD + -IS_WET + Preconditions: + -HAS_HOUSE + +HAS_WOOD + +HAS_TOOLS + [MAKE CLOTHES, 4] + Effects: + +HAS_CLOTHES + -HAS_FABRIC + Preconditions: + +HAS_FABRIC + -IS_WET + [COOK, 0.25] + Effects: + +HAS_FOOD + -HAS_RAW_FOOD + Preconditions: + +HAS_RAW_FOOD + [EAT, 0.1] + Effects: + -HUNGRY + -HAS_FOOD + Preconditions: + +HAS_FOOD + [Total Cost: 38.35] + */ } TEST_CASE("lehmer64 rng", "[test]")