public FeedData(string parse) { var moves = BoardgameManager.Instance.reader.GetConsideredMoves(parse); int maxsim = moves.Max(v => v.Simulations); TotalSimulations = moves.Sum(v => v.Simulations) + maxsim; FirstWeightedUCT = 0; SecondWeightedUCT = 0; foreach (var cm in moves) { if (cm.Simulations == maxsim) { Best = (cm.First != null ? cm.First : cm.Second); } FMove m; m.Move = (cm.First != null ? cm.First : cm.Second); m.FirstUCT = cm.FirstUCT; m.SecondUCT = cm.SecondUCT; m.Who = (cm.First != null ? Player.First : Player.Second); m.Simulations = cm.Simulations; if (TotalSimulations > 0) { int sim = (cm.Simulations == maxsim ? maxsim * 2 : cm.Simulations); float weight = (float)sim / (float)TotalSimulations; FirstWeightedUCT += m.FirstUCT * weight; SecondWeightedUCT += m.SecondUCT * weight; } Moves.Add(m.Move, m); } try { AverageSimulations = moves.Average(v => v.Simulations); double stdDev = Math.Sqrt(moves.Average(v => Math.Pow(v.Simulations - AverageSimulations, 2))); SimulationStdDev = (maxsim - (float)AverageSimulations) / (float)stdDev; } catch (Exception e) { Debug.LogWarning(e); } }
/// <summary> /// Generates the appropriate FML for considering the given move. /// Every 2 seconds, generates the emotion only. /// Every 4 seconds, generates both emotion and move consideration. /// Interprets it instantly. /// </summary> /// <param name="move">Move to consider.</param> public void ConsiderMove(Move move) { if (lastTime == -1) lastTime = Time.time; FMLBody body = new FMLBody(); if (Time.time >= lastTime + 4f) { MentalChunk mc = new MentalChunk(); //eye movement every 4 mc.AddFunction(new ConsiderMoveFunction(move)); mc.owner = me; body.AddChunk(mc); body.AddChunk(getEmotion()); interpret(body); lastTime = Time.time; } else if (Time.time >= lastTime + 2f) { //emotions every second body.AddChunk(getEmotion()); interpret(body); } }
public abstract string WriteMove(Move move);
public ConsiderMoveFunction(Move move) { MoveToConsider = move; }
/// <summary> /// Using the data currently stored, attempt to work out whether the /// move was a "surprise" and such for the AI /// </summary> /// <param name="move">The move in question</param> /// <param name="who">The player who made it</param> /// <returns>The agent's reaction</returns> private void react(Move move, Player who) { float averageSims = (who == Player.First ? firstAverageSims : secondAverageSims); var moves = (who == Player.First ? firstMoves : secondMoves); if (moves == null) return; FMove m; try { m = moves[move]; } catch (Exception e) { Debug.LogWarning("Sync issue"); Debug.Log(move); var ms = new Move[moves.Count]; moves.Keys.CopyTo(ms, 0); Debug.Log(Tools.Stringify<Move>.Array(ms)); return; } Debug.Log(m.Who); if (m.Who != who) return; if ((m.Simulations < averageSims * 0.8f && who != player) || (who == player && !move.Equals(myBestMove))) { Debug.Log("SURPRISED"); surprised.Enable(); } }
/// <summary> /// Evaluates the state of the game via data fed by the GGP AI. /// Adjusts mood accordingly. /// </summary> /// <param name="d">The data</param> /// <param name="isMyTurn">whether it is the agent's turn or not</param> public void EvaluateConfidence(Networking.FeedData d, bool isMyTurn) { if (d.Best == null) return; if (isMyTurn) { myBestMove = d.Best; if (player == Player.First) { firstMoves = d.Moves; firstAverageSims = (float)d.AverageSimulations; } else { secondMoves = d.Moves; secondAverageSims = (float)d.AverageSimulations; } } else { if (player == Player.First) { secondMoves = d.Moves; secondAverageSims = (float)d.AverageSimulations; } else { firstMoves = d.Moves; firstAverageSims = (float)d.AverageSimulations; } } float myUCT, foeUCT, myWUCT, foeWUCT, valence = 0, arousal = 0; float previousConfidence = confidence; valence = 0; arousal = 0; if (player == Player.First) { myUCT = d.Moves[d.Best].FirstUCT; foeUCT = d.Moves[d.Best].SecondUCT; myWUCT = d.FirstWeightedUCT; foeWUCT = d.SecondWeightedUCT; } else { myUCT = d.Moves[d.Best].SecondUCT; foeUCT = d.Moves[d.Best].FirstUCT; myWUCT = d.SecondWeightedUCT; foeWUCT = d.FirstWeightedUCT; } //increment counters for various states //best move is by far most simulated and is advantageous for me count(d.SimulationStdDev > 2f && myUCT + 5f > foeUCT, ref disproportionateFavour); count(myUCT < foeUCT + 5f, ref opponentDisproportionateFavour); //my total weighted uct is greater than my foe's count(myWUCT + 5f > foeWUCT, ref weightedUCTOverFoe); count(myWUCT < foeWUCT + 5f, ref weightedUCTUnderFoe); //sim count high count(Config.GGP.Limit * 0.8 < d.TotalSimulations, ref highSimCount); //only start affecting confidence if these have been true for a few iterations //and stop affecting confidence when it has been true for a generous while if (stabilised(disproportionateFavour)) { confidence += 3f * weight(disproportionateFavour); } if (stabilised(weightedUCTOverFoe)) confidence += 0.5f * weight(weightedUCTOverFoe); if (stabilised(weightedUCTUnderFoe)) confidence -= 0.5f * weight(weightedUCTUnderFoe); if (stabilised(opponentDisproportionateFavour)) { valence -= moodMod * 3f * weight(opponentDisproportionateFavour); confidence -= 8f * weight(opponentDisproportionateFavour); } if (stabilised(highSimCount)) confidence += 0.5f * weight(highSimCount); count(confidence > previousConfidence, ref confidentCount); count(confidence < previousConfidence, ref notConfidentCount); float diff = Mathf.Abs(confidence - previousConfidence); if (diff > 0.7f) { arousal += 7f; } if (stabilised(highSimCount)) { arousal -= moodMod * 8f * weight(highSimCount); } if (stabilised(notConfidentCount)) { //Debug.Log("DROP"); valence -= moodMod * 8f * weight(notConfidentCount); arousal += moodMod * 5f * weight(notConfidentCount); } else if (stabilised(confidentCount)) { //Debug.Log("INCR"); valence += moodMod * 8f * weight(confidentCount); arousal -= moodMod * 5f * weight(confidentCount); } if (confidence > 10) { if (!isMyTurn) { impatience++; if (impatience == 80) { impatient.Enable(); ReduceTurnTime.Enable(); impatience = 0; } } } else { impatience = 0; } mood.Evaluate(valence, arousal); }
public override string WriteMove(Move move) { if (move.Type == MoveType.MOVE || move.Type == MoveType.CAPTURE) return string.Format("( ( {0} {1} {2} ) )", move.Type.ToString().ToLower(), move.From, move.To); return string.Format("( ( {0} {1} ) )", move.Type.ToString().ToLower(), move.From); }