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