java写的麻将小游戏
2018-02-23 23:03
369 查看
过年回家在家打麻将,觉得蛮有趣的,就用java写了一个麻将小游戏(没有界面,只能在控制台玩)。
说明:
使用语言:java(jdk1.7)
开发工具:eclipse
项目集成:maven
不能吃牌
有东西南北中发白
有癞子
可以自摸,可以放炮
其余的麻将知识请自行百度
(2) 字牌(万、条、筒)
(3)风牌(风牌没有任何成员属性)
(4) 麻将的工厂类
(注:用户输入的是2,但是上图中显示打出的牌是第三张,是由于调用discarMaJiang方法时没有减掉1,list的下标是从0开始的,现在这个bug已经被修改了,并且代码中也是正确的,但是需要重新截图比较麻烦,就没有重新截图,请见谅)
本程序的List有如下这么多:
(1)使用一个list表示整局麻将中所有的牌——名称为maJiangs;
(2)使用一个list表示“河”,用来存放所有玩家打出的牌——名称为river;
(3)每个玩家(包括3个电脑)都有一个list用来存放自己的牌——名称为playerMaJiangs;
(4)四个玩家的实例都存放在一个list中——名称为players;
(5)两粒骰子的信息都存放在一个list中——名称为dices;
本程序实现了除胡牌外的全部功能,由于胡牌比较复杂就留着以后研究。另外本程序中也有很多代码不健壮性问题,例如,当玩家之外的人打牌还没有轮到玩家自己时,此时不应该显示“起牌和打牌”选项。本游戏现在只能按照正确的流程才能进行。
本游戏没有界面,只能在控制台玩,后期需要添加上界面。本程序中的Game.java文件其实就是不断地调用其他类的方法,后期改为用户按钮点击事件再调用即可。
本程序在架构方面存在一个问题,根据开发规范,bean中只能放属性和其对应地getter、setter、构造方法、toString方法。其余的代码应该放在业务逻辑层中。虽说本程序考虑了这个问题,但是感觉还是比较混乱,后期还需要修改。
(1)系统架构的设计非常重要,严格按照开发规范进行开发非常重要;
(2)学习了简单工厂的设计模式、单例的设计模式(学习了单例,但是感觉不适用就没用了)
(3)熟练使用集合类的工具类Collections非常重要;
(4)变量和方法的命名严格按照见名知意的原则非常重要;
(5)提高代码健壮性非常重要;
说明:
使用语言:java(jdk1.7)
开发工具:eclipse
项目集成:maven
1 麻将说明
1.1 方位说明(请注意“人”这个玩家的位置)
1.2 规则说明
可以碰牌、杠牌不能吃牌
有东西南北中发白
有癞子
可以自摸,可以放炮
其余的麻将知识请自行百度
2 架构图
3 工程结构图
4 代码如下:
4.1关于麻将的bean:
(1) 麻将的父类package com.wllfengshu.bean.majiang; /** * * @author Administrator * 一切麻将类的父类 */ public class MaJiang { /** * 类型:万、条、筒: 1 2 3 * 东、南、西、北、中、发、白:4、5、6、7、8、9、10 */ private int type; public int getType() { return type; } public void setType(int type) { this.type = type; } @Override public String toString() { return "MaJiang [type=" + type + "]"; } }
(2) 字牌(万、条、筒)
package com.wllfengshu.bean.majiang; /** * * @author Administrator * 字牌的bean:包含 万、条、筒 * 1 2 3 */ public class MaJiangNumber extends MaJiang{ /** * 数字:1~9 */ private int number; public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } @Override public String toString() { String maJiangNumberStr = "["; switch (this.getType()) { case 1: maJiangNumberStr+=this.getNumber()+"万"; break; case 2: maJiangNumberStr+=this.getNumber()+"条"; break; case 3: maJiangNumberStr+=this.getNumber()+"筒"; break; } maJiangNumberStr+="]"; return maJiangNumberStr; } }
(3)风牌(风牌没有任何成员属性)
package com.wllfengshu.bean.majiang; /** * * @author Administrator * 风牌的bean:包含 东、南、西、北、中、发、白 * 1、 2、 3、 4、 5、 6、 7 */ public class MaJiangWind extends MaJiang{ @Override public String toString() { String maJiangWindStr="["; switch (this.getType()) { case 4: maJiangWindStr+="东风"; break; case 5: maJiangWindStr+="南风"; break; case 6: maJiangWindStr+="西风"; break; case 7: maJiangWindStr+="北风"; break; case 8: maJiangWindStr+="红中"; break; case 9: maJiangWindStr+="发财"; break; case 10: maJiangWindStr+="白板"; break; } maJiangWindStr+="]"; return maJiangWindStr; } }
(4) 麻将的工厂类
package com.wllfengshu.bean.majiang; /** * * @author Administrator * 麻将的工厂类,所有麻将必须通过这个类进行实例化 */ public class MaJiangFactory { /** * 通过这个方法创建一张麻将 * @param type 类型 */ public MaJiang createMaJiang(int type){ //一次只允许创建一张麻将 MaJiang maJiang=null; if (type<=3) { maJiang=new MaJiangNumber(); maJiang.setType(type); }else { maJiang=new MaJiangWind(); maJiang.setType(type); } return maJiang; } }
4.2关于骰子的bean
package com.wll 1a3f7 fengshu.bean.dice; /** * * @author Administrator * 骰子的bean */ public class Dice { /** * 骰子的点数,1~6的整数 */ private int num; public int getNum() { return num; } public void setNum(int num) { this.num = num; } @Override public String toString() { return "Dice [num=" + num + "]"; } }
4.3 关于玩家的bean(后期可以把其余的电脑也改为人来玩)
package com.wllfengshu.bean.player; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.wllfengshu.bean.majiang.MaJiang; import com.wllfengshu.bean.majiang.MaJiangNumber; import com.wllfengshu.bean.majiang.MaJiangWind; import com.wllfengshu.middleware.ShuffleMaJiang; /** * * @author Administrator * 玩家 */ public class Player { /** * 玩家姓名 */ private String name; /** * 每个玩家的牌都放在playerMaJiangs中 */ private List<MaJiang> playerMaJiangs=new ArrayList<MaJiang>(); /** * 用来指示“每个玩家的牌”在playerMaJiangs中的下标 */ private int playerMaJiangsIndex=0; public String getName() { return name; } public void setName(String name) { this.name = name; } public List<MaJiang> getPlayerMaJiangs() { return playerMaJiangs; } public void setPlayerMaJiangs(List<MaJiang> playerMaJiangs) { this.playerMaJiangs = playerMaJiangs; } @Override public String toString() { return "Player [name=" + name + "]"; } /** * 起牌:从ShuffleMaJiang中的maJiangs中取一粒麻将,放入到自己的playerMaJiangs中 * @param index “从ShuffleMaJiang中的maJiangs”获取麻将的指定的位置 */ public void gainMaJiang(int index){ //从ShuffleMaJiang中的maJiangs中取一粒麻将,放入到自己的playerMaJiangs中 playerMaJiangs.add(playerMaJiangsIndex, ShuffleMaJiang.maJiangs.get(index)); playerMaJiangsIndex++; //原来的ShuffleMaJiang的maJiangs中的牌减少这一粒 ShuffleMaJiang.maJiangs.remove(index); } /** * 打牌:从自己的playerMaJiangs中取一粒牌,放入到ShuffleMaJiang中的river中 */ public MaJiang discardMaJiang(int index){ if ((index>playerMaJiangs.size()) || (index<=0)) { System.out.println("输入的牌不存在"); return null; } //从自己的playerMaJiangs中取一粒牌,放入到ShuffleMaJiang中的river中 ShuffleMaJiang.river.add(ShuffleMaJiang.riverIndex, playerMaJiangs.get(index-1)); ShuffleMaJiang.riverIndex++; //自己的playerMaJiangs中减少这一粒牌 playerMaJiangs.remove(index); return playerMaJiangs.get(index); } /** * 输出该玩家拥有的牌 */ public void printMaJiangs(){ for (MaJiang maJiang : playerMaJiangs) { int type = maJiang.getType(); //输出字牌 if (type<=3) { MaJiangNumber maJiangNumber=(MaJiangNumber)maJiang; System.out.print(maJiangNumber+","); //输出风牌 }else { MaJiangWind maJiangWind=(MaJiangWind)maJiang; System.out.print(maJiangWind+","); } } } /** * 碰牌:河里刚打出的牌,在玩家手中有两张同样的牌,就可以碰牌 */ public void touchCards(){ //获取河里刚打出的牌 MaJiang riverLastJiang = ShuffleMaJiang.river.get(ShuffleMaJiang.riverIndex-1); //遍历自己的所有的牌,是否包含上面的牌,并且有两张 int frequency = Collections.frequency(playerMaJiangs, riverLastJiang); if (frequency>=2) { System.out.println("【碰牌成功】"); //把碰的牌移除 playerMaJiangs.remove(riverLastJiang); playerMaJiangs.remove(riverLastJiang); return; }else { System.out.println("【没有对应的两张牌,碰牌失败】"); } } /** * 杠牌:河里刚打出的牌,在玩家手中有3张同样的牌,就可以杠牌 */ public void barCards(){ //获取河里刚打出的牌 MaJiang riverLastJiang = ShuffleMaJiang.river.get(ShuffleMaJiang.riverIndex-1); //遍历自己的所有的牌,是否包含上面的牌,并且有两张 int frequency = Collections.frequency(playerMaJiangs, riverLastJiang); if (frequency>=3) { System.out.println("【杠牌成功】"); //把杠的牌移除 playerMaJiangs.remove(riverLastJiang); playerMaJiangs.remove(riverLastJiang); playerMaJiangs.remove(riverLastJiang); return; }else { System.out.println("【没有对应的三张牌,杠牌失败】"); } } /** * 胡牌:满足胡牌的规则 */ public void huCards(){ //难度较大,以后再研究 } }
4.4 洗牌
package com.wllfengshu.middleware; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.wllfengshu.bean.majiang.MaJiang; import com.wllfengshu.bean.majiang.MaJiangFactory; import com.wllfengshu.bean.majiang.MaJiangNumber; import com.wllfengshu.bean.majiang.MaJiangWind; /** * 洗牌 */ public class ShuffleMaJiang { /** * 牌局中所有的牌:使用List放所有的牌 */ public static List<MaJiang> maJiangs=new ArrayList<MaJiang>(); /** * 用来指示“牌局中所有的牌”的当前下标 */ public static int maJiangsIndex=0; /** * 河:用来存放玩家打出的牌 */ public static List<MaJiang> river=new ArrayList<MaJiang>(); /** * 用来指示“河”的当前下标 */ public static int riverIndex=0; public ShuffleMaJiang() throws InterruptedException { //创建一副麻将 createMaJiangs(); //输出此时的所有的牌 System.out.println("【初始化所有的牌:】"); printMaJiangs(0); //把初始牌打乱 chaosMaJiangs(); //输出此时的所有的牌 System.out.println("【洗牌后所有的牌:】"); printMaJiangs(0); System.out.println("【按照东南西北四个方向输出的牌(牌局里的牌):】"); printMaJiangs(1); //下标恢复 riverIndex=0; maJiangsIndex=135; } /** * 创建一副麻将 * @throws InterruptedException */ private void createMaJiangs() throws InterruptedException { //创建麻将的工厂 MaJiangFactory maJiangFactory = new MaJiangFactory(); //循环中的i用来把1到10代表的牌填入数组 for (int i = 1; i <= 10 ; i++ ) { //对万、条、筒进行填入 if (i<=3) { //循环中的j用来存字牌的数值 for (int j = 1; j <= 9; j++) { //循环中的g表示每种字牌有4张 for (int g = 1; g <= 4; g++) { MaJiangNumber maJiangNumber=(MaJiangNumber) maJiangFactory.createMaJiang(i); maJiangNumber.setNumber(j); maJiangs.add(maJiangsIndex, maJiangNumber); maJiangsIndex++; } } //对 东、南、西、北、中、发、白进行填入 }else { //循环中的g表示每种风牌有4张 for (int g = 1; g <= 4; g++) { MaJiangWind maJiangWind=(MaJiangWind) maJiangFactory.createMaJiang(i); maJiangs.add(maJiangsIndex, maJiangWind); maJiangsIndex++; } } } System.out.println(); //睡一会,显得更加逼真 Thread.sleep(100); } /** * 输出一副牌 * @param direction 0表示输出为一行,1表示按照四个方位进行输出 * @throws InterruptedException */ public void printMaJiangs(int direction) throws InterruptedException { for (int i=0;i<maJiangs.size();i++) { //以下是按照方位输出 if (direction==1) { if (i==0) { System.out.print("【桌子东方(玩家)】"); }else if(i==34){ System.out.print("\n【桌子南方(电脑)】"); }else if(i==68){ System.out.print("\n【桌子西方(电脑)】"); }else if(i==102){ System.out.print("\n【桌子北方(电脑)】"); } } MaJiang maJiangTemp=maJiangs.get(i); int type = maJiangTemp.getType(); //输出字牌 if (type<=3) { MaJiangNumber maJiangNumber=(MaJiangNumber)maJiangTemp; System.out.print(maJiangNumber+","); //输出风牌 }else { MaJiangWind maJiangWind=(MaJiangWind)maJiangTemp; System.out.print(maJiangWind+","); } } System.out.println(); //睡一会,显得更加逼真 Thread.sleep(100); } /** * 把初始牌打乱 */ private void chaosMaJiangs(){ Collections.shuffle(maJiangs); } /** * 由于第一次起牌很有可能是在整副牌的中间位置开始起牌的,然后再向后起牌。此时需要把起始位置前的牌,重新放到maJiangs中的最后,来保证整副牌的完整性 * @throws InterruptedException */ public void moveMaJiangs() throws InterruptedException{ //把开始位置前的牌复制到list的末尾 for (int i = 0; i < maJiangsIndex; i++) { maJiangs.add(maJiangs.size(),maJiangs.get(i)); } //复制后,把开始位置前的牌删除 for (int i = 0; i < maJiangsIndex; i++) { maJiangs.remove(i); } //输出移动位置后的整副牌 System.out.println("【移动位置后的整副牌:】"); printMaJiangs(0); //移动过后,起始位置变为了第一张牌,需要把下标复位 maJiangsIndex=0; } /** * 输出河里的牌 * @throws InterruptedException */ public void printMaJiangsRiver() throws InterruptedException { for (int i=0;i<river.size();i++) { MaJiang maJiangTemp=river.get(i); int type = maJiangTemp.getType(); //输出字牌 if (type<=3) { MaJiangNumber maJiangNumber=(MaJiangNumber)maJiangTemp; System.out.print(maJiangNumber+","); //输出风牌 }else { MaJiangWind maJiangWind=(MaJiangWind)maJiangTemp; System.out.print(maJiangWind+","); } } System.out.println(); //睡一会,显得更加逼真 Thread.sleep(100); } }
4.4掷骰子
package com.wllfengshu.middleware; import java.util.ArrayList; import java.util.List; import com.wllfengshu.bean.dice.Dice; /** * * @author Administrator * 掷骰子:掷两粒骰子 */ public class HurlDice { /** * 骰子的所有数据都存在里面(2粒) */ public static List<Dice> dices=new ArrayList<Dice>(); /** * 两粒骰子 */ private int dice1Num,dice2Num; /** * 方向(在哪个方位开牌) */ private int direction; /** * 指定方向中的某个位置开始起牌 */ private int place; public HurlDice() throws InterruptedException{ //创建骰子 createDices(); //打印点数 printDices(); //获取方向:在哪个方位开牌 getDirection(); //获取指定方向中的某个位置开始起牌 getPlace(); } /** * 创建两粒骰子 * @throws InterruptedException */ private void createDices() throws InterruptedException{ //实例化两粒骰子 Dice dice1=new Dice(); Dice dice2=new Dice(); //随机产生两粒骰子的点数 dice1Num=(int)(Math.random()*6+1); Thread.sleep(100);//睡一会,防止产生的两个随机数相同的几率过高 dice2Num=(int)(Math.random()*6+1); //设置第一粒骰子 dice1.setNum(dice1Num); //设置第二粒骰子 dice2.setNum(dice2Num); //把数据都存放到List中 dices.add(dice1); dices.add(dice2); } /** * 打印两粒骰子的点数 */ private void printDices(){ System.out.println("【骰子的点数:"+dice1Num+" , "+dice2Num+"】"); } /** * 获取方向:direction (在哪个方位开牌) */ private int getDirection(){ //计算在哪个方向切牌 direction=(dice1Num+dice2Num)%4; switch (direction) { case 0: System.out.println("【在东方起牌】"); break; case 1: System.out.println("【在南方起牌】"); break; case 2: System.out.println("【在西方起牌】"); break; case 3: System.out.println("【在北方起牌】"); break; } return direction; } /** * 获取指定方向中的某个位置开始起牌 */ private int getPlace(){ //计算在上述方向中的某个位置开始起牌 place=dice1Num<dice2Num?dice1Num:dice2Num; System.out.println("【起牌从距离该方向左边第"+place+"墩牌开始(一墩为两张牌)】"); return place; } /** * 计算出从整副牌的什么位置开始起牌 */ public int getStartIndex(){ //计算取牌的位置 int startIndex=direction*(136/4)+place*2; System.out.println("【从整副牌的第"+startIndex+"张开始起牌】"); return startIndex; } }
4.6初始化玩家
package com.wllfengshu.middleware; import java.util.ArrayList; import java.util.List; import com.wllfengshu.bean.player.Player; /** * * @author Administrator * 初始化玩家:创建四个玩家(包括3个电脑) */ public class InitPlayer { /** * 4个玩家的信息都存放在List中,下标为0是人,其余的为电脑 */ public static List<Player> players=new ArrayList<Player>(); private Player player=null,computer1=null,computer2=null,computer3=null; public InitPlayer() { //创建4个玩家 createPlayer(); } /** * 创建4个玩家 */ private void createPlayer(){ player = new Player(); computer1 = new Player(); computer2 = new Player(); computer3 = new Player(); player.setName("玩家"); computer1.setName("电脑1"); computer2.setName("电脑2"); computer3.setName("电脑3"); players.add(player); players.add(computer1); players.add(computer2); players.add(computer3); } /** * 输出四个玩家手中的牌 */ public void printPlayer(){ //输出当前玩家手中的牌 System.out.println("【当前玩家手中的牌如下:】"); System.out.print("【玩家】"); player.printMaJiangs(); System.out.print("\n【电脑】"); computer1.printMaJiangs(); System.out.print("\n【电脑】"); computer2.printMaJiangs(); System.out.print("\n【电脑】"); computer3.printMaJiangs(); System.out.println(); } /** * 第一次起牌:轮流起牌,每次起4张,一共起3轮 */ public void haveFirstBoard(){ //共3轮 for (int i = 0; i < 3; i++) { //玩家,每次起4张 for (int j = 0; j < 4; j++) { player.gainMaJiang(ShuffleMaJiang.maJiangsIndex); } //电脑1,每次起4张 for (int j = 0; j < 4; j++) { computer1.gainMaJiang(ShuffleMaJiang.maJiangsIndex); } //电脑2,每次起4张 for (int j = 0; j < 4; j++) { computer2.gainMaJiang(ShuffleMaJiang.maJiangsIndex); } //电脑3,每次起4张 for (int j = 0; j < 4; j++) { computer3.gainMaJiang(ShuffleMaJiang.maJiangsIndex); } } } /** * 第二次起牌:跳庄(玩家拿第1和第5张,电脑1拿第2张,电脑2拿第3张,电脑3拿第4张) */ public void haveJumpBoard(){ player.gainMaJiang(0); player.gainMaJiang(4); computer1.gainMaJiang(1); computer2.gainMaJiang(2); computer3.gainMaJiang(3); } /** * 翻癞子(癞子可以当成是任何一张牌) */ public void haveWildBoard(){ System.out.println("【癞子是:"+ShuffleMaJiang.maJiangs.get(5)+"】"); //直接移除第6张牌 ShuffleMaJiang.maJiangs.remove(5); } }
4.7 游戏类
package com.wllfengshu.game; import java.util.Scanner; import java.util.regex.Pattern; import com.wllfengshu.bean.player.Player; import com.wllfengshu.middleware.HurlDice; import com.wllfengshu.middleware.InitPlayer; import com.wllfengshu.middleware.ShuffleMaJiang; /** * * @author Administrator * 游戏:整个的游戏流程 */ public class Game { public static void main(String[] args) throws InterruptedException { @SuppressWarnings("resource") Scanner scanner=new Scanner(System.in); //初始化玩家 InitPlayer initPlayer=null; //四个玩家 Player player=null,computer1=null,computer2=null,computer3=null; //麻将 ShuffleMaJiang shuffleMaJiang=null; //骰子 HurlDice hurlDice=null; System.out.println("【欢迎开始“麻将”小游戏。请输入:[Y:开始游戏],[其他输入:退出游戏]】"); String inputStart = scanner.nextLine(); if ("Y".equalsIgnoreCase(inputStart)) { System.out.print("【开始初始化麻将桌...】"); Thread.sleep(100); //洗牌 shuffleMaJiang=new ShuffleMaJiang(); }else { System.out.println("【游戏结束,再见!】"); System.exit(0); } System.out.println("【初始化完毕,是否开始掷骰子?请输入:[Y:是],[其他输入:退出游戏]】"); String inputDice = scanner.nextLine(); if ("Y".equalsIgnoreCase(inputDice)) { //掷骰子 hurlDice=new HurlDice(); }else { System.out.println("【游戏结束,再见!】"); System.exit(0); } System.out.println("【掷骰子完毕,是否开始第一次起牌(轮流起牌,每次起4张,一共起3轮)?请输入:[Y:是],[其他输入:退出游戏]】"); String inputFirstBoard = scanner.nextLine(); if ("Y".equalsIgnoreCase(inputFirstBoard)) { //计算出从整副牌的什么位置开始起牌 int startIndex = hurlDice.getStartIndex(); //设置整副牌的开始位置 ShuffleMaJiang.maJiangsIndex=startIndex-1; //移动起始位置前的牌到list末尾 shuffleMaJiang.moveMaJiangs(); //玩家 initPlayer = new InitPlayer(); //第一次起牌 initPlayer.haveFirstBoard(); //输出此时玩家双手中的牌 initPlayer.printPlayer(); //输出牌局中的整副牌(剩余的牌) System.out.println("【此时牌局中的剩余的牌:】"); shuffleMaJiang.printMaJiangs(0); }else { System.out.println("【游戏结束,再见!】"); System.exit(0); } System.out.println("【第一次起牌完毕,是否开始跳庄(玩家拿第1和第5张,电脑1拿第2张,电脑2拿第3张,电脑3拿第4张)?请输入:[Y:是],[其他输入:退出游戏]】"); String inputJumpBoard = scanner.nextLine(); if ("Y".equalsIgnoreCase(inputJumpBoard)) { //第二次起牌:跳庄 initPlayer.haveJumpBoard(); //输出此时玩家双手中的牌 initPlayer.printPlayer(); //输出牌局中的整副牌(剩余的牌) System.out.println("【此时牌局中的剩余的牌:】"); shuffleMaJiang.printMaJiangs(0); }else { System.out.println("【游戏结束,再见!】"); System.exit(0); } System.out.println("【跳庄完毕,是否开始翻癞子(癞子可以当成是任何一张牌)?请输入:[Y:是],[其他输入:退出游戏]】"); String inputWildBoard = scanner.nextLine(); if ("Y".equalsIgnoreCase(inputWildBoard)) { //翻癞子 initPlayer.haveWildBoard(); }else { System.out.println("【游戏结束,再见!】"); System.exit(0); } System.out.println("【您是庄家,请打一张牌。请输入:[待打出牌对应的顺序,例如:1表示打出第一张牌],[非数字输入:退出游戏]】"); String inputdiscardBoard = scanner.nextLine(); Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$"); if (pattern.matcher(inputdiscardBoard).matches()) { player=initPlayer.players.get(0); computer1=initPlayer.players.get(1); computer2=initPlayer.players.get(2); computer3=initPlayer.players.get(3); //打一张牌 player.discardMaJiang(Integer.valueOf(inputdiscardBoard)-1); //输出此时玩家双手中的牌 System.out.println("【此时玩家手中的牌:】"); player.printMaJiangs(); //输出河里的牌 System.out.println("\n【河里牌:】"); shuffleMaJiang.printMaJiangsRiver(); }else { System.out.println("【游戏结束,再见!】"); System.exit(0); } //以下是正式打麻将的逻辑,还存在很多问题 while(true){ //电脑起牌 computer1.gainMaJiang(0); //电脑打出一张牌 System.out.println("【电脑打出了:"+computer1.discardMaJiang(1)+"】"); //玩家开始 System.out.println("【开始打牌:请输入:[1:起牌],[2:打牌],[3:碰牌],[4:杠牌],[5:胡牌],[6:不做操作],[其他输入:退出游戏]】"); String inputOperate = scanner.nextLine(); if (shuffleMaJiang.maJiangs.size()==0) { System.out.println("【留局】"); System.out.println("【游戏结束,再见!】"); System.exit(0); } if ("1".equals(inputOperate)) { player.gainMaJiang(0); }else if("2".equals(inputOperate)) { player.discardMaJiang(0); }else if("3".equals(inputOperate)) { player.touchCards(); }else if("4".equals(inputOperate)) { player.barCards(); }else if("5".equals(inputOperate)) { player.huCards(); }else if("6".equals(inputOperate)){ //不做处理,继续下一次 continue; }else { System.out.println("【游戏结束,再见!】"); System.exit(0); } } } }
5游戏玩法如下:
5.1是否开始游戏
5.2是否掷骰子
5.3第一轮起牌
5.4跳庄
5.5翻癞子
5.6打出一张牌
(注:用户输入的是2,但是上图中显示打出的牌是第三张,是由于调用discarMaJiang方法时没有减掉1,list的下标是从0开始的,现在这个bug已经被修改了,并且代码中也是正确的,但是需要重新截图比较麻烦,就没有重新截图,请见谅)
6 分析
麻将在洗牌完毕后的叠放是两层的,但是本程序中并没有使用二维数组,而是使用了一个List,原因之一是使用ArrayList的随机排序功能十分方便。另外,其实我们也可以把两层叠放的麻将看成是一维的,因为取牌(除庄家跳牌外)都是从上玩下的,而且这样做对于代码而言会更加方便,如下图:本程序的List有如下这么多:
(1)使用一个list表示整局麻将中所有的牌——名称为maJiangs;
(2)使用一个list表示“河”,用来存放所有玩家打出的牌——名称为river;
(3)每个玩家(包括3个电脑)都有一个list用来存放自己的牌——名称为playerMaJiangs;
(4)四个玩家的实例都存放在一个list中——名称为players;
(5)两粒骰子的信息都存放在一个list中——名称为dices;
本程序实现了除胡牌外的全部功能,由于胡牌比较复杂就留着以后研究。另外本程序中也有很多代码不健壮性问题,例如,当玩家之外的人打牌还没有轮到玩家自己时,此时不应该显示“起牌和打牌”选项。本游戏现在只能按照正确的流程才能进行。
本游戏没有界面,只能在控制台玩,后期需要添加上界面。本程序中的Game.java文件其实就是不断地调用其他类的方法,后期改为用户按钮点击事件再调用即可。
本程序在架构方面存在一个问题,根据开发规范,bean中只能放属性和其对应地getter、setter、构造方法、toString方法。其余的代码应该放在业务逻辑层中。虽说本程序考虑了这个问题,但是感觉还是比较混乱,后期还需要修改。
7 总结
总之,代码还存在许多的问题,但是通过此次开发,我学习到了如下:(1)系统架构的设计非常重要,严格按照开发规范进行开发非常重要;
(2)学习了简单工厂的设计模式、单例的设计模式(学习了单例,但是感觉不适用就没用了)
(3)熟练使用集合类的工具类Collections非常重要;
(4)变量和方法的命名严格按照见名知意的原则非常重要;
(5)提高代码健壮性非常重要;
相关文章推荐
- java写的小游戏
- 用java swing编写的雷霆战机小游戏
- java实现贪吃蛇小游戏
- java小游戏-双人五子棋小案例
- Java基础学习之Random类和Robot类及猜数小游戏
- 俄罗斯方块,我的java学习之路,小游戏
- Java太阳系小游戏分析和源代码
- java之小游戏
- java swing开发打飞机的小游戏源代码下载
- JAVA实战:一个桌球小游戏
- JAVA小游戏代码(剪刀石头布)
- 《都市摩天楼》-诺基亚经典JAVA小游戏登录iOS
- java项目实战——Java打飞机小游戏(附完整源码)
- java swing开发短小精悍的俄罗斯方块小游戏源代码下载,仅300行代码
- java小游戏第三弹 贪吃蛇
- JAVA游戏编程学习笔记(四)Java PinBall 简单弹球小游戏【1】
- 自制小游戏,(根据java书进行改进的)
- java拼图小游戏
- java实践:小游戏:猜数字、判断回文数 。
- 纪念自己编写的第一个java小游戏,飞翔小鸟