• 算法思路

   把多元运算转化为两元运算,先从四个数中取出两个数进行运算,然后把运算结果和第三个数进行运算,再把结果与第四个数进行运算。

主要步骤:

  1. 将4个整数放入数组中。
  2. 数组中取前两个数进行运算,将运算结果存入数组,并按顺序存在数组中。
  3. 重复(2)
  4. 将最后两个数进行运算,结果存在数组中,并与24进行比较。
  5.      (2)(3)(4)运算过程,主要靠栈来实现,当是+、- 时,可以在栈顶进行所有的操作,当是*、/时,只能进行乘除操作。

    import java.awt.BorderLayout;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;

    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;

    public class TwentyFourPoke_Game extends JFrame {
        private JButton jbsolution = new JButton("提示");
        private JButton jbrefresh = new JButton("刷新");
        private JButton jbverify = new JButton("确认");

        private JLabel jlmessage = new JLabel("输入一个表达式:");

        private JTextField jtsolution = new JTextField();
        private JTextField jtexpression = new JTextField();

        private ImagePanel pp = new ImagePanel();

        private int[] card = new int[4];
        private double[] bcard = new double[4];

        private double sum;
        private double[] temp1 = new double[3];
        private double[] temp2 = new double[2];
        private char[] sign = { '+', '-', '*', '/' };

        public TwentyFourPoke_Game() {
            JPanel p1 = new JPanel(new GridLayout(1, 3));
            p1.add(jbsolution);
            p1.add(jtsolution);
            p1.add(jbrefresh);
            JPanel p3 = new JPanel(new GridLayout(1, 3));
            p3.add(jlmessage);
            p3.add(jtexpression);
            p3.add(jbverify);

            add(p1, BorderLayout.NORTH);
            add(pp, BorderLayout.CENTER);
            add(p3, BorderLayout.SOUTH);

            ButtonListener listener = new ButtonListener();
            jbsolution.addActionListener(listener);
            jbrefresh.addActionListener(listener);
            jbverify.addActionListener(listener);

            ImagePanel imagePanel = new ImagePanel();
        }

        class ButtonListener implements ActionListener {
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == jbsolution) {
                    for (int i = 0; i < 4; i++) {
                        bcard[i] = (double) card[i] % 13;
                        if (card[i] % 13 == 0)
                            bcard[i] = 13;
                    }
                    search();
                } else if (e.getSource() == jbrefresh) {
                    pp.sshow();

                } else if (e.getSource() == jbverify) {
                    String expression = jtexpression.getText();
                    // evaluateExpression()计算多项式的值
                    int result = evaluateExpression(expression);
                    if (result == 24) {
                        JOptionPane.showMessageDialog(null, "恭喜你!你答对了!", "消息框", JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(null, "抱歉!请再次尝试。", "消息框", JOptionPane.INFORMATION_MESSAGE);
                    }
                }
            }
        }

        public static double calcute(double a, double b, char c) {
            if (c == '+')
                return a + b;
            else if (c == '-')
                return a - b;
            else if (c == '*')
                return a * b;
            else if (c == '/' && b != 0)
                return a / b;
            else
                return -1;
        }

        public void search() {
            boolean judge = false;
            for (int i = 0; i < 4; i++)
            // 第一次放置的符号
            {
                for (int j = 0; j < 4; j++)
                // 第二次放置的符号
                {
                    for (int k = 0; k < 4; k++)
                    // 第三次放置的符号
                    {
                        for (int m = 0; m < 3; m++)
                        // 首先计算的两个相邻数字,共有3种情况,相当于括号的作用
                        {
                            if (bcard[m + 1] == 0 && sign[i] == '/')
                                break;
                            // 先确定首先计算的两个数字,计算完成相当于剩下三个数,按顺序储存在temp1数组中
                            temp1[m] = calcute(bcard[m], bcard[m + 1], sign[i]);
                            temp1[(m + 1) % 3] = bcard[(m + 2) % 4];
                            temp1[(m + 2) % 3] = bcard[(m + 3) % 4];

                            // 三个数字选出先计算的两个相邻数字,两种情况,相当于第二个括号
                            for (int n = 0; n < 2; n++) {
                                if (temp1[n + 1] == 0 && sign[j] == '/')
                                    break;
                                temp2[n] = calcute(temp1[n], temp1[n + 1], sign[j]);
                                temp2[(n + 1) % 2] = temp1[(n + 2) % 3];
                                // 先确定首先计算的两个数字,计算完成相当于剩下两个数,按顺序储存在temp数组中
                                if (temp2[1] == 0 && sign[k] == '/')
                                    break;
                                sum = calcute(temp2[0], temp2[1], sign[k]);
                                // 计算和
                                if (sum == 24)
                                // 若和为24
                                {
                                    judge = true;
                                    // 判断符为1,表示已求得解
                                    if (m == 0 && n == 0) {
                                        String sss = "((" + (int) bcard[0] + sign[i] + (int) bcard[1] + ")" + sign[j]
                                                + (int) bcard[2] + ")" + sign[k] + (int) bcard[3] + "=" + (int) sum;
                                        jtsolution.setText(sss);
                                        return;
                                    } else if (m == 0 && n == 1) {
                                        String sss = "(" + (int) bcard[0] + sign[i] + (int) bcard[1] + ")" + sign[k] + "("
                                                + (int) bcard[2] + sign[j] + (int) bcard[3] + ")=" + (int) sum;
                                        jtsolution.setText(sss);
                                        return;
                                    } else if (m == 1 && n == 0) {
                                        String sss = "(" + (int) bcard[0] + sign[j] + "(" + (int) bcard[1] + sign[i]
                                                + (int) bcard[2] + "))" + sign[k] + (int) bcard[3] + "=" + (int) sum;
                                        jtsolution.setText(sss);
                                        return;
                                    } else if (m == 2 && n == 0) {
                                        String sss = "(" + (int) bcard[0] + sign[j] + (int) bcard[1] + ")" + sign[k] + "("
                                                + (int) bcard[2] + sign[i] + (int) bcard[3] + ")=" + (int) sum;
                                        jtsolution.setText(sss);
                                        return;
                                    } else if (m == 2 && n == 0) {
                                        String sss = (int) bcard[0] + sign[k] + "(" + (int) bcard[1] + sign[j] + "("
                                                + (int) bcard[2] + sign[i] + (int) bcard[3] + "))=" + (int) sum;
                                        jtsolution.setText(sss);
                                        return;
                                    }
                                    // m=0,1,2 n=0,1表示六种括号放置可能,并按照这六种可能输出相应的格式的计算式

                                }
                            }
                        }
                    }
                }
            }
            if (judge == false)
                jtsolution.setText("没有解决方案!");
            // 如果没有找到结果,符号位为0
        }

        public static int evaluateExpression(String expression) {
            // 创建操作数栈以存储操作数
            java.util.Stack<Integer> operandStack = new java.util.Stack<Integer>();

            // 创建一个操作数栈去存储操作符
            java.util.Stack<Character> operatorStack = new java.util.Stack<Character>();

            // 提取操作数和运算符
            /*
             * 这个构造函数构造一个字符串标记为指定的字符串。 第一个参数:需要操作的字符串 第二个参数:以什么为标准分割
             * 第三个参数:要不要保存作为分割标准的元素,在分割后结果里仍然保存
             */
            java.util.StringTokenizer tokens = new java.util.StringTokenizer(expression, "()+-/*", true);
            while (tokens.hasMoreTokens()) {
                String token = tokens.nextToken().trim(); // .trim()方法是为了去除字符串前后的空格,因为不能以空格为分割标准然后保存空格
                if (token.length() == 0) // 空格
                    continue; // 回到等待循环以提取下一个令牌
                else if (token.charAt(0) == '+' || token.charAt(0) == '-') { // 是+或—(优先级要比*或/要低)
                    while (!operatorStack.isEmpty()
                            && (operatorStack.peek().equals('+') || operatorStack.peek().equals('-')
                                    || operatorStack.peek().equals('*') || operatorStack.peek().equals('/'))) {
                        processAnOperator(operandStack, operatorStack);
                    }
                    // + -入栈
                    operatorStack.push(new Character(token.charAt(0)));
                } else if (token.charAt(0) == '*' || token.charAt(0) == '/') {
                    // 在栈顶进行所有的*/运算
                    while (!operatorStack.isEmpty()
                            && (operatorStack.peek().equals('*') || operatorStack.peek().equals('/'))) {
                        processAnOperator(operandStack, operatorStack);
                    }

                    // */入栈
                    operatorStack.push(new Character(token.charAt(0)));
                } else if (token.trim().charAt(0) == '(') {
                    operatorStack.push(new Character('(')); // (入栈
                } else if (token.trim().charAt(0) == ')') {
                    // 在栈中进行所有是运算知道看到)
                    while (!operatorStack.peek().equals('(')) {
                        processAnOperator(operandStack, operatorStack);
                    }
                    operatorStack.pop(); // (出栈
                } else {
                    // 操作数进栈
                    operandStack.push(new Integer(token));
                }
            }

            // 处理堆栈中所有剩余的运算符
            while (!operatorStack.isEmpty()) {
                processAnOperator(operandStack, operatorStack);
            }

            // 返回结果
            return ((Integer) (operandStack.pop())).intValue();
        }

        public static void processAnOperator(java.util.Stack<Integer> operandStack, java.util.Stack<Character> operatorStack) {
            if (operatorStack.peek().equals('+')) {
                operatorStack.pop();
                int op1 = ((Integer) (operandStack.pop())).intValue();
                int op2 = ((Integer) (operandStack.pop())).intValue();
                operandStack.push(new Integer(op2 + op1));
            } else if (operatorStack.peek().equals('-')) {
                operatorStack.pop();
                int op1 = ((Integer) (operandStack.pop())).intValue();
                int op2 = ((Integer) (operandStack.pop())).intValue();
                operandStack.push(new Integer(op2 - op1));
            } else if (operatorStack.peek().equals('*')) {
                operatorStack.pop();
                int op1 = ((Integer) (operandStack.pop())).intValue();
                int op2 = ((Integer) (operandStack.pop())).intValue();
                operandStack.push(new Integer(op2 * op1));
            } else if (operatorStack.peek().equals('/')) {
                operatorStack.pop();
                int op1 = ((Integer) (operandStack.pop())).intValue();
                int op2 = ((Integer) (operandStack.pop())).intValue();
                operandStack.push(new Integer(op2 / op1));
            }
        }

        class ImagePanel extends JPanel {
            public void sshow() {
                int i;
                for (i = 0; i < 4; i++) {
                    card[i] = (int) (1 + Math.random() * 52);
                }
                repaint();
            }

            public void paintComponent(Graphics g) {
                /*
                 * 每次重绘(repaint())的时候,程序就会调用到自身的paintComponent()
                 * 方法在paintComponent方法中第一行就先调用了super.paintComponent进行界面重绘,
                 * 那么就由父类先进行界面重绘(查看JDK的源代码,你会发现,一般是恢复原状),父类重绘完之后, 界面就恢复到某个界面,
                 */
                super.paintComponent(g);
                int i;
                int w = getWidth() / 4;
                int h = getHeight();
                int x = 0;
                int y = 0;
                for (i = 0; i < 4; i++) {
                    ImageIcon imageIcon = new ImageIcon("src" + card[i] + ".jpg");
                    Image image = imageIcon.getImage();
                    if (image != null) {
                        g.drawImage(image, x, y, w, h, this);
                    }
                    x += w;
                }
            }
        }

        public static void main(String[] args) {
            TwentyFourPoke_Game frame = new TwentyFourPoke_Game();
            frame.setTitle("24 Poke Game");
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(368, 200);
            frame.setVisible(true);
            // void paintComponent(Graphics g);

        }
    }

10-02 20:31