public Step Fill(Bottle targetBottle) { if (IsEmpty() || targetBottle.IsFull()) { return(null); } if (!IsBottle && !targetBottle.IsBottle) { return(null); } var sourceAmount = Amount(); var targetUllage = targetBottle.Ullage(); if (sourceAmount <= targetUllage) { targetBottle.AddWater(sourceAmount); Empty(); return(new Step(_index, targetBottle._index, sourceAmount)); } else { targetBottle.AddWater(targetUllage); AddWater(-targetUllage); return(new Step(_index, targetBottle._index, targetUllage)); } }
public static List <Tuple <string, int, int> > FindPath(Bottle bottle1, Bottle bottle2, int target, List <Tuple <string, int, int> > path) { if (bottle1.Ammount == target || bottle2.Ammount == target) { return(path); } var bestPath = new List <Tuple <string, int, int> >(path); var subSteps = Int32.MaxValue; var bottle1StartAmmount = bottle1.Ammount; var bottle2StartAmmount = bottle2.Ammount; //Never fill a bottle if the other is full if (!bottle2.IsFull() && bottle1.Fill()) { //Check if we have a duplicate state. Only proceed if we are in a unique state var ammount1 = bottle1.Ammount; var ammount2 = bottle2.Ammount; if (!path.Exists(x => x.Item2 == ammount1 && x.Item3 == ammount2)) { //Copy path var subPath = new List <Tuple <string, int, int> >(path); subPath.Add(new Tuple <string, int, int>("Fill " + bottle1.Name + ". " + bottle1.Name + ": " + bottle1.Ammount + "/" + bottle1.Capacity + ". " + bottle2.Name + ": " + bottle2.Ammount + "/" + bottle2.Capacity + ". ", bottle1.Ammount, bottle2.Ammount)); //Continue recursive search var p = FindPath(bottle1, bottle2, target, subPath); if (p.Count < subSteps) { subSteps = p.Count; bestPath = p; } } } //Reset bottles for new branch bottle1.Ammount = bottle1StartAmmount; bottle2.Ammount = bottle2StartAmmount; if (!bottle1.IsFull() && bottle2.Fill()) { var ammount1 = bottle1.Ammount; var ammount2 = bottle2.Ammount; if (!path.Exists(x => x.Item2 == ammount1 && x.Item3 == ammount2)) { var subPath = new List <Tuple <string, int, int> >(path); subPath.Add(new Tuple <string, int, int>("Fill " + bottle2.Name + ". " + bottle1.Name + ": " + bottle1.Ammount + "/" + bottle1.Capacity + ". " + bottle2.Name + ": " + bottle2.Ammount + "/" + bottle2.Capacity + ". ", bottle1.Ammount, bottle2.Ammount)); var p = FindPath(bottle1, bottle2, target, subPath); if (p.Count < subSteps) { subSteps = p.Count; bestPath = p; } } } bottle1.Ammount = bottle1StartAmmount; bottle2.Ammount = bottle2StartAmmount; //Never empty a bottle if the other is empty if (bottle2.Ammount != 0 && bottle1.Pour()) { var ammount1 = bottle1.Ammount; var ammount2 = bottle2.Ammount; if (!path.Exists(x => x.Item2 == ammount1 && x.Item3 == ammount2)) { var subPath = new List <Tuple <string, int, int> >(path); subPath.Add(new Tuple <string, int, int>("Pour " + bottle1.Name + ". " + bottle1.Name + ": " + bottle1.Ammount + "/" + bottle1.Capacity + ". " + bottle2.Name + ": " + bottle2.Ammount + "/" + bottle2.Capacity + ". ", bottle1.Ammount, bottle2.Ammount)); var p = FindPath(bottle1, bottle2, target, subPath); if (p.Count < subSteps) { subSteps = p.Count; bestPath = p; } } } bottle1.Ammount = bottle1StartAmmount; bottle2.Ammount = bottle2StartAmmount; if (bottle2.Ammount != 0 && bottle2.Pour()) { var ammount1 = bottle1.Ammount; var ammount2 = bottle2.Ammount; if (!path.Exists(x => x.Item2 == ammount1 && x.Item3 == ammount2)) { var subPath = new List <Tuple <string, int, int> >(path); subPath.Add(new Tuple <string, int, int>("Pour " + bottle2.Name + ". " + bottle1.Name + ": " + bottle1.Ammount + "/" + bottle1.Capacity + ". " + bottle2.Name + ": " + bottle2.Ammount + "/" + bottle2.Capacity + ". ", bottle1.Ammount, bottle2.Ammount)); var p = FindPath(bottle1, bottle2, target, subPath); if (p.Count < subSteps) { subSteps = p.Count; bestPath = p; } } } bottle1.Ammount = bottle1StartAmmount; bottle2.Ammount = bottle2StartAmmount; if (bottle1.Transfer(ref bottle2)) { var ammount1 = bottle1.Ammount; var ammount2 = bottle2.Ammount; if (!path.Exists(x => x.Item2 == ammount1 && x.Item3 == ammount2)) { var subPath = new List <Tuple <string, int, int> >(path); subPath.Add(new Tuple <string, int, int>("Transfer " + bottle1.Name + " into " + bottle2.Name + ". " + bottle1.Name + ": " + bottle1.Ammount + "/" + bottle1.Capacity + ". " + bottle2.Name + ": " + bottle2.Ammount + "/" + bottle2.Capacity + ". ", bottle1.Ammount, bottle2.Ammount)); var p = FindPath(bottle1, bottle2, target, subPath); if (p.Count < subSteps) { subSteps = p.Count; bestPath = p; } } } bottle1.Ammount = bottle1StartAmmount; bottle2.Ammount = bottle2StartAmmount; if (bottle2.Transfer(ref bottle1)) { var ammount1 = bottle1.Ammount; var ammount2 = bottle2.Ammount; if (!path.Exists(x => x.Item2 == ammount1 && x.Item3 == ammount2)) { var subPath = new List <Tuple <string, int, int> >(path); subPath.Add(new Tuple <string, int, int>("Transfer " + bottle2.Name + " into " + bottle1.Name + ". " + bottle1.Name + ": " + bottle1.Ammount + "/" + bottle1.Capacity + ". " + bottle2.Name + ": " + bottle2.Ammount + "/" + bottle2.Capacity + ". ", bottle1.Ammount, bottle2.Ammount)); var p = FindPath(bottle1, bottle2, target, subPath); if (p.Count < subSteps) { subSteps = p.Count; bestPath = p; } } } return(bestPath); }
private static void PruneActions(Bottle bottleA, Bottle bottleB, Dictionary<string, Action<Bottle, Bottle>> actions) { if (bottleA.IsEmpty()) { actions.Remove("A -> B, "); actions.Remove("E(A), "); } if (bottleB.IsEmpty()) { actions.Remove("B -> A, "); actions.Remove("E(B), "); } if (bottleA.IsFull()) { actions.Remove("B -> A, "); actions.Remove("F(A), "); } if (bottleB.IsFull()) { actions.Remove("A -> B, "); actions.Remove("F(B), "); } }