public override bool ValidateInput(LabConfigurationExerciseEntry exercise, object input) { if (!(exercise is LabConfigurationMultipleChoiceExerciseEntry multipleChoiceExercise)) { throw new ArgumentException("Invalid exercise type", nameof(exercise)); } if (!(input is IEnumerable <int> selectedOptions)) { throw new ArgumentException("Invalid input type", nameof(input)); } var selectedIds = selectedOptions .OrderBy(id => id) .ToArray(); // Extract correct options var correctIds = multipleChoiceExercise.Options .Select((option, index) => (option, index)) .Where(opt => opt !.option.Correct) // IDE says this may be null, which is wrong .Select(opt => opt.index) .OrderBy(id => id) .ToArray(); // Compare if (multipleChoiceExercise.RequireAll) { return(selectedIds.SequenceEqual(correctIds)); } return(selectedIds.Any() && selectedIds.All(id => correctIds.Contains(id))); }
public override bool Update(LabConfigurationExerciseEntry exercise) { if (!(exercise is LabConfigurationStringExerciseEntry stringExercise)) { throw new ArgumentException("Invalid exercise type", nameof(exercise)); } // Is the expected solution still valid? if (stringExercise.AllowAnySolution) { // We allow any solution, so no need to store a name if (SolutionName != null) { // Drop previous solution name SolutionName = null; return(true); } } else { // Check whether the exercise requires a specific, existing solution if (SolutionName == null || stringExercise.ValidSolutions.All(s => s.Name != SolutionName)) { // Pick a random solution var random = stringExercise.ValidSolutions[RandomNumberGenerator.GetInt32(stringExercise.ValidSolutions.Length)]; SolutionName = random.Name; return(true); } } return(false); }
public override string FormatDescriptionString(LabConfigurationExerciseEntry exercise) { if (exercise.DescriptionFormat == null) { return(""); } return(string.Format(exercise.DescriptionFormat, SolutionName)); }
public override bool Update(LabConfigurationExerciseEntry exercise) { if (!(exercise is LabConfigurationScriptExerciseEntry)) { throw new ArgumentException("Invalid exercise type", nameof(exercise)); } // No changes required return(false); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jsonObject = JObject.Load(reader); var exerciseType = jsonObject[nameof(LabConfigurationExerciseEntry.Type)]?.ToObject <LabConfigurationExerciseEntryType>(); LabConfigurationExerciseEntry exercise = exerciseType switch { LabConfigurationExerciseEntryType.String => new LabConfigurationStringExerciseEntry(), LabConfigurationExerciseEntryType.MultipleChoice => new LabConfigurationMultipleChoiceExerciseEntry(), LabConfigurationExerciseEntryType.Script => new LabConfigurationScriptExerciseEntry(), _ => throw new JsonSerializationException("Unknown exercise type") }; serializer.Populate(jsonObject.CreateReader(), exercise); return(exercise); }
public override bool ValidateInput(LabConfigurationExerciseEntry exercise, object input) { if (!(exercise is LabConfigurationStringExerciseEntry stringExercise)) { throw new ArgumentException("Invalid exercise type", nameof(exercise)); } if (!(input is string inputStr)) { throw new ArgumentException("Invalid input type", nameof(input)); } if (stringExercise.UseRegex) { // Match any solution if (stringExercise.AllowAnySolution) { return(stringExercise.ValidSolutions.Any(s => Regex.IsMatch(inputStr, s.Value))); } // Match specific solution var pattern = stringExercise.ValidSolutions.FirstOrDefault(s => s.Name == SolutionName)?.Value; if (pattern == null) { return(false); } return(Regex.IsMatch(inputStr, pattern)); } // Compare against any solution if (stringExercise.AllowAnySolution) { return(stringExercise.ValidSolutions.Any(s => s.Value == inputStr)); } // Compare against specific solutions return(stringExercise.ValidSolutions.FirstOrDefault(s => s.Name == SolutionName)?.Value == inputStr); }
/// <summary> /// Returns a description string for the given exercise, with placeholders replaced by values from this state. /// </summary> /// <param name="exercise">Exercise data.</param> /// <returns></returns> public abstract string FormatDescriptionString(LabConfigurationExerciseEntry exercise);
/// <summary> /// Returns whether the given input is a valid solution. /// </summary> /// <param name="exercise">Exercise data.</param> /// <param name="input">Input.</param> /// <returns></returns> public abstract bool ValidateInput(LabConfigurationExerciseEntry exercise, object input);
/// <summary> /// Checks whether the internal state is still consistent with the given exercise data, and updates it if necessary. /// The return value indicates whether the state has been updated. /// </summary> /// <param name="exercise">Exercise data.</param> public abstract bool Update(LabConfigurationExerciseEntry exercise);
public override string FormatDescriptionString(LabConfigurationExerciseEntry exercise) { return(exercise.DescriptionFormat ?? ""); }
public override bool Update(LabConfigurationExerciseEntry exercise) { return(true); }
public override bool ValidateInput(LabConfigurationExerciseEntry exercise, object input) { // Input validation is left to state service throw new NotSupportedException("Script exercises must be checked using the Docker service."); }