最近在写优雅代码系列的时候,由于程序偏向算法性,代码写得比较PO。于是今天打算用OO来写火柴游戏。谁知道,一旦打开我那OO思想的闸门,就让我意识到什么是厚积薄发,各种设计模式便如一个个性感的美女一样浮现在我脑海中,令我欲罢不能。于是一个个的类便如雪片一般飘散开来。写到兴起,竟抛弃了火柴游戏的实现,写成了一个“多位数运算控制台显示系统”的怪胎。首先来看下这个系统的使用方法:
public static void main(String[] args) { MultiDigit num1 = new MultiDigit(42723); MultiDigit num2 = new MultiDigit(2577); Operation op = OperFactory.getOper('+'); Expression exp = new Expression(num1,num2,op); exp.draw(); }
执行后,运行结果如下:
M M MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM M M MMMM MMMM MMMM MMMM M M M M M M | M M M M --- M M M M M M M M MMMM MMMM M MMMM MMMM -+- MMMM MMMM M M MMMM MMMM MMMM M M M M M M M M M | M M M M --- M M M M M M M M MMMM M MMMM MMMM MMMM MMMM M M M MMMM MMMM MMMM MMMM
且不论这里显示效果不是太好,来说一下这个系统的设计。整个系统大概用到了“单例模式”,“模板模式”,“享元模式”,“工厂模式”,大概20个类,有极佳的可扩展性。不是太难,就不拿出来了。
好了,有了以上这个超强的显示系统。再来分析一下火柴游戏的算法。首先来看一下这张表:
数字 加一 减一 自移动
0 8 6,9
1
2 3
3 9 2
.
.
.
9 8 5,3 6,0
这张是反映火柴可能变化的表,加一表示增加一根火柴,我们将每个数字的变化存到集合dic[],当检验某个表达式时,遍历一下三个数的dic[],如果符合移动规则并且等式成立,则找到了可行解。合理的移动规则有三种:1.没有产生过移动 2.一加一减 3.自移动一次,如何表示和计算这种规则是个难点。我的方法如下,为每个数字附加一个值,见下表:
数字 (0) 加一 (1) 减一 (3) 自移动 (4)
对应三条规则,对于任意三个数字,附加值的计算结果分别为:
0+0+0 = 0
0+1+3 = 4
0+0+4 = 4
可见,sum(3个数) == 0 或4 ,则是符合移动规则的。
于是,一个优雅的方案浮出水面:
import java.util.ArrayList; import java.util.List; import app.matchgame.digit.Expression; import app.matchgame.digit.MultiDigit; import app.matchgame.digit.OperFactory; import app.matchgame.digit.Operation; class Node{ int digit; int flag; public Node(int digit,int flag){ this.digit = digit; this.flag = flag; } } class Digit{ List<Node> dic = new ArrayList<Node>(); int p = 0; public void addNode(Node node){ dic.add(node); } public boolean hasNext(){ return p < dic.size(); } public Node next(){ return dic.get(p++); } public void clear(){ p = 0; } public Digit clone(){ Digit clone = new Digit(); clone.dic = this.dic; clone.p = 0; return clone; } } public class MatchGame { private Digit[] digTable; public void init(){ digTable = new Digit[10]; for (int i = 0; i < digTable.length; i++) { digTable[i] = new Digit(); digTable[i].addNode(new Node(i,0)); } digTable[0].addNode(new Node(8,1)); digTable[0].addNode(new Node(6,4)); digTable[0].addNode(new Node(9,4)); digTable[2].addNode(new Node(3,4)); digTable[3].addNode(new Node(9,1)); digTable[3].addNode(new Node(2,4)); digTable[5].addNode(new Node(6,1)); digTable[5].addNode(new Node(9,1)); digTable[5].addNode(new Node(3,4)); digTable[6].addNode(new Node(8,1)); digTable[6].addNode(new Node(5,3)); digTable[6].addNode(new Node(0,4)); digTable[6].addNode(new Node(9,4)); digTable[7].addNode(new Node(1,3)); digTable[8].addNode(new Node(6,3)); digTable[8].addNode(new Node(9,3)); digTable[9].addNode(new Node(8,1)); digTable[9].addNode(new Node(5,3)); digTable[9].addNode(new Node(3,3)); digTable[9].addNode(new Node(0,4)); digTable[9].addNode(new Node(6,4)); } public void calc(int a,int b,int c, Operation op){ Digit dig1 = digTable[a].clone(); Digit dig2 = digTable[b].clone(); Digit dig3 = digTable[c].clone(); while(dig1.hasNext()){ Node d1 = dig1.next(); dig2.clear(); while(dig2.hasNext()){ Node d2 = dig2.next(); dig3.clear(); while(dig3.hasNext()){ Node d3 = dig3.next(); int tmp = d1.flag + d2.flag + d3.flag; if((tmp == 0 || tmp == 4)&& op.oper(d1.digit,d2.digit) == d3.digit){ MultiDigit num1 = new MultiDigit(d1.digit); MultiDigit num2 = new MultiDigit(d2.digit); Expression exp = new Expression(num1,num2,op); exp.draw(); System.out.println(); } } } } } public static void main(String[] args) { MatchGame demo = new MatchGame(); demo.init(); //此处可根据输入获取相应运算 Operation op = OperFactory.getOper('+'); demo.calc(3, 6, 9,op); } }
运行结果如下:
HHHH HHHH HHHH H | H --- H H HHHH -+- HHHH HHHH H | H H --- H HHHH HHHH HHHH HHHH HHHH HHHH H | H --- H H HHHH -+- HHHH HHHH H | H --- H H HHHH HHHH HHHH