1. 程式人生 > >24點遊戲(Java)

24點遊戲(Java)

題目:24點遊戲是經典的紙牌益智遊戲。
常見遊戲規則:
從撲克中每次取出4張牌。使用加減乘除,第一個能得出24者為贏。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求程式設計解決24點遊戲。
基本要求: 隨機生成4個代表撲克牌牌面的數字字母,程式自動列出所有可能算出24的表示式,用擅長的語言(C/C++/Java或其他均可)實現程式解決問題。
24點遊戲是經典的紙牌益智遊戲

package chengxushejizuoye3;
import java.util.ArrayList;
import java.util.List;

import com.hbhs.algorithm.HBHSAssert;

/**
 * 計算21點遊戲<BR>
 * 給定數字陣列,通過+,-,*,/演算法得出最終的24點
 *
 * @author walter.xu
 */
public class Count24 {
	public static void main(String[] args) {
        List<Integer> result = new ArrayList<Integer>();
        result.add(2);
        result.add(8);
        result.add(2);
        result.add(2);
        int totalCount = 24;
        List<String> operatioins = point(result, totalCount, false);
        for (String str : operatioins) {
            System.out.println(str);
        }  
}
	 /**
     * 演算法思想<BR>
     * 1 將所有的數值按照指定的規則生成所有的可排序的序列
     * 2 針對每一個序列分別計算+,-,*,/操作,並計算最終結果,如果成功記記錄下當前的值
     *
     * @param patternList
     * @param result
     * @return
     */
    public static List<String> point(List<Integer> patternList, int result, boolean easyOperation) {

        HBHSAssert.isTrue(patternList == null || patternList.size() < 2, "Pattern must be more two");
        List<String> resultList = new ArrayList<String>();
        // 建立可使用的操作:加減乘除等
        List<String> availableOperationList = generateAvailableOperations(easyOperation);
        // 構造操作的全排列組合
        List<List<String>> operationList = Permutation.permutation(availableOperationList, patternList.size() - 1, true);
        // 構造撲克牌點數的全排列
        List<List<Integer>> intList = Permutation.permutation(patternList);
        // 依次迭代,並計算結果
        for (int i = 0; i < operationList.size(); i++) {
            List<String> currentOperationList = operationList.get(i);
            for (List<Integer> currentIntGroup : intList) {
                // 計算並生成公式結果,如果不為空,則表示該公式最終結果滿足24點
                String caclExpression = caclAndGenerateExpression(currentIntGroup, currentOperationList, result);
                if (caclExpression != null) resultList.add(caclExpression);
            }
        }
        return resultList;
    }

    // 計算該組合並生成計算表示式
    private static String caclAndGenerateExpression(List<Integer> currentIntGroup, List<String> currentOperationList, int result) {
        int currentCount = currentIntGroup.get(0);    // 獲取第一個值作為當前結果值
        int j = 1;                                    // 下一個值得序號
        for (; j < currentIntGroup.size(); j++) {
            if ("+".equalsIgnoreCase(currentOperationList.get(j - 1))) {
                if (currentIntGroup.get(j) < currentIntGroup.get(j - 1)) break;   // 滿足互換率,防止重複計算
                currentCount += currentIntGroup.get(j);
            } else if ("-".equalsIgnoreCase(currentOperationList.get(j - 1))) {
                if (currentIntGroup.get(j) < currentIntGroup.get(j - 1)) break;   // 滿足互換率,防止重複計算
                currentCount -= currentIntGroup.get(j);
            } else if ("*".equalsIgnoreCase(currentOperationList.get(j - 1))) {
                if (currentIntGroup.get(j) < currentIntGroup.get(j - 1)) break;   // 滿足互換率,防止重複計算
                currentCount *= currentIntGroup.get(j);
            } else if ("/".equalsIgnoreCase(currentOperationList.get(j - 1))) {
                if (currentIntGroup.get(j - 1) % currentIntGroup.get(j) > 0) break;
                currentCount /= currentIntGroup.get(j);
            } else if (">>".equalsIgnoreCase(currentOperationList.get(j - 1))) {
                currentCount = currentCount >> currentIntGroup.get(j);
            } else if ("<<".equalsIgnoreCase(currentOperationList.get(j - 1))) {
                currentCount = currentCount << currentIntGroup.get(j);
            } else if ("^".equalsIgnoreCase(currentOperationList.get(j - 1))) {
                int times = currentIntGroup.get(j);
                int temp = currentCount;
                times--;
                while (times > 0) {
                    currentCount *= temp;
                    times--;
                }
            }
        }
        // 僅當全部引數都使用,並且結果等於期望結果時表示為我們所需要的組合
        if (j == currentIntGroup.size()&&currentCount == result) {
            return formatResult(currentIntGroup, currentOperationList, result);
        }
        return null;
    }

    private static List<String> generateAvailableOperations(boolean easyOperation) {
        List<String> operationList = new ArrayList<String>();
        operationList.add("+");
        operationList.add("-");
        operationList.add("*");
        operationList.add("/");
        if (!easyOperation) {
            operationList.add(">>");
            operationList.add("<<");
            operationList.add("^");
        }
        return operationList;
    }


    private static String formatResult(List<Integer> intList, List<String> operationgList, int result) {
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < operationgList.size(); i++) {
            str.append("(");
        }
        str.append(intList.get(0));
        for (int i = 1; i < intList.size(); i++) {
            str.append("").append(operationgList.get(i - 1)).append(intList.get(i)).append(")");
        }
        str.append(" = ").append(result);
        return str.toString();

    }

    /**
     * 排列組合類<BR>
     * 用於排列組合各種情況適用
     *
     * @author walter.xu
     */
    private static class Permutation {
        public static <T> List<List<T>> permutation(List<T> args) {
            return permutation(args, false);
        }

        public static <T> List<List<T>> permutation(List<T> args, boolean repeatable) {
            return permutation(args, args.size(), repeatable);
        }

        public static <T> List<List<T>> permutation(List<T> args, int totalSize, boolean repeatable) {
            List<List<T>> resultList = new ArrayList<List<T>>();
            List<T> secondPart = new ArrayList<T>();
            permutation(args, secondPart, resultList, totalSize, repeatable);
            return resultList;
        }

        private static <T> void permutation(List<T> firstPart, List<T> secondPart, List<List<T>> resultList,
                                            int totalSize, boolean repeatable) {
            if (totalSize == secondPart.size()) {
                resultList.add(secondPart);
                return;
            }
            for (int i = 0; i < firstPart.size(); i++) {
                List<T> currentFirstPart = new ArrayList<T>(firstPart);
                List<T> currentSecondPart = new ArrayList<T>(secondPart);
                currentSecondPart.add(firstPart.get(i));
                if (!repeatable) {
                    currentFirstPart.remove(i);
                }
                permutation(currentFirstPart, currentSecondPart, resultList, totalSize, repeatable);
            }
        }
    }
}