/// <summary> /// What Hint looks for: /// Gets the placed bloxes /// looks at the bloxes that are expected to be placed /// /// looks for the expected patterns: /// Horizontal line /// Vertical line /// Olhar para o que se faz no final de cada padrão: virar à esquerda,ou à direita? /// /// </summary> public void LoadHint(RootBlox rootBlox) { // 1. Check for mandatory bloxes not used List <Tuple <Type, int> > usedBloxTypeCount = rootBlox.GetAllBloxesBellow().GroupBy(b => b.GetType()).Select(g => new Tuple <Type, int>(g.First().GetType(), g.Count())).ToList(); List <ExpectedBlox> mandatoryBloxesNotUsed = LevelConfiguration.MandatoryBloxes.Where(mb => !usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType && b.Item2 >= mb.MinimumQuantity)).ToList(); // 1. Check for optional bloxes not used List <ExpectedBlox> expectedOptionalBloxesNotUsed = LevelConfiguration.OptionalExpectedBloxes.Where(mb => !usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType && b.Item2 >= mb.MinimumQuantity)).ToList(); }
public Evaluation EvaluateLevel(RootBlox rootBlox) { ObjectiveCheck check; int stars = 0; /// Each level will have 5 objectives: /// 1 - Complete in time /// 2 - Use a number of attempts lesser than the maximum /// 3 - Use a number of blocks lesser than the maximum /// 4 - Use the expected optional bloxes /// 5 - Complete the in game objective (mandatory steps, bloxes, special actions) /// // 1. Time evaluation DateTime expectedEndTime = startTime.AddMinutes(LevelConfiguration.MaxTimeInMinutes); check.exceededMinutes = (DateTime.Now - expectedEndTime).TotalMinutes; // 2. Number of attempts check.exceededAttempts = numberOfAttempts - (int)LevelConfiguration.MaxAttempts; check.numberOfAttempts = numberOfAttempts; // 3. Use a number of code lines lesser than the maximum check.exceededLines = rootBlox.GetChildBloxListInVerticalOrder().Count - (int)LevelConfiguration.MaxCodeLinesExpected; check.usedLines = rootBlox.GetChildBloxListInVerticalOrder().Count; // 4. Right steps. This is a mandatory object, so level shall fail when not accomplished // 4.1 Get all the mandatory steps that were executed, with the special action included // The final count should match the count of LevelConfiguration.MandatorySteps //var queryMandatoryStepsCompleted = from mandatoryStep in LevelConfiguration.MandatorySteps // join plotTile in tilesInScene on mandatoryStep.CoordinateInPlot equals plotTile.PlotPosition // where mandatoryStep != null && plotTile != null && plotTile.SpecialActionExecuted == mandatoryStep.SpecialAction && plotTile.Stepped // select plotTile; var queryMandatoryStepsCompleted = LevelConfiguration.MandatorySteps.Where(ms => tilesInScene.Exists(t => t.Stepped && t.SpecialActionExecuted == ms.SpecialAction && t.PlotPosition == ms.CoordinateInPlot)); bool allTheMandatoryStepsDone = queryMandatoryStepsCompleted.Count() == LevelConfiguration.MandatorySteps.Count; // 4.2 Get all the the not expected steps. It is mandatory that the user restricts to the mandatory steps var queryNotExpectedSteps = from plotTile in tilesInScene join mandatoryStep in LevelConfiguration.MandatorySteps on plotTile.PlotPosition equals mandatoryStep.CoordinateInPlot into mSteps from step in mSteps.DefaultIfEmpty() where step == null && plotTile.Stepped select plotTile; bool notExpectedStepsExist = queryNotExpectedSteps.Count() > 0; check.wrongSteps = queryNotExpectedSteps.Count(); check.mandatorySteps = !notExpectedStepsExist && allTheMandatoryStepsDone; // 5. This list contains the distinct blox types, and their count List <Tuple <Type, int> > usedBloxTypeCount = rootBlox.GetAllBloxesBellow().GroupBy(b => b.GetType()).Select(g => new Tuple <Type, int>(g.First().GetType(), g.Count())).ToList(); List <ExpectedBlox> mandatoryBloxesFullyUsed = LevelConfiguration.MandatoryBloxes.Where(mb => usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType && b.Item2 >= mb.MinimumQuantity)).ToList(); check.mandatoryBloxes = mandatoryBloxesFullyUsed.Count == LevelConfiguration.MandatoryBloxes.Count(); List <ExpectedBlox> expectedOptionalBloxesUsed = LevelConfiguration.OptionalExpectedBloxes.Where(mb => usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType)).ToList(); int numberOfOptionalBloxesUsed = usedBloxTypeCount // Gets all the used bloxes that are of the type of one expected to be used .Where(b => LevelConfiguration.OptionalExpectedBloxes.Exists(mb => mb.BloxType == b.Item1)) // Gets the amount used. If the amount used is bigger than the minimum expected, uses the later value // If it is expected to use 2 bloxes of Int, and 1 of If, we don't want to classify a full use of option bloxes // if the user put 3 Int bloxes .Select(b => Math.Min(b.Item2, LevelConfiguration.OptionalExpectedBloxes.First(o => o.BloxType == b.Item1).MinimumQuantity)).Sum(); check.optionalBloxesUsedPercentage = LevelConfiguration.OptionalExpectedBloxes.Count == 0 ? 1 : numberOfOptionalBloxesUsed * 1f / LevelConfiguration.OptionalExpectedBloxes.Select(o => o.MinimumQuantity).Sum(); check.maxAttemptsExpected = Convert.ToInt32(LevelConfiguration.MaxAttempts); check.maxLinesExpected = Convert.ToInt32(LevelConfiguration.MaxCodeLinesExpected); check.maxMinutesExpected = Convert.ToInt32(LevelConfiguration.MaxTimeInMinutes); check.maxOptionalBloxesExpected = Convert.ToInt32(LevelConfiguration.OptionalExpectedBloxes.Select(o => o.MinimumQuantity).Sum()); check.numberOfOptionalBloxesUsed = numberOfOptionalBloxesUsed; return(new Evaluation(check)); }