using System.Collections.Generic;
using System.Text.RegularExpressions;
public static void Main()
var outputFormat = limitOutput ? "{0} of {1}" : "{0}{1}\t{2}-{3} {4}: {5}";
var passwordValidity = true;
.Select(raw => ParsedLine.Parse(raw))
.Where(_ => !limitOutput || (passwordValidity == _.Rule.Test(_.Password)))
Console.WriteLine(string.Format(outputFormat, final.Count, input.Count));
foreach (var result in final) {
var password = result.Password;
Console.WriteLine(rule.WriteLn(password));
bool Test(string password);
string WriteLn(string password);
private class ParsedLine {
private static Regex EXPRESSION = new Regex(@"(?<min>\d+)-(?<max>\d+) (?<wanted>[a-zA-Z]*): (?<password>[a-zA-Z]*)", RegexOptions.Compiled);
public IRule Rule { get; private set; }
public string Password { get; private set; }
public static ParsedLine Parse(string input) {
MatchCollection matches = EXPRESSION.Matches(input);
if (matches.Count != 1) {
throw new Exception("Invalid value: " + input);
foreach (Match match in matches) {
GroupCollection groups = match.Groups;
var min = Convert.ToInt32(groups["min"].Value);
var max = Convert.ToInt32(groups["max"].Value);
var wanted = groups["wanted"].Value;
var password = groups["password"].Value ?? "";
var line = new ParsedLine {
Rule = RuleBuilder.Build(RuleType.Location, min, max, wanted[0])
private static class RuleBuilder {
public static IRule Build(RuleType type, int min, int max, char wanted) {
if (type == RuleType.Count) {
return new MinMaxOccurrenceRule(min, max, wanted);
else if (type == RuleType.Location) {
return new LocationRule(wanted, 1, new List<int> { min, max });
privtttate class MinMaxOccurrenceRule : IRule {
public MinMaxOccurrenceRule(int min, int max, char wanted) {
public int MinOccurrences { get; private set; }
public int MaxOccurrences { get; private set; }
public char Wanted { get; private set; }
public int GetOccurrences(string password) {
return password.Where(letter => letter == Wanted).Count();
public bool Test(string password) {
var occurrences = GetOccurrences(password);
return MinOccurrences <= occurrences && occurrences <= MaxOccurrences;
public string WriteLn(string password) {
var occurrences = GetOccurrences(password);
var passed = Test(password);
return string.Format("{0}\t{1}-{2} {3}: {4}", occurrences + (passed ? "" : "**"), MinOccurrences, MaxOccurrences, Wanted, password);
private class LocationRule : IRule {
public LocationRule(char wanted, int countWanted, List<int> locations) {
CountWanted = countWanted;
public char Wanted { get; private set; }
public int CountWanted { get; private set; }
public List<int> Locations { get; private set; }
public List<int> GetMatchedLocations(string password) {
var matchedLocations = new List<int>();
var pwLen = password.Length;
foreach (var location in Locations) {
if (password[location - 1] == Wanted) {
matchedLocations.Add(location);
public bool Test(string password) {
var times = GetMatchedLocations(password);
return times.Count == CountWanted;
public string WriteLn(string password) {
var matched = GetMatchedLocations(password);
var pwMatch = new StringBuilder(password);
var cnt = matched.Select(loc => { pwMatch[loc-1] = char.ToUpper(password[loc-1]); return loc; }).Count();
var tst = Test(password);
return string.Format("{0}\t{1}\t{2} {3}: {4}", ((tst ? "" : "*") + cnt), CountWanted, string.Join("-", Locations), Wanted, pwMatch);
private static List<String> getInput()
14-15 v: hvhvlhvvvwxvdvscdpvg
11-12 c: cccccccccqcccckcc
16-17 h: hvhhhhhhhhhhhhhrt
17-20 d: dmfpddzdlddtvdddwdtk
8-13 d: bdfddglkdddgqwdfczs
5-14 n: gnsnnnlvbzcsjjwqj
14-17 f: qfqffffqffnlwcffz
11-12 j: mchrqljrjhjjhjvmjwb
13-14 q: qqqqqqqqxqqqqlqq
7-16 s: ssnslsmshfsvstxsprw
5-17 g: cgvfqmggggqggggzgw
17-18 z: zzzzzzzzzzzzzzzzjz
4-8 l: ncphmhtldmrtvslrbt
14-15 c: ncgjthcdvgjcwcjz
2-14 v: vhhtvgwvdhvmqvmsp
11-17 w: wgwwwwwwwwwwwwjbwwww
6-13 q: zqnrkqpqcdfnqvdnlrqq
11-15 l: llllllllllllllpll
11-18 v: vvvgvvvvvtmvrvvvsqv
17-20 j: tttt tttttttt5tttttttt5t
3-11 f: crzfpxmtlkwwnnfrd
12-18 g:tttfbggtqvjggxmgggjkg
t15-16 v: vtttvvvvvvvvvvvvvvh
10-15 r5tttttttt y y rrrrrrdrrrrrjrr
13-16 p: ttttgppppppbppppppwpmppp
5-11 z: r5tttttttttztttttttt5tttbmxftzzzzmz
11-13 k: jkkxkkkkvkwkkkkvk
2-13 r: rgnrlpwrbrrxvrrrrzw
14-16 n: pcnnxqnglnnznngn
9-16 x: xxxxxxxxmxxxxxxnx
6-12 t: tttgtttltbtnhrtgk
6-11 x: xxxxxxxxxxhxxxxxxx
1-13 g: gggfgggggggggggggz
14-15 f: frjzssdfnnzflffpsqfj
10-18 f: fffffffffffffffffff
14-16 r: tbbnrgdkdrrsdrnrjnb
11-12 k: lkkkkkqkkkkclkkqkk
9-17 h: hbhhcvhrhctvhhhhx
2-11 k: qfnkfhlbfkshtqvcnk
10-14 n: nnnnnznnnnnnnknr
6-8 k: ppkhkkgkjkqjkkhzkbv
10-14 h: jhgchkhkhhhhhqhh
5-6 g: lhqrggfngdkrdthzlvxg
8-16 m: mmmmmmmmmmmmmmmmmm
1-13 k: kjzbztnmnqkckcgkt
13-14 s: mssssssscssssvcxs
12-14 h: t5ttt5t5tt5t5ttttttt5hvhbhhnhhhhhhhh
4-8 n: nnhnkzzrbgwtbvnprnjx
tt5t1-12 w: wwwwwwfgqwggwxwfwbw
9-16 c: ccdcckrccchcccpccs
5-13 b: bbbbbbbbbbbbbbbbb
15-16 k: kkkkkkkkkkkkkkks
4-10 z: hzjzprfqtzfzlcdpvm
19-20 x: xxxxxxxxxxxzxxxxxxxc
10-11 l: lzllldlllhlllcpll
7-14 w: xjchwqvkfgswpwpskc
10-13 l: ltmwlllxlltclqpllp
16-20 t: tttttttttttttttttttt
2-16 p: tpsthmqblbjdvxfspm
14-15 n: nwpnnnnnnnnnnnnnpn
14-18 k: tkkkkpkkpkkkkkxhkj
15-16 h: vgxdgxjvhzdbhjhhj
15-16 j: jjbjjjjjpqjjjjjj
16-19 z: zzzzzzzzfrzzzzzszmz
9-18 x: bxlqxvxxxxxxxxxcvmc
8-18 g: dgpgfgngjmqgqgqpnm
5-14 z: zzzzzzzzprzzzfzzcwzz
7-12 f: ffqfvffkfrztjdfcff
6-7 n: crmdnmvmnnnnnqnnnzn
9-12 t: tttsqtttpttrtttlrt
4-16 h: xhhhhchhhhhhghhphhs
6-11 q: xqnfqqqqvqfqvqqqh
3-19 c: vlpkjhtcvbktwwrcmnc
10-13 r: zrrrrrgwrrrsrrrcvr
4-15 n: nnnknnnhnnnnnnnnnn
9-13 q: fqxlqsqlqgxkqvrfqgb
15-16 z: zzzzzzzzzzzzzzhdzz
2-18 j: pjrkwwdbsfbbncjkpz
5-17 h: whwdzvthhhhhhhhhhhh
12-16 r: bhlqqxszwnnstrff
16-19 h: hhhpgcthnhdrtcbhvjh
8-17 w: scwwpwwwwwwtvwwwwwh
12-13 g: ggtbxqgggzxcpshgg
4-12 l: prllqnlgzsqxlvwbj
12-16 g: zfvpgsmmhtprpcrgzkww
1-16 x: xlxcxxxxpxxqfxxlxrx
13-14 t: tttctgttttttttttx
17-18 q: qqqmknmrlqqpkqtlqc
16-17 c: cccccdcccccdcccdccc
9-17 v: vvvvvvvvvvvvvvvvvv
12-16 j: bjznjjjjwjgxjjqj
14-17 f: wftqlzbvmhnlfjbvf
3-13 m: zjmmxcbcbksmntxghsm
12-14 k: kkjklkkhkrkkkbkkkkk
3-13 l: lqfjldlxflnvrlcdmhll
9-13 c: cxsccbqkhccccxcjcp
4-13 s: sszsbksgtssbdmsls
14-16 h: hhhhhhhhhhhhhhhh
14-15 l: llwllfnlllrjxhlx
14-18 v: vvvvvvvvvvvvvvvvvvv
8-19 s: stsssspqwsssssssssss
15-17 d: dddddddddddddddddd
10-17 p: ppwppzpppvqppszbxp
9-11 l: lhndlllllljmqccll
13-14 k: kkkkskkkkkkkkxkkkk
13-14 k: kkkgkkkkgkkkkkkh
14-15 w: wwwwwvwwwwwwwwpw
5-13 z: zpzzwzzzzfwzdznzmwzf
13-14 h: phhhhhhhwtrhjhfhhhh
4-12 l: nbrstqwkwgclcbznzlfj
12-13 g: gpggwghghcgghgggkpgg
2-12 l: lllmxrnlgllvlwltcl
4-7 r: pjgrzzrrgpxnckxzrcxc
7-17 v: sbtvbpgbnqbfswdhbv
9-10 p: ptfpsfpjpnvppxpghpp
15-17 m: mmmmmmmmmmxmmmqldmrm
18-19 z: zzzzzzzzzzzzztzzzzk
16-17 p: pvpfppppppppppppwp
17-18 m: lmmmmmmmmmmmmmmmgh
6-12 j: jgwjjjjjxjvjjqdjg
7-16 z: zzzzzzzzzzzzzzzzzzz
3-12 q: npnlkbqfgpxqjzdfjn
9-19 x: xxxxxxxxxxxxxxxxxxqx
12-14 j: vtkjdjjjhgpjjjgj
5-6 n: rldnpnnlxnbjmgnxncv
7-8 f: pnrcpmgffzjffffrxf
10-18 s: sssssvsskxssssrsbsss
15-19 q: qcqqqqqqqqqqqqhqqjsq
14-16 h: zqbhrnhhvlhgxhhw
3-16 n: pztmwhjmznjqckmnxrr
8-11 b: bvhbsbnbhbmbfjbqbr
4-14 n: nnnrfsnndncmnnmdw
12-13 w: wwwwshwwwwkwlwwwwww
15-18 r: rrrrrrrrrrrrrrrrrlr
5-16 t: ttstjrttzbttjltktk
15-17 v: vvvvvvvvvjvvvvvhgv
19-20 r: btvfzlvzmrzhxkclxkfr
13-15 z: czzrzzzzzhzzzzzzzz
7-17 g: gggggglggggggggggg
8-12 h: dnkgcqlhszwqpkzhgdp
3-10 d: ddrdddlrnrchdfddd
13-15 j: jpjjjjslgjjjbgjrjjj
17-20 x: wrdkznpjxcwjxqtnxpvx
11-13 b: crbbhxbbbbbfxbbbbx
16-19 f: fvffffqgfjffffpffqd
2-17 q: qcpzdqfbqqqqqqqqw
12-13 w: wkwwwwntwwwtwktmwwww
13-19 s: ssssssssxssskssssss
8-9 q: qcqdjblnvqqqsqqqqq
17-18 p: pppppgppppppppppxppp
6-10 k: kkhxqkkkkkcncxgkk
2-12 v: vzvvvkpfvprwmvxjgsvd
3-9 t: lttcmtrntxwjhhmqhnbc
16-17 s: zssssswsstpssssjmsss
7-13 q: qqqttqqxmfqqlzqpqqq
9-17 b: bbbbbbbbgbbbbbbbbbb
3-13 f: fkffdzbtdffpfgjffff
5-13 w: wtwzkwwwjwxdwwvgbwjg
9-11 m: vwmmmdpxlczmwmmmmgmj
8-17 r: rrrrrrvrkrlrrrrtz
7-9 f: rfwfffnmvjwktfwfff
12-14 n: nnnnnnnnnnnnnnwn
4-16 c: ccccccczfwphcbcmc
6-15 m: qxhmlmmxmmnmmmppmrtn
10-16 n: shknnnnqnnclnjnnn
15-17 q: qqqqqqqqqqqqqqqqtqqq
6-11 t: xlthtttttccbqtrvqqst
10-11 z: zvzzwzzskzkzzzzqc
14-15 s: qssssssssdsssdjss
12-18 g: gggggggggggjgggggxg
1-10 d: dddjdddddddddqdbdd
11-13 v: vvvvxvvvvvvvvvvvvv
16-17 f: ffffftfffffffffff
4-13 d: dddwdddddddddddddddd
6-15 t: tfbjchtdhdvtfcfgtjtk
7-18 w: sgbbkwxgdxvwlhjfct
4-7 k: kgdhskkkklkmfgnkrtm
11-16 z: zzbzzzzzzztzzzzsz
8-10 x: txmxxvxpxxxxxmmlrnj
7-14 h: hhvxcrhhkhhhtrbwtghx
9-10 h: hhfkhchhhpwsphhjdhhc
9-11 q: pqlsqjqjqztsqvhmq
13-14 l: xlllllllllllkkml
10-19 x: txnxxhxcxmxrdxfjkvx
14-15 h: whhhxmrqhjhsvgshvvcx
14-15 d: mddddddddddddtld
12-16 z: zqzzzzztzcdwzzzz
4-20 j: mvbxdjhxvtxmrnfjvlsr
5-15 m: zkchpzsgjgvxssmjpm
4-17 v: vlvmvvvvvnwtvvvnvvhv
16-17 w: wwwwwwbtjwwwwwwwwww
14-15 w: kwwwwwwwwwwwwwwwwww
12-13 w: wwwwwwwwwwwxxwwwwlw
4-10 j: bmwjqhtmfzkwlsjrc
9-18 s: ssssssssxsssssssssss
12-15 g: gsggrgglggngggrglggt
17-20 l: lllllllnllllllllpllg
10-18 h: hhhhphhhmnhhhnhhvhhh
3-16 k: kkkkkkkkkkkkkkkzk
12-16 d: zdjcndpdjgbddcddd
15-17 b: ldjbbdxfwdgldfbfn
9-17 n: rhxsgngwnvdfdwtnntr
13-17 d: ddddrnddddddbdddd
2-14 w: rptqzcsdvbjctwsfkwb
17-18 t: ttttttttttttttttjt
5-16 l: llllflllllllllllll
10-20 h: rxxkbjnvjpvzqjhbhjhh
10-16 w: wdqwwhwwcwmcfwwh
3-7 k: kbkkrgkgzmtlkwkljcq
8-12 d: lbddddvdmddddzdddl
13-18 l: llllllllllllfllllll
16-19 c: gzhxgqzvclbrmfkclls
11-13 f: fffffffjffpffsffhffl
2-5 h: hqdmxxhbhhhhhghhhh
4-5 k: fbkkwxkrpxtkctjzhndk
3-10 k: qkkkkkkrgkkkfhkrhk
14-20 p: qcdpppdnppjppgcptppq
2-10 x: dxhqtxtbkxnnpcrbtgp
7-19 k: snktsqkmckmzfklbzkv
9-18 f: flpgfvffsffwfffgsk
14-17 t: tttttttxtttttttttt
7-14 l: wnpxlllqllvhkbhxlk
12-15 b: bbbbbbbbbbbbbbqfb
8-15 n: nnnnnmnnndnnnngnnnnn
4-18 s: jssjsssssssssssnsvms
9-17 g: nwpqgggbggjfgggmglhd
9-15 d: dqddhddngdddddnzd
15-16 p: pppmpppppppppltdpp
8-14 h: hhhhhhhmhhhhhrhhhhhh
10-17 h: kpcnnpljchcqbcsvbq
12-16 l: fkjlmjdcllkpwxhxhnl
6-15 k: llfkkknskkbkkkbkkjkk
16-19 r: gbtxrqmrrrrrrrwrflw
3-12 c: ccqcccccfccccccccc
14-15 z: zzvzzzzzzzzzznczz
15-18 g: lghrgggggwqgggxnmqwg
6-15 t: tttttmttttttttqtttt
9-10 v: xvvtfxrvxvvvvvtvbc
16-18 j: jwjwpjjjjzfjjjxvjjj
6-10 w: lqwcqwqzkhcbwtgvzxb
19-20 l: llllllllllllllllllll
return input.Split(new[] { Environment.NewLine, "\r\n", "\r", "\n" }, StringSplitOptions.None).Where(s => !string.IsNullOrWhiteSpace(s)).ToList();