## 多个水壶的情况

`````` 1: using System;
2: using System.IO;
3: using Skyiv.Extensions;
4:
5: namespace Skyiv.Ben.Pond
6: {
7:   sealed class Water
8:   {
9:     TextWriter writer; // 往哪写？
10:     int limit;         // 解决方案的步数限制
11:     int target;        // 要达到的目标
12:     Kettle[] kettles;  // 水壶们: 最少两个
13:
14:     public Water(TextWriter writer, int limit, int target, params int[] capacitys)
15:     { // 构造函数
16:       this.writer = writer;
17:       this.limit = limit;
18:       this.target = target;
19:       kettles = new Kettle[capacitys.Length];
20:       for (var i = 0; i < capacitys.Length; i++)
21:         kettles[i] = new Kettle(((char)('A' + i)).ToString(), capacitys[i]);
22:     }
23:
24:     public void Solve()
25:     { // 寻找解决步骤
26:       writer.Write("步数限制:{0} 目标:{1} 水壶们:", limit, target);
27:       foreach (var kettle in kettles)  writer.Write(kettle);
28:       writer.WriteLine(); // 以上三行输出题目的条件
29:       for (int i = 0, k = 1; ; k = -k)
30:       { // 主循环，算法2
31:         if (k > 0) Solve(++i, kettles[kettles.Length - 1].FullUp);
32:         else Solve(++i, kettles[0].Clean);
33:         for (var j = kettles.Length - 1; j > 0; j--)
34:           Solve(++i, kettles[j].Move, kettles[j - 1]);
35:       }
36:     }
37:
38:     void Solve(int step, Func<string> func)
39:     { // 适用于无参数动作：倒空水壶、装满水壶
40:       Solve(step, func());
41:     }
42:
43:     void Solve(int step, Func<Kettle, string> func, Kettle other)
44:     { // 适用于一个参数的动作：将水倒入另一只壶中
45:       Solve(step, func(other));
46:     }
47:
48:     void Solve(int step, string func)
49:     { // 解决步骤的一步
51:       foreach (var kettle in kettles) writer.Write(kettle);
52:       writer.WriteLine();
53:       var isFinished = IsFinished();
54:       if (step < limit && !isFinished) return;
55:       if (isFinished) writer.WriteLine("---- 大功告成 ---------------");
56:       else if (step >= limit) writer.WriteLine("**** 出师未捷身先死 ****");
57:       Environment.Exit(0);
58:     }
59:
60:     bool IsFinished()
61:     { // 是否完成任务?
62:       foreach (var kettle in kettles)
63:         if (kettle.Current == target) return true;
64:       return false;
65:     }
66:   }
67: }
``````

• 装满最后一个水壶。
• 将水从最后一个水壶依次倒入前一个水壶，直至第一个水壶。
• 倒空第一个水壶。
• 将水从最后一个水壶依次倒入前一个水壶，直至第一个水壶。

## 编译和运行

``````Water\$ make && mono ConsoleRunner.exe 3 5 6
dmcs -out:ConsoleRunner.exe ConsoleRunner.cs Water.cs Kettle.cs StringExtensions.cs

1: [装满:B]      [A:0/5][B:6/6]
2: [从B倒入A:5]  [A:5/5][B:1/6]
3: [倒空:A]      [A:0/5][B:1/6]
4: [从B倒入A:1]  [A:1/5][B:0/6]
5: [装满:B]      [A:1/5][B:6/6]
6: [从B倒入A:4]  [A:5/5][B:2/6]
7: [倒空:A]      [A:0/5][B:2/6]
8: [从B倒入A:2]  [A:2/5][B:0/6]
9: [装满:B]      [A:2/5][B:6/6]
10: [从B倒入A:3]  [A:5/5][B:3/6]
---- 大功告成 ---------------
``````

``````Water\$ mono ConsoleRunner.exe 8 2 5 7 12

1: [装满:D]      [A:0/2][B:0/5][C:0/7][D:12/12]
2: [从D倒入C:7]  [A:0/2][B:0/5][C:7/7][D:5/12]
3: [从C倒入B:5]  [A:0/2][B:5/5][C:2/7][D:5/12]
4: [从B倒入A:2]  [A:2/2][B:3/5][C:2/7][D:5/12]
5: [倒空:A]      [A:0/2][B:3/5][C:2/7][D:5/12]
6: [从D倒入C:5]  [A:0/2][B:3/5][C:7/7][D:0/12]
7: [从C倒入B:2]  [A:0/2][B:5/5][C:5/7][D:0/12]
8: [从B倒入A:2]  [A:2/2][B:3/5][C:5/7][D:0/12]
9: [装满:D]      [A:2/2][B:3/5][C:5/7][D:12/12]
10: [从D倒入C:2]  [A:2/2][B:3/5][C:7/7][D:10/12]
11: [从C倒入B:2]  [A:2/2][B:5/5][C:5/7][D:10/12]
12: [从B倒入A:0]  [A:2/2][B:5/5][C:5/7][D:10/12]
13: [倒空:A]      [A:0/2][B:5/5][C:5/7][D:10/12]
14: [从D倒入C:2]  [A:0/2][B:5/5][C:7/7][D:8/12]
---- 大功告成 ---------------
``````