using System.Collections.Generic;
namespace FrozenMountainTest
private static PatternAnalyzer _patternAnalyzer;
static void Main(string[] args)
_patternAnalyzer = new PatternAnalyzer();
TestCasePatternLengthThree();
TestCase_CaseInsensitive();
TestCase_CaseSensitive();
private static void TestCasePatternLengthThree()
const int patternLength = 3;
const string testPattern = "zf3kabxcde224lkzf3mabxc51+crsdtzf3nab=";
const int abxExpectedCount = 2;
const int zf3ExpectedCount = 3;
var result = _patternAnalyzer.Analyze(testPattern, patternLength);
var abxActualCount = result.First(x => x.Pattern == "abx").Occurrences;
var xf3ActualCount = result.First(x => x.Pattern == "zf3").Occurrences;
Assert(abxActualCount, abxExpectedCount, "abx pattern");
Assert(xf3ActualCount, zf3ExpectedCount, "zf3 pattern");
private static void TestCase_CaseInsensitive()
const string key = "mary";
var patternLength = key.Length;
const string testPattern = "Mary had a little lamb, little lamb, little lamb, Mary had a little lamb, its fleece was white as snow.";
const int maryExpectedCount = 2;
var result = _patternAnalyzer.Analyze(testPattern, patternLength, StringComparison.OrdinalIgnoreCase);
var maryActualCount = result.FirstOrDefault(x => x.Pattern.Equals(key, x.Comparison))?.Occurrences ?? 0;
Assert(maryActualCount, maryExpectedCount, "marry pattern ignore case");
private static void TestCase_CaseSensitive()
const string key = "mary";
const int maryExpectedCount = 0;
var patternLength = key.Length;
const string testPattern = "Mary had a little lamb, little lamb, little lamb, Mary had a little lamb, its fleece was white as snow.";
var result = _patternAnalyzer.Analyze(testPattern, patternLength, StringComparison.CurrentCulture);
var maryActualCount = result.FirstOrDefault(x => x.Pattern.Equals(key, x.Comparison))?.Occurrences ?? 0;
Assert(maryActualCount, maryExpectedCount, "marry pattern case sensitive");
private static void Assert(in int actual, in int expected, string pattern)
throw new AssertionFailedException($"{pattern}: input value '{actual}' does not match expected value '{expected}'.");
Console.WriteLine($"{pattern} assertion passed, both actual and expected values are {expected}");
public class PatternAnalyzer
private static readonly Dictionary<StringComparison, StringComparer> _map = new Dictionary<StringComparison, StringComparer>
{ StringComparison.Ordinal, StringComparer.Ordinal },
{ StringComparison.CurrentCulture, StringComparer.CurrentCulture },
{ StringComparison.InvariantCulture, StringComparer.InvariantCulture },
{ StringComparison.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase },
{ StringComparison.CurrentCultureIgnoreCase, StringComparer.CurrentCultureIgnoreCase },
{ StringComparison.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase }
public IList<PatternResult> Analyze(string input, int patternLength)
=> Analyze(input, patternLength, StringComparison.InvariantCultureIgnoreCase);
public IList<PatternResult> Analyze(string input, int patternLength, StringComparison comparison)
_map.TryGetValue(comparison, out var comparer);
var patterns = new List<string>();
for (var index = 0; index < input.Length - patternLength; index++)
var pattern = input.Substring(index, patternLength);
var patternResults = patterns
.GroupBy(x => x, comparer)
.Select(x => new PatternResult(x.Key, x.Count(), comparison))
public class PatternResult
public PatternResult(string pattern, int occurrences, StringComparison comparison)
Occurrences = occurrences;
public string Pattern { get; }
public int Occurrences { get; }
public StringComparison Comparison { get; }
public class AssertionFailedException : Exception
public AssertionFailedException(string message) : base(message)