Logic Grid using Backtracking
My daughter had an assignment to solve a logic grid - recycling days. The puzzle is in the image below.
She needs to finish it the old-fashioned-raw-logic way (which she is doing), but I decided to take a brute-force approach. This is a typical backtracking problem. The approach should be as follows:
1/ Figure out how to model the problem. I decided to model yet using an array of "days" where each day will have a truck, a material and a time
2/ Start by creating the validation function. This is the boring and detailed part that you can't mess up. Just a matter of reading the problem definition and implementing each one of the rules
3/ Then comes the backtracking. DFS using hash tables to keep track of which elements have already been used
Let it run for ~1sec. It outputs the result. I have not shared the results with my daughter... Result and code are below, cheers, ACC.
using System; using System.Collections; namespace RecyclingDays { public class Days { public string truckColor = ""; public string material = ""; public int time = 0; public Days(string truckColor, string material, int time) { this.truckColor = truckColor; this.material = material; this.time = time; } } class Program { static void Main(string[] args) { Days[] days = new Days[4]; for (int i = 0; i < days.Length; i++) days[i] = new Days("", "", 0); int combinationNumber = 0; if (!TryAllCombinations(0, days, new Hashtable(), new Hashtable(), new Hashtable(), ref combinationNumber)) { Console.WriteLine("Impossible!!!"); } } static void PrintDays(Days[] days, int combinationNumber) { string[] weekDays = { "Tue", "Wed", "Thur", "Fri" }; Console.Write("Combination #{0} (Day, Color, Material, Time): ", combinationNumber); for (int i = 0; i < days.Length; i++) { Console.Write("({0},{1},{2},{3}) ", weekDays[i], days[i].truckColor, days[i].material, days[i].time); } Console.WriteLine(); } static bool TryAllCombinations(int dayIndex, Days[] days, Hashtable usedTruckColor, Hashtable usedMaterial, Hashtable usedTime, ref int combinationNumber) { if (dayIndex >= days.Length) { combinationNumber++; int result = Valid(days); if (result == 0) { Console.WriteLine("Found it!"); PrintDays(days, combinationNumber); return true; } else { Console.WriteLine("Combination violates rule #{0}", result); PrintDays(days, combinationNumber); return false; } } string[] truckColors = { "b", "g", "o", "y" }; string[] material = { "a", "b", "g", "p" }; foreach (string c in truckColors) { if (!usedTruckColor.ContainsKey(c)) { usedTruckColor.Add(c, true); foreach (string m in material) { if (!usedMaterial.ContainsKey(m)) { usedMaterial.Add(m, true); for (int t = 5; t <= 8; t++) { if (!usedTime.ContainsKey(t)) { usedTime.Add(t, true); days[dayIndex].truckColor = c; days[dayIndex].material = m; days[dayIndex].time = t; if (TryAllCombinations(dayIndex + 1, days, usedTruckColor, usedMaterial, usedTime, ref combinationNumber)) { return true; } usedTime.Remove(t); } } usedMaterial.Remove(m); } } usedTruckColor.Remove(c); } } return false; } static int Valid(Days[] days) { for (int i = 0; i < days.Length; i++) { //#1: truck arriving at 5 must be orange if (days[i].time == 5 && days[i].truckColor != "o") return 1; //#2 the glass' truck arrives the day after the aluminum's truck if (days[i].material == "g" && (i == 0 || days[i - 1].material != "a")) return 2; //#3: the glass truck arrives either on Thursday or at 7 if (days[i].material == "p" && i != 2 && days[i].time != 7) return 3; //#4: the blue truck arries one hour after the yellow one if (days[i].truckColor == "b") { bool yellowCondition = false; for (int j = 0; j < days.Length; j++) { if (i != j) { if (days[j].truckColor == "y" && days[j].time == days[i].time - 1) { yellowCondition = true; break; } } } if (!yellowCondition) return 4; } //#5: the aluminum is collected at 6 or 7 if (days[i].material == "a" && days[i].time != 6 && days[i].time != 7) return 5; //#6.1: friday's truck arrives at 7 or 8 if (i == 3 && days[i].time != 7 && days[i].time != 8) return 61; //#6.2: paper is not collected at 8 if (days[i].material == "p" && days[i].time == 8) return 62; //#7: batteries are collected the day before the green truck arrives if (days[i].material == "b" && (i + 1 >= days.Length || days[i + 1].truckColor != "g")) return 7; //#8.1: thursday's truck does not arrive at 8 if (i == 2 && days[i].time == 8) return 81; //#8.2: tuesday's truck isn't blue if (i == 0 && days[i].truckColor == "b") return 82; //#9: wednesday's truck is for aluminum or is orange if (i == 1 && days[i].material != "a" && days[i].truckColor != "o") return 9; } return 0; } } }
Comments
Post a Comment