protected Block1Node Create(Field field, BlockPath path, ApplyParameters pars) { var score = pars.Evaluator.GetScore(field, Depth, pars.Parameters); pars.Evaluations++; return(new Block1Node(field, path, score, pars.Next.BranchingFactor1)); }
public virtual BlockPath GetMove(Field field, Field opponent, Block current, Block next, int round) { Logs.Clear(); Pars = new ApplyParameters(Rnd) { Garbage = field.Points / 3, Round = round, MaximumDuration = MaximumDuration, MaximumDepth = MaximumDepth, Evaluator = Evaluator, Generator = Generator, Current = current, Next = next, FirstFilled = field.FirstFilled, Parameters = DefaultEvaluation, }; var oppo = new OpponentEvaluator() { Generator = Pars.Generator }; Pars.Opponent = oppo.Evaluate(opponent, current, next); var move = BlockPath.None; Root = new BlockRootNode(field); // search at least two ply deep. while ((Pars.Depth < 2 || (Pars.Depth < Pars.MaximumDepth && Pars.Elapsed < MinimumDuration)) // Cut if we have a win in 1 or two. && Root.Score != Scores.Wins(Pars.Depth)) { Root.Apply(++Pars.Depth, Pars); Logs.Add(new PlyLog(Pars.Round, Root.BestMove, Root.Score, Pars.Depth, Pars.Elapsed, Pars.Evaluations)); } BestField = Root.BestField; return Root.BestMove; }
protected override BlockRndNode Create(Field field, ApplyParameters pars) { var score = pars.Evaluator.GetScore(field, Depth, pars.Parameters); pars.Evaluations++; return(new BlockRndNode(field, Depth, score)); }
/// <summary>Applies the search on the current node.</summary> /// <param name="depth"> /// The maximum depth to search. /// </param> /// <param name="pars"> /// The parameters needed to apply the search. /// </param> public void Apply(byte depth, ApplyParameters pars) { if (depth > Depth && depth <= pars.MaximumDepth && pars.HasTimeLeft) { if (Children == null) { Children = new List <BlockNodes <BlockRndNode> >(); foreach (var block in pars.Blocks[Depth]) { var nodes = new BlockNodes <BlockRndNode>(block); foreach (var field in pars.Generator.GetFields(Field, block)) { if (!pars.HasTimeLeft) { return; } var applied = BlockNode.Apply(field, Depth, pars); if (!applied.IsNone) { var child = Create(applied, pars); nodes.InsertSorted(child); } } Children.Add(nodes); } } else { foreach (var nodes in Children) { nodes.Apply(depth, pars, BranchingFactor); } } Score = 0; foreach (var nodes in Children) { Score += nodes.GetScore(this); } if (Children.Count == 2) { // Divide by 2. Score >>= 1; } // We can not find valid responses. We will lose next turn. else if (Children.Count == 0) { Score = Scores.Loses(Depth + 1); } else { Score /= Children.Count; } } }
/// <summary>Applies the search on the current node.</summary> /// <param name="depth"> /// The maximum depth to search. /// </param> /// <param name="pars"> /// The parameters needed to apply the search. /// </param> public override void Apply(byte depth, ApplyParameters pars) { if (depth > Depth && depth <= pars.MaximumDepth && pars.HasTimeLeft) { if (Children == null) { var block = GetBlock(pars); Children = new BlockNodes <BlockRndNode>(block); var applied = BlockNode.Apply(Field, Depth, pars); if (!applied.IsNone) { foreach (var field in pars.Generator.GetFields(applied, block)) { if (!pars.HasTimeLeft) { return; } var child = Create(field, pars); // We can kill our opponent. if (child.Field.Points > Field.Points) { var garbageNew = child.Field.Points / 3; if (garbageNew - pars.Garbage > pars.Opponent.FirstFilled2) { child.SetFinalScore(Scores.Wins(2)); } } Children.InsertSorted(child); } } } else { if (Children.Empty()) { return; } Children.Apply(depth, pars, BranchingFactor); } Score = Children.GetScore(this); } }
public virtual BlockPath GetMove(Field field, Field opponent, Block current, Block next, int round) { Logs.Clear(); Pars = new ApplyParameters(Rnd) { Garbage = field.Points / 3, Round = round, MaximumDuration = MaximumDuration, MaximumDepth = MaximumDepth, Evaluator = Evaluator, Generator = Generator, Current = current, Next = next, FirstFilled = field.FirstFilled, Parameters = DefaultEvaluation, }; var oppo = new OpponentEvaluator() { Generator = Pars.Generator }; Pars.Opponent = oppo.Evaluate(opponent, current, next); var move = BlockPath.None; Root = new BlockRootNode(field); // search at least two ply deep. while ((Pars.Depth < 2 || (Pars.Depth < Pars.MaximumDepth && Pars.Elapsed < MinimumDuration)) // Cut if we have a win in 1 or two. && Root.Score != Scores.Wins(Pars.Depth)) { Root.Apply(++Pars.Depth, Pars); Logs.Add(new PlyLog(Pars.Round, Root.BestMove, Root.Score, Pars.Depth, Pars.Elapsed, Pars.Evaluations)); } BestField = Root.BestField; return(Root.BestMove); }
/// <summary>Applies the search on the current node.</summary> /// <param name="depth"> /// The maximum depth to search. /// </param> /// <param name="pars"> /// The parameters needed to apply the search. /// </param> public override void Apply(byte depth, ApplyParameters pars) { if (depth > Depth && depth <= pars.MaximumDepth && pars.HasTimeLeft) { if (Children == null) { BranchingFactor = pars.Current.BranchingFactor0; var block = GetBlock(pars); Children = new BlockNodes <Block1Node>(block); foreach (var candidate in pars.Generator.GetMoves(Field, block)) { if (!pars.HasTimeLeft) { return; } Block1Node child = Create(candidate.Field, candidate.Path, pars); // We can kill our opponent. if (child.Field.Points > Field.Points) { var garbageNew = child.Field.Points / 3; if (garbageNew - pars.Garbage > pars.Opponent.FirstFilled1) { child.SetFinalScore(Scores.Wins(1)); } } Children.InsertSorted(child); } } else { Children.Apply(depth, pars, BranchingFactor); } Score = Children.GetScore(this); } }
/// <summary>Applies the search on the child nodes.</summary> /// <param name="depth"> /// The maximum depth to search. /// </param> /// <param name="pars"> /// The parameters needed to apply the search. /// </param> /// <param name="branchingFactor"> /// The maximum branching factor. /// </param> public void Apply(byte depth, ApplyParameters pars, int branchingFactor) { if (Empty() || depth == 0) { return; } var threshold = this[Math.Min(Count, branchingFactor) - 1].Score; var depthMin1 = (byte)(depth - 1); var dephtMin1Threshold = threshold - 100; foreach (var child in this) { // Only checks moves that are not worse than the threshold. if (child.Score < threshold) { break; } if (child.Score > dephtMin1Threshold) { child.Apply(depth, pars); } else { child.Apply(depthMin1, pars); } // we find a lower move, look for others that are potentially better. if (child.Score < threshold) { threshold = child.Score; } } base.Sort(); }
protected override Block GetBlock(ApplyParameters pars) { return(pars.Current); }
protected override Block1Node Create(Field field, ApplyParameters pars) { throw new NotImplementedException(); }
protected abstract Block GetBlock(ApplyParameters pars);
protected abstract T Create(Field field, ApplyParameters pars);
/// <summary>Applies the search on the current node.</summary> /// <param name="depth"> /// The maximum depth to search. /// </param> /// <param name="pars"> /// The parameters needed to apply the search. /// </param> public abstract void Apply(byte depth, ApplyParameters pars);