Getting the candidate FUP and SBF locations to the planner was actually a bit more difficult than I anticipated. I have implemented it but it isnt in a clean way. I think it will need to be abstracted out further. Currently I have implemented it as a separate step inside the Planner class. This is clearly inefficient but preferable to an uglier implementation that tightly couples the Graph class or similar to the Planner class.

My plan for a cleaner implementation at this stage is to add in an event in the viewshed class which the Planner can tap into; something like OnViewshedValueAssigned(VectorInt2 coord) where the Planner class adds a callback where it will complete the current checks for candidate FUP/SBF eligibility.

The GetBestPlan method is currently a brute force method which checks every single FUP/SBF candidate combination and keeps track of the lowest score (currently the scoring is higher for poorer plans). This had some terrible results initially however with some massaging, some reasonable results are starting to appear. It is very clear that creating a highly robust fitness function is likely the most important element of this project. The intent will be to keep a small terrain and brute force plan until a reasonable fitness function is determined. Once that is established, it is reasonable to move onto the Evolutionary Algorithm element.

This very loosly covers paths that go through line of sight. Currently a poor estimation and needs work, likely in the costfield class

Otherwise the cost is the distance between FUP and enemy location squared

SBF:

As per FUP for costfield over 200000

Otherwise the score is the square distance subtracted from 25000

Very much a placeholder here

This gives an ideal distance (score of 0) of 500m

Should be absolute value otherwise greater distances will be negative score

If the height is greater than the enemy position, the score gets multiplied by 0.4

This means a smaller (better) score for positions higher than the enemy location

Combined:

The angle is subtracted from 90 degrees (90 is ideal)

This is multiplied by 0.1 for weighting

Capped at 1 as a low value (The angle between function always returns positive value)

The combo score is the sum of the FUP and SBF score multiplied by the angle score

An angle closer to 90 degrees will be a smaller value multiplying the other values

This is all very ad hoc so far and more than a little bit of trial and error. It is slowly getting decent results though. It is approaching a point that the plan developed on the test terrain is somewhat tactically reasonable, as can be seen below.

The output of the Planner with the current fitness function. The position in the bottom right is the SBF and the position in the upper left is the FUP location

Much more work needs to be done though, with a range of different test maps.