凑24点游戏实现

1 篇文章 0 订阅

游戏规则

一副扑克牌一共有54张,在不考虑双王的情况下,从剩余的52张牌中每次随机抽取4张扑克牌,通过利用+、-、*、/以及()对4张牌进行数学运算,判断计算的结果是否等于24。

实现原理

在运算过程中,如果不考虑运算符号的优先级情况下,可以将凑24点游戏模型化为如下式子:

A[op1]B[op2]C[op3]D

其中A、B、C以及D代表的是操作数,op1、op2以及op3代表的是运算符。
由于运算符的优先级可以通过()操作符进行转变,因此在实际中可以通过()的不同搭配来迎合运算符的优先级,可以模型化为:
1. 第一种模型

((A[op1]B)[op2](C[op3]D))

这里写图片描述
2. 其余模型

(((A[op1]B)[op2]C)[op3]D)

这里写图片描述

((A[op1](B[op2]C))[op3]D)

这里写图片描述

(A[op1](B[op2](C[op3]D)))

这里写图片描述
通过树的形式将四种模型具现化(如下图,其中op表示运算符,叶节点表示操作数),发现可以将(2)中的三种模型合并为一种。

Java实现

扑克牌类

扑克牌类主要提供了扑克牌的花色表示、数字表示以及结合两者的表示,可通过任意一种进行直接访问。

package com.game.gather24;

public class Card
{
    public final static int MAX_CARDS = 52;
    public final static int MAX_SUITS = 4;
    private final static String []SUITS = new String[]{"C", "D", "H", "S"};     /* 梅花, 方块, 红桃,  黑桃 */
    private final static String [] CARDS = new String[]{"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};

    private String suit;
    private String card;
    private int ranking;

    public Card()
    {

    }
    public Card(int ranking)
    {
        this.card = getCardByRanking(ranking);
        this.suit = getSuitByRanking(ranking);
        this.ranking = ranking;
    }
    public Card(String suit, String card)
    {
//      this.suit = suit;
//      this.card = card;
        this.setCard(card);
        this.setSuit(suit);
        this.setRanking(suit, card);
    }

    private void setRanking(String suit, String card)
    {
        int cardIndex = 0;
        int suitIndex = 0;

        for (int iter = 0; iter < MAX_CARDS / MAX_SUITS; ++iter)
        {
            if (card.equals(CARDS[iter]))
            {
                cardIndex = iter;
                break;
            }
        }
        for (int iter = 0; iter < MAX_SUITS; ++iter)
        {
            if (suit.equals(SUITS[iter]))
            {
                suitIndex = iter;
                break;
            }
        }

        this.ranking = cardIndex * MAX_SUITS + suitIndex;
    }   
    public int getRanking()
    {
        return this.ranking;
    }

    private void setSuit(String suit)
    {
        this.suit = suit;
    }
    public String getSuit()
    {
        return this.suit;
    }

    private void setCard(String card)
    {
        this.card = card;
    }
    public String getCard()
    {
        return this.card;
    }

    public String getCardByRanking(int ranking)
    {
        return CARDS[ranking / MAX_SUITS];
    }
    public String getSuitByRanking(int ranking)
    {
        return SUITS[ranking % MAX_SUITS];
    }

    public int getCardValueByRanking(int ranking)
    {
        String card = getCardByRanking(ranking);
        int cardIndex = 0;

        for (int iter = 0; iter < CARDS.length; ++iter)
        {
            if (card.equals(CARDS[iter]))
            {
                cardIndex = iter;
                return cardIndex + 1;
            }
        }

        return 0;
    }

    public int hashCode()
    {
        return this.ranking;
    }

    public boolean equal(Object obj)
    {
        if (this == obj)
            return true;
        if (obj != null && obj instanceof Card)
        {
            Card card = (Card)obj;
            return (this.hashCode() == card.hashCode());
        }
        else
            return false;
    }

    public String toString()
    {
        return (card + "" + suit);
    }
}

抽象结构类

抽象结构了提供了额两种树结构的统一接口以及部分实现,用于计算结构。

package com.game.gather24;


public abstract class StructForGather24
{
    protected final static double RESULT = 24.0;
    protected final static double PRECISION = 0.000001;
    protected final static int NUM_NUM = 4;
    protected final static int NUM_OPR = 3;

    protected int [] num = new int[NUM_NUM];
    protected String [] opr = new String[NUM_OPR];

    protected String expression;
    protected double finalResult;

    public StructForGather24()
    {
        this.expression = "";
        this.finalResult = 0.0;
    }   
    public StructForGather24(String str)
    {
        this.expression = str;
        this.finalResult = 0.0;
    }
    public StructForGather24(String str, int aNum)
    {
        this.expression = str;
        this.finalResult = Double.parseDouble(Integer.toString(aNum));
    }

    public StructForGather24(int [] aNum, String [] aStr)
    {
        setExpression("");
        setResult(0);

        System.arraycopy(aNum, 0, this.num, 0, NUM_NUM);
        System.arraycopy(aStr, 0, this.opr, 0, NUM_OPR);
    }

    public void insertOpr(String opr, int index)
    {
        if (index < 0)
        {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        else if (index >= NUM_OPR)
        {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + NUM_OPR);
        }

        this.opr[index] = opr;
    }
    public String getOpr(int index)
    {
        if (index < 0)
        {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        else if (index >= NUM_OPR)
        {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + NUM_OPR);
        }

        return opr[index];
    }

    public void insertNum(int num, int index)
    {
        if (index < 0)
        {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        else if (index >= NUM_NUM)
        {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + NUM_NUM);
        }

        this.num[index] = num;
    }
    public int getNum(int index)
    {
        if (index < 0)
        {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        else if (index >= NUM_NUM)
        {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + NUM_NUM);
        }

        return num[index];
    }

    public abstract void computeResult();

    protected void setExpression(String str)
    {
        this.expression = str;
    }
    public String getExpression()
    {
        return expression;
    }

    protected void setResult(int aNum)
    {
        this.finalResult = Double.parseDouble(Integer.toString(aNum));
    }
    public double getResult()
    {
        return finalResult;
    }

    public boolean equal24()
    {
        return (Math.abs(finalResult - RESULT) < PRECISION);
    }
}

具体结构的实现

第一种模型

package com.game.gather24;


/*
 *                 O
 *               /    \
 *              O      O
 *            /  \    /  \
 *           O    O  O    O
 *           1    2  3    4
 */

public class StrFir extends StructForGather24
{   
    private final int TMP_NUM = NUM_NUM - 2;
    private double [] tmpResult = new double[TMP_NUM];

    public StrFir()
    {
        super();
    }
    public  StrFir(int [] aNum, String [] aStr)
    {
        super(aNum, aStr);
    }

    @Override
    public void computeResult()
    {
        for (int i = 0, k = 0; i < NUM_NUM && k < TMP_NUM; i += 2, ++k)
        {
            if (opr[k].contains("+") || opr[k].contains("-") || opr[k].contains("*") || opr[k].contains("/"))
            {
                switch (opr[k])
                {
                case "+":
                    tmpResult[k] = Double.parseDouble(Integer.toString(num[i])) + 
                                                Double.parseDouble(Integer.toString(num[i + 1]));
                    break;

                case "-":
                    tmpResult[k] = Double.parseDouble(Integer.toString(num[i])) - 
                                                Double.parseDouble(Integer.toString(num[i + 1]));
                    break;

                case "*":
                    tmpResult[k] = Double.parseDouble(Integer.toString(num[i])) * 
                                                Double.parseDouble(Integer.toString(num[i + 1]));
                    break;

                case "/":
                    tmpResult[k] = Double.parseDouble(Integer.toString(num[i])) / 
                                                Double.parseDouble(Integer.toString(num[i + 1]));
                    break;          
                }
            }
            else
            {
                System.out.println("不允许使用除(+,-,*,/)之外的操作符!");
                return ;
            }
        }

        if (opr[NUM_OPR - 1].contains("+") || opr[NUM_OPR - 1].contains("-") || 
                opr[NUM_OPR - 1].contains("*") || opr[NUM_OPR - 1].contains("/"))
        {
            switch (opr[NUM_OPR - 1])
            {
            case "+":
                finalResult = tmpResult[0] + tmpResult[1];
                break;

            case "-":
                finalResult = tmpResult[0] - tmpResult[1];
                break;

            case "*":
                finalResult = tmpResult[0] * tmpResult[1];
                break;

            case "/":
                finalResult = tmpResult[0] / tmpResult[1];
                break;
            }
        }
        else
        {
            System.out.println("不允许使用除(+,-,*,/)之外的操作符!");
            return ;
        }

        expression = "";
        if (equal24())
        {
            expression = "(" + num[0] + opr[0] + num[1] + ")" + opr[2] + "(" + num[2] + opr[1] + num[3] + ")";
        }
    }   
}

第二种模型

package com.game.gather24;


/*
 *                 O
 *               /   \
 *              O     O
 *            /   \ 
 *           O     O 
 *          / \
 *         O   O
 */

public class StrSec extends StructForGather24
{
    private final int TMP_NUM = NUM_NUM;        /* 最后一个用于存放finalResult */
    private double [] tmpResult = new double[TMP_NUM];

    public StrSec()
    {
        super();
    }
    public  StrSec(int [] aNum, String [] aStr)
    {
        super(aNum, aStr);
    }

    @Override
    public void computeResult()
    {
        tmpResult[0] = Double.parseDouble(Integer.toString(num[0]));

        for (int i = 1; i < NUM_NUM; ++i)
        {
            if (opr[i - 1].contains("+") || opr[i - 1].contains("-") || opr[i - 1].contains("*") || opr[i - 1].contains("/"))
            {
                switch (opr[i - 1])
                {
                case "+":
                    tmpResult[i] = tmpResult[i - 1] + Double.parseDouble(Integer.toString(num[i]));
                    break;

                case "-":
                    tmpResult[i] = tmpResult[i - 1] - Double.parseDouble(Integer.toString(num[i]));
                    break;

                case "*":
                    tmpResult[i] = tmpResult[i - 1] * Double.parseDouble(Integer.toString(num[i]));
                    break;

                case "/":
                    tmpResult[i] = tmpResult[i - 1] / Double.parseDouble(Integer.toString(num[i]));
                    break;
                }
            }
            else
            {
                System.out.println("不允许使用除(+,-,*,/)之外的操作符!");
                return ;
            }
        }

        finalResult = tmpResult[TMP_NUM - 1];
        if (equal24())
        {
            expression = "(((" + num[0];
            for (int i = 1; i < NUM_NUM; ++i)
            {
                expression += opr[i - 1] + num[i] + ")";
            }
        }
    }
}

游戏类

涉及到洗牌、发牌以及计算等。

package com.game.gather24;

import java.util.Random;
import java.util.Scanner;
import java.util.Vector;

public class Game
{
    private static final int NUM_OPR_COMBINE = 64;
    private static final int NUM_NUM_COMBINE = 24;

//  private static final String [] gameResult = new String[]{new String("Victory"), new String("Defeat")};
    private static final String [] oper = new String[]{"*", "/", "+", "-"};
    private static final int NUM_CARDS = 4;

    private Vector<Card> initCards = new Vector<>(Card.MAX_CARDS);
    private Vector<Card> saveCards = new Vector<>(Card.MAX_CARDS);

    private Card inUseCards[] = new Card[NUM_CARDS];

    private StructForGather24 treeFir;
    private StructForGather24 treeSec;

    public int RadomIndex(int bound)
    {
        Random rd = new Random();
        return rd.nextInt(bound);
    }

    /* 洗牌 */
    public void shuffleCards(Vector<Card> cards)
    {
        for (int iter = 0; iter < cards.size(); ++iter)
        {
            int pos = RadomIndex(cards.size());
            Card temp = cards.elementAt(iter);
            cards.setElementAt(cards.elementAt(pos), iter);
            cards.setElementAt(temp, pos);
        }
    }

    public void dealCard(Vector<Card> cards)
    {
        for (int iter = 0; iter < NUM_CARDS; ++iter)
        {
            inUseCards[iter]= cards.get(0);
            cards.removeElementAt(0);
        }
    }

    public void initGame()
    {
        if (initCards.isEmpty() && !saveCards.isEmpty())
        {
            initCards.addAll(saveCards);
            saveCards.clear();
            shuffleCards(initCards);
        }
        else
        {
            for (int iter = 0; iter < Card.MAX_CARDS; ++iter)
            {
                initCards.add(iter, new Card(iter));
            }
            shuffleCards(initCards);
        }
    }

    public void compute(Card [] cardSrc)
    {
        int m, n;
        int token = 0;      /* 0 --> null, 1 --> treeFir, 2 -- >  treeSec*/
        int [] cardNum = new int[NUM_CARDS];
        String [][] tmpOpr = new String[NUM_OPR_COMBINE][StructForGather24.NUM_OPR];
        int [][] tmpNum = new int[NUM_NUM_COMBINE][StructForGather24.NUM_NUM];

        for (int iter = 0; iter < NUM_CARDS; ++iter)
        {
            cardNum[iter] = cardSrc[iter].getCardValueByRanking(cardSrc[iter].getRanking());
        }

        /* 构造符号 */
        m = 0;
        for (int i = 0; i < oper.length; ++i)
        {
            for (int j = 0; j < oper.length; ++j)
            {
                tmpOpr[m] = new String[]{oper[i], oper[j], "*"};
                tmpOpr[m + 1] = new String[]{oper[i], oper[j], "/"};
                tmpOpr[m + 2] = new String[]{oper[i], oper[j],  "+"};
                tmpOpr[m + 3] = new String[]{oper[i], oper[j],  "-"};
                m += 4;
            }
        }

        /* 构造数字 */                      // 更高效的办法?????
        m = 0;
        boolean [] flag = new boolean[NUM_CARDS];
        for (int i = 0; i < StructForGather24.NUM_NUM; ++i)
        {
            flag[i] = true;
            for (int j = 0; j < StructForGather24.NUM_NUM; ++j)
            {
                if (flag[j])
                    continue;
                flag[j] = true;
                for (int k = 0; k < StructForGather24.NUM_NUM; ++k)
                {
                    if (flag[k])
                        continue;
                    flag[k] = true;
                    for (int l = 0; l < StructForGather24.NUM_NUM; ++l)
                    {
                        if (flag[l])
                            continue;
                        tmpNum[m++] = new int[]{cardNum[i], cardNum[j], cardNum[k], cardNum[l]};
                    }
                    flag[k] = false;
                }
                flag[j] = false;
            }
            flag[i] = false;
        }

        for  (m = 0, token = 0; m < NUM_NUM_COMBINE; ++m)
        {
            for  (n = 0; n < NUM_OPR_COMBINE; ++n)
            {
                treeFir = new StrFir(tmpNum[m], tmpOpr[n]);
                treeFir.computeResult();

                if (treeFir.equal24())
                {
                    token = 1;
                    break;
                }

                treeSec = new StrSec(tmpNum[m], tmpOpr[n]);
                treeSec.computeResult();

                if (treeSec.equal24())
                {
                    token = 2;
                    break;
                }
            }
            if (n < NUM_OPR_COMBINE)
            {
                break;
            }
        }

        if (token == 0)
        {
            System.out.println("无解!");
        }
        else if (token == 1)
        {
            System.out.println(treeFir.getExpression());
        }
        else 
        {
            System.out.println(treeSec.getExpression());
        }
    }

    public void exitGame()
    {
        initCards.clear();
        saveCards.clear();
    }

    public void startGame()
    {
        String [] select = new String[]{new String("Continue"), new String("Exit")};
        String choice = "continue";
        Scanner scanner = new Scanner(System.in);
        int step = 0;

        do
        {
            if (!choice.toLowerCase().equals(select[0].toLowerCase()))
            {
                System.out.println("Game over at :" + step);
                scanner.close();
                break;
            }
            if (initCards.isEmpty())
            {
                initGame();
            }

            dealCard(initCards);

            for (int iter = 0; iter < NUM_CARDS; ++iter)
            {
                System.out.print(inUseCards[iter].toString());
                if (iter != NUM_CARDS - 1)
                {
                    System.out.print(" ");
                }
                else
                {
                    System.out.print("\n");
                }
            }

            compute(inUseCards);            

            ++step;
            System.out.println("Game count:" + step);
            System.out.println("Please your select(\"continue\" or \"exit\"):");
        } while((choice = scanner.nextLine()) != null);

        exitGame();
    }
}

客户端类

在此并为提供具体的Frame实现,只提供了命令行交互实现。

package com.game.gather24;

public class StartGame
{
    public static void main(String [] args)
    {
        new Game().startGame();
    }
}

资源下载地址1https://github.com/chenchen199427/CardGame
资源下载地址2http://download.csdn.net/detail/u013201628/9824768

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值