/* * departure location: 43-237 or 251-961 * departure station: 27-579 or 586-953 * departure platform: 31-587 or 608-967 * departure track: 26-773 or 784-973 * departure date: 41-532 or 552-956 * departure time: 33-322 or 333-972 * arrival location: 30-165 or 178-965 * arrival station: 31-565 or 571-968 * arrival platform: 36-453 or 473-963 * arrival track: 35-912 or 924-951 * class: 39-376 or 396-968 * duration: 31-686 or 697-974 * price: 28-78 or 96-971 * route: 32-929 or 943-955 * row: 40-885 or 896-968 * seat: 26-744 or 765-967 * train: 46-721 or 741-969 * type: 30-626 or 641-965 * wagon: 48-488 or 513-971 * zone: 34-354 or 361-973 * * your ticket: * 151,71,67,113,127,163,131,59,137,103,73,139,107,101,97,149,157,53,109,61 * * nearby tickets: * 680,418,202,55,792,800,896,801,312,252,721,702,24,112,608,837,98,222,797,364 */ internal static TicketInformation Parse(string filename) { var lines = File.ReadAllLines(filename); int inputMode = 0; var result = new TicketInformation(); for (int lineIndex = 0; lineIndex < lines.Length; lineIndex++) { var line = lines[lineIndex]; if (line == string.Empty) { inputMode++; continue; } if (line == "your ticket:" || line == "nearby tickets:") { continue; } switch (inputMode) { case 0: { var parts = line.Split(": "); var ranges = parts[1].Split(" or "); var rangeA = ranges[0].Split("-").Select(n => int.Parse(n)).ToArray(); var rangeB = ranges[1].Split("-").Select(n => int.Parse(n)).ToArray(); result.Details.Add(parts[0], new TicketRange[] { new TicketRange(rangeA[0], rangeA[1]), new TicketRange(rangeB[0], rangeB[1]) }); } break; case 1: { var numbers = line.Split(','); result.MyTicket = numbers.Select(n => int.Parse(n)).ToArray(); } break; case 2: { var numbers = line.Split(','); result.NearbyTickets.Add(numbers.Select(n => int.Parse(n)).ToArray()); } break; } } return(result); }
public static string Run(TicketInformation ticketInformation) { var invalidNumbers = new List <int>(); var validTickets = new List <int[]>(); var suspectedKeys = new Dictionary <int, List <string> >(); for (int n = 0; n < ticketInformation.MyTicket.Length; n++) { suspectedKeys.Add(n, ticketInformation.Details.Keys.ToList()); } foreach (var nearbyTicket in ticketInformation.NearbyTickets) { bool validTicket = true; for (var index = 0; index < nearbyTicket.Length; index++) { var value = nearbyTicket[index]; bool validForAtleastOneField = false; foreach (var detail in ticketInformation.Details) { var ranges = detail.Value; if ((ranges[0].From <= value && ranges[0].To >= value) || (ranges[1].From <= value && ranges[1].To >= value)) { validForAtleastOneField = true; } } if (!validForAtleastOneField) { invalidNumbers.Add(value); validTicket = false; } } if (validTicket) { validTickets.Add(nearbyTicket); } } foreach (var ticket in validTickets) { for (int index = 0; index < ticket.Length; index++) { var value = ticket[index]; foreach (var detail in ticketInformation.Details) { var ranges = detail.Value; var notInRange = (ranges[0].From > value || ranges[0].To < value) && (ranges[1].From > value || ranges[1].To < value); if (notInRange && suspectedKeys[index].Contains(detail.Key)) { suspectedKeys[index].Remove(detail.Key); } } } } var listOfKeys = new HashSet <string>(ticketInformation.Details.Keys); while (listOfKeys.Count > 0) { var lonelyKey = suspectedKeys.Where(k => k.Value.Count == 1 && listOfKeys.Contains(k.Value[0])).First().Value.Single(); foreach (var keyValuePair in suspectedKeys) { if (keyValuePair.Value.Count > 1 && keyValuePair.Value.Contains(lonelyKey)) { suspectedKeys[keyValuePair.Key].Remove(lonelyKey); } } listOfKeys.Remove(lonelyKey); } // Unnecessary rewrite to "detail => value" form, but I wanted it in that form as a design choice. var detailInformation = new Dictionary <string, int>(); foreach (var suspectedKey in suspectedKeys) { detailInformation.Add(suspectedKey.Value[0], suspectedKey.Key); } long total = 1; foreach (var detail in detailInformation.Where(k => k.Key.StartsWith("departure"))) { total *= ticketInformation.MyTicket[detail.Value]; } return(total.ToString()); }