public IntPair GetAIMove() { // strategy 1: try all moves and choose the one with best AIscore List <IntPair> possibleMoves = GetPossibleMoves(); // self-explanatory if (possibleMoves.Count == 0) { throw new Exception("No moves for AI."); } else if (possibleMoves.Count == 1) { return(possibleMoves[0]); } List <AIMinimax> scoredMoves = new List <AIMinimax>(); // The score of the simulated move is calculated for the opponent. // Therefore we want to minimize it. // Randomize equal scores a bit. foreach (IntPair move in possibleMoves) { Board sim = SimulateMove(move.i, move.j); scoredMoves.Add(new AIMinimax { pos = move, score = sim.AIScore(), rand = UnityEngine.Random.Range(0, 100) }); } // sort moves scoredMoves.Sort((x, y) => (10000 * x.score + x.rand).CompareTo(10000 * y.score + y.rand)); // normalize // this is just plain heuristics // keep cBest best options // the worst option gets score 1, better gets more // just weigh best cBest options w.r.t. normalized weighths int baseScore = scoredMoves[scoredMoves.Count - 1].score + 1; int cBest = Math.Min(3, scoredMoves.Count); scoredMoves = scoredMoves.GetRange(0, cBest); int randPool = 0; foreach (AIMinimax move in scoredMoves) { move.score = baseScore - move.score; move.score = move.score * move.score; // square randPool += move.score; } int rand = UnityEngine.Random.Range(0, randPool); int m = 0; while (scoredMoves[m].score < rand) { rand -= scoredMoves[m].score; m++; } // TODO string dbg = ""; foreach (AIMinimax move in scoredMoves) { dbg += " " + move.score; } Debug.Log("Normalized AIScores: " + dbg + " Chosen: " + scoredMoves[m].score); return(scoredMoves[m].pos); // int r = UnityEngine.Random.Range(0, possibleMoves.Count); // return new IntPair(possibleMoves[r].i, possibleMoves[r].j); }