internal void RenderFastForward( bool render, Block <T> oldTip, Block <T> newTip, Block <T> branchpoint, IReadOnlyList <Block <T> > fastForwardPath, StateCompleterSet <T> stateCompleters) { if (render && ActionRenderers.Any()) { _logger.Debug("Rendering actions in new chain."); long count = 0; foreach (Block <T> block in fastForwardPath) { ImmutableList <ActionEvaluation> evaluations = ActionEvaluator.Evaluate(block, stateCompleters).ToImmutableList(); count += RenderActions( evaluations: evaluations, block: block, stateCompleters: stateCompleters); } _logger.Debug( $"{nameof(Swap)}() completed rendering {{Count}} actions.", count); foreach (IActionRenderer <T> renderer in ActionRenderers) { renderer.RenderBlockEnd(oldTip, newTip); } } }
internal void RenderRewind( bool render, Block <T> oldTip, Block <T> newTip, Block <T> branchpoint, IReadOnlyList <Block <T> > rewindPath, StateCompleterSet <T> stateCompleters) { if (render && ActionRenderers.Any()) { // Unrender stale actions. _logger.Debug("Unrendering abandoned actions..."); long count = 0; foreach (Block <T> block in rewindPath) { ImmutableList <ActionEvaluation> evaluations = ActionEvaluator.Evaluate(block, stateCompleters) .ToImmutableList().Reverse(); count += UnrenderActions( evaluations: evaluations, block: block, stateCompleters: stateCompleters); } _logger.Debug( $"{nameof(Swap)}() completed unrendering {{Actions}} actions.", count); } }
public void StateDeepCopyTest() { var game = new GameInstance(3); var ability = new AbilityInfo(3, 1, 1, 0); var abilityId = game.AddAbilityWithInfo(ability); var abilities1 = new List <int>(); var abilities2 = new List <int> { abilityId }; var info1 = new MobInfo(TeamColor.Red, 5, 1, 0, abilities1); var info2 = new MobInfo(TeamColor.Blue, 5, 1, 1, abilities2); var m1 = game.AddMobWithInfo(info1); var m2 = game.AddMobWithInfo(info2); game.PrepareEverything(); var copy = game.CopyStateOnly(); TestHelpers.GameInstancesEqual(game, copy); var copy2 = copy.CopyStateOnly(); ActionEvaluator.F(copy2, UctAction.AbilityUseAction(abilityId, m1, m2)); TestHelpers.GameInstancesEqual(game, copy); TestHelpers.MobManagersEqual(game.MobManager, copy2.MobManager); TestHelpers.MapsEqual(game.Map, copy2.Map); }
public void BasicIniciativeTest() { var game = new GameInstance(3); var m2 = game.AddMobWithInfo(new MobInfo(TeamColor.Blue, 10, 10, 2, new List <int>())); var m3 = game.AddMobWithInfo(new MobInfo(TeamColor.Blue, 10, 10, 3, new List <int>())); var m4 = game.AddMobWithInfo(new MobInfo(TeamColor.Red, 10, 10, 4, new List <int>())); var m1 = game.AddMobWithInfo(new MobInfo(TeamColor.Red, 10, 10, 1, new List <int>())); game.PrepareEverything(); Assert.AreEqual(game.CurrentMob, m1); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(game.CurrentMob, m2); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(game.CurrentMob, m3); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(game.CurrentMob, m4); // At this point a new turn should start ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(game.CurrentMob, m1); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(game.CurrentMob, m2); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(game.CurrentMob, m3); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(game.CurrentMob, m4); }
/// <summary> /// Runs a playout with two given controllers and reports the result. /// </summary> public static PlayoutResult Playout(GameInstance game, IMobController ai1, IMobController ai2) { var hub = new GameEventHub(game); game.MobManager.Teams[TeamColor.Red] = ai1; game.MobManager.Teams[TeamColor.Blue] = ai2; const int maxIterations = 100; int i = 0; for (; i < maxIterations && !game.IsFinished; i++) { game.CurrentController.FastPlayTurn(hub); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); } float totalMaxHp = 0; float totalCurrentHp = 0; foreach (var mobId in game.MobManager.Mobs) { totalMaxHp += game.MobManager.MobInfos[mobId].MaxHp; totalCurrentHp += Math.Max(0, game.State.MobInstances[mobId].Hp); } int red = 0; int blue = 0; Utils.Log(LogSeverity.Error, nameof(GameEvaluator), $"Playout time limit reached at {maxIterations} rounds"); if (i < maxIterations && game.VictoryTeam.HasValue) { if (game.VictoryTeam.Value == TeamColor.Red) { red++; } else { blue++; } Accounting.IncrementWinner(game.VictoryController); } var gamePercentage = totalCurrentHp / totalMaxHp; Debug.Assert(gamePercentage >= 0); var mobsCount = game.MobManager.Mobs.Count; var dis = new Normal(mobsCount * 2, mobsCount); dis.Density(mobsCount * 2); return(new PlayoutResult(i, gamePercentage, game.State.AllPlayed, i == maxIterations, red, blue)); }
internal long RenderActions( IReadOnlyList <ActionEvaluation> evaluations, Block <T> block, StateCompleterSet <T> stateCompleters) { DateTimeOffset startTime = DateTimeOffset.UtcNow; _logger.Debug( "Rendering actions in block #{BlockIndex} {BlockHash}...", block.Index, block.Hash); if (evaluations is null) { evaluations = ActionEvaluator.Evaluate(block, stateCompleters); } long count = 0; foreach (var evaluation in evaluations) { foreach (IActionRenderer <T> renderer in ActionRenderers) { if (evaluation.Exception is null) { renderer.RenderAction( evaluation.Action, evaluation.InputContext.GetUnconsumedContext(), evaluation.OutputStates); } else { renderer.RenderActionError( evaluation.Action, evaluation.InputContext.GetUnconsumedContext(), evaluation.Exception); } count++; } } TimeSpan renderDuration = DateTimeOffset.Now - startTime; _logger .ForContext("Tag", "Metric") .ForContext("Subtag", "BlockRenderDuration") .Debug( "Finished rendering {RenderCount} renders for actions in " + "block #{BlockIndex} {BlockHash} in {DurationMs:F0}ms.", count, block.Index, block.Hash, renderDuration.TotalMilliseconds); return(count); }
public void Idempotent() { // NOTE: This test checks that blocks can be evaluated idempotently. Also it checks // the action results in pre-evaluation step and in evaluation step are equal. const int repeatCount = 2; var signer = new PrivateKey(); var timestamp = DateTimeOffset.UtcNow; var txAddress = signer.ToAddress(); var txs = new[] { Transaction <RandomAction> .Create( nonce : 0, privateKey : signer, genesisHash : null, actions : new[] { new RandomAction(txAddress), }), }; var stateStore = new TrieStateStore(new MemoryKeyValueStore()); HashAlgorithmGetter hashAlgorithmGetter = _ => HashAlgorithmType.Of <SHA256>(); PreEvaluationBlock <RandomAction> noStateRootBlock = MineGenesis( hashAlgorithmGetter: hashAlgorithmGetter, miner: GenesisMiner.PublicKey, timestamp: timestamp, transactions: txs ); Block <RandomAction> stateRootBlock = noStateRootBlock.Evaluate(GenesisMiner, null, stateStore); var actionEvaluator = new ActionEvaluator <RandomAction>( hashAlgorithmGetter: hashAlgorithmGetter, policyBlockAction: null, stateGetter: ActionEvaluator <RandomAction> .NullStateGetter, balanceGetter: ActionEvaluator <RandomAction> .NullBalanceGetter, trieGetter: null); var generatedRandomNumbers = new List <int>(); AssertPreEvaluationBlocksEqual(stateRootBlock, noStateRootBlock); for (int i = 0; i < repeatCount; ++i) { var actionEvaluations = actionEvaluator.Evaluate( noStateRootBlock, StateCompleterSet <RandomAction> .Reject); generatedRandomNumbers.Add( (Integer)actionEvaluations[0].OutputStates.GetState(txAddress)); actionEvaluations = actionEvaluator.Evaluate( stateRootBlock, StateCompleterSet <RandomAction> .Reject); generatedRandomNumbers.Add( (Integer)actionEvaluations[0].OutputStates.GetState(txAddress)); } for (int i = 1; i < generatedRandomNumbers.Count; ++i) { Assert.Equal(generatedRandomNumbers[0], generatedRandomNumbers[i]); } }
/// <summary> /// Simulates the playout till the end and calculates a reward. /// </summary> public static float DefaultPolicy(GameInstance game, TeamColor startingTeam) { if (game.IsFinished) { Debug.Assert(game.VictoryTeam.HasValue || game.AllDead, "game.VictoryTeam.HasValue"); return(CalculateDeltaReward(game, startingTeam, game.VictoryTeam)); } Debug.Assert(game.CurrentTeam.HasValue, "game.CurrentTeam.HasValue"); var copy = game.CopyStateOnly(); const int maxDefaultPolicyIterations = 200; int iterations = maxDefaultPolicyIterations; ReplayRecorder.Instance.Clear(); bool wasMove = false; while (!copy.IsFinished && iterations-- > 0) { var action = ActionGenerator.DefaultPolicyAction(copy); if (action.Type == UctActionType.Move) { if (wasMove) { action = UctAction.EndTurnAction(); } wasMove = true; } if (action.Type == UctActionType.EndTurn) { wasMove = false; } if (action.Type == UctActionType.Null) { throw new InvalidOperationException(); } ActionEvaluator.FNoCopy(copy, action); } if (iterations <= 0) { ReplayRecorder.Instance.SaveAndClear(game, 0); //throw new InvariantViolationException("MCTS playout timeout"); Utils.Log(LogSeverity.Error, nameof(UctAlgorithm), $"DefaultPolicy ran out of time (over {maxDefaultPolicyIterations} iterations for playout), computed results are likely wrong."); return(0); } TeamColor?victoryTeam = copy.VictoryTeam; return(CalculateDeltaReward(game, startingTeam, victoryTeam)); }
/// <summary> /// Returns a list of best possible actions until the end of a turn. /// </summary> private List <UctAction> SelectBestActions(UctNode root) { var result = new List <UctAction>(); UctNode current = root; do { if (current.Children.Count == 0) { break; } UctNode max = current.Children.FastMax(c => c.Q / c.N); if (max.Q / max.N < 0.2) { var state = current.State.CopyStateOnly(); do { var action = ActionGenerator.RuleBasedAction(state); state = ActionEvaluator.F(state, action); if (action.Type == UctActionType.EndTurn) { goto done; } else { result.Add(action); if (action.Type == UctActionType.DefensiveMove) { goto done; } } } while (true); } if (max.Action.Type != UctActionType.EndTurn) { if (max.IsTerminal) { //Console.WriteLine("Found terminal"); } result.Add(max.Action); } current = max; } while (current.Action.Type != UctActionType.EndTurn); done: return(result); }
public static Transaction <T> CreateUnsigned( long nonce, PublicKey publicKey, BlockHash?genesisHash, IEnumerable <T> actions, IImmutableSet <Address> updatedAddresses = null, DateTimeOffset?timestamp = null ) { var signer = new Address(publicKey); if (ReferenceEquals(updatedAddresses, null)) { updatedAddresses = ImmutableHashSet <Address> .Empty; } DateTimeOffset ts = timestamp ?? DateTimeOffset.UtcNow; ImmutableArray <T> actionsArray = actions.ToImmutableArray(); if (!actionsArray.IsEmpty) { // FIXME: Although we are assuming all block hashes are SHA256 digest, we should // parametrize this in the future. BlockHash emptyBlockHash = BlockHash.FromHashDigest(default(HashDigest <SHA256>)); var evalUpdatedAddresses = ActionEvaluator <T> .GetUpdatedAddresses( new Transaction <T>( nonce, signer, publicKey, genesisHash, updatedAddresses, ts, actionsArray)); if (!updatedAddresses.IsSupersetOf(evalUpdatedAddresses)) { updatedAddresses = updatedAddresses.Union(evalUpdatedAddresses); } } return(new Transaction <T>( nonce, signer, publicKey, genesisHash, updatedAddresses, ts, actionsArray)); }
public void FastPlayTurn(GameEventHub eventHub) { do { var possibleActions = ActionGenerator.PossibleActions(_gameInstance, null, true, true); var chosenAction = possibleActions[Generator.Random.Next(possibleActions.Count)]; if (chosenAction.Type == UctActionType.EndTurn) { break; } ActionEvaluator.FNoCopy(_gameInstance, chosenAction); } while (!_gameInstance.IsFinished); }
public void IsFinishedFastAutoUpdateTest() { var game = new GameInstance(3); var a1 = game.AddAbilityWithInfo(new AbilityInfo(5, 1, 5, 0)); var m1 = game.AddMobWithInfo(new MobInfo(TeamColor.Red, 1, 10, 0, new[] { a1 })); var m2 = game.AddMobWithInfo(new MobInfo(TeamColor.Blue, 1, 10, 0, new[] { a1 })); game.PrepareEverything(); Assert.IsFalse(game.IsFinished); ActionEvaluator.FNoCopy(game, UctAction.AbilityUseAction(a1, m1, m2)); Assert.IsTrue(game.IsFinished); }
public void FastPlayTurn(GameEventHub eventHub) { var uct = new UctAlgorithm(_thinkTime, _expoExplo); var result = uct.UctSearch(_gameInstance); foreach (var action in result.Actions) { Debug.Assert(action.Type != UctActionType.EndTurn, "node.Action.Type != UctActionType.EndTurn"); ActionEvaluator.FNoCopy(_gameInstance, action); } ExponentialMovingAverage.Instance.Average(result.MillisecondsPerIteration); LogActions(result); }
/// <summary> /// Expands a given node, adding a new possible state. /// </summary> /// <param name="node"></param> /// <returns></returns> public static UctNode Expand(UctNode node) { var type = node.Action.Type; var allowMove = type != UctActionType.Move && type != UctActionType.DefensiveMove; node.PrecomputePossibleActions(allowMove, true || type != UctActionType.EndTurn); var action = node.PossibleActions[node.Children.Count]; var child = new UctNode(0, 0, action, ActionEvaluator.F(node.State, action)); child.Parent = node; node.Children.Add(child); return(child); }
public void FastPlayTurn(GameEventHub eventHub) { do { var action = ActionGenerator.RuleBasedAction(_gameInstance); if (action.Type == UctActionType.EndTurn) { break; } ActionEvaluator.FNoCopy(_gameInstance, action); if (action.Type == UctActionType.DefensiveMove) { break; } } while (!_gameInstance.IsFinished); }
internal long UnrenderActions( IReadOnlyList <ActionEvaluation> evaluations, Block <T> block, StateCompleterSet <T> stateCompleters) { _logger.Debug( "Unrender actions in block #{BlockIndex} {BlockHash}", block?.Index, block?.Hash); if (evaluations is null) { evaluations = ActionEvaluator.Evaluate(block, stateCompleters) .Reverse().ToImmutableList(); } long count = 0; foreach (ActionEvaluation evaluation in evaluations) { foreach (IActionRenderer <T> renderer in ActionRenderers) { if (evaluation.Exception is null) { renderer.UnrenderAction( evaluation.Action, evaluation.InputContext.GetUnconsumedContext(), evaluation.OutputStates); } else { renderer.UnrenderActionError( evaluation.Action, evaluation.InputContext.GetUnconsumedContext(), evaluation.Exception); } } count++; } return(count); }
public void DefaultPolicyTest() { var game = new GameInstance(3); var ability1 = new AbilityInfo(1, 1, 1, 0); var a1 = game.AddAbilityWithInfo(ability1); var ability2 = new AbilityInfo(3, 1, 1, 0); var a2 = game.AddAbilityWithInfo(ability2); var abilities1 = new List <int>(); var abilities2 = new List <int> { a1, a2 }; var info1 = new MobInfo(TeamColor.Red, 5, 1, 0, abilities1); var info2 = new MobInfo(TeamColor.Blue, 5, 1, 1, abilities2); game.AddMobWithInfo(info1); game.AddMobWithInfo(info2); game.PrepareEverything(); Assert.IsFalse(game.IsFinished); var uct = new UctAlgorithm(100); var result = UctAlgorithm.DefaultPolicy(game, TeamColor.Red); Assert.AreEqual(0, result); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); Assert.AreEqual(TeamColor.Blue, game.CurrentTeam); var bestAction = ActionGenerator.DefaultPolicyAction(game); Console.WriteLine($"Best: {bestAction}"); var node = uct.UctSearch(game); Console.WriteLine(node); }
// This initializes the Bot. // Finds the spawner, player and grid. Also creates the // evaluators public override void Init() { spawner = GameObject.FindObjectOfType <Spawner>(); player = GetComponentInParent <PlayerController>(); if (!enemy) { PlayerController[] allplayer = FindObjectsOfType <PlayerController>(); foreach (PlayerController pl in allplayer) { if (!pl.Equals(player)) { enemy = pl; } } } gridEvaluator = new GridEvaluator(gridMaker.GetComponent <GridMaker>().GetGrid()); towerEvaluator = new TowerEvaluator(); towerEvaluator.SetTowerList(GetTowerStructureList()); actionEvaluator = new ActionEvaluator(); enemyEvaluator = new EnemyEvaluator(GetEnemyStructureList()); }
/// <summary> /// Render actions of the given <paramref name="block"/>. /// </summary> /// <param name="evaluations"><see cref="ActionEvaluation"/>s of the block. If it is /// <c>null</c>, evaluate actions of the <paramref name="block"/> again.</param> /// <param name="block"><see cref="Block{T}"/> to render actions.</param> /// <param name="stateCompleters">The strategy to complement incomplete block states. /// <see cref="StateCompleterSet{T}.Recalculate"/> by default.</param> /// <returns>The number of actions rendered.</returns> internal long RenderActions( IReadOnlyList <ActionEvaluation> evaluations, Block <T> block, StateCompleterSet <T> stateCompleters) { _logger.Debug("Render actions in block {blockIndex}: {block}", block?.Index, block); if (evaluations is null) { evaluations = ActionEvaluator.Evaluate(block, stateCompleters); } long count = 0; foreach (var evaluation in evaluations) { foreach (IActionRenderer <T> renderer in ActionRenderers) { if (evaluation.Exception is null) { renderer.RenderAction( evaluation.Action, evaluation.InputContext.GetUnconsumedContext(), evaluation.OutputStates); } else { renderer.RenderActionError( evaluation.Action, evaluation.InputContext.GetUnconsumedContext(), evaluation.Exception); } count++; } } return(count); }
/// <summary> /// Recalculates and complements all <i>missing</i> block states including and upto given /// <paramref name="blockHash"/> starting from the genesis block. /// </summary> /// <param name="blockHash">The inclusive limit of target hash to terminate complementation. /// </param> /// <remarks> /// <para> /// If a complementation of the entire blockchain is needed, call with the tip hash of the /// <see cref="BlockChain{T}"/>. /// </para> /// <para> /// Unlike <see cref="RecalculateBlockStates"/>, this method skips recalculations if states /// are found for intermediate blocks. This may not be fully secure if states for /// blocks in <see cref="IStateStore"/> are somehow corrupted. /// </para> /// </remarks> internal void ComplementAllBlockStates(BlockHash blockHash) { _logger.Verbose("Complementing all block states upto {BlockHash}...", blockHash); // Prevent recursive trial to recalculate & complement incomplete block states by // mistake; if the below code works as intended, these state completers must never // be invoked. StateCompleterSet <T> stateCompleters = StateCompleterSet <T> .Reject; // Calculates and fills the incomplete states on the fly. foreach (BlockHash hash in BlockHashes) { Block <T> block = this[hash]; if (StateStore.ContainsStateRoot(block.StateRootHash)) { continue; } IReadOnlyList <ActionEvaluation> evaluations = ActionEvaluator.Evaluate( block, stateCompleters); _rwlock.EnterWriteLock(); try { SetStates(block, evaluations); } finally { _rwlock.ExitWriteLock(); } if (blockHash.Equals(hash)) { break; } } }
/// <summary> /// Runs a playout with the given encounter defined by a DNA pair and both controllers. /// </summary> public static int Playout(GameInstance game, DNA d1, DNA d2, IMobController c1, IMobController c2) { GameSetup.OverrideGameDna(game, d1, d2); game.AssignAiControllers(c1, c2); int iterations = Constants.MaxPlayoutEvaluationIterations; var hub = new GameEventHub(game); while (!game.IsFinished && iterations-- > 0) { game.CurrentController.FastPlayTurn(hub); ActionEvaluator.FNoCopy(game, UctAction.EndTurnAction()); } if (Constants.GetLogBuffer().ToString().Length != 0) { Console.WriteLine(Constants.GetLogBuffer()); } Constants.ResetLogBuffer(); return(Constants.MaxPlayoutEvaluationIterations - iterations); }
// FIXME it's very dangerous because replacing Id means // ALL blocks (referenced by MineBlock(), etc.) will be changed. internal System.Action Swap( BlockChain <T> other, bool render, StateCompleterSet <T>?stateCompleters = null) { if (other is null) { throw new ArgumentNullException(nameof(other)); } // As render/unrender processing requires every step's states from the branchpoint // to the new/stale tip, incomplete states need to be complemented anyway... StateCompleterSet <T> completers = stateCompleters ?? StateCompleterSet <T> .Recalculate; if (Tip.Equals(other.Tip)) { // If it's swapped for a chain with the same tip, it means there is no state change. // Hence render is unnecessary. render = false; } else { _logger.Debug( "The blockchain was reorged from " + "{OldChainId} (#{OldTipIndex} {OldTipHash}) " + "to {NewChainId} (#{NewTipIndex} {NewTipHash}).", Id, Tip.Index, Tip.Hash, other.Id, other.Tip.Index, other.Tip.Hash); } System.Action renderSwap = () => { }; _rwlock.EnterUpgradeableReadLock(); try { // Finds the branch point. Block <T> branchpoint = FindTopCommon(this, other); if (branchpoint is null) { const string msg = "A chain cannot be reorged into a heterogeneous chain with a " + "different genesis."; throw new InvalidGenesisBlockException(Genesis.Hash, other.Genesis.Hash, msg); } _logger.Debug( "The branchpoint is #{BranchpointIndex} {BranchpointHash}.", branchpoint.Index, branchpoint ); Block <T> oldTip = Tip, newTip = other.Tip; ImmutableList <Block <T> > rewindPath = GetRewindPath(this, branchpoint.Hash); ImmutableList <Block <T> > fastForwardPath = GetFastForwardPath(other, branchpoint.Hash); // If there is no rewind, it is not considered as a reorg. bool reorg = rewindPath.Count > 0; _rwlock.EnterWriteLock(); try { IEnumerable <Transaction <T> > GetTxsWithRange(BlockChain <T> chain, Block <T> start, Block <T> end) => Enumerable .Range((int)start.Index + 1, (int)(end.Index - start.Index)) .SelectMany(x => { // FIXME: Change the type of IBlockContent<T>.Transactions to // IImmutableSet<Transaction<T>>, and define a distinct property // to Block<T> for this ordering. Block <T> block = chain[x]; return(ActionEvaluator <T> .OrderTxsForEvaluation( block.ProtocolVersion, block.Transactions, block.PreEvaluationHash )); }); // It assumes reorg is small size. If it was big, this may be heavy task. ImmutableHashSet <Transaction <T> > unstagedTxs = GetTxsWithRange(this, branchpoint, Tip).ToImmutableHashSet(); ImmutableHashSet <Transaction <T> > stageTxs = GetTxsWithRange(other, branchpoint, other.Tip).ToImmutableHashSet(); ImmutableHashSet <Transaction <T> > restageTxs = unstagedTxs.Except(stageTxs); foreach (Transaction <T> restageTx in restageTxs) { StagePolicy.Stage(this, restageTx); } Guid obsoleteId = Id; Id = other.Id; Store.SetCanonicalChainId(Id); _blocks = new BlockSet <T>(Policy.GetHashAlgorithm, Store); TipChanged?.Invoke(this, (oldTip, newTip)); Store.DeleteChainId(obsoleteId); } finally { _rwlock.ExitWriteLock(); } renderSwap = () => RenderSwap( render: render, oldTip: oldTip, newTip: newTip, branchpoint: branchpoint, rewindPath: rewindPath, fastForwardPath: fastForwardPath, stateCompleters: completers); } finally { _rwlock.ExitUpgradeableReadLock(); } return(renderSwap); }
/** <summary> * To write out the value of an ASTExpr, invoke the evaluator in eval.g * to walk the tree writing out the values. For efficiency, don't * compute a bunch of strings and then pack them together. Write out directly. * </summary> * * <remarks> * Compute separator and wrap expressions, save as strings so we don't * recompute for each value in a multi-valued attribute or expression. * * If they set anchor option, then inform the writer to push current * char position. * </remarks> */ public override int Write( StringTemplate self, IStringTemplateWriter @out ) { if ( _exprTree == null || self == null || @out == null ) { return 0; } // handle options, anchor, wrap, separator... StringTemplateAST anchorAST = (StringTemplateAST)GetOption( "anchor" ); if ( anchorAST != null ) { // any non-empty expr means true; check presence @out.PushAnchorPoint(); } @out.PushIndentation( Indentation ); HandleExprOptions( self ); //System.out.println("evaluating tree: "+exprTree.toStringList()); ActionEvaluator eval = null; #if COMPILE_EXPRESSIONS bool compile = self.Group != null && self.Group.EnableCompiledExpressions; bool cache = compile && self.Group.EnableCachedExpressions; System.Func<StringTemplate, IStringTemplateWriter, int> evaluator = EvaluateAction; if (compile) { if (!cache || EvaluateAction == null) { // caching won't help here because AST is read only EvaluatorCacheMisses++; evaluator = GetEvaluator(this, AST); if (cache) EvaluateAction = evaluator; } else { EvaluatorCacheHits++; } } else #endif { eval = new ActionEvaluator(self, this, @out, _exprTree); } int n = 0; try { // eval and write out tree #if COMPILE_EXPRESSIONS if (compile) { n = evaluator(self, @out); } else #endif { n = eval.action(); } } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + _exprTree.ToStringTree(), re ); } @out.PopIndentation(); if ( anchorAST != null ) { @out.PopAnchorPoint(); } return n; }
public static UctNode FromAction(GameInstance game, UctAction action) { return(new UctNode(action, ActionEvaluator.F(game, action))); }
static System.Func<StringTemplate, IStringTemplateWriter, bool> GetEvaluator( ASTExpr chunk, ITree condition ) { if ( EnableDynamicMethods ) { try { DynamicMethod method = null; #if CACHE_FUNCTORS if ( !_methods.TryGetValue( condition, out method ) ) #endif { Type[] parameterTypes = { typeof( ASTExpr ), typeof( StringTemplate ), typeof( IStringTemplateWriter ) }; method = new DynamicMethod( "ConditionEvaluator" + _evaluatorNumber, typeof( bool ), parameterTypes, typeof( ConditionalExpr ), true ); method.DefineParameter( 1, ParameterAttributes.None, "chunk" ); method.DefineParameter( 2, ParameterAttributes.None, "self" ); method.DefineParameter( 3, ParameterAttributes.None, "writer" ); _evaluatorNumber++; var gen = method.GetILGenerator(); ActionEvaluator evalCompiled = new ActionEvaluator( null, chunk, null, condition ); evalCompiled.ifConditionCompiled( gen ); gen.Emit( OpCodes.Ret ); #if CACHE_FUNCTORS _methods[condition] = method; #endif } var dynamicEvaluator = (System.Func<StringTemplate, IStringTemplateWriter, bool>)method.CreateDelegate( typeof( System.Func<StringTemplate, IStringTemplateWriter, bool> ), chunk ); return dynamicEvaluator; } catch { // fall back to functional (or interpreted) version } } if ( EnableFunctionalMethods ) { try { ActionEvaluator evalFunctional = new ActionEvaluator( null, chunk, null, condition ); var functionalEvaluator = evalFunctional.ifConditionFunctional(); HoldsConditionFuncAndChunk holder = new HoldsConditionFuncAndChunk() { func = functionalEvaluator, chunk = chunk }; return (System.Func<StringTemplate, IStringTemplateWriter, bool>)System.Delegate.CreateDelegate( typeof( System.Func<StringTemplate, IStringTemplateWriter, bool> ), holder, typeof( ConditionalExpr ).GetMethod( "CallFunctionalConditionEvaluator" ) ); } catch { // fall back to interpreted version } } return new System.Func<StringTemplate, IStringTemplateWriter, bool>( ( self, @out ) => { ActionEvaluator eval = new ActionEvaluator( self, chunk, @out, condition ); return eval.ifCondition(); } ); }
/** <summary> * To write out the value of a condition expr, invoke the evaluator in eval.g * to walk the condition tree computing the boolean value. If result * is true, then write subtemplate. * </summary> */ public override int Write( StringTemplate self, IStringTemplateWriter @out ) { if ( AST == null || self == null || @out == null ) { return 0; } //System.Console.Out.WriteLine( "evaluating conditional tree: " + AST.ToStringTree() ); #if !COMPILE_EXPRESSIONS ActionEvaluator eval = null; #endif int n = 0; try { bool testedTrue = false; // get conditional from tree and compute result #if COMPILE_EXPRESSIONS if ( EvaluateCondition == null ) EvaluateCondition = GetEvaluator( this, AST.GetChild( 0 ) ); bool includeSubtemplate = EvaluateCondition( self, @out ); // eval and write out tree #else ITree cond = AST.GetChild( 0 ); eval = new ActionEvaluator( self, this, @out, cond ); // eval and write out trees bool includeSubtemplate = eval.ifCondition(); #endif //System.Console.Out.WriteLine( "subtemplate " + _subtemplate ); // IF if ( includeSubtemplate ) { n = WriteSubTemplate( self, @out, _subtemplate ); testedTrue = true; } // ELSEIF else if ( _elseIfSubtemplates != null && _elseIfSubtemplates.Count > 0 ) { for ( int i = 0; i < _elseIfSubtemplates.Count; i++ ) { ElseIfClauseData elseIfClause = _elseIfSubtemplates[i]; #if COMPILE_EXPRESSIONS if ( elseIfClause.EvaluateCondition == null ) elseIfClause.EvaluateCondition = GetEvaluator( this, elseIfClause.expr.AST ); includeSubtemplate = elseIfClause.EvaluateCondition( self, @out ); #else eval = new ActionEvaluator( self, this, @out, elseIfClause.expr.AST ); includeSubtemplate = eval.ifCondition(); #endif if ( includeSubtemplate ) { WriteSubTemplate( self, @out, elseIfClause.st ); testedTrue = true; break; } } } // ELSE if ( !testedTrue && _elseSubtemplate != null ) { // evaluate ELSE clause if present and IF condition failed StringTemplate s = _elseSubtemplate.GetInstanceOf(); s.EnclosingInstance = self; s.Group = self.Group; s.NativeGroup = self.NativeGroup; n = s.Write( @out ); } // cond==false and no else => Missing output not empty if (!testedTrue && _elseSubtemplate == null) n = Missing; } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + AST.ToStringTree(), re ); } return n; }
public void EvaluateTxs() { DumbAction MakeAction(Address address, char identifier, Address?transferTo = null) { return(new DumbAction( targetAddress: address, item: identifier.ToString(), recordRehearsal: false, recordRandom: true, transfer: transferTo is Address to ? Tuple.Create <Address, Address, BigInteger>(address, to, 5) : null)); } Address[] addresses = { _txFx.Address1, _txFx.Address2, _txFx.Address3, _txFx.Address4, _txFx.Address5, }; HashAlgorithmType hashAlgorithm = HashAlgorithmType.Of <SHA256>(); HashAlgorithmGetter hashAlgoGetter = _ => hashAlgorithm; Block <DumbAction> genesis = MineGenesisBlock <DumbAction>( hashAlgoGetter, TestUtils.GenesisMiner ); ActionEvaluator <DumbAction> actionEvaluator = new ActionEvaluator <DumbAction>( hashAlgorithmGetter: _ => HashAlgorithmType.Of <SHA256>(), policyBlockAction: null, stateGetter: ActionEvaluator <DumbAction> .NullStateGetter, balanceGetter: ActionEvaluator <DumbAction> .NullBalanceGetter, trieGetter: null); IAccountStateDelta previousStates = genesis.ProtocolVersion > 0 ? new AccountStateDeltaImpl( ActionEvaluator <DumbAction> .NullAccountStateGetter, ActionEvaluator <DumbAction> .NullAccountBalanceGetter, genesis.Miner) : new AccountStateDeltaImplV0( ActionEvaluator <DumbAction> .NullAccountStateGetter, ActionEvaluator <DumbAction> .NullAccountBalanceGetter, genesis.Miner); Assert.Empty( actionEvaluator.EvaluateTxs( block: genesis, previousStates: previousStates)); Transaction <DumbAction>[] block1Txs = { Transaction <DumbAction> .Create( nonce: 0, privateKey: _txFx.PrivateKey1, genesisHash: genesis.Hash, actions: new[] { MakeAction(addresses[0], 'A', addresses[1]), MakeAction(addresses[1], 'B', addresses[2]), }, timestamp: DateTimeOffset.MinValue.AddSeconds(2)), Transaction <DumbAction> .Create( nonce: 0, privateKey: _txFx.PrivateKey2, genesisHash: genesis.Hash, actions: new[] { MakeAction(addresses[2], 'C', addresses[3]) }, timestamp: DateTimeOffset.MinValue.AddSeconds(4)), Transaction <DumbAction> .Create( nonce: 0, privateKey: _txFx.PrivateKey3, genesisHash: genesis.Hash, actions: new DumbAction[0], timestamp: DateTimeOffset.MinValue.AddSeconds(7)), }; int i = 0; foreach (Transaction <DumbAction> tx in block1Txs) { _logger.Debug("{0}[{1}] = {2}", nameof(block1Txs), i, tx.Id); } Block <DumbAction> block1 = MineNextBlock( genesis, hashAlgoGetter, GenesisMiner, block1Txs, new byte[] { } ); previousStates = block1.ProtocolVersion > 0 ? new AccountStateDeltaImpl( ActionEvaluator <DumbAction> .NullAccountStateGetter, ActionEvaluator <DumbAction> .NullAccountBalanceGetter, block1.Miner) : new AccountStateDeltaImplV0( ActionEvaluator <DumbAction> .NullAccountStateGetter, ActionEvaluator <DumbAction> .NullAccountBalanceGetter, block1.Miner); var evals = actionEvaluator.EvaluateTxs( block1, previousStates).ToImmutableArray(); int randomValue = 0; (int TxIdx, int ActionIdx, string[] UpdatedStates, Address Signer)[] expectations =
private void LogActions(UctSearchResult result) { float abilityUse = ActionEvaluator.ActionCounts[UctActionType.AbilityUse]; float attackMove = ActionEvaluator.ActionCounts[UctActionType.AttackMove]; float defensiveMove = ActionEvaluator.ActionCounts[UctActionType.DefensiveMove]; float move = ActionEvaluator.ActionCounts[UctActionType.Move]; float endTurn = ActionEvaluator.ActionCounts[UctActionType.EndTurn]; float useCounts = abilityUse + attackMove + defensiveMove + move; string endRatio = (endTurn / useCounts).ToString("0.00"); string abilityMoveRatio = ((abilityUse + attackMove) / (move + defensiveMove)).ToString("0.00"); if (Constants.MctsLogging) { foreach (var action in result.Actions) { Console.WriteLine($"action: {action}"); } Console.WriteLine( $"#sum: {ActionEvaluator.Actions}[ability/move ratio: {abilityMoveRatio}] [end ratio: {endRatio}] {ActionEvaluator.ActionCountString()}"); } }
/// <summary> /// Generates possible attack move actions. /// </summary> public static void GenerateAttackMoveActions(GameInstance state, CachedMob mob, List <UctAction> result) { var mobInfo = mob.MobInfo; var mobInstance = mob.MobInstance; foreach (var enemyId in state.MobManager.Mobs) { var target = state.CachedMob(enemyId); if (!GameInvariants.IsTargetableNoSource(state, mob, target)) { continue; } AxialCoord myCoord = mobInstance.Coord; AxialCoord?closestCoord = null; int? distance = null; int? chosenAbilityId = null; foreach (var coord in state.Map.EmptyCoords) { if (!state.Map.IsVisible(coord, target.MobInstance.Coord)) { continue; } var possibleMoveAction = GameInvariants.CanMoveTo(state, mob, coord); if (possibleMoveAction.Type == UctActionType.Null) { continue; } Debug.Assert(possibleMoveAction.Type == UctActionType.Move); foreach (var abilityId in mobInfo.Abilities) { if (!GameInvariants.IsAbilityUsableFrom(state, mob, coord, target, abilityId)) { continue; } int myDistance = state.Pathfinder.Distance(myCoord, coord); if (!closestCoord.HasValue) { chosenAbilityId = abilityId; closestCoord = coord; distance = myDistance; } else if (distance.Value > myDistance) { chosenAbilityId = abilityId; closestCoord = coord; distance = myDistance; } } } if (closestCoord.HasValue) { if (Constants.AttackMoveEnabled) { var action = UctAction.AttackMoveAction(mob.MobId, closestCoord.Value, chosenAbilityId.Value, target.MobId); var after = ActionEvaluator.F(state, action.ToPureMove()); GameInvariants.AssertValidAbilityUseAction(after, action.ToPureAbilityUse()); GameInvariants.AssertValidAction(state, action); result.Add(action); } else { var action = UctAction.MoveAction(mob.MobId, closestCoord.Value); GameInvariants.AssertValidAction(state, action); result.Add(action); } } } }
private void ValidateReorgEnd( Block <T> oldTip, Block <T> newTip, Block <T> branchpoint) { if (!(BlockChain is BlockChain <T> chain)) { return; } IBlockPolicy <T> policy = chain.Policy; IStore store = chain.Store; InvalidRenderException <T> heterogeneousGenesisError = Error(Records, "Reorg occurred from the chain with different genesis."); List <IAction> expectedUnrenderedActions = new List <IAction>(); BlockHeader header = oldTip.Header; IEnumerable <TxId> txIds = oldTip.Transactions.Select(tx => tx.Id); while (!header.Hash.Equals(branchpoint.Hash)) { if (policy.BlockAction is IAction blockAction) { expectedUnrenderedActions.Add(blockAction); } IEnumerable <Transaction <T> > transactions = txIds.Select(store.GetTransaction <T>); transactions = ActionEvaluator <T> .OrderTxsForEvaluation( header.ProtocolVersion, transactions, header.PreEvaluationHash ); expectedUnrenderedActions.AddRange( transactions.SelectMany(t => t.Actions).Cast <IAction>().Reverse()); BlockDigest prevDigest = store.GetBlockDigest( header.PreviousHash ?? throw heterogeneousGenesisError ) ?? throw Error(Records, $"Failed to load block {header.PreviousHash}."); header = prevDigest.GetHeader(policy.GetHashAlgorithm); txIds = prevDigest.TxIds.Select(b => new TxId(b.ToBuilder().ToArray())); } IEnumerable <IAction> expectedRenderedActionsBuffer = new List <IAction>(); header = newTip.Header; txIds = newTip.Transactions.Select(tx => tx.Id); while (!header.Hash.Equals(branchpoint.Hash)) { IEnumerable <Transaction <T> > transactions = txIds.Select(store.GetTransaction <T>); transactions = ActionEvaluator <T> .OrderTxsForEvaluation( header.ProtocolVersion, transactions, header.PreEvaluationHash ); IEnumerable <IAction> actions = transactions.SelectMany(t => t.Actions).Cast <IAction>(); if (policy.BlockAction is IAction blockAction) { #if NET472 || NET471 || NET47 || NET462 || NET461 // Even though .NET Framework 4.6.1 or higher supports .NET Standard 2.0, // versions lower than 4.8 lacks Enumerable.Append(IEnumerable<T>, T) method. actions = actions.Concat(new IAction[] { blockAction }); #else #pragma warning disable PC002 actions = actions.Append(blockAction); #pragma warning restore PC002 #endif } expectedRenderedActionsBuffer = actions.Concat(expectedRenderedActionsBuffer); BlockDigest prevDigest = store.GetBlockDigest( header.PreviousHash ?? throw heterogeneousGenesisError ) ?? throw Error(Records, $"Failed to load block {header.PreviousHash}."); header = prevDigest.GetHeader(policy.GetHashAlgorithm); txIds = prevDigest.TxIds.Select(b => new TxId(b.ToBuilder().ToArray())); } IAction[] expectedRenderedActions = expectedRenderedActionsBuffer.ToArray(); List <IAction> actualRenderedActions = new List <IAction>(); List <IAction> actualUnrenderedActions = new List <IAction>(); foreach (var record in Records.Reverse()) { if (record is RenderRecord <T> .Reorg b && b.Begin) { break; } if (record is RenderRecord <T> .ActionBase a) { if (a.Render) { actualRenderedActions.Add(a.Action); } else { actualUnrenderedActions.Add(a.Action); } } } actualRenderedActions.Reverse(); actualUnrenderedActions.Reverse(); string ReprAction(IAction?action) { if (action is null) { return("[N/A]"); } return(action.PlainValue.Inspect(loadAll: true) .Replace(" \n ", " ") .Replace(" \n", " ") .Replace("\n ", " ") .Replace("\n", " ")); } string MakeErrorMessage(string prefix, IList <IAction> expected, IList <IAction> actual) { int expectN = expected.Count; int actualN = actual.Count; if (expectN != actualN) { prefix += $" (expected: {expectN} actions, actual: {actualN} actions):"; } var buffer = new StringBuilder(); for (int i = 0, count = Math.Max(expectN, actualN); i < count; i++) { IAction?e = i < expectN ? expected[i] : null; IAction?a = i < actualN ? actual[i] : null; if (!(e is null || a is null) && e.PlainValue.Equals(a.PlainValue)) { buffer.Append($"\n\t {ReprAction(e)}"); }
/** <summary> * Evaluate an argument list within the context of the enclosing * template but store the values in the context of self, the * new embedded template. For example, bold(item=item) means * that bold.item should get the value of enclosing.item. * </summary> */ protected virtual void EvaluateArguments( StringTemplate self ) { StringTemplateAST argumentsAST = self.ArgumentsAST; if ( argumentsAST == null || argumentsAST.GetChild( 0 ) == null ) { // return immediately if missing tree or no actual args return; } // Evaluate args in the context of the enclosing template, but we // need the predefined args like 'it', 'attr', and 'i' to be // available as well so we put a dummy ST between the enclosing // context and the embedded context. The dummy has the predefined // context as does the embedded. StringTemplate enclosing = self.EnclosingInstance; StringTemplate argContextST = new StringTemplate( self.Group, "" ); argContextST.Name = "<invoke " + self.Name + " arg context>"; argContextST.EnclosingInstance = enclosing; argContextST.ArgumentContext = self.ArgumentContext; ActionEvaluator eval = new ActionEvaluator( argContextST, this, null, argumentsAST ); /* System.out.println("eval args: "+argumentsAST.toStringList()); System.out.println("ctx is "+self.getArgumentContext()); */ try { // using any initial argument context (such as when obj is set), // evaluate the arg list like bold(item=obj). Since we pass // in any existing arg context, that context gets filled with // new values. With bold(item=obj), context becomes: // {[obj=...],[item=...]}. Dictionary<string, object> ac = eval.argList( self, self.ArgumentContext ); self.ArgumentContext = ac; } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + argumentsAST.ToStringTree(), re ); } }
/** <summary> * A expr is normally just a string literal, but is still an AST that * we must evaluate. The expr can be any expression such as a template * include or string cat expression etc... Evaluate with its own writer * so that we can convert to string and then reuse, don't want to compute * all the time; must precompute w/o writing to output buffer. * </summary> */ public virtual string EvaluateExpression( StringTemplate self, object expr ) { if ( expr == null ) { return null; } StringTemplateAST exprAST = expr as StringTemplateAST; if ( exprAST != null ) { #if COMPILE_EXPRESSIONS System.Func<StringTemplate, IStringTemplateWriter, int> value; #if CACHE_FUNCTORS if ( !_evaluators.TryGetValue( expr, out value ) ) #endif { value = GetEvaluator( this, exprAST ); #if CACHE_FUNCTORS _evaluators[expr] = value; #endif } #endif // must evaluate, writing to a string so we can hang on to it StringWriter buf = new StringWriter(); IStringTemplateWriter sw = self.Group.GetStringTemplateWriter( buf ); { try { #if COMPILE_EXPRESSIONS value( self, sw ); #else ActionEvaluator eval = new ActionEvaluator( self, this, sw, exprAST ); // eval tree eval.action(); #endif } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + _exprTree.ToStringTree(), re ); } } return buf.ToString(); } else { // just in case we expand in the future and it's something else return expr.ToString(); } }
public static float PlayoutAction(GameInstance game, UctAction action, TeamColor startingTeam) { return(DefaultPolicy(ActionEvaluator.F(game, action), startingTeam)); }
/** <summary> * To write out the value of an ASTExpr, invoke the evaluator in eval.g * to walk the tree writing out the values. For efficiency, don't * compute a bunch of strings and then pack them together. Write out directly. * </summary> * * <remarks> * Compute separator and wrap expressions, save as strings so we don't * recompute for each value in a multi-valued attribute or expression. * * If they set anchor option, then inform the writer to push current * char position. * </remarks> */ public override int Write( StringTemplate self, IStringTemplateWriter @out ) { if ( _exprTree == null || self == null || @out == null ) { return 0; } // handle options, anchor, wrap, separator... StringTemplateAST anchorAST = (StringTemplateAST)GetOption( "anchor" ); if ( anchorAST != null ) { // any non-empty expr means true; check presence @out.PushAnchorPoint(); } @out.PushIndentation( Indentation ); HandleExprOptions( self ); //System.out.println("evaluating tree: "+exprTree.toStringList()); #if COMPILE_EXPRESSIONS if ( EvaluateAction == null ) EvaluateAction = GetEvaluator( this, AST ); #else ActionEvaluator eval = new ActionEvaluator( self, this, @out, _exprTree ); #endif int n = 0; try { // eval and write out tree #if COMPILE_EXPRESSIONS n = EvaluateAction( self, @out ); #else n = eval.action(); #endif } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + _exprTree.ToStringTree(), re ); } @out.PopIndentation(); if ( anchorAST != null ) { @out.PopAnchorPoint(); } return n; }