Java入门第三季 7-1简易扑克牌练习

这是我的Java入门第三季 7-1简易扑克牌练习。
首先创建的类比较多,但是会更容易理解。除了Card及Player类以外,还创建了Host类GetPlayers类分别代表主人及录入数据的人员,类中分别有对应的方法。在判断输入的玩家id是否与原有玩家id重复的时候尝试使用了异常的方法(虽然还不太懂)。
具体的实现难点上面:
比较牌的大小:首先给Card类一个id属性,在牌组创建的时候从小到大给每张牌一个独一无二的id(如:方块2的id为0,梅花2的id为1,,,黑桃A的id为51),只需比较id即可,这个比起人为的判断方式,先比较数字或字母再比较花色要容易很多。
洗牌操作:首先把按顺序生成的牌组拿在手上,把第一张牌放在桌子上构成初始牌堆,拿第二张牌去插入初始牌堆,有两种方式(第一张牌的上方或第一张牌的下方),只需取[0,2)中的随机整数即可,再把这两张牌作为二代牌堆,拿第三张牌去插入二代牌堆,有三种方式(上方,中间,下方),依此类推,插完所有牌之后洗牌操作就完成了。此种洗牌方法的优势:1.不需要检查随机数是否重复;2.List中的add方法其实就是插入的操作,以上操作很容易实现。

Card类(代表卡牌)

package com.imooc;
/**
 * Card类
 * 有color,value,id 三个属性及一个静态的num
 * 重写compareTo()方法
 *
 */
public class Card implements Comparable<Card>{
    //花色
    String color;
    //字符2~10,JQKA
    String value;
    //id,用于比较牌的大小,每张牌对应唯一一个id
    int id;
    //静态属性,用于自动生成id
    static int num=0;

    public Card(String color,String value) {
        this.color = color;
        this.value = value;
        //每创建一张牌num加一,相应id也加一
        this.id = num;
        num++;
    }
    //重写compareTo()方法,只需比较id即可
    @Override
    public int compareTo(Card o) {
        // TODO Auto-generated method stub
        //id需要转换为包装类才能调用compareTo()方法
        return Integer.valueOf(this.id).compareTo(Integer.valueOf(o.id));
    }   
}

Player类(代表玩家)

package com.imooc;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Player玩家类
 * 有id,name,maxCard,cardsInHand属性
 * 有 getCard()拿牌,maxCard()整理得到最大牌,showCards()展示手牌方法
 * 重写了compareTo()方法
 */
public class Player implements Comparable<Player> {
    //设置一个id,避免混淆同名字的玩家
    int id;
    //姓名
    String name;
    //手牌List
    List<Card> cardsInHand = new ArrayList<Card>();
    //最大手牌
    Card maxCard;
    //构造函数
    public Player(int id,String name) {
        this.name = name;
        this.id = id;   
    }

    //重写compareTo方法,比较玩家手上最大的牌
    @Override
    public int compareTo(Player o) {

        return this.maxCard.compareTo(o.maxCard);
    }
    //拿牌的方法
    public void getCard(Card card) {
        cardsInHand.add(card);
    }
    //获取最大手牌的方法,先整理手牌,这样最大的那张牌则在手牌最末尾
    public void maxCard() {
        Collections.sort(cardsInHand);
        maxCard = cardsInHand.get(cardsInHand.size()-1);
        System.out.println("玩家"+name+"已选出最大的牌:"+maxCard.color+maxCard.value);
    }
    //展示手牌
    public void showCards() {
        System.out.println(name+"的手牌为:");
        for(Card card :cardsInHand) {
            System.out.print("["+card.color+card.value+"]  ");
        }
        System.out.println("");
    }

}

Host类(代表主人:负责拿牌,洗牌,发牌等操作)

package com.imooc;

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

/**
 * 创建一个主人类,表示主人
 * 属性:一个List包含所有的卡牌
 * 方法:获取所有牌的方法,洗牌的方法,按照一定规则发牌的方法,判断大小的方法
 */
public class Host {
    //创建一个牌组的List
    List<Card> cards = new ArrayList<Card>();

    //不用关心主人的其他属性,只要有牌,会干活就行
    public Host() {

    }
    /*
     * 功能:模拟主人拿出所有牌并展示
     * 实现方式:按顺序创建所有牌加入cards中并展示
     */
    public void getAllCards(){

        String[] values = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
        String[] colors = {"方块","红心","梅花","黑桃"};
        //依次取出value和color生成卡牌card加入list中,注意卡牌生成顺序为先小后大,相应的id也是从小到大,例如:方块2的id是0
        for(String value:values) {
            for(String color:colors) {
                cards.add(new Card(color,value));
            }
        }
        //展示每张牌证明牌没有问题
        System.out.println("-----------主人拿出扑克牌并展示------------");
        for(Card card:cards) {
            System.out.print(card.color+card.value);
            //最后一张牌后面为".",其他牌后面为","
            if(card.id == 51) {
                System.out.print(".");
                continue;
            }
            //每8张牌换一行
            System.out.print(",");
            if(card.id % 8 == 7)
                System.out.println();

        }
        System.out.println("");
        System.out.println("-----------牌没有问题------------");
    }
    /**
     * 功能:模拟主人洗牌
     * 实现方式:将第一张牌拿出来,第二张牌插入第一张牌构成的牌堆,有两个位置可以选择,即第一张牌的上方或者下方,随机生成{0,1}中的随机数
     * 第三张牌插入前两张牌构成的牌堆中,有三个位置可以选择,以此类推,不用担心随机数重复的情况
     */
    public void randomCards(){
        System.out.println("-----------开始洗牌------------");
        //新建一个List用来装洗牌后的牌组
        List<Card> newCards = new ArrayList<Card>();
        //将第一张牌放在新的List中
        newCards.add(cards.get(0));
        //创建一个随机数生成器
        Random random = new Random();
        //随机生成插入码,将原牌组中编号为i的牌插入新的牌组
        for(int i=1;i<cards.size();i++) {
            //生成插入码,代表插入的位置,插入的可选位置数量为新牌组卡牌数加一
            int site = random.nextInt(newCards.size()+1);
            //插入到相应位置
            newCards.add(site, cards.get(i));
        }
        cards = newCards;
        System.out.println("-----------洗牌完毕-----------");

    }
    /**
     * 按相应规则发牌
     * 
     */
    public void distributeCards(List<Player> players) {
        System.out.println("-----------开始发牌-----------");
        //牌组中牌顶的指针
        int indexCard = 0;
        //每人发两张牌
        for(int i=0;i<2;i++){
            for(Player pl:players) {
                pl.getCard(cards.get(indexCard));
                indexCard++;
            }
        }
        System.out.println("-----------发牌完毕-----------");
    }
    /**
     * 判定谁的最大牌最大的方法
     * 
     */
    public void judge(List<Player> players) {
        System.out.println("-----------主人判定大小-----------");
        Collections.sort(players);
        System.out.println("-----------判定完毕-----------");
        Player winner = players.get(players.size()-1);

        System.out.println("获胜者是:"+winner.name);
    }
}

GetPlayers类(代表录入信息的前台)

package com.imooc;

import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;

/**
 * 创建一个前台类,负责搜集玩家的资料并录入
 * 属性:玩家数n,玩家集合plays.
 * 方法:ScanName()获取名字和id的方法,判断id 是否有效的valid()方法
 */

public class GetPlayers {
    public List<Player> players = new ArrayList<Player>();
    int n;
    public GetPlayers(int n) {
        this.n = n;
    }

    //检验输入的id是否有效,当list中存在此id时抛出异常
    public void valid(int id)throws ExistIdException {

        for(Player pl:players) {
            if(id == pl.id) {
                System.out.println("-----------该id已被占用-----------");
                throw new ExistIdException();
            }       
        }
    }
    //录入玩家的姓名与id
    public void ScanName(){
        //n名玩家
        for(int i=0;i<n;i++){

            String name;
            int id;
            //一直循环直到获取到正确格式的姓名,貌似不会产生异常
            System.out.println("-----------请输入玩家姓名-----------");
            while(true) {
                //很奇怪,Scanner对象在while外面新建的话,第一次输入有误,后面就会一直自动循环,直接跳过id = input.nextInt();
                //所以每个循环里面都新建了一个Scanner对象,前面的警告'input' is never closed也不知道应该怎么处理
                Scanner input = new Scanner(System.in);

                try {
                    name = input.next();
                    break;
                }catch(InputMismatchException e){
                    System.out.println("-----------名字应为字符串-----------");
                    System.out.println("-----------请重新输入名字-----------");
                }
            }
            //一直循环直到获取到正确格式的id,且id不与玩家List中的重复 
            System.out.println("-----------请输入玩家id-----------");
            while(true) {
                Scanner input = new Scanner(System.in);
                try {
                    //nextInt()方法会触发InputMismatchException异常
                    id = input.nextInt();
                    //valid()方法会触发ExistIdException异常
                    this.valid(id);
                    break;

                }catch(InputMismatchException e){
                    System.out.println("-----------id应为整数-----------");
                    System.out.println("-----------请重新输入id-----------");
                }catch(ExistIdException e) {
                    System.out.println("-----------请重新输入id-----------");    
                }

            }
            //产生一名新玩家加入到List中
            players.add(new Player(id,name));
            System.out.println("欢迎  "+players.get(i).name);

        }
        System.out.println("-----------"+n+"位玩家已就坐-----------");    
    }   
}

ExistIdException类(自定义异常,目前还是空的,把GetPlayers类里面的所有ExistIdException换成Exception一样可以正常运行,功能待开发)

package com.imooc;

/**
 * 创建的自定义异常类,
 * 目前还不知道有啥用
 *
 */
public class ExistIdException extends Exception{

}

GameStart类(包含main函数)

package com.imooc;

public class GameStart {

    public static void main(String[] args) {
        //两名玩家
        int n = 2;
        //前台lily开始录入玩家信息
        GetPlayers lily = new GetPlayers(n);
        lily.ScanName();
        //主人tom开始拿牌,洗牌,发牌
        Host tom = new Host();
        tom.getAllCards();
        tom.randomCards();
        tom.distributeCards(lily.players);
        //玩家依次整理手牌,取出最大牌
        for(Player pl:lily.players){
            pl.maxCard();   
        }
        //主人tom判定结果
        tom.judge(lily.players);
        //玩家依次展示手牌
        for(Player pl:lily.players) {
            pl.showCards();
        }   
    }
}

输入正常时的界面
《Java入门第三季 7-1简易扑克牌练习》
输入异常时的界面
《Java入门第三季 7-1简易扑克牌练习》
《Java入门第三季 7-1简易扑克牌练习》

点赞