public void PourFrom_LargeToSmallOverflow_VolumeIsCorrect() { var bottleA = new Bottle {Capacity = 5, Volume = 5}; var bottleB = new Bottle {Capacity = 3}; bottleA.PourInto(bottleB); Assert.That(bottleA.Volume, Is.EqualTo(2)); Assert.That(bottleB.Volume, Is.EqualTo(3)); }
public void PourFrom_SmallToLargeOverflow_VolumeIsCorrect() { var bottleA = new Bottle {Capacity = 5, Volume = 3}; var bottleB = new Bottle {Capacity = 3, Volume = 3}; bottleB.PourInto(bottleA); Assert.That(bottleA.Volume, Is.EqualTo(5)); Assert.That(bottleB.Volume, Is.EqualTo(1)); }
public void PourInto(Bottle b) { var free = b.Capacity - b.Volume; if (free >= Volume) { b.Volume += Volume; Volume = 0; return; } b.Volume = b.Capacity; Volume -= free; }
public static List<string> Solve(int capacityBottleA, int capacityBottleB, int desiredVolume) { var bottleA = new Bottle {Capacity = capacityBottleA}; var bottleB = new Bottle {Capacity = capacityBottleB}; var solution = string.Empty; for (var i = 1; i < 8; i++) { var s = Solve(solution, 0, i, bottleA, bottleB, desiredVolume); if (s.Any()) return s; } return new List<string>(); }
static void Main(string[] args) { while (true) { Console.WriteLine("Set first bottles capacity:"); var cap1 = Console.ReadLine(); var bottle1 = new Bottle(Convert.ToInt32(cap1)); Console.WriteLine(); Console.WriteLine("Set second bottles capacity:"); var cap2 = Console.ReadLine(); var bottle2 = new Bottle(Convert.ToInt32(cap2)); Console.WriteLine(); Console.WriteLine("Set target value:"); var targ = Console.ReadLine(); var target = Convert.ToInt32(targ); if (target > bottle1.Capacity && target > bottle2.Capacity || target <= 0) { throw new ArgumentException("Unreachable target value"); } var path = new List <Tuple <string, int, int> >(); path.Add(new Tuple <string, int, int>("Start. " + bottle1.Name + ": " + bottle1.Ammount + "/" + bottle1.Capacity + ". " + bottle2.Name + ": " + bottle2.Ammount + "/" + bottle2.Capacity + ". ", 0, 0)); path = FindPath(bottle1, bottle2, target, path); Console.WriteLine(); foreach (var step in path) { Console.WriteLine(step.Item1); } Console.ReadLine(); } }
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), "); } }
public Bottle(Bottle b) { Capacity = b.Capacity; Volume = b.Volume; }
private static List<string> Solve(string path, int depth, int limit, Bottle bottleA, Bottle bottleB, int desiredVolume) { if (bottleA.Volume == desiredVolume) return new List<string> {path + "A ;"}; if (bottleB.Volume == desiredVolume) return new List<string> {path + "B ;"}; if (depth > limit) return new List<string> { path + ";" }; var actions = new Dictionary<string, Action<Bottle, Bottle>> { {"A -> B, ", (a, b) => a.PourInto(b)}, {"B -> A, ", (a, b) => b.PourInto(a)}, {"E(A), ", (a, b) => a.Empty()}, {"E(B), ", (a, b) => b.Empty()}, {"F(A), ", (a, b) => a.Fill()}, {"F(B), ", (a, b) => b.Fill()}, }; PruneActions(bottleA, bottleB, actions); return actions.Select(action => { var newBottleA = new Bottle(bottleA); var newBottleB = new Bottle(bottleB); action.Value(newBottleA, newBottleB); var s = Solve(path + action.Key, depth+1, limit, newBottleA, newBottleB, desiredVolume); return s; }).Aggregate(new List<string>(), (x, y) => x.Concat(y).ToList()).Where(s => s.EndsWith("A ;") || s.EndsWith("B ;")).ToList(); }