java實(shí)現(xiàn)24點(diǎn)游戲
游戲規(guī)則
從撲克中每次取出4張牌。使用加減乘除,第一個(gè)能得出24者為贏。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求編程解決24點(diǎn)游戲。
基本要求
- 隨機(jī)生成4個(gè)代表撲克牌牌面的數(shù)字字母,程序自動(dòng)列出所有可能算出24的表達(dá)式
- 列出表達(dá)式無重復(fù)
- 用戶初始生命值為一給定值(比如3),初始分?jǐn)?shù)為0。隨機(jī)生成4個(gè)代表撲克牌牌面的數(shù)字或字母,由用戶輸入包含這4個(gè)數(shù)字或字母的運(yùn)算表達(dá)式(可包含括號),如果表達(dá)式計(jì)算結(jié)果為24則代表用戶贏了此局。
- 使用計(jì)時(shí)器要求用戶在規(guī)定時(shí)間內(nèi)輸入表達(dá)式,如果規(guī)定時(shí)間內(nèi)運(yùn)算正確則加分,超時(shí)或運(yùn)算錯(cuò)誤則進(jìn)入下一題并減少生命值(不扣分)。
- 所有成績均可記錄在TopList.txt文件中。
解表達(dá)式基本思路
采用窮舉法列舉每一種存在的可能,接著判斷是否值為24,如果等于24,則將表達(dá)式存入Set集合,最終遍歷Set集合即可得到所有表達(dá)式。具體思路如下:
1.采用隨機(jī)數(shù)生成4個(gè)符合要求的數(shù)據(jù),假設(shè)四個(gè)數(shù)據(jù)為n1,n2,n3,n4 。
2.把數(shù)據(jù)相互組合可以得到如下組合:n1和n2 ,n1和n3,n1和n4,n2和n3,n2和n4,n3和n4
3.將上面的組合進(jìn)行各種可能的運(yùn)算例如:n1+n2,n1-n2,n2-n1,n1*n2,n1/n2,n2/n1等等。
4.把上面組合計(jì)算出來的結(jié)果存入進(jìn)對應(yīng)的數(shù)組中例如:組合相加的結(jié)果存入add數(shù)組,相減的結(jié)果存入sub數(shù)組……最終將這些數(shù)組存入一個(gè)list集合中,目的是為了方便通過循環(huán)遍歷出每一種組合。
5.通過循環(huán)去遍歷每一種組合,把這些組合在一起進(jìn)行相加,相減等運(yùn)算,記錄結(jié)果為24的表達(dá)式。在這里需要注意的是,因?yàn)閿?shù)組得值為兩個(gè)數(shù)字的運(yùn)算結(jié)果,所以需要根據(jù)當(dāng)前循環(huán)變量的值和list集合以及數(shù)組存入數(shù)據(jù)的順序去把表達(dá)式格式化成四個(gè)數(shù)字組成的表達(dá)式,否則表達(dá)式只有兩個(gè)數(shù)字。
- 需要注意的是:在遍歷集合的過程中,由于集合中存入的數(shù)組的數(shù)據(jù)為兩個(gè)數(shù)據(jù)組合的形式,所以遍歷是只需要控制好下標(biāo),使的每一個(gè)表達(dá)式中只有n1,n2,n3,n4這四個(gè)數(shù)據(jù),而不會(huì)出現(xiàn)類似于n1,n2,n1,n3 這種組合的方式。
- 具體的流程圖入下圖所示:
玩家運(yùn)算基本思路
在java中使用Timer和Canender即可實(shí)現(xiàn)定時(shí)的功能,而判斷表達(dá)式是否正確,在java中使用Script引擎調(diào)用eval方法即可判斷表達(dá)式的值是否正確,具體思路如下:
1.初始化生命值,和分?jǐn)?shù)
2.由系統(tǒng)給出四個(gè)數(shù)字
3.玩家給出答案
4.判斷給出的答案中的數(shù)字和系統(tǒng)給出的數(shù)字是否吻合,如果吻合進(jìn)入5,否則,生命值減一。
5.借助Timer類的schedule()判斷是否超時(shí),如果沒有超時(shí),進(jìn)入6,否則,生命值減一。
6.借助script引擎的eval()方法可以判斷表達(dá)式是否正確,如果正確,分?jǐn)?shù)加一,否則,生命值減一。
當(dāng)生命值大于0時(shí)執(zhí)行2,3,4,5,6操做,否則將當(dāng)前分?jǐn)?shù)寫入文件。
流程圖如下圖所示
編碼
Game類,主要實(shí)現(xiàn)由系統(tǒng)隨機(jī)生成數(shù)據(jù),并計(jì)算可能的表達(dá)式
為了避免除零異常采用了float類型的數(shù)組進(jìn)行存儲(chǔ)
import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Scanner; import java.util.Set; /** * * Title: Test Description: 1. 采用隨機(jī)數(shù)生成4個(gè)符合要求的數(shù)據(jù),假設(shè)四個(gè)數(shù)據(jù)為n1,n2,n3,n4 。 * 2.把數(shù)據(jù)相互組合可以得到如下組合:n1和n2 ,n1和n3,n1和n4,n2和n3,n2和n4。 * 3.將上面的組合進(jìn)行各種可能的運(yùn)算例如:n1+n2,n1-n2,n2-n1,n1*n2,n1/n2,n2/n1等等。 * 4.把上面組合計(jì)算出來的結(jié)果存入進(jìn)對應(yīng)的數(shù)組中例如:組合相加的結(jié)果存入add數(shù)組,相減的結(jié)果存入sub數(shù)組……最終將這些數(shù)組存入一個(gè)list集合中,目的是為了方便通過循環(huán)遍歷出每一種組合。 * 5.通過循環(huán)去遍歷每一種組合,把這些組合在一起進(jìn)行相加,相減等運(yùn)算,記錄結(jié)果為24的表達(dá)式 * @author jianglei */ public class Game { static Set<String> set = new HashSet<String>();// 使用Set存儲(chǔ)算式表達(dá)式可以避免有重復(fù)的結(jié)果 float[] data = new float[4];// 存放數(shù)據(jù)的集合 float[] add = new float[6];// 存放組合相加的結(jié)果的集合 float[] sub1 = new float[6];// 存放相減的結(jié)果(兩個(gè)數(shù)相減的結(jié)果存在兩種可能) float[] sub2 = new float[6];// 存放相減的結(jié)果 float[] mul = new float[6];// 存放相乘 float[] div1 = new float[6];// 存放相除(兩個(gè)數(shù)相除的結(jié)果存在兩種可能) float[] div2 = new float[6];// 存放相除 List<float[]> list = new ArrayList<float[]>();// 存放組合結(jié)果運(yùn)算的集合 /** * * Title: combine * </p> * Description: 該方法用來獲取每兩個(gè)數(shù)字的組合組合, 用1代表第一個(gè)數(shù)字,2代表第二個(gè)數(shù)字....共有六種組合方式,分別如下: * 1和2,1和3,1和 4,2和 3,2和 4,3和 4 在上面的組合中,每一種組合都對應(yīng)著 加減乘除 這四種運(yùn)算 * 將上述的組合的每種計(jì)算結(jié)果存入上面聲明的集合 */ public void conbine(float n1, float n2, float n3, float n4) { add[0] = n1 + n2; add[1] = n1 + n3; add[2] = n1 + n4; add[3] = n2 + n3; add[4] = n2 + n4; add[5] = n3 + n4; sub1[0] = n1 - n2; sub1[1] = n1 - n3; sub1[2] = n1 - n4; sub1[3] = n2 - n3; sub1[4] = n2 - n4; sub1[5] = n3 - n4; sub1[5] = n3 + n4; sub2[0] = n2 - n1; sub2[1] = n3 - n1; sub2[2] = n4 - n1; sub2[3] = n3 - n2; sub2[4] = n4 - n2; sub2[5] = n4 - n3; mul[0] = n2 * n1; mul[1] = n3 * n1; mul[2] = n4 * n1; mul[3] = n3 * n2; mul[4] = n4 * n2; mul[5] = n4 * n3; div1[0] = n1 / n2; div1[1] = n1 / n3; div1[2] = n1 / n4; div1[3] = n2 / n3; div1[4] = n2 / n4; div1[5] = n3 / n4; div2[0] = n2 / n1; div2[1] = n3 / n1; div2[2] = n4 / n1; div2[3] = n3 / n2; div2[4] = n4 / n2; div2[5] = n4 / n3; list.add(add);// 把各種組合加入到list集合中,方便通過循環(huán)來遍歷每一種組合方式 list.add(sub1); list.add(sub2); list.add(mul); list.add(div1); list.add(div2); } public void getData() { Random r = new Random(); // 獲取1——13的的數(shù)字的集合 data[0] = r.nextInt(12) + 1; data[1] = r.nextInt(12) + 1; data[2] = r.nextInt(12) + 1; data[3] = r.nextInt(12) + 1; System.out.print("四個(gè)數(shù)字為:"); for (float f : data) switch ((int) f) {// 將11,12,13,1變成J,Q,K,A case 1: System.out.print("A" + " "); break; case 11: System.out.print("J" + " "); break; case 12: System.out.print("O" + " "); break; case 13: System.out.print("K" + " "); break; default: System.out.print((int) f + " "); break; } System.out.println(); boolean flag = false;// 通過該變量去判斷是否存在表達(dá)式 conbine(data[0], data[1], data[2], data[3]); for (int a = 0; a < 3; a++) {// 有種組合方式,分別遍歷每一種組合方法 for (int b = 0; b < 6; b++) {// 窮舉每一個(gè)組合和他們之間的運(yùn)算 for (int c = 0; c < 6; c++) {// 判斷每一種組合的每一種運(yùn)算結(jié)果是否等于24 if ((list.get(b)[a] + list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "+", set); flag = true; } // 減法 if ((list.get(b)[a] - list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "-", set); } if ((list.get(b)[5 - a] - list.get(c)[a]) == 24) { DataFormat.judge(a, b, c, data, "-", set); flag = true; } // 乘法 if ((list.get(b)[a] * list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "*", set); flag = true; } // 除法 if ((list.get(b)[a] / list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "/", set); flag = true; } if ((list.get(b)[5 - a] / list.get(c)[a]) == 24) { DataFormat.judge(a, b, c, data, "/", set); flag = true; } } } } if (!flag) System.out.println("沒有表達(dá)式滿足條件"); }
AutoGame類主要實(shí)現(xiàn)由系統(tǒng)給定數(shù)值,用戶輸入表達(dá)式來根據(jù)結(jié)過進(jìn)行計(jì)分,并將分?jǐn)?shù)寫入文件
import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.Random; import java.util.Scanner; import java.util.Timer; import java.util.TimerTask; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class AutoGame { static boolean flag = true;//該變量標(biāo)識(shí)是否超時(shí) static int life = 3;//初始化生命值 static int score=0;//初始化分?jǐn)?shù) /** *開始游戲的方法,該方法通過當(dāng)前生命值判斷是否結(jié)束 */ public void start() throws IOException { Calendar date = Calendar.getInstance();//實(shí)例化Calendar對象 while(life>0) {//當(dāng)生命值大于0才會(huì)進(jìn)行 flag=true;//初始化分?jǐn)?shù)標(biāo)記 date.setTime(new Date()); date.add(Calendar.SECOND, 20);//設(shè)置限定時(shí)間 Timer timer = new Timer(); //當(dāng)達(dá)到限定時(shí)間將會(huì)執(zhí)行run()方法,即把全局變量flag變?yōu)閒alse timer.schedule(new RemindTask(), date.getTime()); int answer = answer(); switch(answer) { case -1: System.out.println("表達(dá)式錯(cuò)誤?。?當(dāng)前生命值為"+life+" 分?jǐn)?shù)為:"+score); break; case -2: System.out.println("輸入超時(shí)?。?當(dāng)前生命值為"+life+" 分?jǐn)?shù)為:"+score); break; case -3: System.out.println("結(jié)果錯(cuò)誤?。?當(dāng)前生命值為"+life+" 分?jǐn)?shù)為:"+score); break; case 1: System.out.println("正確,得到1分獎(jiǎng)勵(lì)??! 當(dāng)前生命值為"+life+" 分?jǐn)?shù)為:"+score); break; } System.out.println("----------"); } System.out.println("游戲結(jié)束……分?jǐn)?shù)為: "+score);//循環(huán)結(jié)束也就是生命值為0,打印游戲結(jié)束 saveScore(score);//將玩家當(dāng)前分?jǐn)?shù)存入文件 return; } /** * * Title: getData</p> * Description:給定任意的數(shù)據(jù) * @return */ private float[] getData() { float[] data = new float[4]; Random r = new Random();//隨機(jī)生成四個(gè)數(shù)據(jù)存入數(shù)組中 data[0] = r.nextInt(12) + 1; data[1] = r.nextInt(12) + 1; data[2] = r.nextInt(12) + 1; data[3] = r.nextInt(12) + 1; System.out.print("四個(gè)數(shù)字為:"); for (float f : data) switch ((int) f) { case 1: System.out.print("A" + " "); break; case 11: System.out.print("J" + " "); break; case 12: System.out.print("O" + " "); break; case 13: System.out.print("K" + " "); break; default: System.out.print((int) f + " "); break; } System.out.println("請開始作答,時(shí)間20秒"); return data; } /** * * Title: answer</p> * Description:根據(jù)用戶輸入返回false或true * 1.輸入不含給定值,返回FALSE * 2.輸入超時(shí),返回false * 3.輸入表達(dá)式的值不為24,返回false * 否則,返回true * @return -1代表輸入的表達(dá)式與系統(tǒng)給出的數(shù)字不吻合 * @return -2代表用戶計(jì)算結(jié)果超時(shí) * @return -3代表結(jié)果錯(cuò)誤 * @return 1代表用戶計(jì)算正確 */ public int answer() { Scanner sc = new Scanner(System.in); float[] data = getData();//獲取給定的數(shù)據(jù) //獲取script引擎,調(diào)用eval()方法來判斷表達(dá)式是否正確 ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn"); String exper = sc.next(); try { String res = String.valueOf(scriptEngine.eval(exper)); for (int i = 0; i < data.length; i++) if (!exper.contains(data[i] + "")) {//輸入的表達(dá)式不含給定的值 life--; return -1; } if(!flag) {//判斷超時(shí) life--; return -2; } if (res.equals("24")) {//回答正確并且沒有超時(shí) score++;//分?jǐn)?shù)加一 return 1; } life--; } catch (ScriptException e) { System.out.println("表達(dá)式輸入不合法"); } return -3; } /** * Title: saveScore</p> * Description: 該方法表示將玩家當(dāng)前分?jǐn)?shù)存入TopList.txt文件 * @param score 需要存入的分?jǐn)?shù) * @throws IOException */ public static void saveScore(int score) throws IOException { FileOutputStream fos = new FileOutputStream("e:/TopList.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write((score+"").getBytes());//把分?jǐn)?shù)寫入文件 bos.close(); } public static void main(String[] args) throws IOException { saveScore(1); } } /** * * Title: RemindTask * Description:該TimerTask并且重寫run()可以實(shí)現(xiàn)在指定的定時(shí)時(shí)間執(zhí)行run方法的內(nèi)容 * @author jianglei */ class RemindTask extends TimerTask { @Override public void run() { AutoGame.flag = false;//當(dāng)超時(shí)會(huì)把全局變量flag變?yōu)閒alse } }
DataFormat類根據(jù)a b c是三個(gè)循環(huán)變量將兩個(gè)組合數(shù)字的運(yùn)算格式化成四個(gè)數(shù)字的表達(dá)式
由于代碼比較長,在這里只留一種情況的,其余的情況與它類似
import java.util.Set; /** * * Title: GetFoamat * Description: 該類通過在循環(huán)中的a b c的值判斷出當(dāng)前所參與運(yùn)算的值與參加運(yùn)算的符號,假設(shè)四個(gè)值為n0,n1,n2,n3 * 形參 a、b、c為循環(huán)變量,形參n數(shù)組為參與運(yùn)算的四個(gè)數(shù)字,形參op表示當(dāng)前進(jìn)行的運(yùn)算類型,形參set為存儲(chǔ)結(jié)果的容器 */ public class DataFormat { public static void judge(int a,int b,int c,float[]n,String op,Set<String> set) { StringBuilder sb = new StringBuilder(); if(a==0) {//n0和n1 與n2和n3之間的運(yùn)算 if(b==0) {//n0+n1 if(c==0) {//n2+n3 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("+").append(n[3]).append(")").append("=24"); }if(c==1) {//n2-n3 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("-").append(n[3]).append(")").append("=24"); }if(c==2) {//n3-n2 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[3]).append("-").append(n[2]).append(")").append("=24"); }if(c==3) {// n2*n3 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("*").append(n[3]).append(")").append("=24"); }if(c==4) {// n2/n3 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("/").append(n[3]).append(")").append("=24"); }if(c==5) {// n3/n2 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[3]).append("/").append(n[2]).append(")").append("=24"); } //將運(yùn)算表達(dá)式存入容器 set.add(sb.toString()); //將sb清空 sb = new StringBuilder(); }if(b==1) {//n0-n1 //由于這種代碼篇幅比較長,在這里省略了,思路和上面的一致 }
測試
import java.io.IOException; import java.util.Scanner; public class Test { public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); Game t = new Game(); System.out.println("----------"); System.out.println("1.隨機(jī)生成數(shù)判斷"); System.out.println("2.用戶輸入運(yùn)算式"); System.out.println("請選擇"); char op = sc.next().charAt(0); switch (op) { case '1': t.getData(); for (String str : t.set) { System.out.println(str.replaceAll(".0", "")); } break; case '2': AutoGame a = new AutoGame(); a.start(); break; default: System.out.println("輸入錯(cuò)誤"); } } }
運(yùn)行結(jié)果
以下用戶輸入表達(dá)式的運(yùn)行結(jié)果
測試過程中在該情況下的測試數(shù)據(jù)是由自己給出的為1 1 12 12這四個(gè)數(shù)字
分?jǐn)?shù)存入文件
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 利用Java編寫24點(diǎn)小游戲的實(shí)例代碼
- java實(shí)現(xiàn)24點(diǎn)紙牌游戲
- Java實(shí)現(xiàn)24點(diǎn)小游戲
- Java編寫的24點(diǎn)紙牌游戲
- Java Swing實(shí)現(xiàn)坦克大戰(zhàn)游戲
- Java實(shí)戰(zhàn)之飛翔的小鳥小游戲
- Java實(shí)現(xiàn)五子棋游戲
- Java實(shí)現(xiàn)的迷宮游戲
- Java實(shí)戰(zhàn)入門之雙色球彩票小游戲
- Java實(shí)戰(zhàn)之貪吃蛇小游戲(源碼+注釋)
- 用Java實(shí)現(xiàn)24點(diǎn)游戲
相關(guān)文章
java實(shí)現(xiàn)圖片轉(zhuǎn)base64字符串 java實(shí)現(xiàn)base64字符串轉(zhuǎn)圖片
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)圖片轉(zhuǎn)base64字符串,java實(shí)現(xiàn)base64字符串轉(zhuǎn)圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02Spring項(xiàng)目中swagger用法與swagger-ui使用
這篇文章主要介紹了Spring項(xiàng)目中swagger用法與swagger-ui使用,通過圖文并茂的形式給大家介紹了編寫springboot項(xiàng)目的方法及導(dǎo)入spring-fox依賴的代碼詳解,需要的朋友可以參考下2021-05-05Redis Java Lettuce驅(qū)動(dòng)框架原理解析
這篇文章主要介紹了Redis Java Lettuce驅(qū)動(dòng)框架原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12Springboot 讀取自定義pro文件注入static靜態(tài)變量方式
這篇文章主要介紹了Springboot 讀取自定義pro文件注入static靜態(tài)變量方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07使用IntelliJ IDEA 2017.2.5 x64中的Spring Initializr插件快速創(chuàng)建Spring
這篇文章主要介紹了使用IntelliJ IDEA 2017.2.5 x64中的Spring Initializr插件快速創(chuàng)建Spring Boot/Cloud工程(圖解),需要的朋友可以參考下2018-01-01maven倉庫repositories和mirrors的配置及區(qū)別詳解
這篇文章主要介紹了maven倉庫repositories和mirrors的配置及區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07SpringBoot短鏈接跳轉(zhuǎn)的代碼實(shí)現(xiàn)
短鏈跳轉(zhuǎn)是一種通過將長鏈接轉(zhuǎn)換為短鏈接的方式,以便在互聯(lián)網(wǎng)上進(jìn)行鏈接共享和傳播的技術(shù),短鏈將原始長鏈接通過特定算法轉(zhuǎn)換為較短的鏈接,使得它更容易分享、傳播和展示,本文給大家介紹了SpringBoot短鏈接跳轉(zhuǎn)的代碼實(shí)現(xiàn),需要的朋友可以參考下2024-03-03Java設(shè)計(jì)模式之策略模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
策略模式是對算法的封裝,把一系列的算法分別封裝到對應(yīng)的類中,并且這些類實(shí)現(xiàn)相同的接口,相互之間可以替換。接下來通過本文給大家分享Java設(shè)計(jì)模式之策略模式,感興趣的朋友一起看看吧2017-08-08