private static void Test(Field field, EvaluatorParameters pars, int expected) { var evaluator = new Evaluator(); var actual = evaluator.GetScore(field, 0, pars.Calc()); Assert.AreEqual(expected, actual); }
private void SetParameters(CodeExpression root, EvaluatorParameters parameters) { if (root is CodeBinaryOperatorExpression) { CodeBinaryOperatorExpression bin = (CodeBinaryOperatorExpression)root; this.SetParameters(bin.Left, parameters); this.SetParameters(bin.Right, parameters); } else { if (root is CodePrimitiveExpression) { CodePrimitiveExpression primitive = (CodePrimitiveExpression)root; int parameterNumber = EvaluatorGenerator.GetParameterIndex(primitive, false); if (parameterNumber >= 0) { parameters.SetParameter(parameterNumber, primitive.Value); } } else { throw new ApplicationException("Cannot evaluate a rule until all variables have been set."); } } }
public BotData Add(EvaluatorParameters defPars) { var id = GetNewId(); var bot = new BotData(id, defPars); TryAdd(id, bot); return(bot); }
private EvaluatorParameters GetHolePars() { var pars = new EvaluatorParameters() { HolesReachable = new ParamCurve(1), HolesUnreachable = new ParamCurve(100), }; return pars; }
private EvaluatorParameters GetHolePars() { var pars = new EvaluatorParameters() { HolesReachable = new ParamCurve(1), HolesUnreachable = new ParamCurve(100), }; return(pars); }
public void PerfectClearPotential_SingleLine2_1() { var pars = new EvaluatorParameters() { PerfectClearPotential = new ParamCurve(1), }; Test(@" .......... ........XX" , pars, 1); }
public void TSpinDoublePotential_TFitWithToBlocades_0() { var pars = new EvaluatorParameters() { TSpinDoublePotential = new ParamCurve(1), }; Test(@" .......... .X.X...... X...XXXXXX XX.XXXXXXX", pars, 0); }
public void PerfectClearPotential_2Rows8EmptyCells_1() { var pars = new EvaluatorParameters() { PerfectClearPotential = new ParamCurve(1), }; Test(@" .......... XXX......X XXXXX..XXX" , pars, 1); }
public void GetDefault_None_ParametersToString() { var pars = EvaluatorParameters.GetDefault(); var act = BotData.ParametersToString(pars); Console.Write(act); var bots = new Bots(); bots.Add(pars); bots.Save(new FileInfo("default.xml")); }
public void TDoubleClearPotential_NoBlock_1() { var pars = new EvaluatorParameters() { TDoubleClearPotential = new ParamCurve(1), }; Test(@" .......... ......X... X...XXXXXX XX.XXXXXXX" , pars, 1); }
public void PerfectClearPotential_WrongNumberOfBlocks_0() { var pars = new EvaluatorParameters() { PerfectClearPotential = new ParamCurve(1), }; Test(@" .......... XXXXXX...X XXXXXX..XX XXXXXX.XXX" , pars, 0); }
public void TSpinDoublePotential_TFit_1() { var pars = new EvaluatorParameters() { TSpinDoublePotential = new ParamCurve(1), }; Test(@" .......... ...X...... X...XXXXXX XX.XXXXXXX" , pars, 1); }
public void TSpinDoublePotential_TFitWithCenterBlocades_0() { var pars = new EvaluatorParameters() { TSpinDoublePotential = new ParamCurve(1), }; Test(@" .......... .XX....... X...XXXXXX XX.XXXXXXX" , pars, 0); }
public static BattleBot Create(MT19937Generator rnd, EvaluatorParameters defPars, int maxDepth) { return new BattleBot() { DecisionMaker = new NodeDecisionMaker(rnd) { MaximumDepth = maxDepth, Evaluator = new Evaluator(), Generator = new MoveGenerator(), DefaultEvaluation = defPars, } }; }
public void TSpinSinglePotential_Row1Score_1() { var pars = new EvaluatorParameters() { TSpinSingle1Potential = new ParamCurve(1), }; Test(@" .......... ....XX.... XXXXX...XX .....X.XXX" , pars, 1); }
public static BattleBot Create(MT19937Generator rnd, EvaluatorParameters defPars, int maxDepth) { return(new BattleBot() { DecisionMaker = new NodeDecisionMaker(rnd) { MaximumDepth = maxDepth, Evaluator = new Evaluator(), Generator = new MoveGenerator(), DefaultEvaluation = defPars, } }); }
public void SingleEmpties_TwoColomns_2x2() { var pars = new EvaluatorParameters() { SingleEmpties = new int[] { 0, 0, 1, 0, 0, 0 } }; Test(@" .......... X......X.. X...XXXXX. XX.XXX.XX. XX..XXXXX." , pars, 2 * 2); }
public void TSpinSinglePotential_NoBlockade_0() { var pars = new EvaluatorParameters() { TSpinSingle0Potential = new ParamCurve(1), }; Test(@" .......... .......... X..XX..... XXXXX....X X..XX...XX XXXXXX.XXX" , pars, 0); }
public void TSpinSinglePotential_HasScoreBecauseLowerRow_1() { var pars = new EvaluatorParameters() { TSpinSingle0Potential = new ParamCurve(1), }; Test(@" .......... .......... X..XX..... XXXXXX...X X.XXX...XX XXXXXX.XXX" , pars, 1); }
private void OnEvaluateClick(object sender, EventArgs e) { EvaluatorParameters parameters = evaluator.CreateEmptyParameters(); this.SetParameters(currentExpressionValue, parameters); this.resultLabel.Text = evaluator.Evaluate(parameters).ToString(); Graphics graphics = resultLabel.CreateGraphics(); SizeF resultSizeF = graphics.MeasureString(resultLabel.Text, resultLabel.Font); Size resultSize = Size.Truncate(resultSizeF); this.resultLabel.Width = resultSize.Width + 1; this.ResizePanel(); }
public void Save_OneBot_ToFile() { var collection = new SimulationBotCollection() { new BotData() { Id = 17, Locked = true, DefPars = EvaluatorParameters.GetDefault(), }, }; var file = new FileInfo("collection.xml"); collection.Save(file); }
public void TSpinDoublePotential_ClearWithT_0() { var pars = new EvaluatorParameters() { TSpinDoublePotential = new ParamCurve(1), }; Test(@" .......... .......... .......... X......... X..XX..... XXXXXX...X XXXXXX..XX XXXXXX.XXX" , pars, 0); }
public void SingleEmpties_3Colomns_3x2() { var field = @" .......... X......X.. X...X..X.. XX.XXX.XX. XX..XX.XX." ; var pars = new EvaluatorParameters() { SingleEmpties = new int[] { 0, 0, 0, 1, 0, 0 } }; var expected = 3 * 2; Test(field, pars, expected); }
public void SingleGroupBonus_AllKindOfRows_1111() { var field = @" .......... .........X ........XX .......XXX ......XXXX .....XXXXX ....XXXXXX ...XXXXXXX ..XXXXXXXX .XXXXXXXXX XXXXXXXX.."; var pars = new EvaluatorParameters() { SingleGroupBonus = new int[] { 1, 10, 100, 1000 }, }; var expected = 1111; Test(field, pars, expected); }
public void SingleGroupBonus_AllKindOfRows_1111() { var field = @" .......... .........X ........XX .......XXX ......XXXX .....XXXXX ....XXXXXX ...XXXXXXX ..XXXXXXXX .XXXXXXXXX XXXXXXXX.."; var pars = new EvaluatorParameters() { SingleGroupBonus = new int[] { 1, 10, 100, 1000 }, }; var expected = 1111; Test(field, pars, expected); }
public static string ParametersToString(EvaluatorParameters pars) { var writer = new StringBuilder(); writer.AppendLine("{"); foreach (var prop in Props) { if (prop.PropertyType == typeof(int)) { int val = (int)prop.GetValue(pars); writer.AppendFormat("{0} = {1},", prop.Name, val); writer.AppendLine(); } else if (prop.PropertyType == typeof(bool)) { bool val = (bool)prop.GetValue(pars); writer.AppendFormat("{0} = {1},", prop.Name, val.ToString().ToLowerInvariant()); writer.AppendLine(); } else if (prop.PropertyType == typeof(int[])) { int[] vals = (int[])prop.GetValue(pars); writer.AppendFormat("{0} = new [] {{ {1} }},", prop.Name, String.Join(",", vals)); writer.AppendLine(); } else if (prop.PropertyType == typeof(ParamCurve)) { ParamCurve val = (ParamCurve)prop.GetValue(pars); writer.AppendFormat("{0} = {1},", prop.Name, val); writer.AppendLine(); } } writer.AppendLine("};"); return(writer.ToString()); }
public void TDoubleClearPotential_NoBlock_1() { var pars = new EvaluatorParameters() { TDoubleClearPotential = new ParamCurve(1), }; Test(@" .......... ......X... X...XXXXXX XX.XXXXXXX", pars, 1); }
public static EvaluatorParameters GetDef() { return(EvaluatorParameters.GetDefault().Calc()); }
public void TSpinSinglePotential_HasScoreBecauseLowerRow_1() { var pars = new EvaluatorParameters() { TSpinSingle0Potential = new ParamCurve(1), }; Test(@" .......... .......... X..XX..... XXXXXX...X X.XXX...XX XXXXXX.XXX", pars, 1); }
public void PerfectClearPotential_SingleLine2_1() { var pars = new EvaluatorParameters() { PerfectClearPotential = new ParamCurve(1), }; Test(@" .......... ........XX", pars, 1); }
public void PerfectClearPotential_WrongNumberOfBlocks_0() { var pars = new EvaluatorParameters() { PerfectClearPotential = new ParamCurve(1), }; Test(@" .......... XXXXXX...X XXXXXX..XX XXXXXX.XXX", pars, 0); }
public void TSpinSinglePotential_NoBlockade_0() { var pars = new EvaluatorParameters() { TSpinSingle0Potential = new ParamCurve(1), }; Test(@" .......... .......... X..XX..... XXXXX....X X..XX...XX XXXXXX.XXX", pars, 0); }
/// <summary>Gets the (static) score of a field.</summary> /// <remarks> /// Normally, this function should be split in several sub methods. But as /// this is the most executed code of the all AI, speed is everything. The /// penalty for calling a method is small, but here, we don't want to spoil it. /// </remarks> public int GetScore(Field field, int depth, EvaluatorParameters pars) { #if !DEBUG unchecked { // we trust this not to overflow. #endif var score = 0; #region A block on the 1st and 8th will disallow the clearance of a row one turn earlier. var firstFilled = field.FirstFilled; if (firstFilled > 0 && firstFilled < field.RowCount && (field[firstFilled] & Mask1st8thColomn) != 0) { firstFilled--; } // Evaluation for free space. score += pars.EmptyRowsCalc[firstFilled]; #endregion // Points for static evaluation. score += field.Points * pars.PointsCalc[firstFilled]; score += field.Combo * pars.ComboCalc[firstFilled]; score += field.Skips * pars.SkipsCalc[firstFilled]; var rowIndex = field.FirstFilled; var row0 = 0; var row1 = 0; var row2 = 0; var row3 = 0; var row0Mirror = 0; var row0Holes = 0; int row0Open = Row.Filled; int row0Closed = 0; var countHoleReachable = 0; var countHoleUnreachable = 0; var countRow0 = 0; var countRow0Holes = 0; var countRow0Group = 0; var countRow1 = 0; var countRow1Group = 0; var countRow2Group = 0; #region Reachable Area var rowIndexHoles = -1; for (; rowIndex < field.RowCount; rowIndex++) { // For holes use an index based on the first filled. rowIndexHoles++; row0 = field[rowIndex]; row0Mirror = row0 ^ Row.Filled; // Not reachable, redo as unreachable. if ((row0Open & row0Mirror) == 0) { rowIndex--; break; } row0Holes = row0Mirror & row0Closed; countRow0 = Row.Count[row0]; countRow0Group = Row.Groups[row0Mirror]; #region Add points for grouping score += pars.Groups[countRow0Group]; if (countRow0Group == 1) { // Get bonuses for lines that can potentially be cleared by one block. if (countRow0 >= 6) { score += pars.SingleGroupBonus[countRow0 - 6]; } } else { // Add score for single empties. var singleEmpties = Row.SingleEmpties[row0 | row0Closed]; score += pars.SingleEmptiesCalc[singleEmpties]; } #endregion #region Handle holes if (row0Holes != 0) { countRow0Holes = Row.Count[row0Holes]; if (countRow0Holes == 1) { switch (row0Holes) { // X......... case 0x001: //.XX....... if ((row0Mirror & 0x006) == 0x006) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .X........ case 0x002: //..XX...... if ((row0Mirror & 0x00C) == 0x00C) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ..X....... case 0x004: //XX........ OR ...XX..... if ((row0Mirror & 0x003) == 0x003 || (row0Mirror & 0x018) == 0x018) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ...X...... case 0x008: //.XX....... OR ....XX.... if ((row0Mirror & 0x006) == 0x006 || (row0Mirror & 0x030) == 0x030) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ....X..... case 0x010: //..XX...... OR .....XX... if ((row0Mirror & 0x00C) == 0x00C || (row0Mirror & 0x060) == 0x060) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .....X.... case 0x020: //...XX..... OR ......XX.. if ((row0Mirror & 0x018) == 0x018 || (row0Mirror & 0x0C0) == 0x0C0) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ......X... case 0x040: //....XX.... OR .......XX. if ((row0Mirror & 0x030) == 0x030 || (row0Mirror & 0x180) == 0x180) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .......X.. case 0x080: //.....XX... OR ........XX if ((row0Mirror & 0x060) == 0x060 || (row0Mirror & 0x300) == 0x300) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ........X. case 0x100: //......XX.. if ((row0Mirror & 0x0C0) == 0x0C0) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .........X case 0x200: //.......XX. if ((row0Mirror & 0x180) == 0x180) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; } } else { countHoleUnreachable += countRow0Holes * pars.HolesUnreachableCalc[rowIndexHoles]; } #region Single T-spin upper if (countRow1 == 7 && countRow1Group == 1) { // .X.X...... (2 groups) if (Row.Groups[(row1 ^ Row.Filled) ^ row0Mirror] == 2) { score += pars.TSpinSingle1PotentialCalc[rowIndex]; } } } #endregion #region T-spin potential #region Double T-spin // X...XXXXXX // XX.XXXXXXX else if (countRow0 == 9 && countRow1 == 7 && countRow1Group == 1) { // X...XXXXXX // XX.XXXXXXX // ---------- // .X.X...... (2 groups) if (Row.Groups[(row1 ^ Row.Filled) ^ row0Mirror] == 2) { // ...X...... // X...XXXXXX // ---------- // X..XXXXXXX (count 8) var merged = Row.Count[row1 | row2]; if (merged == 8) { score += pars.TSpinDoublePotentialCalc[rowIndex]; } else if (merged == 7) { score += pars.TDoubleClearPotentialCalc[rowIndex]; } } } #endregion #region Single T-spin lower // X...XXX??X // XX.XXXXXXX else if (countRow0 == 9 && countRow1 < 7) { // X...XXXXX? // XX.XXXXXXX // ---------- // .X.X...... (1 group more than before) if (Row.Groups[row1 | row0Mirror] == Row.Groups[row1] + 1) { // the hole on row zero should stitch to 1 group, not to 2. var merged = row2 | row0Mirror; if (Row.Groups[merged] == Row.Groups[row2]) { score += pars.TSpinSingle0PotentialCalc[rowIndex]; } } } #endregion #endregion // With 7 in row1 see hole part. #endregion // Update history. row0Open &= row0Mirror; row0Closed |= row0; countRow1 = countRow0; countRow2Group = countRow1Group; countRow1Group = countRow0Group; row3 = row2; row2 = row1; row1 = row0; } #endregion #region Unreachable area var unreachbleGroups = 0; score += pars.UnreachableRowsCalc[field.RowCount - rowIndex]; for (; rowIndex < field.RowCount; rowIndex++) { row0Mirror = field[rowIndex] ^ Row.Filled; unreachbleGroups = Row.Groups[row0Mirror]; // Points for groups. score += pars.Groups[unreachbleGroups]; // Points for holes. countRow0Holes = Row.Count[row0Mirror]; countHoleUnreachable += countRow0Holes * pars.HolesUnreachableCalc[rowIndexHoles]; rowIndexHoles++; } #endregion #region Perfect clear if (countHoleReachable == 0 && countHoleUnreachable == 0) { var filled = field.RowCount - field.FirstFilled; if (filled < 5) { var hasPerfectClearPotential = false; if (filled == 1) { hasPerfectClearPotential = row0 == PerfectClearOneRow0 || row0 == PerfectClearOneRow1 || row0 == PerfectClearOneRow2 || // 4 empty cells as one group. (Row.Count[row0] == 6 && Row.Groups[row0Mirror] == 1); } else { var toFill = filled * 10 - field.Count; hasPerfectClearPotential = // Can be divided by 4. (toFill & 3) == 0 && // maximum block left only. toFill <= 12 && // Can be filled 'easily' because all space is connected. Row.Groups[row0Mirror] == 1 && Row.Groups[row1 ^ Row.Filled] == 1 && Row.Groups[row2 ^ Row.Filled] == 1 && Row.Groups[row3 ^ Row.Filled] == 1; } if (hasPerfectClearPotential) { score += pars.PerfectClearPotentialCalc[field.RowCount]; } } } #endregion score += countHoleReachable; score += countHoleUnreachable; return score; #if !DEBUG } // end unchecked. #endif }
public void SingleEmpties_TwoColomns_2x2() { var pars = new EvaluatorParameters() { SingleEmpties = new int[] { 0, 0, 1, 0, 0, 0 } }; Test(@" .......... X......X.. X...XXXXX. XX.XXX.XX. XX..XXXXX.", pars, 2 * 2); }
public BlockPath GetMove(Field field, Field opponent, Block current, Block next, int round, EvaluatorParameters pars) { Pars = new ApplyParameters(Rnd) { Round = round, MaximumDuration = MaximumDuration, MaximumDepth = MaximumDepth, Evaluator = Evaluator, Generator = Generator, Current = current, Next = next, FirstFilled = field.FirstFilled, Parameters = pars, }; Root = new BlockRootNode(field); while (Pars.Depth < Pars.MaximumDepth && Pars.HasTimeLeft) { Root.Apply(++Pars.Depth, Pars); Logs.Add(new PlyLog(Pars.Round, Root.BestMove, Root.Score, Pars.Depth, Pars.Elapsed, Pars.Evaluations)); Console.WriteLine(Logs.Last()); } BestField = Root.BestField; return(Root.BestMove); }
public void SingleEmpties_3Colomns_3x2() { var field = @" .......... X......X.. X...X..X.. XX.XXX.XX. XX..XX.XX."; var pars = new EvaluatorParameters() { SingleEmpties = new int[] { 0, 0, 0, 1, 0, 0 } }; var expected = 3 * 2; Test(field, pars, expected); }
private static void Test(string str, EvaluatorParameters pars, int expected) { var field = Field.Create(0, 0, 0, str); Test(field, pars, expected); }
private static void Test(Field field, EvaluatorParameters pars, int expected) { var evaluator = new Evaluator(); var actual = evaluator.GetScore(field, 0, pars.Calc()); Assert.AreEqual(expected, actual); }
public BlockPath GetMove(Field field, Block current, Block next, int round) { return(GetMove(field, current, next, round, EvaluatorParameters.GetDefault())); }
public void PerfectClearPotential_2Rows8EmptyCells_1() { var pars = new EvaluatorParameters() { PerfectClearPotential = new ParamCurve(1), }; Test(@" .......... XXX......X XXXXX..XXX", pars, 1); }
public BlockPath GetMove(Field field, Block current, Block next, int round, EvaluatorParameters pars) { return(GetMove(field, Field.Empty, current, next, round, pars)); }
/// <summary>Gets the (static) score of a field.</summary> /// <remarks> /// Normally, this function should be split in several sub methods. But as /// this is the most executed code of the all AI, speed is everything. The /// penalty for calling a method is small, but here, we don't want to spoil it. /// </remarks> public int GetScore(Field field, int depth, EvaluatorParameters pars) { #if !DEBUG unchecked { // we trust this not to overflow. #endif var score = 0; #region A block on the 1st and 8th will disallow the clearance of a row one turn earlier. var firstFilled = field.FirstFilled; if (firstFilled > 0 && firstFilled < field.RowCount && (field[firstFilled] & Mask1st8thColomn) != 0) { firstFilled--; } // Evaluation for free space. score += pars.EmptyRowsCalc[firstFilled]; #endregion // Points for static evaluation. score += field.Points * pars.PointsCalc[firstFilled]; score += field.Combo * pars.ComboCalc[firstFilled]; score += field.Skips * pars.SkipsCalc[firstFilled]; var rowIndex = field.FirstFilled; var row0 = 0; var row1 = 0; var row2 = 0; var row3 = 0; var row0Mirror = 0; var row0Holes = 0; int row0Open = Row.Filled; int row0Closed = 0; var countHoleReachable = 0; var countHoleUnreachable = 0; var countRow0 = 0; var countRow0Holes = 0; var countRow0Group = 0; var countRow1 = 0; var countRow1Group = 0; var countRow2Group = 0; #region Reachable Area var rowIndexHoles = -1; for (; rowIndex < field.RowCount; rowIndex++) { // For holes use an index based on the first filled. rowIndexHoles++; row0 = field[rowIndex]; row0Mirror = row0 ^ Row.Filled; // Not reachable, redo as unreachable. if ((row0Open & row0Mirror) == 0) { rowIndex--; break; } row0Holes = row0Mirror & row0Closed; countRow0 = Row.Count[row0]; countRow0Group = Row.Groups[row0Mirror]; #region Add points for grouping score += pars.Groups[countRow0Group]; if (countRow0Group == 1) { // Get bonuses for lines that can potentially be cleared by one block. if (countRow0 >= 6) { score += pars.SingleGroupBonus[countRow0 - 6]; } } else { // Add score for single empties. var singleEmpties = Row.SingleEmpties[row0 | row0Closed]; score += pars.SingleEmptiesCalc[singleEmpties]; } #endregion #region Handle holes if (row0Holes != 0) { countRow0Holes = Row.Count[row0Holes]; if (countRow0Holes == 1) { switch (row0Holes) { // X......... case 0x001: //.XX....... if ((row0Mirror & 0x006) == 0x006) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .X........ case 0x002: //..XX...... if ((row0Mirror & 0x00C) == 0x00C) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ..X....... case 0x004: //XX........ OR ...XX..... if ((row0Mirror & 0x003) == 0x003 || (row0Mirror & 0x018) == 0x018) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ...X...... case 0x008: //.XX....... OR ....XX.... if ((row0Mirror & 0x006) == 0x006 || (row0Mirror & 0x030) == 0x030) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ....X..... case 0x010: //..XX...... OR .....XX... if ((row0Mirror & 0x00C) == 0x00C || (row0Mirror & 0x060) == 0x060) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .....X.... case 0x020: //...XX..... OR ......XX.. if ((row0Mirror & 0x018) == 0x018 || (row0Mirror & 0x0C0) == 0x0C0) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ......X... case 0x040: //....XX.... OR .......XX. if ((row0Mirror & 0x030) == 0x030 || (row0Mirror & 0x180) == 0x180) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .......X.. case 0x080: //.....XX... OR ........XX if ((row0Mirror & 0x060) == 0x060 || (row0Mirror & 0x300) == 0x300) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // ........X. case 0x100: //......XX.. if ((row0Mirror & 0x0C0) == 0x0C0) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; // .........X case 0x200: //.......XX. if ((row0Mirror & 0x180) == 0x180) { countHoleReachable += pars.HolesReachableCalc[rowIndexHoles]; } else { countHoleReachable += pars.HolesUnreachableCalc[rowIndexHoles]; } break; } } else { countHoleUnreachable += countRow0Holes * pars.HolesUnreachableCalc[rowIndexHoles]; } #region Single T-spin upper if (countRow1 == 7 && countRow1Group == 1) { // .X.X...... (2 groups) if (Row.Groups[(row1 ^ Row.Filled) ^ row0Mirror] == 2) { score += pars.TSpinSingle1PotentialCalc[rowIndex]; } } } #endregion #region T-spin potential #region Double T-spin // X...XXXXXX // XX.XXXXXXX else if (countRow0 == 9 && countRow1 == 7 && countRow1Group == 1) { // X...XXXXXX // XX.XXXXXXX // ---------- // .X.X...... (2 groups) if (Row.Groups[(row1 ^ Row.Filled) ^ row0Mirror] == 2) { // ...X...... // X...XXXXXX // ---------- // X..XXXXXXX (count 8) var merged = Row.Count[row1 | row2]; if (merged == 8) { score += pars.TSpinDoublePotentialCalc[rowIndex]; } else if (merged == 7) { score += pars.TDoubleClearPotentialCalc[rowIndex]; } } } #endregion #region Single T-spin lower // X...XXX??X // XX.XXXXXXX else if (countRow0 == 9 && countRow1 < 7) { // X...XXXXX? // XX.XXXXXXX // ---------- // .X.X...... (1 group more than before) if (Row.Groups[row1 | row0Mirror] == Row.Groups[row1] + 1) { // the hole on row zero should stitch to 1 group, not to 2. var merged = row2 | row0Mirror; if (Row.Groups[merged] == Row.Groups[row2]) { score += pars.TSpinSingle0PotentialCalc[rowIndex]; } } } #endregion #endregion // With 7 in row1 see hole part. #endregion // Update history. row0Open &= row0Mirror; row0Closed |= row0; countRow1 = countRow0; countRow2Group = countRow1Group; countRow1Group = countRow0Group; row3 = row2; row2 = row1; row1 = row0; } #endregion #region Unreachable area var unreachbleGroups = 0; score += pars.UnreachableRowsCalc[field.RowCount - rowIndex]; for (; rowIndex < field.RowCount; rowIndex++) { row0Mirror = field[rowIndex] ^ Row.Filled; unreachbleGroups = Row.Groups[row0Mirror]; // Points for groups. score += pars.Groups[unreachbleGroups]; // Points for holes. countRow0Holes = Row.Count[row0Mirror]; countHoleUnreachable += countRow0Holes * pars.HolesUnreachableCalc[rowIndexHoles]; rowIndexHoles++; } #endregion #region Perfect clear if (countHoleReachable == 0 && countHoleUnreachable == 0) { var filled = field.RowCount - field.FirstFilled; if (filled < 5) { var hasPerfectClearPotential = false; if (filled == 1) { hasPerfectClearPotential = row0 == PerfectClearOneRow0 || row0 == PerfectClearOneRow1 || row0 == PerfectClearOneRow2 || // 4 empty cells as one group. (Row.Count[row0] == 6 && Row.Groups[row0Mirror] == 1); } else { var toFill = filled * 10 - field.Count; hasPerfectClearPotential = // Can be divided by 4. (toFill & 3) == 0 && // maximum block left only. toFill <= 12 && // Can be filled 'easily' because all space is connected. Row.Groups[row0Mirror] == 1 && Row.Groups[row1 ^ Row.Filled] == 1 && Row.Groups[row2 ^ Row.Filled] == 1 && Row.Groups[row3 ^ Row.Filled] == 1; } if (hasPerfectClearPotential) { score += pars.PerfectClearPotentialCalc[field.RowCount]; } } } #endregion score += countHoleReachable; score += countHoleUnreachable; return(score); #if !DEBUG } // end unchecked. #endif }
public void TSpinSinglePotential_Row1Score_1() { var pars = new EvaluatorParameters() { TSpinSingle1Potential = new ParamCurve(1), }; Test(@" .......... ....XX.... XXXXX...XX .....X.XXX", pars, 1); }
private static void Test(string str, EvaluatorParameters pars, int expected) { var field = Field.Create(0, 0, 0, str); Test(field, pars, expected); }
public void TSpinDoublePotential_TFit_1() { var pars = new EvaluatorParameters() { TSpinDoublePotential = new ParamCurve(1), }; Test(@" .......... ...X...... X...XXXXXX XX.XXXXXXX", pars, 1); }
public BotData(int id, EvaluatorParameters def) : this() { Id = id; DefPars = def.Calc(); }