Waiting for a procces to finish before returning a value

So I am in a bit of a stumble. I have a machine learning algorithm that is trying to learn a clone I made of the game 2048. for the algorithm to work I have a function that is supposed to run the game and return the final score every single time. the problem is that I can’t figure out how to make the function wait for the game to finish running before returning the value.
Here is my code:

   public double RunExperiment(Organizm organizm, Neat neat)
    {
        double score = 0;
        this.organizm = organizm;
        game = Instantiate(gamePrefab,transform);
        StartCoroutine(waitUntillLoss());
        score = game.GetComponent<GameMasterScript>().GetScore();
        if(score >= 2000)
        {
            Champion = organizm;
            Satisfactory = true;
        }
        Destroy(game);
        return score;
    }

    IEnumerator waitUntillLoss()
    {
        yield return new WaitUntil(() => game.GetComponent<GameMasterScript>().loss|| game.GetComponent<GameMasterScript>().GetScore() >= 2000);
    }

and the code that calls it:

                foreach (Organizm o in AllOrganizms)
                {
                    double c = experiment.RunExperiment(o, this);
                    o.fittness = c;
                }

I can’t make the function a coroutine because I can’t return anything from a coroutine

You can use callbacks for this - essentially, pass along a delegate (a pointer to a method itself) as a parameter, and the coroutine will call that method with that parameter. The callback does whatever it is your code would have done with the return value.

void RunTestThenPrint() {
StartCoroutine(RunTestCoroutine(PrintDoubleResult) );
}

void PrintDoubleResult(float d) {
Debug.Log($"Result was {d}");
}

IEnumerator RunTestCoroutine(System.Action<double> callback) {
yield return new WaitForSeconds(1f);
callback(2.5);
}

You can also do this inline (this is called a lambda function for some reason) if this helps make the code easier to follow - I wanted to use the syntax as seen above because it’s clearer what’s actually happening, but in practice I tend to use lambda functions more:

void RunTestThenPrint() {
StartCoroutine(RunTestCoroutine(
   (d) => {
      Debug.Log($"Result was {d}");
   });
}

Callbacks and delegates are a huge topic with lots of details, and this is barely scratching the surface. They’re very fun and I highly recommend googling some of these terms to learn more!

I am familiar with the topic but it still doesn’t solve my problem. I hoped I would be able to do it without changing the underlying implementation of the machine learning algorithm but apparently I can’t.

Nope, not really. At the very least, not in a single-threaded application. If you’re waiting for a return value, the entire thread must be stuck waiting for that return value. (This is exactly why coroutines have “yield return” in them; those are the times when the function actually returns, and the only thing special is that they save their state when they do, so that the Unity engine can go back into them each frame until they finish)

It might be possible to run this in a second thread, and your function here would just use Thread.Sleep until some “isDone” bool is set, and then returns its result. Your machine learning algorithm itself would have to be on a separate thread, which has the potential to create a bunch of problems if the ML algorithm needs to use any Unity functionality (most of which can only be used from the main thread). And threading in general can create problems if you’re not particularly familiar with it, which is why I’m not going to try to give any code samples for it here.