1. 程式人生 > >Java利用遞迴演算法實現24點遊戲

Java利用遞迴演算法實現24點遊戲

24點遊戲

經典的紙牌益智遊戲,常見遊戲規則:

        從撲克中每次取出4張牌。使用加減乘除,第一個能得出24者為贏。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求程式設計解決24點遊戲。

        基本要求: 隨機生成4個代表撲克牌牌面的數字字母,程式自動列出所有可能算出24的表示式,用擅長的語言(C/C++/Java或其他均可)實現程式解決問題。

          1.程式風格良好(使用自定義註釋模板)

          2.列出表示式無重複。

         提高要求:使用者初始生命值為一給定值(比如3),初始分數為0。隨機生成4個代表撲克牌牌面的數字或字母,由使用者輸入包含這4個數字或字母的運算表示式(可包含括號),如果表示式計算結果為24則代表使用者贏了此局。

         1. 程式風格良好(使用自定義註釋模板)

         2.使用計時器要求使用者在規定時間內輸入表示式,如果規定時間內運算正確則加分,超時或運算錯誤則進入下一題並減少生命值(不扣分)。

         3.所有成績均可記錄在TopList.txt檔案中。

一. 演算法思路

     輸入四個數n1,n2,n3,n4,求解目標數T=24以及一組計算操作符"+" "-" "*" "/" ,求所有由該組數字及操作符組成的多項式表示式集合,其值等於目標數T ,即T = 24    演算法思路如下:       1.在集合{n1,n2,n3n4}中,首先取兩個數字,如n1,n2,與操作符集合進行組合,分別得到一組表示式:n1*n2,n1+n2,n1-n2,n1/n2,n2-n1,n2/n1.(其中由於"-"和"/"操作符,左右互換會導致計算結果不同,所以

在該組合中,包含"-"和"/"操作符的表示式各有兩個,運算元先後順序不同)        2.對於新得到的每個表示式,都可以和原集合中剩下的元素,組合成新的集合組,同時,我將每次得到的表示式,都用"()"包住,以保證計算先後順序:{(n1*n2),n3,n4}{(n1+n2),n3,n4}{(n1-n2),n3,n4}{(n1/n2),n3,n4}{(n2-n1),n3,n4}{(n2/n1),n3,n4}       3.基於以上方法,對集合中所有元素進行兩兩組合,並與剩餘元素形成新的集合。由此,我們得到了一組元素為k-1個的集合組      4.對新集合組中的每一個集合,重複以上1-3步,可得到一組包含k-2個元素的集合組...以此類推,最後會得到一組集合,其中每個集合都只包含一個元素,這個就是我們合成的最終表示式
      5.對第四步得到的表示式集合進行求解,判斷其是否等於目標數24,將符合條件的過濾出來,即得到所有滿足條件的表示式。

package TwentyfourGame;

import java.util.ArrayList;
import java.util.Scanner;

public class TfGame {
    public static void main(String[] args) {
    	//輸入提示
    	System.out.println("—————————歡迎進入24點遊戲———————————");
        System.out.println("請隨機輸入四個1-13之間的整數(以空格隔開):");
        ArrayList<Integer> list = inputNum();   //呼叫輸入函式
        tfCal(list, new ArrayList<String>());   //計算24點方法, 實參list為輸入的資料, new ArrayList<String>()用來 表示計算過程
        System.out.println("——————————————end———————————————");
    }
    
    //輸入方法,將輸入的四個數存入陣列佇列list中,並返回
    private static ArrayList<Integer> inputNum() {
        ArrayList<Integer> alist = new ArrayList<Integer>();  //ArrayList<Integer>表示只能接收整型資料
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < 4; i++) {         //將四個數新增到陣列佇列中
            alist.add(scanner.nextInt());
        }
        return alist;  //返回值為陣列佇列中的四個數
    }

    //計算24點遊戲的方法
    public static boolean tfCal(ArrayList<Integer> list, ArrayList<String> str) {
        int length = list.size();    
        if (length > 1) {
        	/**利用雙重迴圈取出兩個數的計算所有情況
        	 * 若list的長度為4,那麼第一個數的下標和第二個數的下標分別為
        	 * 0  1
        	 * 1  2
        	 * 2  3
        	 */
            for (int i = 0; i < length - 1; i++) {     
                for (int j = i + 1; j < length; j++) {
                    //加法運算
                    int b = list.remove(j);  //移除list中的下標為j的元素,並將此數賦值給b
                    int a = list.remove(i);  //同上,將值賦給a
                    list.add(0, a + b);      //將兩數的計算結果新增到原佇列
                    str.add(a + "+" + b + "=" + (a + b));//此處是儲存計算的過程
                    tfCal(list, str);    //遞迴調動
                    //下面四句話是為了還原list佇列,特別強調進棧和出棧的順序
                    list.remove(0);
                    list.add(i, a);
                    list.add(j, b);
                    str.remove(str.size() - 1);

                    //減運算(a-b),原理與上面加法計算相同
                    b = list.remove(j);
                    a = list.remove(i);
                    list.add(0, a - b);
                    str.add(a + "-" + b + "=" + (a - b));
                    tfCal(list, str);
                    list.remove(0);
                    list.add(i, a);
                    list.add(j, b);
                    str.remove(str.size() - 1);

                    //減運算(b-a)
                    b = list.remove(j);
                    a = list.remove(i);
                    list.add(0, b - a);
                    str.add(b + "-" + a + "=" + (b - a));
                    tfCal(list, str);
                    list.remove(0);
                    list.add(i, a);
                    list.add(j, b);
                    str.remove(str.size() - 1);

                    //乘運算
                    b = list.remove(j);
                    a = list.remove(i);
                    list.add(0, a * b);
                    str.add(a + "*" + b + "=" + (a * b));
                    tfCal(list, str);
                    list.remove(0);
                    list.add(i, a);
                    list.add(j, b);
                    str.remove(str.size() - 1);

                    //除運算(a/b)
                    b = list.remove(j);
                    a = list.remove(i);
                    if (b != 0 && a % b == 0) {
                        list.add(0, a / b);
                        str.add(a + "/" + b + "=" + (a / b));
                        tfCal(list, str);
                        list.remove(0);
                        list.add(i, a);
                        list.add(j, b);
                        str.remove(str.size() - 1);
                    } else {
                        list.add(i, a);
                        list.add(j, b);
                    }

                    //除運算(b/a)
                    b = list.remove(j);
                    a = list.remove(i);
                    if (a != 0 && b % a == 0) {
                        list.add(0, b / a);
                        str.add(b + "/" + a + "=" + (b / a));
                        tfCal(list, str);
                        list.remove(0);
                        list.add(i, a);
                        list.add(j, b);
                        str.remove(str.size() - 1);
                    } else {
                        list.add(i, a);
                        list.add(j, b);
                    }
                }
            }
        } else {
            if (str.get(str.size() - 1).endsWith("=24")) {   //endsWith()方法用於測試字串是否以指定字尾結束
        	   for (String temp : str) {
                   System.out.print(temp + " ");
               }  
               System.out.println();
            }               
        }
    }
}

二.執行結果

三.學習心得

  自己的演算法學習有待提高,需要不斷鍛鍊邏輯思維能力。