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);
        }
Beispiel #2
0
        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.");
                }
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #9
0
        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);
        }
Beispiel #20
0
        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);
		}
Beispiel #28
0
 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);
		}
Beispiel #35
0
        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);
		}
Beispiel #39
0
 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);
		}
Beispiel #41
0
 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();
 }