课程设计之Java实现简易小游戏——>《扑克牌斗牛》

在实现扑克牌斗牛项目前,我们先了解什么是斗牛?我们如何用Java实现呢??

1. 斗牛规则

斗牛规则:在纸牌斗牛规则里:大小王除外,52张牌,K最大,A最小,J,Q,K都是10点,然后点数依次排列最后A是1点。牌局开始每个人抓五张牌,玩家需要将手中三张牌10点的倍数,称为“牛”。其余的两张牌加起来算点数,去掉十位只留个位数来进行比较,如果剩下两张正好是10点,根据纸牌斗牛规则,这副牌就是“斗牛”。

2. Card类

由于我们Java语言是面向对象的语言,我们首先要做的就是将扑克牌抽象出一种类,让计算机可以读懂。那么我们该如何描述一个卡牌类呢??
在这里插入图片描述
我们发现扑克牌有点数花色之分,我们就从这个方向来定义:

public String suit;//花色
public int rank;//点数
public String rankFace;//花牌

其中比较特别的有J、Q、K、A、鬼牌,那么我们应该特殊照顾

普通牌的初始化(构造方法)如下:

//初始化2~10的牌
public Card(String suit, int rank) {
        this.suit = suit;
        this.rank = rank;
}

花牌(J、Q、K、A)鬼牌(大小王)的初始化(构造方法)如下:

 /**
     * 初始化花牌 J、Q、K、A、大小王
     * @param suit
     * @param rankFace
     */
    public Card(String suit,String rankFace,int rank) {
        this.suit = suit;
        this.face = rankFace;
        this.rank=rank;
    }

其次我们还需要对各种花色和特殊的花牌进行定义:

 public static String[] SUITS={"♥","♠","♦","♣"};
 public static String[] RANKFACES={"J","Q","K","A"};

我们为了更好的测验我们的牌,重写了一个打印方法如下:

 @Override
    public String toString() {
        if(this.suit=="BigKing"||this.suit=="SmallKing"){
            return "{"+this.suit+"}";
        }
        if(this.rankFace=="J"||this.rankFace=="Q"||this.rankFace=="K"||this.rankFace=="A"){
            return "{"+this.suit+rankFace+"}";
        }
        return "{"+this.suit+rank+"}";
    }

完整的Card类如下:

package democard;

public class Card {
    public String suit;//花色
    public int rank;//点数
    public String face;//花牌
    public static String[] SUITS={"♥","♠","♦","♣"};
    public static String[] RANKFACES={"J","Q","K","A"};

    /**
     * 初始化2~10的牌
     * @param suit
     * @param rank
     */
    public Card(String suit, int rank) {
        this.suit = suit;
        this.rank = rank;
    }

    /**
     * 初始化花牌 J、Q、K、A、大小王
     * @param suit
     * @param rankFace
     */
    public Card(String suit,String rankFace,int rank) {
        this.suit = suit;
        this.face = rankFace;
        this.rank=rank;
    }

    @Override
    public String toString() {
        if(this.suit=="BigKing"||this.suit=="SmallKing"){
            return "{"+this.suit+"}";
        }
        if(this.face=="J"||this.face=="Q"||this.face=="K"||this.face=="A"){
            return "{"+this.suit+face+"}";
        }
        return "{"+this.suit+rank+"}";
    }
}

在完成了对扑克牌的抽象定义后,我们需要对其中的玩法进行实现,我们创建一个新的类Game

3. Game类

3.1 创建一个扑克牌

 /**
     * 初始化牌
     * @return
     */
    public List<Card> createCard(){
        List<Card> cardList=new ArrayList<>();

        //2~10的牌
        for (int i = 0; i <Card.SUITS.length ; i++) {
            for (int j = 2; j <= 10; j++) {
                Card card=new Card(Card.SUITS[i],j);
                cardList.add(card);
            }
        }

        //J、Q、K
        for (int i = 0; i <Card.SUITS.length ; i++) {
            for (int j = 0; j <Card.RANKFACES.length-1; j++) {
                Card card=new Card(Card.SUITS[i],Card.RANKFACES[j],10);
                cardList.add(card);
            }
        }

        //A
        for (int i = 0; i < Card.SUITS.length; i++) {
            Card card=new Card(Card.SUITS[i],Card.RANKFACES[3],1);
            cardList.add(card);
        }

        //大小王
        Card cardBigKing=new Card("BigKing",10);
        cardList.add(cardBigKing);
        Card cardSmallKing=new Card("SmallKing",10);
        cardList.add(cardSmallKing);

        return cardList;
    }

3.2 洗牌

玩牌最重要的就是让每一张牌都成为随机的,所以此时我们要调用一个Java中提供的随机方法Random()
特别注意Random方法中的参数必须是大于0的

 Random random=new Random();

实现的逻辑:

让Random随机找一个数,让cardList数组的下标进行随机交换,最后实现洗牌的效果

public List<Card> shuffleCard(List<Card> cardList){
        Random random=new Random();
        for (int i = 0; i < cardList.size(); i++) {
            int randIndex=random.nextInt(i+1);//bound的值必须大于0
            Card tmp=cardList.get(i);
            cardList.set(i,cardList.get(randIndex));
            cardList.set(randIndex,tmp);
        }
        return cardList;
}

3.3 发牌

洗完牌后,我们要将洗过的牌发给每一位玩家,并开始游戏

我们是如何实现发牌的呢??

我们一直将牌的顶部的牌进行抽取,类似与链表中的头删,我们对其进行一定次数的头删,就可以实现将牌堆中的牌发给玩家的效果

那么我们又该如何对各位玩家的牌进行管理呢??

此时,我们创建一个二维数组,里面存放每一位玩家的手牌地址,对其访问就可以找到对应玩家的牌

public List<List<Card>> dealCard(List<Card> cardList){
        //创建一个二维数组,里面存放每一位玩家的手牌地址,实现管理所有玩家牌的效果
        List<List<Card>> hand=new ArrayList<>();
        
        //分别创建玩家一、二、三的一维数组,用于存放手牌
        List<Card> hand1=new ArrayList<>();
        List<Card> hand2=new ArrayList<>();
        List<Card> hand3=new ArrayList<>();

        //将每一位玩家的地址存储在二维数组中,实现管理效果
        hand.add(hand1);
        hand.add(hand2);
        hand.add(hand3);

        //头删,实现玩家取牌的效果
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 5; j++) {
                Card card= cardList.remove(0);
                hand.get(i).add(card);
            }
        }
        return hand;
}

3.4 展示玩家手牌

//将二维数组传递过来,即可实现查看玩家手牌的效果
public  void display(List<List<Card>> hand){
       //遍历循环打印三位玩家手牌
        for (int i = 0; i <3 ; i++) {
            System.out.println("第"+(i+1)+"个人的牌是:"+hand.get(i));
        }
}

3.5 计算各位玩家的比赛成绩

3.5.1计算每位玩家牌的总点数
 /**
     * 计算总点数
     * @param hand
     * @return
     */
    public int sumNumber(List<Card> hand){
        int sum=0;
        for (int i = 0; i < 5; i++) {
            sum+=hand.get(i).rank;
        }
        return sum;
    }
3.5.2 利用回溯算法组合出所有的牌组合

注意点: 引用类型不能直接用于计算,我们计算点数时,只要用对象调用对象成员中的成员变量即可,
这里我们的思路是先利用回溯算法将可能的组合找出来,然后利用剩下两张牌计算最后的结果,对比最优解返回
回溯算法可以在此题中给你一定的启发:组合

    /**
     * 回溯算法组合牌
     * @param cards
     * @return
     */
    public List<List<Card>> combine(List<Card> cards) {
        //res用于存放组合结果
        List<List<Card>> res = new ArrayList<>();
        //c用于存放每一组可能
        List<Card> c = new ArrayList<>();
        //5 表示总共5张牌
        //3 表示要组合的牌数
        //0 表示从0下标开始
        //c 是用于存放每一种可能的组合牌
        //res 用于管理每一种可能
        generateCombinations(5, 3, 0, c,cards,res);
        return res;
    }

    /**
     * 回溯求所有组合结果
     * @param n
     * @param k
     * @param start 开始搜索新元素的位置
     * @param c 当前已经找到的组合
     */
    private void generateCombinations(int n,int k,int start,List<Card> c,List<Card> cards,List<List<Card>> res) {
        //c.size() == k 表示已存满三张牌
        if (c.size() == k) {
            //这里需要注意java的值传递
            //此处必须使用重新创建对象的形式,否则 res 列表中存放的都是同一个引用
            res.add(new ArrayList<>(c));
            return;
        }

        //通过终止条件,进行剪枝优化,避免无效的递归
        //c中还剩 k - c.size()个空位,所以[ i ... n]中至少要有k-c.size()个元素
        //所以i最多为 n - (k - c.size())
        for(int i = start;i <= n - (k - c.size()) ; i++) {
            c.add((cards.get(i)));
            generateCombinations(n, k, i + 1, c,cards,res);
            //记得回溯状态啊
            c.remove(c.size() - 1);
        }
    }
3.5.3 找到最优解🐂
 /**
     * 找牛
     * @param res
     * @return
     */
    public  int findMaxCOw(List<List<Card>> res,int sum){
        int [] cowGroup = new int[10];
        int cow=0;
        for (int i = 0; i <10 ; i++) {
            cow=res.get(i).get(0).rank+res.get(i).get(1).rank+res.get(i).get(2).rank;
            if(cow%10==0){
                cowGroup[i]=sum-cow;
            }
        }
        int maxCow=0;
        for (int i = 0; i < cowGroup.length; i++) {
            if(cowGroup[i]>maxCow){
                maxCow=cowGroup[i]%10;
            }
            if(cowGroup[i]%10==0&&cowGroup[i]!=0){
                return 10;
            }
        }
        return maxCow;
    }

3.6 完整Game 类

package democard;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Game {

    /**
     * 初始化牌
     * @return
     */
    public List<Card> createCard(){
        List<Card> cardList=new ArrayList<>();

        //2~10的牌
        for (int i = 0; i <Card.SUITS.length ; i++) {
            for (int j = 2; j <= 10; j++) {
                Card card=new Card(Card.SUITS[i],j);
                cardList.add(card);
            }
        }

        //J、Q、K
        for (int i = 0; i <Card.SUITS.length ; i++) {
            for (int j = 0; j <Card.RANKFACES.length-1; j++) {
                Card card=new Card(Card.SUITS[i],Card.RANKFACES[j],10);
                cardList.add(card);
            }
        }

        //A
        for (int i = 0; i < Card.SUITS.length; i++) {
            Card card=new Card(Card.SUITS[i],Card.RANKFACES[3],1);
            cardList.add(card);
        }

        //大小王
        Card cardBigKing=new Card("BigKing",10);
        cardList.add(cardBigKing);
        Card cardSmallKing=new Card("SmallKing",10);
        cardList.add(cardSmallKing);

        return cardList;
    }


    /**
     * 洗牌
     * @param cardList
     * @return
     */
    public List<Card> shuffleCard(List<Card> cardList){
        Random random=new Random();
        for (int i = 0; i < cardList.size(); i++) {
            int randIndex=random.nextInt(i+1);//bound的值必须大于0
            Card tmp=cardList.get(i);
            cardList.set(i,cardList.get(randIndex));
            cardList.set(randIndex,tmp);
        }
        return cardList;
    }


    /**
     * 发牌
     * @param cardList
     * @return
     */
    public List<List<Card>> dealCard(List<Card> cardList){
        List<List<Card>> hand=new ArrayList<>();
        List<Card> hand1=new ArrayList<>();
        List<Card> hand2=new ArrayList<>();
        List<Card> hand3=new ArrayList<>();

        hand.add(hand1);
        hand.add(hand2);
        hand.add(hand3);


        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 5; j++) {
                Card card= cardList.remove(0);
                hand.get(i).add(card);
            }
        }
        return hand;
    }



    /**
     * 展示玩家手牌
     * @param hand
     */
    public void display(List<List<Card>> hand){
        for (int i = 0; i <3 ; i++) {
            System.out.println("第"+(i+1)+"个人的牌是:"+hand.get(i));
        }
    }


    /**
     * 计算总点数
     * @param hand
     * @return
     */
    public int sumNumber(List<Card> hand){
        int sum=0;
        for (int i = 0; i < 5; i++) {
            sum+=hand.get(i).rank;
        }
        return sum;
    }

    /**
     * 找牛
     * @param res
     * @return
     */
    public  int findMaxCOw(List<List<Card>> res,int sum){
        int [] cowGroup = new int[10];
        int cow=0;
        for (int i = 0; i <10 ; i++) {
            cow=res.get(i).get(0).rank+res.get(i).get(1).rank+res.get(i).get(2).rank;
            if(cow%10==0){
                cowGroup[i]=sum-cow;
            }
        }
        int maxCow=0;
        for (int i = 0; i < cowGroup.length; i++) {
            if(cowGroup[i]>maxCow){
                maxCow=cowGroup[i]%10;
            }
            if(cowGroup[i]%10==0&&cowGroup[i]!=0){
                return 10;
            }
        }
        return maxCow;
    }

    /**
     * 回溯算法组合牌
     * @param cards
     * @return
     */
    public List<List<Card>> combine(List<Card> cards) {
        //res用于存放组合结果
        List<List<Card>> res = new ArrayList<>();
        //c用于存放每一组可能
        List<Card> c = new ArrayList<>();
        generateCombinations(5, 3, 0, c,cards,res);
        return res;
    }

    /**
     * 回溯求所有组合结果
     * @param n
     * @param k
     * @param start 开始搜索新元素的位置
     * @param c 当前已经找到的组合
     */
    private void generateCombinations(int n,int k,int start,List<Card> c,List<Card> cards,List<List<Card>> res) {
        if (c.size() == k) {
            //这里需要注意java的值传递
            //此处必须使用重新创建对象的形式,否则 res 列表中存放的都是同一个引用
            res.add(new ArrayList<>(c));
            return;
        }

        //通过终止条件,进行剪枝优化,避免无效的递归
        //c中还剩 k - c.size()个空位,所以[ i ... n]中至少要有k-c.size()个元素
        //所以i最多为 n - (k - c.size())
        for(int i = start;i <= n - (k - c.size()) ; i++) {
            c.add((cards.get(i)));
            generateCombinations(n, k, i + 1, c,cards,res);
            //记得回溯状态啊
            c.remove(c.size() - 1);
        }
    }

    /**
     * 计算各位玩家的比赛成绩,并打印比赛结果
     * @param hand
     */
    public void findCow(List<List<Card>> hand){
        int maxCow1=calculate(hand,0);
        System.out.println("牛"+maxCow1);
        int maxCow2=calculate(hand,1);
        System.out.println("牛"+maxCow2);
        int maxCow3=calculate(hand,2);
        System.out.println("牛"+maxCow3);
        disPlayOutCome(maxCow1,maxCow2,maxCow3);
    }

    /**
     * 打印比赛结果
     * @param play1
     * @param play2
     * @param play3
     */
    public void disPlayOutCome(int play1,int play2,int play3){
        if(play1==play2&&play1>play3){
            System.out.println("--------------------------");
            System.out.println("|play1 and play2 victory!|");
            System.out.println("--------------------------");
            return;
        }
        if(play2==play3&&play2>play1){
            System.out.println("--------------------------");
            System.out.println("|play2 and play3 victory!|");
            System.out.println("--------------------------");
            return;
        }
        if(play1==play3&&play1>play2){
            System.out.println("--------------------------");
            System.out.println("|play1 and play3 victory!|");
            System.out.println("--------------------------");
            return;
        }
        if(play1==play2&&play1==play3){
            System.out.println("------------");
            System.out.println("|Every Draw!|");
            System.out.println("|----------|");
            return;
        }

        if(play1>play2&&play1>play3){
            System.out.println("----------------");
            System.out.println("|play1 victory|!");
            System.out.println("----------------");
        }

        if(play2>play1&&play2>play3){
            System.out.println("----------------");
            System.out.println("|play2 victory!|");
            System.out.println("----------------");
        }

        if(play3>play1&&play3>play2){
            System.out.println("----------------");
            System.out.println("|play3 victory!|");
            System.out.println("----------------");
        }
    }
}

4. Test 类

4.1 菜单打印

/**
     * 菜单展示
     */
    public static void menu() {
        System.out.println("----------------------------------");
        System.out.println("|         欢迎来到扑克牌游戏!       |");
        System.out.println("|         1.玩游戏                |");
        System.out.println("|         2.游戏规则              |");
        System.out.println("|         3.退出游戏              |");
        System.out.println("----------------------------------");
    }

    /**
     * 菜单选择
     * @param choice
     */
    public static void select(Game game,int choice){



        switch (choice){
            case 1:
                List<Card> cardList=game.createCard();//创建一副牌
                System.out.println("初始化牌:"+cardList);//初始化的牌
                List<Card> cardListByShuffled=game.shuffleCard(cardList);//洗过的牌
                System.out.println("洗过的牌:"+cardListByShuffled);
                System.out.println("======展示各玩家手牌======");
                List<List<Card>> dealByCard=game.dealCard(cardListByShuffled);
                game.display(dealByCard);
                System.out.println("=========比赛结果========");
                game.findCow(dealByCard);
                break;
            case 2:
                System.out.println("游戏规则:");
                System.out.println("三方抓牌,每人抓五张,其中三张牌和为十的倍数");
                System.out.println("被认为有'牛',若没有三张牌没有凑到十的倍数,就认为没'牛'");
                System.out.println("剩余两张牌之和个位数为多少,就是牛几");
                System.out.println("最后比谁的牛大,谁就获胜");
                System.out.println("若三方都没牛,或者牛一样大,则认为平局");
                break;
            case 3:
                System.out.println("退出游戏!!");
                System.exit(0);
        }
    }

4.2 主方法调用

public static void main(String[] args) {

        menu();
        int choice=0;
        do {
            Scanner sc = new Scanner(System.in);
            choice= sc.nextInt();
            select(choice);
        }while(choice!=0);
}

4.3 完整Test类

package democard;

import java.util.List;
import java.util.Scanner;

public class Test {

    /**
     * 菜单展示
     */
    public static void menu() {
        System.out.println("----------------------------------");
        System.out.println("|         欢迎来到扑克牌游戏!       |");
        System.out.println("|         1.玩游戏                |");
        System.out.println("|         2.游戏规则              |");
        System.out.println("|         3.退出游戏              |");
        System.out.println("----------------------------------");
    }

    /**
     * 菜单选择
     * @param choice
     */
    public static void select(Game game,int choice){

        switch (choice){
            case 1:
                List<Card> cardList=game.createCard();//创建一副牌
                System.out.println("初始化牌:"+cardList);//初始化的牌
                List<Card> cardListByShuffled=game.shuffleCard(cardList);//洗过的牌
                System.out.println("洗过的牌:"+cardListByShuffled);
                System.out.println("======展示各玩家手牌======");
                List<List<Card>> dealByCard=game.dealCard(cardListByShuffled);
                game.display(dealByCard);
                System.out.println("=========比赛结果========");
                game.findCow(dealByCard);
                break;
            case 2:
                System.out.println("游戏规则:");
                System.out.println("三方抓牌,每人抓五张,其中三张牌和为十的倍数");
                System.out.println("被认为有'牛',若没有三张牌没有凑到十的倍数,就认为没'牛'");
                System.out.println("剩余两张牌之和个位数为多少,就是牛几");
                System.out.println("最后比谁的牛大,谁就获胜");
                System.out.println("若三方都没牛,或者牛一样大,则认为平局");
                break;
            case 3:
                System.out.println("退出游戏!!");
                System.exit(0);
        }
    }
    
    public static void main(String[] args) {
        Game game=new Game();
        menu();
        int choice=0;
        do {
            Scanner sc = new Scanner(System.in);
            choice= sc.nextInt();
            select(game,choice);
        }while(choice!=0);
    }
}

5. 游戏界面(控制台)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值