这是我的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();
}
}
}
输入正常时的界面
输入异常时的界面